feat(medusa): Migrate SearchService to TS + add SearchInterface (#1922)
This commit is contained in:
1 parent
6014872a72
commit
204dd23a39
7 files changed
+234
-93
No files matched your search
@@ -8,3 +8,4 @@ export * from "./notification-service"
|
|||||||
export * from "./price-selection-strategy"
|
export * from "./price-selection-strategy"
|
||||||
export * from "./models/base-entity"
|
export * from "./models/base-entity"
|
||||||
export * from "./models/soft-deletable-entity"
|
export * from "./models/soft-deletable-entity"
|
||||||
|
export * from "./search-service"
|
||||||
@@ -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 { 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 {
|
import {
|
||||||
BaseService as LegacyBaseService,
|
BaseService as LegacyBaseService,
|
||||||
PaymentService,
|
|
||||||
FulfillmentService,
|
|
||||||
FileService,
|
FileService,
|
||||||
|
FulfillmentService,
|
||||||
OauthService,
|
OauthService,
|
||||||
SearchService,
|
PaymentService,
|
||||||
} from "medusa-interfaces"
|
} from "medusa-interfaces"
|
||||||
import { createRequireFromPath } from "medusa-core-utils"
|
|
||||||
import _ from "lodash"
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import fs from "fs"
|
import { EntitySchema } from "typeorm"
|
||||||
import { asValue, asClass, asFunction, aliasTo } from "awilix"
|
|
||||||
import { sync as existsSync } from "fs-exists-cached"
|
|
||||||
import {
|
import {
|
||||||
AbstractTaxService,
|
AbstractTaxService,
|
||||||
|
isBatchJobStrategy,
|
||||||
isFileService,
|
isFileService,
|
||||||
|
isNotificationService,
|
||||||
|
isPriceSelectionStrategy,
|
||||||
|
isSearchService,
|
||||||
isTaxCalculationStrategy,
|
isTaxCalculationStrategy,
|
||||||
TransactionBaseService as BaseService,
|
TransactionBaseService as BaseService,
|
||||||
isNotificationService,
|
|
||||||
isBatchJobStrategy,
|
|
||||||
isPriceSelectionStrategy,
|
|
||||||
} from "../interfaces"
|
} from "../interfaces"
|
||||||
import formatRegistrationName from "../utils/format-registration-name"
|
import { MiddlewareService } from "../services"
|
||||||
import {
|
import {
|
||||||
ClassConstructor,
|
ClassConstructor,
|
||||||
ConfigModule,
|
ConfigModule,
|
||||||
Logger,
|
Logger,
|
||||||
MedusaContainer,
|
MedusaContainer,
|
||||||
} from "../types/global"
|
} from "../types/global"
|
||||||
import { MiddlewareService } from "../services"
|
import formatRegistrationName from "../utils/format-registration-name"
|
||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
@@ -418,7 +418,7 @@ export async function registerServices(
|
|||||||
),
|
),
|
||||||
[`fileService`]: aliasTo(name),
|
[`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
|
// Add the service directly to the container in order to make simple
|
||||||
// resolution if we already know which search provider we need to use
|
// resolution if we already know which search provider we need to use
|
||||||
container.register({
|
container.register({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { MedusaContainer } from "../types/global"
|
import { MedusaContainer } from "../types/global"
|
||||||
import DefaultSearchService from "../services/search"
|
|
||||||
import { Logger } from "../types/global"
|
import { Logger } from "../types/global"
|
||||||
import { EventBusService } from "../services"
|
import { EventBusService } from "../services"
|
||||||
|
import { AbstractSearchService } from "../interfaces"
|
||||||
|
|
||||||
export const SEARCH_INDEX_EVENT = "SEARCH_INDEX_EVENT"
|
export const SEARCH_INDEX_EVENT = "SEARCH_INDEX_EVENT"
|
||||||
|
|
||||||
@@ -21,7 +21,8 @@ export default async ({
|
|||||||
}: {
|
}: {
|
||||||
container: MedusaContainer
|
container: MedusaContainer
|
||||||
}): Promise<void> => {
|
}): Promise<void> => {
|
||||||
const searchService = container.resolve<DefaultSearchService>("searchService")
|
const searchService =
|
||||||
|
container.resolve<AbstractSearchService<never>>("searchService")
|
||||||
const logger = container.resolve<Logger>("logger")
|
const logger = container.resolve<Logger>("logger")
|
||||||
if (searchService.isDefault) {
|
if (searchService.isDefault) {
|
||||||
logger.warn(
|
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
|
|
||||||
@@ -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 ProductService from "../services/product"
|
||||||
import { indexTypes } from "medusa-core-utils"
|
import { indexTypes } from "medusa-core-utils"
|
||||||
import { Product } from "../models"
|
import { Product } from "../models"
|
||||||
import { SearchService } from "../services"
|
import { ISearchService } from "../interfaces"
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
eventBusService: EventBusService
|
eventBusService: EventBusService
|
||||||
searchService: SearchService
|
searchService: ISearchService<never>
|
||||||
productService: ProductService
|
productService: ProductService
|
||||||
}
|
}
|
||||||
|
|
||||||
class SearchIndexingSubscriber {
|
class SearchIndexingSubscriber {
|
||||||
private readonly eventBusService_: EventBusService
|
private readonly eventBusService_: EventBusService
|
||||||
private readonly searchService_: SearchService
|
private readonly searchService_: ISearchService<never>
|
||||||
private readonly productService_: ProductService
|
private readonly productService_: ProductService
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
@@ -29,7 +29,7 @@ class SearchIndexingSubscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
indexDocuments = async (): Promise<void> => {
|
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 hasMore = true
|
||||||
|
|
||||||
let lastSeenId = ""
|
let lastSeenId = ""
|
||||||
|
|||||||
Reference in new issue
Block a user