diff --git a/package.json b/package.json index f6ea32c..1afa554 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@merokudao/dapp-store-registry", - "version": "0.1.100", + "version": "0.1.101", "description": "The dApp Store registry for MerokuDAO dAapp Store", "repository": { "type": "git", @@ -25,7 +25,6 @@ "access": "public" }, "dependencies": { - "@opensearch-project/opensearch": "^2.2.0", "@stdlib/nlp-porter-stemmer": "^0.0.7", "@types/json2csv": "^5.0.4", "ajv": "^8.11.2", diff --git a/src/handlers/index.ts b/src/handlers/index.ts deleted file mode 100644 index 293ebf8..0000000 --- a/src/handlers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./opensearch-handlers"; diff --git a/src/handlers/opensearch-handlers/appStoresConfig.json b/src/handlers/opensearch-handlers/appStoresConfig.json deleted file mode 100644 index 20e4aa8..0000000 --- a/src/handlers/opensearch-handlers/appStoresConfig.json +++ /dev/null @@ -1,268 +0,0 @@ -{ - "settings": { - "index": { - "number_of_shards": 2, - "number_of_replicas": 1 - }, - "analysis": { - "analyzer": { - "autocomplete": { - "tokenizer": "autocomplete_tokenizer", - "filter": ["lowercase"] - }, - "autocomplete_search": { - "tokenizer": "lowercase" - } - }, - "tokenizer": { - "autocomplete_tokenizer": { - "type": "edge_ngram", - "min_gram": 2, - "max_gram": 20, - "token_chars": ["letter", "digit"] - } - } - } - }, - "mappings": { - "properties": { - "name": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "nameKeyword": { - "type": "keyword" - }, - "description": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "url": { - "type": "text" - }, - "external_url": { - "type": "text" - }, - "images": { - "properties": { - "logo": { - "type": "keyword" - }, - "banner": { - "type": "keyword" - }, - "screenshots": { - "type": "text" - } - } - }, - "key": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "keyKeyword": { - "type": "keyword" - }, - "storeId": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "storeIdKeyword": { - "type": "keyword" - }, - "minAge": { - "type": "integer" - }, - "isForMatureAudience": { - "type": "boolean" - }, - "isSelfModerated": { - "type": "boolean" - }, - "language": { - "type": "text" - }, - "expiryDate": { - "type": "date" - }, - "whitelistedDAppIds": { - "type": "text" - }, - "bannedDAppIds": { - "type": "text" - }, - "geoRestrictions": { - "properties": { - "allowedCountries": { - "type": "text" - }, - "blockedCountries": { - "type": "text" - } - } - }, - "developer": { - "properties": { - "legalName": { - "type": "keyword" - }, - "logo": { - "type": "keyword" - }, - "website": { - "type": "keyword" - }, - "credentials": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - } - } - }, - "tags": { - "type": "text" - }, - "category": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "categoryKeyword": { - "type": "keyword" - }, - "minted": { - "type": "boolean" - }, - "ownerAddress": { - "type": "keyword" - }, - "tokenId": { - "type": "keyword" - }, - "cdn": { - "properties": { - "images": { - "properties": { - "logo": { - "type": "keyword" - }, - "banner": { - "type": "keyword" - }, - "screenshots": { - "type": "text" - } - } - } - } - }, - "githubId": { "type": "text" }, - "featuredSections": { - "type": "nested", - "properties": { - "title": { "type": "text" }, - "description": { "type": "text" }, - "key": { "type": "text" }, - "dappIds": { "type": "text" } - } - }, - "attributes": { - "type": "nested", - "properties": { - "display_type": { "type": "text" }, - "trait_type": { "type": "text" }, - "value": { "type": "text" } - } - }, - "dappsEnrich": { - "type": "nested", - "properties": { - "dappId": { "type": "text" }, - "fields": { - "properties": { - "minAge": { "type": "integer" }, - "description": { "type": "keyword" }, - "isForMatureAudience": { "type": "boolean" }, - "geoRestrictions": { - "properties": { - "allowedCountries": { - "type": "text" - }, - "blockedCountries": { - "type": "text" - } - } - }, - "tags": { "type": "text" }, - "images": { - "properties": { - "logo": { - "type": "keyword" - }, - "banner": { - "type": "keyword" - }, - "screenshots": { - "type": "nested", - "properties": { - "index": { "type": "keyword" }, - "value": { "type": "keyword" } - } - } - } - } - } - } - } - }, - "image": { "type": "text" }, - "isVerified": { - "type": "boolean" - } - } - }, - "_source": { - "autocompleteFields": [ - "name", - "storeId", - "key", - "url", - "category", - "minAge", - "isForMatureAudience", - "ownerAddress" - ], - "searchFields": [ - "name", - "description", - "url", - "images", - "key", - "minAge", - "isForMatureAudience", - "isSelfModerated", - "language", - "tags", - "category", - "geoRestrictions", - "ownerAddress", - "minted", - "cdn", - "tokenId", - "attributes", - "featuredSections", - "dappsEnrich", - "whitelistedDAppIds", - "bannedDAppIds" - ] - } -} diff --git a/src/handlers/opensearch-handlers/config.json b/src/handlers/opensearch-handlers/config.json deleted file mode 100644 index 3291f14..0000000 --- a/src/handlers/opensearch-handlers/config.json +++ /dev/null @@ -1,311 +0,0 @@ -{ - "settings": { - "index": { - "number_of_shards": 2, - "number_of_replicas": 1 - }, - "analysis": { - "analyzer": { - "autocomplete": { - "tokenizer": "autocomplete_tokenizer", - "filter": ["lowercase"] - }, - "autocomplete_search": { - "tokenizer": "lowercase" - } - }, - "tokenizer": { - "autocomplete_tokenizer": { - "type": "edge_ngram", - "min_gram": 2, - "max_gram": 20, - "token_chars": ["letter", "digit"] - } - } - } - }, - "mappings": { - "properties": { - "name": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "nameKeyword": { - "type": "keyword" - }, - "description": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "appUrl": { - "type": "text" - }, - "downloadBaseUrls": { - "type": "nested", - "properties": { - "url": { "type": "keyword" }, - "platform": { "type": "keyword" }, - "minVersion": { "type": "keyword" }, - "maxVersion": { "type": "keyword" }, - "packageId": { "type": "keyword" }, - "version": { "type": "keyword" }, - "versionCode": { "type": "keyword" }, - "screenDPI": { "type": "keyword" } - } - }, - "contracts": { - "type": "nested", - "properties": { - "address": { "type": "keyword" }, - "chainId": { "type": "keyword" } - } - }, - "images": { - "properties": { - "logo": { - "type": "keyword" - }, - "banner": { - "type": "keyword" - }, - "screenshots": { - "type": "text" - } - } - }, - "repoUrl": { - "type": "keyword" - }, - "dappId": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "dappIdKeyword": { - "type": "keyword" - }, - "minAge": { - "type": "integer" - }, - "isForMatureAudience": { - "type": "boolean" - }, - "isSelfModerated": { - "type": "boolean" - }, - "language": { - "type": "text" - }, - "version": { - "type": "keyword" - }, - "isListed": { - "type": "boolean" - }, - "listDate": { - "type": "date" - }, - "expiryDate": { - "type": "date" - }, - "availableOnPlatform": { - "type": "text" - }, - "geoRestrictions": { - "properties": { - "allowedCountries": { - "type": "text" - }, - "blockedCountries": { - "type": "text" - } - } - }, - "developer": { - "properties": { - "legalName": { - "type": "keyword" - }, - "logo": { - "type": "keyword" - }, - "website": { - "type": "keyword" - }, - "credentials": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - } - } - }, - "tags": { - "type": "text" - }, - "chains": { - "type": "text" - }, - "category": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "categoryKeyword": { - "type": "keyword" - }, - "packageId": { - "type": "keyword" - }, - "walletApiVersion": { - "type": "keyword" - }, - "subCategory": { - "type": "text" - }, - "subCategoryKeyword": { - "type": "keyword" - }, - "minted": { - "type": "boolean" - }, - "referredBy": { - "properties": { - "name": { - "type": "text" - }, - "url": { - "type": "text" - } - } - }, - "privacyPolicyUrl": { - "type": "keyword" - }, - "support": { - "properties": { - "url": { - "type": "keyword" - }, - "email": { - "type": "keyword" - } - } - }, - "metrics": { - "properties": { - "downloads": { "type": "integer" }, - "installs": { "type": "integer" }, - "uninstalls": { "type": "integer" }, - "ratingsCount": { "type": "integer" }, - "visits": { "type": "integer" }, - "impressions": { "type": "integer" }, - "rating": { "type": "double" } - } - }, - "ownerAddress": { - "type": "keyword" - }, - "tokenId": { - "type": "keyword" - }, - "cdn": { - "properties": { - "images": { - "properties": { - "logo": { - "type": "keyword" - }, - "banner": { - "type": "keyword" - }, - "screenshots": { - "type": "text" - } - } - }, - "downloadBaseUrls": { - "type": "nested", - "properties": { - "url": { "type": "keyword" }, - "platform": { "type": "keyword" }, - "minVersion": { "type": "keyword" }, - "maxVersion": { "type": "keyword" }, - "packageId": { "type": "keyword" }, - "version": { "type": "keyword" }, - "versionCode": { "type": "keyword" }, - "screenDPI": { "type": "keyword" } - } - } - } - }, - "whitelistedForStores": { - "type": "keyword" - }, - "featuredForStores": { - "type": "keyword" - }, - "attributes": { - "type": "nested", - "properties": { - "display_type": { "type": "text" }, - "trait_type": { "type": "text" }, - "value": { "type": "text" } - } - }, - "isVerified": { - "type": "boolean" - } - } - }, - "_source": { - "autocompleteFields": [ - "name", - "dappId", - "appUrl", - "category", - "minAge", - "isForMatureAudience", - "ownerAddress" - ], - "searchFields": [ - "name", - "description", - "appUrl", - "downloadBaseUrls", - "contracts", - "images", - "repoUrl", - "dappId", - "minAge", - "isForMatureAudience", - "isSelfModerated", - "isListed", - "language", - "version", - "versionCode", - "listDate", - "availableOnPlatform", - "tags", - "category", - "geoRestrictions", - "chains", - "packageId", - "walletApiVersion", - "metrics", - "ownerAddress", - "referredBy", - "minted", - "subCategory", - "cdn", - "whitelistedForStores", - "tokenId" - ] - } -} diff --git a/src/handlers/opensearch-handlers/connection.ts b/src/handlers/opensearch-handlers/connection.ts deleted file mode 100644 index c43a009..0000000 --- a/src/handlers/opensearch-handlers/connection.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Client } from "@opensearch-project/opensearch"; - -import { OpenSearchConnectionOptions } from "../../interfaces"; - -/** - * a client to interact with opensearch server - * return client - */ -export class OpensearchClient { - connection: string; - constructor(options: OpenSearchConnectionOptions) { - this.connection = options.connection; - } - public client(): Client { - return new Client({ - node: this.connection, - ssl: { - rejectUnauthorized: false - // ca: fs.readFileSync(ca_certs_path), - // You can turn off certificate verification (rejectUnauthorized: false) if you're using self-signed certificates with a hostname mismatch. - // cert: fs.readFileSync(client_cert_path), - // key: fs.readFileSync(client_key_path) - } - }); - } -} diff --git a/src/handlers/opensearch-handlers/devConfig.json b/src/handlers/opensearch-handlers/devConfig.json deleted file mode 100644 index baaed1e..0000000 --- a/src/handlers/opensearch-handlers/devConfig.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "settings": { - "index": { - "number_of_shards": 2, - "number_of_replicas": 1 - }, - "analysis": { - "analyzer": { - "autocomplete": { - "tokenizer": "autocomplete_tokenizer", - "filter": ["lowercase"] - }, - "autocomplete_search": { - "tokenizer": "lowercase" - } - }, - "tokenizer": { - "autocomplete_tokenizer": { - "type": "edge_ngram", - "min_gram": 2, - "max_gram": 20, - "token_chars": ["letter", "digit"] - } - } - } - }, - "mappings": { - "properties": { - "legalName": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "legalNameKeyword": { - "type": "keyword" - }, - "name": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "description": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "website": { - "type": "keyword" - }, - "external_url": { - "type": "keyword" - }, - "image": { - "type": "keyword" - }, - "images": { - "properties": { - "logo": { - "type": "keyword" - } - } - }, - "devId": { - "type": "text", - "analyzer": "autocomplete", - "search_analyzer": "autocomplete_search" - }, - "devIdKeyword": { - "type": "keyword" - }, - "minAge": { - "type": "integer" - }, - "expiryDate": { - "type": "date" - }, - "ownerAddress": { - "type": "keyword" - }, - "tokenId": { - "type": "keyword" - }, - "cdn": { - "properties": { - "images": { - "properties": { - "logo": { - "type": "keyword" - } - } - } - } - }, - "credentials": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "attributes": { - "type": "nested", - "properties": { - "display_type": { "type": "text" }, - "trait_type": { "type": "text" }, - "value": { "type": "text" } - } - }, - "minted": { - "type": "boolean" - }, - "listDate": { - "type": "date" - }, - "isListed": { - "type": "boolean" - } - } - }, - "_source": { - "autocompleteFields": ["legalName", "devId", "website", "ownerAddress"], - "searchFields": [ - "legalName", - "description", - "website", - "images", - "cdn", - "external_url", - "name", - "credentials", - "ownerAddress", - "minted", - "cdn", - "tokenId" - ] - } -} diff --git a/src/handlers/opensearch-handlers/index.ts b/src/handlers/opensearch-handlers/index.ts deleted file mode 100644 index abe64d0..0000000 --- a/src/handlers/opensearch-handlers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./request"; diff --git a/src/handlers/opensearch-handlers/request.ts b/src/handlers/opensearch-handlers/request.ts deleted file mode 100644 index d831a5f..0000000 --- a/src/handlers/opensearch-handlers/request.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { OpensearchClient } from "./connection"; -import { Client } from "@opensearch-project/opensearch"; -import { - AppStoreSchemaDoc, - DAppSchemaDoc, - DeveloperSchemaDoc, - OpenSearchConnectionOptions, - PaginationQuery -} from "../../interfaces"; - -export const methods = { - PUT: "PUT", - POST: "POST", - GET: "GET", - DELETE: "DELETE" -}; -export class OpensearchRequest { - opensearchClient: Client; - constructor(options: OpenSearchConnectionOptions) { - this.opensearchClient = new OpensearchClient(options).client(); - } - - /** - * will create a empty index - * add setting of cluster - * add mapping/schema of docs - * @param index name of the index - * @returns index name - */ - public async createIndex(index: string, settings: object, mappings: object) { - return this.opensearchClient.indices.create({ - index, - body: { - settings, - mappings - } - }); - } - - /** - * insert a new doc to database - * @param index index name - * @param body doc - * @returns response - */ - public async createDoc( - index: string, - body: DAppSchemaDoc | AppStoreSchemaDoc | DeveloperSchemaDoc - ) { - return this.opensearchClient.index({ - index, - body, - id: body.id, - refresh: true - }); - } - - /** - * insert multipe docs - * @param index index name - * @param body array of docs - */ - public async createBulkDoc(body: any) { - return this.opensearchClient.helpers.bulk(body); - } - - /** - * do search based on providing query - * @param index index name - * @param body query - * @returns list of docs - */ - public async search(index: string, body: PaginationQuery): Promise { - return this.opensearchClient.search({ - index, - body - }); - } - - /** - * delete a doc - * @param index index name - * @param id id of doc - * @returns response - */ - public async deleteDoc(index: string, id: string) { - return this.opensearchClient.delete({ - index, - id - }); - } - - public async removeAliasName(index: string, alias: string) { - const allIndexs = await this.opensearchClient.indices.getAlias({ - name: alias - }); - if (!allIndexs || !allIndexs.body) return; - Object.keys(allIndexs.body) - .filter(aI => aI != index) - .forEach(async aI => { - await this.opensearchClient.indices.deleteAlias({ - index: aI, - name: alias - }); - }); - return; - } - public async attachAliasName(index: string, alias: string) { - return this.opensearchClient.indices.putAlias({ index, name: alias }); - } - - /** - * insert a new doc to database - * @param index index name - * @param body doc - * @returns response - */ - public async updateDoc( - index: string, - body: DAppSchemaDoc | AppStoreSchemaDoc | DeveloperSchemaDoc - ): Promise { - const id = body.id; - delete body.id; - return this.opensearchClient.update({ - index, - id, - body: { doc: body }, - refresh: true - } as any); - } - - /** - * search for given query and return a scroll id - * this scroll id context will be remebered for q minutes - * after if call made again with the same scroll id - * then the context will be renewed for another 1m - * @param index index name - * @param body query - * @returns response - */ - public async initiateScrollSearch( - index: string, - body: PaginationQuery - ): Promise { - return this.opensearchClient.search({ - index, - body, - scroll: "30s" - }); - } - /** - * on each call return next page of scroll_id - * @param scrollId get next page result - * @returns - */ - public async scrollDocs(scrollId: string): Promise { - return this.opensearchClient.scroll({ - scroll: "1m", - scroll_id: scrollId - }); - } - - /** - * delete snapshot of scroll - * @param scrollIds scroll ids - * @returns acknowledge - */ - public async deleteScrollIds(scrollIds: string[]): Promise { - return this.opensearchClient.clearScroll({ - scroll_id: scrollIds - }); - } - - /** - * get all documents based on filters - * @param index - * @param body - * @returns - */ - public async getTotalDocsCount( - index: string, - body: PaginationQuery - ): Promise { - return this.opensearchClient.count({ - index, - body - }); - } - - /** - * update multiple docs in a single request - * @param index string - * @param body doc[] - * @returns - */ - public async updateDocs(index: string, body: any): Promise { - return this.opensearchClient.bulk({ - index, - refresh: true, - body - }); - } - - public async updateByQuery(index: string, body: any): Promise { - return this.opensearchClient.update_by_query({ index, body }); - } -} diff --git a/src/interfaces/dAppSchema.ts b/src/interfaces/dAppSchema.ts index b0a83ff..3997972 100644 --- a/src/interfaces/dAppSchema.ts +++ b/src/interfaces/dAppSchema.ts @@ -184,4 +184,7 @@ export interface DAppSchema { tokenId?: string; metrics?: object; verification?: VerificationDetails; + version?: string; + versionCode?: string; + packageId?: string; } diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 94bccc0..dc212d2 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -2,7 +2,6 @@ export * from "./dAppSchema"; export * from "./featuredSections"; export * from "./registrySchema"; export * from "./filterOptions"; -export * from "./opensearchResponse"; export * from "./dAppStoreSchema"; export * from "./reviewSchema"; export * from "./developerSchema"; diff --git a/src/interfaces/opensearchResponse.ts b/src/interfaces/opensearchResponse.ts deleted file mode 100644 index 3214b62..0000000 --- a/src/interfaces/opensearchResponse.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { DAppSchema } from "./dAppSchema"; -import { StoreSchema } from "./dAppStoreSchema"; -import { DeveloperSchema } from "./developerSchema"; - -export interface CreateIndexRes { - acknowledged: boolean; - shards_acknowledged: boolean; - index: string; -} - -export interface BulkInsertRes { - total: number; - failed: number; - retry: number; - successful: number; - noop: number; - time: number; - bytes: number; - aborted: boolean; -} - -export interface OpenSearchCompositeQuery { - bool: { - must: object[]; - must_not: object[]; - should: object[]; - filter: object[]; - }; -} - -export interface PaginationQuery { - _source?: string[]; - query: OpenSearchCompositeQuery; - from?: number; - size?: number; - sort?: object[]; - aggs?: any; -} - -export interface DAppSearchDataSchema extends DAppSchema { - tokenId?: string; - ownerAddress?: string; - metrics?: object; - featuredForStores?: string[]; -} - -export interface DAppSchemaSearch { - id: string; - index: string; - _source: DAppSearchDataSchema; -} - -export interface SearchResult { - body: { - took: number; - timed_out: boolean; - _shards: object; - _scroll_id?: string; - hits: { - total: { - value: number; - relation: string; - }; - max_score: string; - hits: DAppSchemaSearch[]; - }; - aggregations?: any; - }; -} - -export interface OpenSearchConnectionOptions { - connection: string; -} - -export interface Pagination { - page?: string; - pageCount?: number; - limit?: number; -} - -export interface StandardResponse { - status: number; - message?: string[]; - data?: object[]; - pagination?: Pagination; - scrollId?: string; -} - -export interface AddDappPayload { - name?: string; - email?: string; - accessToken?: string; - githubID?: string; - dapp: DAppSchema; - org?: string | undefined; -} - -export interface DeleteDappPayload { - name: string; - email: string; - accessToken: string; - githubID: string; - dappId: string; - org: string | undefined; -} - -export interface DocsCountResponse extends StandardResponse { - countRes: { - count: number; - dappIds: string[]; - }; -} - -export interface FinalQuery { - finalQuery: PaginationQuery; - limit: number; -} - -export interface DAppSchemaDoc extends DAppSchema { - id?: string; - nameKeyword: string; - categoryKeyword?: string; - subCategoryKeyword?: string; - dappIdKeyword: string; -} - -export interface AppStoreSchemaDoc extends StoreSchema { - id?: string; - keyKeyword: string; - categoryKeyword?: string; - storeIdKeyword: string; -} - -export interface UpdateAppStoreBulkDocs { - doc: AppStoreSchemaDoc; - update: { _index: string; _id: string }; -} - -export interface UpdateDAppSchemaBulkDocs { - doc: DAppSchemaDoc; - update: { _index: string; _id: string }; -} - -export interface DeveloperSchemaDoc extends DeveloperSchema { - id: string; - devIdKeyword: string; -} - -export interface Bucket { - key: string; - doc_count: number; - subCategory?: { - buckets: Bucket[]; - }; -} diff --git a/src/interfaces/searchOptions.ts b/src/interfaces/searchOptions.ts index 1117f34..c9251f6 100644 --- a/src/interfaces/searchOptions.ts +++ b/src/interfaces/searchOptions.ts @@ -38,15 +38,6 @@ export interface OrderParams { name?: string; } -export interface SortByOrderQuery { - _score?: { order: string }; - listDate?: { order: string }; - "metrics.rating"?: { order: string }; - "metrics.visits"?: { order: string }; - "metrics.installs"?: { order: string }; - nameKeyword?: { order: string }; -} - export interface ObjectStringValueType { [key: string]: string[] | string; } diff --git a/src/lib/index.ts b/src/lib/index.ts index 479a4d4..79c0496 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,3 +1,2 @@ export * from "./registry"; -export * from "./v1"; export * from "./dappStore"; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 1a9eae7..1878633 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,18 +1,10 @@ -import * as opensearchConfig from "../handlers/opensearch-handlers/config.json"; - -const { - _source: { autocompleteFields, searchFields } -} = opensearchConfig; import { DAppStoreSchema, StoresSchema, - OpenSearchCompositeQuery, - PaginationQuery, DappEnrichPayload, EnrichSchema, ScreenShotSchema, - DAppSchema, - FinalQuery + DAppSchema } from "../interfaces"; import storesJson from "../dappStore.json"; import registryJson from "./../registry.json"; @@ -34,20 +26,10 @@ import { DappStoreRegistry, RegistryStrategy } from "./registry"; import crypto from "crypto"; import { CategoryObject, - FilterOptionsSearch, - ObjectStringValueType, - OrderParams, - SortByOrderQuery + ObjectStringValueType } from "../interfaces/searchOptions"; const debug = Debug("@merokudao:dapp-store-registry:utils"); -const defaultBoost = process.env.DEFAULT_BOOST || "1"; -const boostScore = { - name: parseInt(process.env.BOOST_NAME || defaultBoost), - description: parseInt(process.env.BOOST_DESCRIPTION || defaultBoost), - dappId: parseInt(process.env.BOOST_DAPPID || defaultBoost), - category: parseInt(process.env.BOOST_CATEGORY || defaultBoost) -}; export class cloneable { public static deepCopy(source: T): T { @@ -71,48 +53,6 @@ export class cloneable { } } -export const recordsPerPage = 20; -export const recordsPerPageAutoComplete = 7; - -/** - * return order - * @param params - * @returns - */ -export const orderBy = (params: OrderParams) => { - const order: SortByOrderQuery[] = [{ _score: { order: "desc" } }]; - try { - params = JSON.parse(params as string); - } catch (error) { - // - } - const { - rating = null, - visits = null, - installs = null, - listDate = null, - name = null - } = params; - if (rating) { - order.push({ "metrics.rating": { order: rating } }); - } - if (visits) { - order.push({ "metrics.visits": { order: visits } }); - } - if (installs) { - order.push({ "metrics.installs": { order: installs } }); - } - - if (listDate) { - order.push({ listDate: { order: listDate } }); - } - - if (name) { - order.push({ nameKeyword: { order: name } }); - } - return order; -}; - export const validateSchema = (json: StoresSchema | DAppStoreSchema) => { let uniqueIDs: string[]; if ("title" in json) { @@ -330,205 +270,6 @@ export const getCatSubCatMapping = ( }); }; -export const searchFilters = ( - search: string, - payload: FilterOptionsSearch, - autoComplete = false -): FinalQuery => { - const query: OpenSearchCompositeQuery = { - bool: { - must: [], - must_not: [], - should: [], - filter: [] - } - }; - const { - isForMatureAudience = null, - minAge = null, - chainId = null, - language = null, - availableOnPlatform = null, - listedOnOrAfter = null, - listedOnOrBefore = null, - allowedInCountries = null, - blockedInCountries = null, - categories = [], - subCategories = [], - isListed = "true", - developer = null, - page = 1, - ownerAddress = null, - isMinted = null, - tokenIds = [], - storeKey = "", - featured = false, - whitelistedDAppIds = null, - bannedDAppIds = null - } = payload; - let { limit = recordsPerPage, dappId = "", searchById = false } = payload; - if (autoComplete && search && search.endsWith(".app")) { - searchById = true; - dappId = search.trim(); - search = ""; - query.bool.must.push({ - match: { isListed: isListed === "true" ? true : false } - }); - } - - if ( - whitelistedDAppIds && - Array.isArray(whitelistedDAppIds) && - whitelistedDAppIds.length - ) { - query.bool.filter.push({ - terms: { dappIdKeyword: whitelistedDAppIds } - }); - } - - if (bannedDAppIds && Array.isArray(bannedDAppIds) && bannedDAppIds.length) { - query.bool.must_not.push({ - terms: { dappIdKeyword: bannedDAppIds } - }); - } - - if (dappId.length && typeof dappId === "string") - dappId = dappId.split(",").map((di: string) => di.trim()); - // eslint-disable-next-line no-extra-boolean-cast - if (!!isForMatureAudience) - query.bool.must.push({ - match: { - isForMatureAudience: isForMatureAudience === "true" ? true : false - } - }); - - if (storeKey.length) - query.bool.must.push({ term: { whitelistedForStores: storeKey } }); - if (storeKey.length && featured) - query.bool.must.push({ term: { featured: storeKey } }); - else if (featured) - query.bool.must.push({ exists: { field: "featuredForStores" } }); - if (minAge) query.bool.must.push({ range: { minAge: { gte: minAge } } }); - if (chainId) query.bool.must.push({ match: { chains: chainId } }); - if (language) query.bool.must.push({ match: { language } }); - if (availableOnPlatform) - query.bool.must.push({ - terms: { availableOnPlatform } - }); - if (listedOnOrAfter) - query.bool.must.push({ range: { listDate: { gte: listedOnOrAfter } } }); - if (listedOnOrBefore) - query.bool.must.push({ range: { listDate: { lte: listedOnOrBefore } } }); - - // it should be filter users location current not more then one country - if (allowedInCountries && allowedInCountries.length) { - query.bool.should.push({ - terms: { "geoRestrictions.allowedCountries": allowedInCountries } - }); - allowedInCountries.forEach((ac: string) => { - query.bool.must_not.push({ - term: { "geoRestrictions.blockedCountries": ac } - }); - }); - } - // it should be filter users location current not more then one country - if (blockedInCountries && blockedInCountries.length) - query.bool.must.push({ - terms: { "geoRestrictions.blockedCountries": blockedInCountries } - }); - - if (developer && developer.id) - query.bool.must.push({ - match: { "developer.credentials.id": developer.id.trim() } - }); - - // create a category query with or between each category + apply subCategory filter - // category filter is must match but in case of multiple categories a doc atleast match to one category - // once a doc matched to one category it should match for subcategory if any values passed for sub category - const catSubCatMapping = getCatSubCatMapping(categories, subCategories); - if (catSubCatMapping.length) { - const categoryQuery = catSubCatMapping.map(catMapp => { - const { category, subCategory } = catMapp; - if (!subCategory.length) return { match: { category } }; - return { - bool: { - must: [ - { match: { category } }, - { terms: { subCategoryKeyword: subCategory } } - ] - } - }; - }); - query.bool.must.push({ bool: { should: categoryQuery } }); - } - - if (dappId.length) query.bool.must.push({ terms: { dappIdKeyword: dappId } }); - if (tokenIds.length) query.bool.must.push({ terms: { tokenId: tokenIds } }); - - // search on customer string - if (!!search && search.length) { - query.bool.should.push({ - match: { - name: { - query: search, - boost: boostScore.name, - fuzziness: "6", - operator: "and" - } - } - }); - query.bool.should.push({ - match: { - description: { - query: search, - boost: boostScore.description, - fuzziness: "3" - } - } - }); - query.bool.should.push({ - match: { daapId: { query: search, boost: boostScore.dappId } } - }); - query.bool.should.push({ - match: { category: { query: search, boost: boostScore.category } } - }); - query.bool.filter.push({ - term: { isListed: isListed === "true" ? true : false } - }); - // query.bool.filter.push({ term: { isVerified: true} }); - } - - if (ownerAddress) query.bool.must.push({ match: { ownerAddress } }); - - if (isMinted) - query.bool.must.push({ - match: { minted: isMinted === "true" ? true : false } - }); - - if (isListed && !searchById && !search && !ownerAddress) - query.bool.must.push({ - match: { isListed: isListed === "true" ? true : false } - }); - - // if (!ownerAddress) - // query.bool.filter.push({ term: { isVerified: true} }); - - payload.page = parseInt(page as string); - payload.page = payload.page > 0 ? payload.page : 1; - const limitV1 = autoComplete ? recordsPerPageAutoComplete : recordsPerPage; - if (limit > limitV1) limit = limitV1; - if (typeof limit === "string") limit = parseInt(limit); - const finalQuery: PaginationQuery = { - _source: autoComplete ? autocompleteFields : searchFields, - query, - from: (payload.page - 1) * limit, - size: limit, - sort: orderBy((payload.orderBy || {}) as OrderParams) - }; - - return { finalQuery, limit }; -}; - export const addNewDappEnrichDataForStore = ( data: DappEnrichPayload, currDappStores: StoresSchema, diff --git a/src/lib/v1/appStores.ts b/src/lib/v1/appStores.ts deleted file mode 100644 index d0a8e49..0000000 --- a/src/lib/v1/appStores.ts +++ /dev/null @@ -1,570 +0,0 @@ -import { format } from "date-fns"; - -import { OpensearchRequest } from "../../handlers"; -import { - _source, - mappings, - settings -} from "../../handlers/opensearch-handlers/appStoresConfig.json"; -import { - AppStoreSchemaDoc, - DocsCountResponse, - OpenSearchCompositeQuery, - OpenSearchConnectionOptions, - PaginationQuery, - SearchResult, - StandardResponse, - StoreSchema -} from "../../interfaces"; -import { orderBy, recordsPerPage, recordsPerPageAutoComplete } from "../utils"; -import { - AppStoreSearchPayload, - FilterOptionsSearch, - OrderParams -} from "../../interfaces/searchOptions"; - -const defaultBoost = process.env.DEFAULT_BOOST || "1"; -const boostScore = { - name: parseInt(process.env.BOOST_NAME || defaultBoost), - description: parseInt(process.env.BOOST_DESCRIPTION || defaultBoost), - storeId: parseInt(process.env.BOOST_APP_STORE_KEY || defaultBoost), - category: parseInt(process.env.BOOST_CATEGORY || defaultBoost) -}; -export const searchAppStore = { - indexPrefix: `${process.env.ENVIRONMENT}_app_store`, - alias: `${process.env.ENVIRONMENT}_app_store_search_index` -}; - -export const MAX_RESULT_WINDOW_APP_STORE = 10000; - -export class AppStoreRegistry { - openSearchApis: OpensearchRequest; - constructor(openSearchOptions: OpenSearchConnectionOptions) { - this.openSearchApis = new OpensearchRequest(openSearchOptions); - } - - /** - * Prepaire query for search, filters, search by id, tokens, ownerAddress - * @param search - * @param payload - * @returns - */ - private searchQuery = (search: string, payload: AppStoreSearchPayload) => { - const query: OpenSearchCompositeQuery = { - bool: { - must: [], - must_not: [], - should: [], - filter: [] - } - }; - const { - isForMatureAudience = null, - minAge = null, - language = null, - allowedInCountries = null, - blockedInCountries = null, - category = [], - isListed = "true", - developer = null, - page = 1, - searchById = false, - ownerAddress = null, - tokenIds = "", - listedOnOrAfter = null, - listedOnOrBefore = null, - isMinted = null - } = payload; - let { limit = recordsPerPage, key = "", storeId = "" } = payload; - - if (key.length && typeof key === "string") - key = key.split(",").map((di: string) => di.trim()); - - if (storeId.length && typeof storeId === "string") - storeId = storeId.split(",").map((di: string) => di.trim()); - // eslint-disable-next-line no-extra-boolean-cast - if (!!isForMatureAudience) - query.bool.must.push({ - match: { - isForMatureAudience: isForMatureAudience === "true" ? true : false - } - }); - - if (minAge) query.bool.must.push({ range: { minAge: { gte: minAge } } }); - if (language) query.bool.must.push({ match: { language } }); - if (listedOnOrAfter) - query.bool.must.push({ range: { listDate: { gte: listedOnOrAfter } } }); - if (listedOnOrBefore) - query.bool.must.push({ range: { listDate: { lte: listedOnOrBefore } } }); - - // it should be filter users location current not more then one country - if (allowedInCountries && allowedInCountries.length) { - query.bool.should.push({ - terms: { "geoRestrictions.allowedCountries": allowedInCountries } - }); - allowedInCountries.forEach((ac: string) => { - query.bool.must_not.push({ - term: { "geoRestrictions.blockedCountries": ac } - }); - }); - } - // it should be filter users location current not more then one country - if (blockedInCountries && blockedInCountries.length) - query.bool.must.push({ - terms: { "geoRestrictions.blockedCountries": blockedInCountries } - }); - - if (developer && developer.id) - query.bool.must.push({ - match: { "developer.credentials.id": developer.id.trim() } - }); - - if (key.length) query.bool.must.push({ terms: { keyKeyword: key } }); - if (storeId.length) { - query.bool.must.push({ - bool: { - should: [ - { terms: { keyKeyword: storeId } }, - { terms: { storeIdKeyword: storeId } } - ] - } - }); - } - if (tokenIds.length) - query.bool.must.push({ - terms: { - tokenId: tokenIds - .split(",") - .map((c: string) => c.trim()) - .filter((c: string) => c.length) - } - }); - - // search on customer string - if (!!search && search.length) { - query.bool.should.push({ - match: { name: { query: search, boost: boostScore.name } } - }); - query.bool.should.push({ - match: { description: { query: search, boost: boostScore.description } } - }); - query.bool.should.push({ - match: { storeId: { query: search, boost: boostScore.storeId } } - }); - query.bool.should.push({ - match: { category: { query: search, boost: boostScore.category } } - }); - query.bool.filter.push({ - term: { isListed: isListed === "true" ? true : false } - }); - // query.bool.filter.push({ term: { isVerified: true} }); - } - - if (ownerAddress) query.bool.must.push({ match: { ownerAddress } }); - - if (isMinted) - query.bool.must.push({ - match: { minted: isMinted === "true" ? true : false } - }); - if (isListed && !searchById && !search && !ownerAddress) - query.bool.must.push({ - match: { isListed: isListed === "true" ? true : false } - }); - if (category.length) - query.bool.must.push({ - terms: { - categoryKeyword: category - } - }); - - // if (!ownerAddress) - // query.bool.filter.push({ term: { isVerified: true} }); - - payload.page = parseInt(page as string); - payload.page = payload.page > 0 ? payload.page : 1; - if (limit > recordsPerPage) limit = recordsPerPage; - if (typeof limit === "string") limit = parseInt(limit); - const finalQuery: PaginationQuery = { - _source: _source.searchFields, - query, - from: (payload.page - 1) * limit, - size: limit, - sort: orderBy((payload.orderBy || {}) as OrderParams) - }; - return { finalQuery, limit }; - }; - - /** - * Preppaire query for autocomplete search - * @param search - * @param payload - * @returns - */ - private searchAutoComplete = ( - search: string, - payload: AppStoreSearchPayload - ) => { - const query: OpenSearchCompositeQuery = { - bool: { - must: [], - must_not: [], - should: [], - filter: [] - } - }; - - query.bool.should.push({ - match: { name: { query: search, fuzziness: 6, boost: boostScore.name } } - }); - query.bool.should.push({ - match: { description: { query: search, boost: boostScore.description } } - }); - query.bool.should.push({ - match: { - storeId: { query: search, fuzziness: "AUTO", boost: boostScore.storeId } - } - }); - query.bool.should.push({ - match: { category: { query: search, boost: boostScore.category } } - }); - query.bool.filter.push({ term: { isListed: true } }); - // query.bool.filter.push({ term: { isVerified: true} }); - - const finalQuery: PaginationQuery = { - _source: _source.autocompleteFields, - query, - from: 0, - size: recordsPerPageAutoComplete, - sort: orderBy((payload.orderBy || {}) as OrderParams) - }; - return { finalQuery }; - }; - - /** - * prepare payload for bulk insert - * @param index - * @returns - */ - public addBulkDocsToIndex = async ( - index: string, - appStores: StoreSchema[] = [] - ) => { - if (!appStores.length) return; - - const appStoreDocs = appStores.map(d => { - return { - id: d.storeId, - keyKeyword: d.key, - storeIdKeyword: d.storeId, - categoryKeyword: d.category, - ...d - }; - }); - const appStoreDocsBulk = { - datasource: appStoreDocs, - onDocument(doc: StoreSchema) { - return { index: { _index: index, _id: doc.storeId } }; - } - }; - return this.openSearchApis.createBulkDoc(appStoreDocsBulk); - }; - - /** - * create new search index with data from file or gitlab repo - * @returns acknowledgement - */ - public createIndex = async () => { - const indexName = `${searchAppStore.indexPrefix}_${format( - new Date(), - "yyyy-MM-dd-HH-mm-ss" - )}`; - await this.openSearchApis.createIndex(indexName, settings, mappings); - return { - status: 200, - message: ["success"], - indexName - }; - }; - - /** - * set alias to deploy a index, remove alias from old index - * @param indexName - * @returns - */ - public liveIndex = async (indexName: string) => { - // await this.addBulkDocsToIndex(indexName); - await this.openSearchApis.attachAliasName(indexName, searchAppStore.alias); - await this.openSearchApis.removeAliasName(indexName, searchAppStore.alias); - return { - status: 200, - message: ["success"], - indexName - }; - }; - - public async createDoc(appStore: StoreSchema): Promise { - /** - * have to add if any action have to do onchain - */ - await this.openSearchApis.createDoc(searchAppStore.alias, { - id: appStore.storeId, - keyKeyword: appStore.key, - storeIdKeyword: appStore.storeId, - categoryKeyword: appStore.category, - ...appStore - }); - return { - status: 200, - message: ["success"] - }; - } - - public deleteDoc = async (dappId: string): Promise => { - await this.openSearchApis.deleteDoc(searchAppStore.alias, dappId); - return { - status: 200, - message: ["success"] - }; - }; - - /** - * Performs search & filter on the dApps in the registry. This always returns the dApps - * that are listed. - * @param queryTxt The text to search for - * @param filterOpts The filter options. Defaults to `{ isListed: true}` - * @returns The filtered & sorted list of dApps - */ - public search = async ( - queryTxt: string, - filterOpts: AppStoreSearchPayload = { isListed: "true" } - ): Promise => { - const { finalQuery, limit } = this.searchQuery(queryTxt, filterOpts); - if ( - (finalQuery.from || 0) + (finalQuery.size || 0) > - MAX_RESULT_WINDOW_APP_STORE - ) - return this.maxWindowError(finalQuery, limit); - - const result: SearchResult = await this.openSearchApis.search( - searchAppStore.alias, - finalQuery - ); - const { - hits: { - hits: response, - total: { value } - } - } = result.body || { hits: { hits: [] } }; - const pageCount = Math.ceil(value / limit); - return { - status: 200, - message: ["success"], - data: response.map(rs => rs._source), - pagination: { - page: filterOpts.page as string, - limit, - pageCount - } - }; - }; - - /** - * search by dapp id - * @param queryTxt dappId - * @returns if matches return dappInfo - */ - public searchById = async (id: string): Promise => { - const { finalQuery } = this.searchQuery("", { - storeId: id, - searchById: true - }); - const result: SearchResult = await this.openSearchApis.search( - searchAppStore.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: res && res.map(rs => rs._source) - }; - }; - - public autoComplete = async ( - queryTxt: string, - filterOpts: AppStoreSearchPayload = { isListed: "true" } - ): Promise => { - const { finalQuery } = this.searchAutoComplete(queryTxt, filterOpts); - const result: SearchResult = await this.openSearchApis.search( - searchAppStore.alias, - finalQuery - ); - const { - hits: { hits: response } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: response && response.map(rs => rs._source) - }; - }; - - /** - * search by Owner Address - * @param ownerAddress dappId - * @returns if matches return dappInfo - */ - public searchOwnerAddress = async ( - ownerAddress: string - ): Promise => { - const { finalQuery } = this.searchQuery("", { - ownerAddress - }); - const result: SearchResult = await this.openSearchApis.search( - searchAppStore.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: res && res.map(rs => rs._source) - }; - }; - - /** - * update dapp to index, when new app is registered on dapp store - * @param name - * @param dapp - * @param org - * @returns acknowledge - */ - public async updateDoc(appStore: StoreSchema): Promise { - /** - * have to add if any action have to do onchain - */ - await this.openSearchApis.updateDoc(searchAppStore.alias, { - id: appStore.storeId, - keyKeyword: appStore.key, - storeIdKeyword: appStore.storeId, - categoryKeyword: appStore.category, - ...appStore - }); - return { status: 200, message: ["success"] }; - } - - /** - * retrun Error response if - * @param finalQuery quey - * @param limit limit - * @returns response - */ - private maxWindowError( - finalQuery: FilterOptionsSearch, - limit: number - ): StandardResponse { - return { - status: 400, - message: ["Error: Reached max page allowed, use filters to search"], - data: [], - pagination: { - page: finalQuery.page as string, - limit, - pageCount: (finalQuery.page as number) - 1 - } - }; - } - - /** - * call scroll docs - * @param filterOpts payload fields - * @returns - */ - public async scrollDocs( - filterOpts: AppStoreSearchPayload - ): Promise { - const { scrollId = null } = filterOpts; - let result: SearchResult; - if (scrollId) result = await this.openSearchApis.scrollDocs(scrollId); - else { - const { finalQuery } = this.searchQuery("", filterOpts); - delete finalQuery.from; - Object.assign(finalQuery, { size: filterOpts.size || 200 }); - Object.assign(finalQuery, { - _source: filterOpts._source || finalQuery._source - }); - result = await this.openSearchApis.initiateScrollSearch( - searchAppStore.alias, - finalQuery - ); - } - const { - body: { - hits: { hits: res }, - _scroll_id - } - } = result || { body: { hits: { hits: [] }, _scroll_id: null } }; - return { - status: 200, - message: ["success"], - scrollId: _scroll_id, - data: res && res.map(rs => rs._source) - }; - } - - /** - * delete scroll snapshots - * @param ids scroll ids - * @returns - */ - public async deleteScroller(ids: string[]) { - return this.openSearchApis.deleteScrollIds(ids); - } - - public async getTotalDocsCount( - filterOpts: AppStoreSearchPayload = { isListed: "true" } - ): Promise { - const { finalQuery } = this.searchQuery("", filterOpts); - delete finalQuery._source; - delete finalQuery.from; - delete finalQuery.size; - delete finalQuery.sort; - const res = await this.openSearchApis.getTotalDocsCount( - searchAppStore.alias, - finalQuery - ); - return { - status: 200, - message: ["success"], - countRes: res.body - }; - } - - /** - * update multiple docs - * @param index string - * @param body { isVerfied: true, dappId } - * @returns - */ - public async updateDocs(index: string, body: AppStoreSchemaDoc[]) { - const chunks = []; - while (body.length > 0) { - let chunk = body.splice(0, 500); - chunk = chunk.reduce((aggs: any[], doc: AppStoreSchemaDoc) => { - aggs = aggs.concat([ - { update: { _index: index, _id: doc.storeId } }, - { doc } - ]); - return aggs; - }, []); - chunks.push(chunk); - } - return Promise.allSettled( - chunks.map(chunk => this.openSearchApis.updateDocs(index, chunk)) - ); - } -} diff --git a/src/lib/v1/dev.ts b/src/lib/v1/dev.ts deleted file mode 100644 index a217d7c..0000000 --- a/src/lib/v1/dev.ts +++ /dev/null @@ -1,499 +0,0 @@ -import { format } from "date-fns"; - -import { OpensearchRequest } from "../../handlers"; -import { - _source, - settings, - mappings -} from "../../handlers/opensearch-handlers/devConfig.json"; -import { - DeveloperSchema, - DeveloperSchemaDoc, - DocsCountResponse, - OpenSearchCompositeQuery, - OpenSearchConnectionOptions, - PaginationQuery, - SearchResult, - StandardResponse -} from "../../interfaces"; -import { orderBy, recordsPerPage, recordsPerPageAutoComplete } from "../utils"; -import { - DeveloperSearchPayload, - FilterOptionsSearch, - OrderParams -} from "../../interfaces/searchOptions"; - -const defaultBoost = process.env.DEFAULT_BOOST || "1"; -const boostScore = { - name: parseInt(process.env.BOOST_NAME || defaultBoost), - description: parseInt(process.env.BOOST_DESCRIPTION || defaultBoost), - devId: parseInt(process.env.BOOST_APP_STORE_KEY || defaultBoost) -}; -export const searchDev = { - indexPrefix: `${process.env.ENVIRONMENT}_dev_nfts`, - alias: `${process.env.ENVIRONMENT}_dev_nfts_search_index` -}; - -export const MAX_RESULT_WINDOW_DEV = 10000; - -export class DevRegistry { - openSearchApis: OpensearchRequest; - constructor(openSearchOptions: OpenSearchConnectionOptions) { - this.openSearchApis = new OpensearchRequest(openSearchOptions); - } - - /** - * Prepaire query for search, filters, search by id, tokens, ownerAddress - * @param search - * @param payload - * @returns - */ - private searchQuery = (search: string, payload: DeveloperSearchPayload) => { - const query: OpenSearchCompositeQuery = { - bool: { - must: [], - must_not: [], - should: [], - filter: [] - } - }; - const { - page = 1, - // searchById = false, - ownerAddress = null, - tokenIds = "" - // listedOnOrAfter = null, - // listedOnOrBefore = null, - // isListed = "true" - } = payload; - let { limit = recordsPerPage, devId = "" } = payload; - - if (devId.length && typeof devId === "string") - devId = devId.split(",").map((di: string) => di.trim()); - // eslint-disable-next-line no-extra-boolean-cast - - // if (listedOnOrAfter) - // query.bool.must.push({ range: { listDate: { gte: listedOnOrAfter } } }); - // if (listedOnOrBefore) - // query.bool.must.push({ range: { listDate: { lte: listedOnOrBefore } } }); - - if (devId.length) query.bool.must.push({ terms: { devIdKeyword: devId } }); - if (tokenIds.length) - query.bool.must.push({ - terms: { - tokenId: tokenIds - .split(",") - .map((c: string) => c.trim()) - .filter((c: string) => c.length) - } - }); - - // search on customer string - if (!!search && search.length) { - query.bool.should.push({ - match: { name: { query: search, boost: boostScore.name } } - }); - query.bool.should.push({ - match: { description: { query: search, boost: boostScore.description } } - }); - query.bool.should.push({ - match: { devId: { query: search, boost: boostScore.devId } } - }); - // query.bool.filter.push({ - // term: { isListed: isListed === "true" ? true : false } - // }); - // query.bool.filter.push({ term: { isVerified: true} }); - } - - if (ownerAddress) query.bool.must.push({ match: { ownerAddress } }); - - // if (isListed && !searchById && !search && !ownerAddress) - // query.bool.must.push({ - // match: { isListed: isListed === "true" ? true : false } - // }); - - // if (!ownerAddress) - // query.bool.filter.push({ term: { isVerified: true} }); - - payload.page = parseInt(page as string); - payload.page = payload.page > 0 ? payload.page : 1; - if (limit > recordsPerPage) limit = recordsPerPage; - if (typeof limit === "string") limit = parseInt(limit); - const finalQuery: PaginationQuery = { - _source: _source.searchFields, - query, - from: (payload.page - 1) * limit, - size: limit, - sort: orderBy((payload.orderBy || {}) as OrderParams) - }; - return { finalQuery, limit }; - }; - - /** - * Preppaire query for autocomplete search - * @param search - * @param payload - * @returns - */ - private searchAutoComplete = ( - search: string, - payload: DeveloperSearchPayload - ) => { - const query: OpenSearchCompositeQuery = { - bool: { - must: [], - must_not: [], - should: [], - filter: [] - } - }; - - query.bool.should.push({ - match: { - legalName: { query: search, fuzziness: 6, boost: boostScore.name } - } - }); - query.bool.should.push({ - match: { description: { query: search, boost: boostScore.description } } - }); - query.bool.should.push({ - match: { - devId: { query: search, fuzziness: "AUTO", boost: boostScore.devId } - } - }); - // query.bool.filter.push({ term: { isListed: true } }); - // query.bool.filter.push({ term: { isVerified: true} }); - - const finalQuery: PaginationQuery = { - _source: _source.autocompleteFields, - query, - from: 0, - size: recordsPerPageAutoComplete, - sort: orderBy((payload.orderBy || {}) as OrderParams) - }; - return { finalQuery }; - }; - - /** - * prepare payload for bulk insert - * @param index - * @returns - */ - public addBulkDocsToIndex = async ( - index: string, - developers: DeveloperSchema[] = [] - ) => { - if (!developers.length) return; - - const appStoreDocs = developers.map(d => { - return { - id: d.devId, - devIdKeyword: d.devId, - ...d - }; - }); - const appStoreDocsBulk = { - datasource: appStoreDocs, - onDocument(doc: DeveloperSchema) { - return { index: { _index: index, _id: doc.devId } }; - } - }; - return this.openSearchApis.createBulkDoc(appStoreDocsBulk); - }; - - /** - * create new search index with data from file or gitlab repo - * @returns acknowledgement - */ - public createIndex = async () => { - const indexName = `${searchDev.indexPrefix}_${format( - new Date(), - "yyyy-MM-dd-HH-mm-ss" - )}`; - await this.openSearchApis.createIndex(indexName, settings, mappings); - return { - status: 200, - message: ["success"], - indexName - }; - }; - - /** - * set alias to deploy a index, remove alias from old index - * @param indexName - * @returns - */ - public liveIndex = async (indexName: string) => { - // await this.addBulkDocsToIndex(indexName); - await this.openSearchApis.attachAliasName(indexName, searchDev.alias); - await this.openSearchApis.removeAliasName(indexName, searchDev.alias); - return { - status: 200, - message: ["success"], - indexName - }; - }; - - public async createDoc( - developer: DeveloperSchema - ): Promise { - /** - * have to add if any action have to do onchain - */ - await this.openSearchApis.createDoc(searchDev.alias, { - id: developer.devId, - devIdKeyword: developer.devId, - ...developer - }); - return { - status: 200, - message: ["success"] - }; - } - - public deleteDoc = async (dappId: string): Promise => { - await this.openSearchApis.deleteDoc(searchDev.alias, dappId); - return { - status: 200, - message: ["success"] - }; - }; - - /** - * Performs search & filter on the dApps in the registry. This always returns the dApps - * that are listed. - * @param queryTxt The text to search for - * @param filterOpts The filter options. Defaults to `{ isListed: true}` - * @returns The filtered & sorted list of dApps - */ - public search = async ( - queryTxt: string, - filterOpts: DeveloperSearchPayload = { isListed: "true" } - ): Promise => { - const { finalQuery, limit } = this.searchQuery(queryTxt, filterOpts); - if ((finalQuery.from || 0) + (finalQuery.size || 0) > MAX_RESULT_WINDOW_DEV) - return this.maxWindowError(finalQuery, limit); - - const result: SearchResult = await this.openSearchApis.search( - searchDev.alias, - finalQuery - ); - const { - hits: { - hits: response, - total: { value } - } - } = result.body || { hits: { hits: [] } }; - const pageCount = Math.ceil(value / limit); - return { - status: 200, - message: ["success"], - data: response.map(rs => rs._source), - pagination: { - page: filterOpts.page as string, - limit, - pageCount - } - }; - }; - - /** - * search by dapp id - * @param queryTxt dappId - * @returns if matches return dappInfo - */ - public searchById = async (id: string): Promise => { - const { finalQuery } = this.searchQuery("", { - devId: id, - searchById: true - }); - const result: SearchResult = await this.openSearchApis.search( - searchDev.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: res && res.map(rs => rs._source) - }; - }; - - public autoComplete = async ( - queryTxt: string, - filterOpts: DeveloperSearchPayload = { isListed: "true" } - ): Promise => { - const { finalQuery } = this.searchAutoComplete(queryTxt, filterOpts); - const result: SearchResult = await this.openSearchApis.search( - searchDev.alias, - finalQuery - ); - const { - hits: { hits: response } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: response && response.map(rs => rs._source) - }; - }; - - /** - * search by Owner Address - * @param ownerAddress dappId - * @returns if matches return dappInfo - */ - public searchOwnerAddress = async ( - ownerAddress: string - ): Promise => { - const { finalQuery } = this.searchQuery("", { - ownerAddress - }); - const result: SearchResult = await this.openSearchApis.search( - searchDev.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: res && res.map(rs => rs._source) - }; - }; - - /** - * update dapp to index, when new app is registered on dapp store - * @param name - * @param dapp - * @param org - * @returns acknowledge - */ - public async updateDoc( - developer: DeveloperSchema - ): Promise { - /** - * have to add if any action have to do onchain - */ - await this.openSearchApis.updateDoc(searchDev.alias, { - id: developer.devId, - devIdKeyword: developer.devId, - ...developer - }); - return { status: 200, message: ["success"] }; - } - - /** - * retrun Error response if - * @param finalQuery quey - * @param limit limit - * @returns response - */ - private maxWindowError( - finalQuery: FilterOptionsSearch, - limit: number - ): StandardResponse { - return { - status: 400, - message: ["Error: Reached max page allowed, use filters to search"], - data: [], - pagination: { - page: finalQuery.page as string, - limit, - pageCount: (finalQuery.page as number) - 1 - } - }; - } - - /** - * call scroll docs - * @param filterOpts payload fields - * @returns - */ - public async scrollDocs( - filterOpts: DeveloperSearchPayload - ): Promise { - const { scrollId = null } = filterOpts; - let result: SearchResult; - if (scrollId) result = await this.openSearchApis.scrollDocs(scrollId); - else { - const { finalQuery } = this.searchQuery("", filterOpts); - delete finalQuery.from; - Object.assign(finalQuery, { size: filterOpts.size || 200 }); - Object.assign(finalQuery, { - _source: filterOpts._source || finalQuery._source - }); - result = await this.openSearchApis.initiateScrollSearch( - searchDev.alias, - finalQuery - ); - } - const { - body: { - hits: { hits: res }, - _scroll_id - } - } = result || { body: { hits: { hits: [] }, _scroll_id: null } }; - return { - status: 200, - message: ["success"], - scrollId: _scroll_id, - data: res && res.map(rs => rs._source) - }; - } - - /** - * delete scroll snapshots - * @param ids scroll ids - * @returns - */ - public async deleteScroller(ids: string[]) { - return this.openSearchApis.deleteScrollIds(ids); - } - - public async getTotalDocsCount( - filterOpts: DeveloperSearchPayload = { isListed: "true" } - ): Promise { - const { finalQuery } = this.searchQuery("", filterOpts); - delete finalQuery._source; - delete finalQuery.from; - delete finalQuery.size; - delete finalQuery.sort; - const res = await this.openSearchApis.getTotalDocsCount( - searchDev.alias, - finalQuery - ); - return { - status: 200, - message: ["success"], - countRes: res.body - }; - } - - /** - * update multiple docs - * @param index string - * @param body { isVerfied: true, dappId } - * @returns - */ - public async updateDocs(index: string, body: DeveloperSchemaDoc[]) { - const chunks = []; - while (body.length > 0) { - let chunk = body.splice(0, 500); - chunk = chunk.reduce((aggs: any[], doc: DeveloperSchemaDoc) => { - aggs = aggs.concat([ - { update: { _index: index, _id: doc.devId } }, - { doc } - ]); - return aggs; - }, []); - chunks.push(chunk); - } - return Promise.allSettled( - chunks.map(chunk => this.openSearchApis.updateDocs(index, chunk)) - ); - } -} diff --git a/src/lib/v1/index.ts b/src/lib/v1/index.ts deleted file mode 100644 index 14c2385..0000000 --- a/src/lib/v1/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./registry"; -export * from "./appStores"; -export * from "./dev"; diff --git a/src/lib/v1/registry.ts b/src/lib/v1/registry.ts deleted file mode 100644 index 37ff2f6..0000000 --- a/src/lib/v1/registry.ts +++ /dev/null @@ -1,620 +0,0 @@ -import { format } from "date-fns"; - -import { OpensearchRequest } from "../../handlers"; -import { - settings, - mappings -} from "../../handlers/opensearch-handlers/config.json"; -import { - AddDappPayload, - Bucket, - DAppSchema, - DAppSchemaDoc, - DeleteDappPayload, - DocsCountResponse, - OpenSearchConnectionOptions, - PaginationQuery, - SearchResult, - StandardResponse -} from "../../interfaces"; -import { DappStoreRegistry } from "../"; -import { searchFilters } from "../utils"; -import debug from "debug"; -import { - FilterOptionsSearch, - ObjectArrayOfStringValueType -} from "../../interfaces/searchOptions"; - -export const searchRegistry = { - indexPrefix: `${process.env.ENVIRONMENT}_dapp_registries`, - alias: `${process.env.ENVIRONMENT}_dapp_search_index` -}; - -export const MAX_RESULT_WINDOW = 10000; - -export class DappStoreRegistryV1 { - openSearchApis: OpensearchRequest; - dappStoreRegistry: DappStoreRegistry; - constructor(openSearchOptions: OpenSearchConnectionOptions) { - this.openSearchApis = new OpensearchRequest(openSearchOptions); - this.dappStoreRegistry = new DappStoreRegistry(); - } - - /** - * prepare payload for bulk insert - * @param index - * @returns - */ - public addBulkDocsToIndex = async ( - index: string, - dapps: DAppSchema[] = [] - ) => { - if (!dapps.length) return; - - const dappDocs = dapps.map(d => { - return { - id: d.dappId, - nameKeyword: d.name, - subCategoryKeyword: d.subCategory, - categoryKeyword: d.category, - dappIdKeyword: d.dappId, - ...d - } as DAppSchemaDoc; - }); - const chunks = []; - while (dappDocs.length > 0) { - const chunk = dappDocs.splice(0, 500); - const bulkChunk = { - datasource: chunk, - onDocument(doc: DAppSchemaDoc) { - return { index: { _index: index, _id: doc.id } }; - } - }; - chunks.push(bulkChunk); - } - return Promise.allSettled( - chunks.map(chunk => this.openSearchApis.createBulkDoc(chunk)) - ); - }; - - /** - * create new search index with data from file or gitlab repo - * @returns acknowledgement - */ - public createIndex = async () => { - const indexName = `${searchRegistry.indexPrefix}_${format( - new Date(), - "yyyy-MM-dd-HH-mm-ss" - )}`; - await this.openSearchApis.createIndex(indexName, settings, mappings); - return { - status: 200, - message: ["success"], - indexName - }; - }; - - /** - * set alias to deploy a index, remove alias from old index - * @param indexName - * @returns - */ - public liveIndex = async (indexName: string) => { - // await this.addBulkDocsToIndex(indexName); - await this.openSearchApis.attachAliasName(indexName, searchRegistry.alias); - await this.openSearchApis.removeAliasName(indexName, searchRegistry.alias); - return { - status: 200, - message: ["success"], - indexName - }; - }; - - /** - * Returns the list of dApps that are listed in the registry. You can optionally - * filter the results. - * @param filterOpts The filter options. Defaults to `{ isListed: true}` - * @returns The list of dApps that are listed in the registry - */ - public dApps = async ( - filterOpts: FilterOptionsSearch = { isListed: "true" } - ): Promise => { - const { finalQuery, limit } = searchFilters("", filterOpts); - - if ((finalQuery.from || 0) + (finalQuery.size || 0) > MAX_RESULT_WINDOW) - return this.maxWindowError(finalQuery, limit); - - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { - hits: response, - total: { value } - } - } = result.body || { hits: { hits: [] } }; - const pageCount = Math.ceil(value / limit); - return { - status: 200, - message: ["success"], - data: response.map(rs => rs._source), - pagination: { - page: filterOpts.page as string, - limit, - pageCount - } - }; - }; - - /** - * add new dapp to index, when new app is registered on dapp store - * @param name - * @param email - * @param accessToken - * @param githubID - * @param dapp - * @param org - * @returns acknowledge - */ - public async addOrUpdateDapp( - payload: AddDappPayload - ): Promise { - const { name, email, githubID, dapp, org = undefined } = payload; - /** - * have to add if any action have to do onchain - */ - debug( - `deleting the app, name: ${name}, email: ${email}, githubId: ${githubID}, org: ${org}` - ); - await this.openSearchApis.createDoc(searchRegistry.alias, { - id: dapp.dappId, - nameKeyword: dapp.name, - subCategoryKeyword: dapp.subCategory as string, - categoryKeyword: dapp.category, - dappIdKeyword: dapp.dappId, - ...dapp - }); - return { - status: 200, - message: ["success"] - }; - } - - /** - * delete the dapp from index, not longer exists the dapp on our dappstore kit - * @param name - * @param email - * @param accessToken - * @param githubID - * @param dappId dappId of the dapp - * @param org - * @returns acknowledgement - */ - public deleteDapp = async ( - payload: DeleteDappPayload - ): Promise => { - const { name, email, githubID, dappId, org = undefined } = payload; - /**have to write code for on chain actions*/ - debug( - `deleting the app, name: ${name}, email: ${email}, githubId: ${githubID}, org: ${org}` - ); - await this.openSearchApis.deleteDoc(searchRegistry.alias, dappId); - return { - status: 200, - message: ["success"] - }; - }; - - /** - * Performs search & filter on the dApps in the registry. This always returns the dApps - * that are listed. - * @param queryTxt The text to search for - * @param filterOpts The filter options. Defaults to `{ isListed: true}` - * @returns The filtered & sorted list of dApps - */ - public search = async ( - queryTxt: string, - filterOpts: FilterOptionsSearch = { isListed: "true" } - ): Promise => { - const { finalQuery, limit } = searchFilters(queryTxt, filterOpts); - if ((finalQuery.from || 0) + (finalQuery.size || 0) > MAX_RESULT_WINDOW) - return this.maxWindowError(finalQuery, limit); - - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { - hits: response, - total: { value } - } - } = result.body || { hits: { hits: [] } }; - const pageCount = Math.ceil(value / limit); - return { - status: 200, - message: ["success"], - data: response.map(rs => rs._source), - pagination: { - page: filterOpts.page as string, - limit, - pageCount - } - }; - }; - - /** - * search by dapp id - * @param queryTxt dappId - * @returns if matches return dappInfo - */ - public searchByDappId = async ( - queryTxt: string - ): Promise => { - const { finalQuery } = searchFilters("", { - dappId: queryTxt, - searchById: true - }); - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: res && res.map(rs => rs._source) - }; - }; - - public autoComplete = async ( - queryTxt: string, - filterOpts: FilterOptionsSearch = { isListed: "true" } - ): Promise => { - const { finalQuery } = searchFilters(queryTxt, filterOpts, true); - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { hits: response } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: response && response.map(rs => rs._source) - }; - }; - - /** - * search by Owner Address - * @param ownerAddress dappId - * @returns if matches return dappInfo - */ - public searchOwnerAddress = async ( - ownerAddress: string - ): Promise => { - const { finalQuery } = searchFilters("", { - ownerAddress - }); - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - data: res && res.map(rs => rs._source) - }; - }; - - /** - * update dapp to index, when new app is registered on dapp store - * @param name - * @param dapp - * @param org - * @returns acknowledge - */ - public async updateDapp(payload: AddDappPayload): Promise { - const { dapp } = payload; - /** - * have to add if any action have to do onchain - */ - await this.openSearchApis.updateDoc(searchRegistry.alias, { - id: dapp.dappId, - nameKeyword: dapp.name, - subCategoryKeyword: dapp.subCategory, - categoryKeyword: dapp.category, - dappIdKeyword: dapp.dappId, - ...dapp - }); - return { - status: 200, - message: ["success"] - }; - } - - /** - * retrun Error response if - * @param finalQuery quey - * @param limit limit - * @returns response - */ - private maxWindowError( - finalQuery: FilterOptionsSearch, - limit: number - ): StandardResponse { - return { - status: 400, - message: ["Error: Reached max page allowed, use filters to search"], - data: [], - pagination: { - page: finalQuery.page as string, - limit, - pageCount: (finalQuery.page as number) - 1 - } - }; - } - - /** - * call scroll docs - * @param filterOpts payload fields - * @returns - */ - public async scrollDocs( - filterOpts: FilterOptionsSearch - ): Promise { - const { scrollId = null } = filterOpts; - let result: SearchResult; - if (scrollId) result = await this.openSearchApis.scrollDocs(scrollId); - else { - const { finalQuery } = searchFilters("", filterOpts); - delete finalQuery.from; - Object.assign(finalQuery, { size: filterOpts.size || 200 }); - Object.assign(finalQuery, { - _source: filterOpts._source || finalQuery._source - }); - result = await this.openSearchApis.initiateScrollSearch( - searchRegistry.alias, - finalQuery - ); - } - const { - body: { - hits: { hits: res }, - _scroll_id - } - } = result || { body: { hits: { hits: [] }, _scroll_id: null } }; - return { - status: 200, - message: ["success"], - scrollId: _scroll_id, - data: res && res.map(rs => rs._source) - }; - } - - /** - * delete scroll snapshots - * @param ids scroll ids - * @returns - */ - public async deleteScroller(ids: string[]) { - return this.openSearchApis.deleteScrollIds(ids); - } - - public async getTotalDocsCount( - filterOpts: FilterOptionsSearch = { isListed: "true" } - ): Promise { - const { finalQuery } = searchFilters("", filterOpts); - delete finalQuery._source; - delete finalQuery.from; - delete finalQuery.size; - delete finalQuery.sort; - const res = await this.openSearchApis.getTotalDocsCount( - searchRegistry.alias, - finalQuery - ); - return { - status: 200, - message: ["success"], - countRes: res.body - }; - } - - /** - * get all dapp Ids matched for query - * @param dappId - * @returns all Matched dappIds - */ - public async getDappIDs( - dappId: string, - size = 20 - ): Promise { - const { finalQuery } = searchFilters("", { - dappId, - searchById: true - }); - Object.assign(finalQuery, { _source: ["dappId"], size, from: 0 }); - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - return { - status: 200, - message: ["success"], - countRes: { - count: res.length, - dappIds: res && res.map(rs => rs._source.dappId) - } - }; - } - - /** - * get all dapp Ids matched for query - * @param dappId - * @returns all Matched dappIds - */ - public async getFeaturedDappIDs( - storeKey: string | null - ): Promise { - const query = { featured: true }; - if (storeKey) Object.assign(query, { storeKey }); - const { finalQuery } = searchFilters("", query); - Object.assign(finalQuery, { - _source: ["dappId", "featuredForStores"], - size: 500 - }); - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { hits: res } - } = result.body || { hits: { hits: [] } }; - - // start: format featured section for all stores - const storeDappIdMapping = res.reduce( - (aggs: ObjectArrayOfStringValueType, value) => { - const { dappId, featuredForStores = [] } = value._source; - return featuredForStores.reduce( - (aggs1: ObjectArrayOfStringValueType, storeId: string) => { - aggs1[storeId] = aggs1[storeId] || []; - aggs1[storeId].push(dappId); - return aggs1; - }, - aggs - ); - }, - {} - ); - const data = Object.keys(storeDappIdMapping).map((storeId: string) => { - return { - title: `${storeId} whitelist`, - description: `A curated list of dapps.`, - dappIds: storeDappIdMapping[storeId], - key: storeId - }; - }); - // end: format feartured section for all stores - - return { - status: 200, - message: ["success"], - data - }; - } - - /** - * update multiple docs - * @param index string - * @param body { isVerfied: true, dappId } - * @returns - */ - public async updateDocs(index: string, body: DAppSchema[]) { - const chunks = []; - while (body.length > 0) { - let chunk = body.splice(0, 500); - chunk = chunk.reduce((aggs: any[], doc: DAppSchema) => { - aggs = aggs.concat([ - { update: { _index: index, _id: doc.dappId } }, - { - doc: { - nameKeyword: doc.name, - subCategoryKeyword: doc.subCategory, - categoryKeyword: doc.category, - dappIdKeyword: doc.dappId, - ...doc - } - } - ]); - return aggs; - }, []); - chunks.push(chunk); - } - return Promise.allSettled( - chunks.map(chunk => this.openSearchApis.updateDocs(index, chunk)) - ); - } - - public async updateByQuery(index: string, body: string) { - return this.openSearchApis.updateByQuery(index, body); - } - - private aggsByCatSubcat(finalQuery: PaginationQuery) { - finalQuery.aggs = { - category: { - terms: { - field: "categoryKeyword", - size: 1000 - }, - aggs: { - subCategory: { - terms: { - field: "subCategoryKeyword", - size: 1000 - } - } - } - } - }; - return finalQuery; - } - - /** - * Get dapps count based on category and subcategory - * @param filterOpts - * @returns - */ - public async getCategoriesAggs( - filterOpts: FilterOptionsSearch = { isListed: "true" } - ) { - let { finalQuery } = searchFilters("", filterOpts); - delete finalQuery.from; - delete finalQuery._source; - delete finalQuery.sort; - finalQuery.size = 0; - finalQuery = this.aggsByCatSubcat(finalQuery); - const result: SearchResult = await this.openSearchApis.search( - searchRegistry.alias, - finalQuery - ); - const { - hits: { total }, - aggregations - } = result.body; - const categories = - (aggregations.category && aggregations.category.buckets) || []; - const categoriesMap = categories - .filter((bucket: Bucket) => bucket.doc_count > 0) - .map((bucket: Bucket) => { - const { subCategory, key, doc_count } = bucket; - const filteredCategory = subCategory?.buckets.filter( - subBucket => subBucket.doc_count > 0 - ); - return { - category: key, - count: doc_count, - subCategory: filteredCategory?.map(x => x.key), - subCategoriesWithCount: filteredCategory?.map(subBucket => { - return { subCategory: subBucket.key, count: subBucket.doc_count }; - }) - }; - }); - - return { - status: 200, - message: ["success"], - total: total.value, - data: categoriesMap - }; - } -} diff --git a/yarn.lock b/yarn.lock index e00eb1c..2318b80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -356,17 +356,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@opensearch-project/opensearch@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@opensearch-project/opensearch/-/opensearch-2.2.0.tgz#2a31a67242bf3bacedc9644a0c68893eb5fb9420" - integrity sha512-E0f2Hooruz9y+17AF69oyyruikVMAEr1TxcQBNEQV4aQnI3o0+6CjqZS+t94SCZdWRTuN7HjIIVGbaYCJDpxgA== - dependencies: - aws4 "^1.11.0" - debug "^4.3.1" - hpagent "^1.2.0" - ms "^2.1.3" - secure-json-parse "^2.4.0" - "@sinclair/typebox@^0.25.16": version "0.25.23" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.23.tgz#1c15b0d2b872d89cc0f47c7243eacb447df8b8bd" @@ -1427,11 +1416,6 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -aws4@^1.11.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" - integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== - axios@*: version "1.3.3" resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.3.tgz#e7011384ba839b885007c9c9fae1ff23dceb295b" @@ -1723,7 +1707,7 @@ date-fns@^2.29.3: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== -debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: +debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2562,11 +2546,6 @@ hosted-git-info@^4.0.1: dependencies: lru-cache "^6.0.0" -hpagent@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-1.2.0.tgz#0ae417895430eb3770c03443456b8d90ca464903" - integrity sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA== - html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -3310,7 +3289,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1, ms@^2.1.3: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3909,11 +3888,6 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -secure-json-parse@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" - integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== - "semver@2 || 3 || 4 || 5", semver@^5.5.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"