add: abstract search functionality to core + adjust meilisearch-plugin
add SearchService interface to medusa-interfaces add DefaultSearchService skeleton implementation to core add search-index.js loader to core for indexing db documents add SearchSubscriber to core add loadToSearchEngine method in ProductService switch order of loaders in core to load subscriptions AFTER plugins adjust service and loader for medusa-plugin-meilisearch
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
import { Router } from "express"
|
||||
import routes from "./routes/"
|
||||
|
||||
export default (container) => {
|
||||
const app = Router()
|
||||
|
||||
routes(app)
|
||||
|
||||
return app
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export default (fn) => (...args) => fn(...args).catch(args[2])
|
||||
@@ -1,5 +0,0 @@
|
||||
import { default as wrap } from "./await-middleware"
|
||||
|
||||
export default {
|
||||
wrap,
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { Router } from "express"
|
||||
import bodyParser from "body-parser"
|
||||
import middlewares from "../middlewares"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default (app) => {
|
||||
app.use("/meilisearch", route)
|
||||
|
||||
route.post(
|
||||
"/search",
|
||||
bodyParser.json(),
|
||||
middlewares.wrap(require("./meilisearch").default)
|
||||
)
|
||||
|
||||
return app
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
|
||||
export default async (req, res) => {
|
||||
const schema = Validator.object()
|
||||
.keys({
|
||||
q: Validator.string().required(),
|
||||
})
|
||||
.options({ allowUnknown: true })
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
|
||||
try {
|
||||
const { q, ...options } = value
|
||||
|
||||
const meiliSearchService = req.scope.resolve("meilisearchService")
|
||||
|
||||
const results = await meiliSearchService.search(q, options)
|
||||
|
||||
res.status(200).send(results)
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,14 @@
|
||||
import {
|
||||
defaultProductFields,
|
||||
defaultProductRelations,
|
||||
flattenSkus,
|
||||
} from "../utils"
|
||||
const INDEX_NS = "medusa-commerce"
|
||||
|
||||
export default async (container, options) => {
|
||||
try {
|
||||
const meilisearchService = container.resolve("meilisearchService")
|
||||
const productService = container.resolve("productService")
|
||||
const searchService = container.resolve("searchService")
|
||||
|
||||
const products = await productService.list(
|
||||
{},
|
||||
{
|
||||
select: defaultProductFields,
|
||||
relations: defaultProductRelations,
|
||||
}
|
||||
await Promise.all(
|
||||
Object.entries(options.settings).map(([key, value]) =>
|
||||
searchService.updateSettings(`${INDEX_NS}_${key}`, value)
|
||||
)
|
||||
)
|
||||
const productsWithSkus = products.map((product) => flattenSkus(product))
|
||||
|
||||
await meilisearchService.updateSettings()
|
||||
await meilisearchService.addDocuments(productsWithSkus)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
@@ -1,36 +1,46 @@
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
import { SearchService } from "medusa-interfaces"
|
||||
import { MeiliSearch } from "meilisearch"
|
||||
|
||||
class MeilisearchService extends BaseService {
|
||||
constructor({ eventBusService }, options) {
|
||||
class MeiliSearchService extends SearchService {
|
||||
constructor(container, options) {
|
||||
super()
|
||||
|
||||
this.eventBus_ = eventBusService
|
||||
|
||||
this.options_ = options
|
||||
|
||||
this.client_ = new MeiliSearch(options.config).index("products")
|
||||
this.client_ = new MeiliSearch(options.config)
|
||||
}
|
||||
|
||||
deleteAllDocuments() {
|
||||
return this.client_.deleteAllDocuments()
|
||||
createIndex(indexName, options) {
|
||||
return this.client_.createIndex(indexName, options)
|
||||
}
|
||||
|
||||
addDocuments(documents) {
|
||||
return this.client_.addDocuments(documents)
|
||||
getIndex(indexName) {
|
||||
return this.client_.index(indexName)
|
||||
}
|
||||
|
||||
deleteDocument(document_id) {
|
||||
return this.client_.deleteDocument(document_id)
|
||||
addDocuments(indexName, documents) {
|
||||
return this.client_.index(indexName).addDocuments(documents)
|
||||
}
|
||||
|
||||
search(query, options) {
|
||||
return this.client_.search(query, options)
|
||||
replaceDocuments(indexName, documents) {
|
||||
return this.client_.index(indexName).addDocuments(documents)
|
||||
}
|
||||
|
||||
updateSettings() {
|
||||
return this.client_.updateSettings(this.options_.settings)
|
||||
deleteDocument(indexName, document_id) {
|
||||
return this.client_.index(indexName).deleteDocument(document_id)
|
||||
}
|
||||
|
||||
deleteAllDocuments(indexName) {
|
||||
return this.client_.index(indexName).deleteAllDocuments()
|
||||
}
|
||||
|
||||
search(indexName, query, options) {
|
||||
return this.client_.index(indexName).search(query, options)
|
||||
}
|
||||
|
||||
updateSettings(indexName, settings) {
|
||||
return this.client_.index(indexName).updateSettings(settings)
|
||||
}
|
||||
}
|
||||
|
||||
export default MeilisearchService
|
||||
export default MeiliSearchService
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import {
|
||||
defaultProductRelations,
|
||||
defaultProductFields,
|
||||
flattenSkus,
|
||||
} from "../utils"
|
||||
|
||||
class MeilisearchSubscriber {
|
||||
constructor(
|
||||
{ eventBusService, meilisearchService, productService },
|
||||
options
|
||||
) {
|
||||
this.eventBus_ = eventBusService
|
||||
|
||||
this.meilisearchService_ = meilisearchService
|
||||
|
||||
this.productService_ = productService
|
||||
|
||||
this.eventBus_.subscribe("product.created", this.handleProductCreation)
|
||||
|
||||
this.eventBus_.subscribe("product.updated", this.handleProductUpdate)
|
||||
|
||||
this.eventBus_.subscribe("product.deleted", this.handleProductDeletion)
|
||||
|
||||
this.eventBus_.subscribe(
|
||||
"product-variant.created",
|
||||
this.handleProductVariantChange
|
||||
)
|
||||
|
||||
this.eventBus_.subscribe(
|
||||
"product-variant.updated",
|
||||
this.handleProductVariantChange
|
||||
)
|
||||
|
||||
this.eventBus_.subscribe(
|
||||
"product-variant.deleted",
|
||||
this.handleProductVariantChange
|
||||
)
|
||||
}
|
||||
|
||||
handleProductCreation = async (data) => {
|
||||
const product = await this.retrieveProduct_(data.id)
|
||||
await this.meilisearchService_.addDocuments([product])
|
||||
}
|
||||
|
||||
retrieveProduct_ = async (product_id) => {
|
||||
const product = await this.productService_.retrieve(product_id, {
|
||||
relations: defaultProductRelations,
|
||||
select: defaultProductFields,
|
||||
})
|
||||
const flattenedProduct = flattenSkus(product)
|
||||
return flattenedProduct
|
||||
}
|
||||
|
||||
handleProductUpdate = async (data) => {
|
||||
const product = await this.retrieveProduct_(data.id)
|
||||
await this.meilisearchService_.addDocuments([product])
|
||||
}
|
||||
|
||||
handleProductDeletion = async (data) => {
|
||||
await this.meilisearchService_.deleteDocument(data.id)
|
||||
}
|
||||
|
||||
handleProductVariantChange = async (data) => {
|
||||
const product = await this.retrieveProduct_(data.product_id)
|
||||
await this.meilisearchService_.addDocuments([product])
|
||||
}
|
||||
}
|
||||
|
||||
export default MeilisearchSubscriber
|
||||
@@ -1,29 +0,0 @@
|
||||
export const flattenSkus = (product) => {
|
||||
const skus = product.variants.map((v) => v.sku).filter(Boolean)
|
||||
product.sku = skus
|
||||
return product
|
||||
}
|
||||
|
||||
export const defaultProductFields = [
|
||||
"id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"handle",
|
||||
"is_giftcard",
|
||||
"discountable",
|
||||
"thumbnail",
|
||||
"profile_id",
|
||||
"collection_id",
|
||||
"type_id",
|
||||
"origin_country",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
export const defaultProductRelations = [
|
||||
"variants",
|
||||
"tags",
|
||||
"type",
|
||||
"collection",
|
||||
]
|
||||
Reference in New Issue
Block a user