feat(medusa): Migrate SearchService to TS + add SearchInterface (#1922)
This commit is contained in:
committed by
GitHub
parent
6014872a72
commit
204dd23a39
@@ -8,3 +8,4 @@ export * from "./notification-service"
|
||||
export * from "./price-selection-strategy"
|
||||
export * from "./models/base-entity"
|
||||
export * from "./models/soft-deletable-entity"
|
||||
export * from "./search-service"
|
||||
|
||||
127
packages/medusa/src/interfaces/search-service.ts
Normal file
127
packages/medusa/src/interfaces/search-service.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { TransactionBaseService } from "./transaction-base-service"
|
||||
import { SearchService } from "medusa-interfaces"
|
||||
|
||||
export interface ISearchService<T extends TransactionBaseService<never>> {
|
||||
options: Record<string, unknown>
|
||||
|
||||
/**
|
||||
* Used to create an index
|
||||
* @param indexName the index name
|
||||
* @param options the options
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
createIndex(indexName: string, options: unknown): unknown
|
||||
|
||||
/**
|
||||
* Used to get an index
|
||||
* @param indexName - the index name.
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
getIndex(indexName: string): unknown
|
||||
|
||||
/**
|
||||
* Used to index documents by the search engine provider
|
||||
* @param indexName the index name
|
||||
* @param documents documents array to be indexed
|
||||
* @param type of documents to be added (e.g: products, regions, orders, etc)
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
addDocuments(indexName: string, documents: unknown, type: string): unknown
|
||||
|
||||
/**
|
||||
* Used to replace documents
|
||||
* @param indexName the index name.
|
||||
* @param documents array of document objects that will replace existing documents
|
||||
* @param type type of documents to be replaced (e.g: products, regions, orders, etc)
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
replaceDocuments(indexName: string, documents: unknown, type: string): unknown
|
||||
|
||||
/**
|
||||
* Used to delete document
|
||||
* @param indexName the index name
|
||||
* @param document_id the id of the document
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
deleteDocument(indexName: string, document_id: string | number): unknown
|
||||
|
||||
/**
|
||||
* Used to delete all documents
|
||||
* @param indexName the index name
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
deleteAllDocuments(indexName: string): unknown
|
||||
|
||||
/**
|
||||
* Used to search for a document in an index
|
||||
* @param indexName the index name
|
||||
* @param query the search query
|
||||
* @param options
|
||||
* - any options passed to the request object other than the query and indexName
|
||||
* - additionalOptions contain any provider specific options
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
search(indexName: string, query: string | null, options: unknown): unknown
|
||||
|
||||
/**
|
||||
* Used to update the settings of an index
|
||||
* @param indexName the index name
|
||||
* @param settings settings object
|
||||
* @return returns response from search engine provider
|
||||
*/
|
||||
updateSettings(indexName: string, settings: unknown): unknown
|
||||
}
|
||||
|
||||
export abstract class AbstractSearchService<
|
||||
T extends TransactionBaseService<never>
|
||||
>
|
||||
extends TransactionBaseService<T>
|
||||
implements ISearchService<T>
|
||||
{
|
||||
abstract readonly isDefault
|
||||
protected readonly options_: Record<string, unknown>
|
||||
|
||||
get options(): Record<string, unknown> {
|
||||
return this.options_
|
||||
}
|
||||
|
||||
protected constructor(container, options) {
|
||||
super(container, options)
|
||||
this.options_ = options
|
||||
}
|
||||
|
||||
abstract createIndex(indexName: string, options: unknown): unknown
|
||||
|
||||
abstract getIndex(indexName: string): unknown
|
||||
|
||||
abstract addDocuments(
|
||||
indexName: string,
|
||||
documents: unknown,
|
||||
type: string
|
||||
): unknown
|
||||
|
||||
abstract replaceDocuments(
|
||||
indexName: string,
|
||||
documents: unknown,
|
||||
type: string
|
||||
): unknown
|
||||
|
||||
abstract deleteDocument(
|
||||
indexName: string,
|
||||
document_id: string | number
|
||||
): unknown
|
||||
|
||||
abstract deleteAllDocuments(indexName: string): unknown
|
||||
|
||||
abstract search(
|
||||
indexName: string,
|
||||
query: string | null,
|
||||
options: unknown
|
||||
): unknown
|
||||
|
||||
abstract updateSettings(indexName: string, settings: unknown): unknown
|
||||
}
|
||||
|
||||
export function isSearchService(obj: unknown): boolean {
|
||||
return obj instanceof AbstractSearchService || obj instanceof SearchService
|
||||
}
|
||||
@@ -1,37 +1,37 @@
|
||||
import glob from "glob"
|
||||
import { aliasTo, asClass, asFunction, asValue } from "awilix"
|
||||
import { Express } from "express"
|
||||
import { EntitySchema } from "typeorm"
|
||||
import fs from "fs"
|
||||
import { sync as existsSync } from "fs-exists-cached"
|
||||
import glob from "glob"
|
||||
import _ from "lodash"
|
||||
import { createRequireFromPath } from "medusa-core-utils"
|
||||
import {
|
||||
BaseService as LegacyBaseService,
|
||||
PaymentService,
|
||||
FulfillmentService,
|
||||
FileService,
|
||||
FulfillmentService,
|
||||
OauthService,
|
||||
SearchService,
|
||||
PaymentService,
|
||||
} from "medusa-interfaces"
|
||||
import { createRequireFromPath } from "medusa-core-utils"
|
||||
import _ from "lodash"
|
||||
import path from "path"
|
||||
import fs from "fs"
|
||||
import { asValue, asClass, asFunction, aliasTo } from "awilix"
|
||||
import { sync as existsSync } from "fs-exists-cached"
|
||||
import { EntitySchema } from "typeorm"
|
||||
import {
|
||||
AbstractTaxService,
|
||||
isBatchJobStrategy,
|
||||
isFileService,
|
||||
isNotificationService,
|
||||
isPriceSelectionStrategy,
|
||||
isSearchService,
|
||||
isTaxCalculationStrategy,
|
||||
TransactionBaseService as BaseService,
|
||||
isNotificationService,
|
||||
isBatchJobStrategy,
|
||||
isPriceSelectionStrategy,
|
||||
} from "../interfaces"
|
||||
import formatRegistrationName from "../utils/format-registration-name"
|
||||
import { MiddlewareService } from "../services"
|
||||
import {
|
||||
ClassConstructor,
|
||||
ConfigModule,
|
||||
Logger,
|
||||
MedusaContainer,
|
||||
} from "../types/global"
|
||||
import { MiddlewareService } from "../services"
|
||||
import formatRegistrationName from "../utils/format-registration-name"
|
||||
import logger from "./logger"
|
||||
|
||||
type Options = {
|
||||
@@ -418,7 +418,7 @@ export async function registerServices(
|
||||
),
|
||||
[`fileService`]: aliasTo(name),
|
||||
})
|
||||
} else if (loaded.prototype instanceof SearchService) {
|
||||
} else if (isSearchService(loaded.prototype)) {
|
||||
// Add the service directly to the container in order to make simple
|
||||
// resolution if we already know which search provider we need to use
|
||||
container.register({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MedusaContainer } from "../types/global"
|
||||
import DefaultSearchService from "../services/search"
|
||||
import { Logger } from "../types/global"
|
||||
import { EventBusService } from "../services"
|
||||
import { AbstractSearchService } from "../interfaces"
|
||||
|
||||
export const SEARCH_INDEX_EVENT = "SEARCH_INDEX_EVENT"
|
||||
|
||||
@@ -21,7 +21,8 @@ export default async ({
|
||||
}: {
|
||||
container: MedusaContainer
|
||||
}): Promise<void> => {
|
||||
const searchService = container.resolve<DefaultSearchService>("searchService")
|
||||
const searchService =
|
||||
container.resolve<AbstractSearchService<never>>("searchService")
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
if (searchService.isDefault) {
|
||||
logger.warn(
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import { SearchService } from "medusa-interfaces"
|
||||
|
||||
/**
|
||||
* Default class that implements SearchService but provides stuv implementation for all methods
|
||||
* @extends SearchService
|
||||
*/
|
||||
class DefaultSearchService extends SearchService {
|
||||
constructor(container, options) {
|
||||
super()
|
||||
|
||||
this.isDefault = true
|
||||
|
||||
this.logger_ = container.logger
|
||||
this.options_ = options
|
||||
}
|
||||
|
||||
get options() {
|
||||
return this.options_
|
||||
}
|
||||
|
||||
createIndex(indexName, options) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: createIndex must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
getIndex(indexName) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: getIndex must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
addDocuments(indexName, documents, type) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: addDocuments must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
replaceDocuments(indexName, documents, type) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: replaceDocuments must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
deleteDocument(indexName, document_id) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: deleteDocument must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
deleteAllDocuments(indexName) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: deleteAllDocuments must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
search(indexName, query, options) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: search must be overridden a the child class"
|
||||
)
|
||||
return { hits: [] }
|
||||
}
|
||||
|
||||
updateSettings(indexName, settings) {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: updateSettings must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default DefaultSearchService
|
||||
83
packages/medusa/src/services/search.ts
Normal file
83
packages/medusa/src/services/search.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { EntityManager } from "typeorm"
|
||||
import { AbstractSearchService } from "../interfaces/search-service"
|
||||
import { Logger } from "../types/global"
|
||||
|
||||
type InjectedDependencies = {
|
||||
logger: Logger
|
||||
manager: EntityManager
|
||||
}
|
||||
|
||||
export default class DefaultSearchService extends AbstractSearchService<DefaultSearchService> {
|
||||
isDefault = true
|
||||
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager | undefined
|
||||
protected readonly logger_: Logger
|
||||
protected readonly options_: Record<string, unknown>
|
||||
|
||||
constructor({ logger, manager }: InjectedDependencies, options) {
|
||||
super(
|
||||
{
|
||||
logger,
|
||||
},
|
||||
options
|
||||
)
|
||||
|
||||
this.options_ = options
|
||||
this.logger_ = logger
|
||||
this.manager_ = manager
|
||||
}
|
||||
|
||||
createIndex(indexName: string, options: unknown): void {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: createIndex must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
getIndex(indexName: string): void {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: getIndex must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
addDocuments(indexName: string, documents: unknown, type: string): void {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: addDocuments must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
replaceDocuments(indexName: string, documents: unknown, type: string): void {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: replaceDocuments must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
deleteDocument(indexName: string, document_id: string | number): void {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: deleteDocument must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
deleteAllDocuments(indexName: string): void {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: deleteAllDocuments must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
|
||||
search(
|
||||
indexName: string,
|
||||
query: unknown,
|
||||
options: unknown
|
||||
): { hits: unknown[] } {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: search must be overridden a the child class"
|
||||
)
|
||||
return { hits: [] }
|
||||
}
|
||||
|
||||
updateSettings(indexName: string, settings: unknown): void {
|
||||
this.logger_.warn(
|
||||
"This is an empty method: updateSettings must be overridden by a child class"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,17 @@ import { SEARCH_INDEX_EVENT } from "../loaders/search-index"
|
||||
import ProductService from "../services/product"
|
||||
import { indexTypes } from "medusa-core-utils"
|
||||
import { Product } from "../models"
|
||||
import { SearchService } from "../services"
|
||||
import { ISearchService } from "../interfaces"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService
|
||||
searchService: SearchService
|
||||
searchService: ISearchService<never>
|
||||
productService: ProductService
|
||||
}
|
||||
|
||||
class SearchIndexingSubscriber {
|
||||
private readonly eventBusService_: EventBusService
|
||||
private readonly searchService_: SearchService
|
||||
private readonly searchService_: ISearchService<never>
|
||||
private readonly productService_: ProductService
|
||||
|
||||
constructor({
|
||||
@@ -29,7 +29,7 @@ class SearchIndexingSubscriber {
|
||||
}
|
||||
|
||||
indexDocuments = async (): Promise<void> => {
|
||||
const TAKE = this.searchService_?.options?.batch_size ?? 1000
|
||||
const TAKE = (this.searchService_?.options?.batch_size as number) ?? 1000
|
||||
let hasMore = true
|
||||
|
||||
let lastSeenId = ""
|
||||
|
||||
Reference in New Issue
Block a user