more adjustments
move indexing logic to plugin remove loadToSearchEngine from ProductService adjust medusa core accordingly
This commit is contained in:
@@ -1,5 +1,54 @@
|
|||||||
|
import { transformProduct } from "../utils/transform-products"
|
||||||
|
|
||||||
const INDEX_NS = "medusa-commerce"
|
const INDEX_NS = "medusa-commerce"
|
||||||
|
|
||||||
|
async function loadIntoSearchEngine(container) {
|
||||||
|
const meilisearchService = container.resolve("meilisearchService")
|
||||||
|
const productService = container.resolve("productService")
|
||||||
|
|
||||||
|
const TAKE = 20
|
||||||
|
const totalCount = await productService.count()
|
||||||
|
let iterCount = 0,
|
||||||
|
lastSeenId = "prod"
|
||||||
|
|
||||||
|
while (iterCount < totalCount) {
|
||||||
|
const products = await productService.list(
|
||||||
|
{ id: { gt: lastSeenId } },
|
||||||
|
{
|
||||||
|
select: [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"subtitle",
|
||||||
|
"description",
|
||||||
|
"handle",
|
||||||
|
"is_giftcard",
|
||||||
|
"discountable",
|
||||||
|
"thumbnail",
|
||||||
|
"profile_id",
|
||||||
|
"collection_id",
|
||||||
|
"type_id",
|
||||||
|
"origin_country",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
],
|
||||||
|
relations: ["variants", "tags", "type", "collection"],
|
||||||
|
take: TAKE,
|
||||||
|
order: { id: "ASC" },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const transformedProducts = products.map(transformProduct)
|
||||||
|
|
||||||
|
await meilisearchService.addDocuments(
|
||||||
|
`medusa-commerce_products`,
|
||||||
|
transformedProducts
|
||||||
|
)
|
||||||
|
|
||||||
|
iterCount += products.length
|
||||||
|
lastSeenId = products.at(-1).id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default async (container, options) => {
|
export default async (container, options) => {
|
||||||
try {
|
try {
|
||||||
const meilisearchService = container.resolve("meilisearchService")
|
const meilisearchService = container.resolve("meilisearchService")
|
||||||
@@ -9,6 +58,8 @@ export default async (container, options) => {
|
|||||||
meilisearchService.updateSettings(`${INDEX_NS}_${key}`, value)
|
meilisearchService.updateSettings(`${INDEX_NS}_${key}`, value)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await loadIntoSearchEngine(container)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import { transformProduct } from "../utils/transform-products"
|
||||||
|
|
||||||
|
class ProductSearchSubscriber {
|
||||||
|
constructor(
|
||||||
|
{ eventBusService, meilisearchService, productService },
|
||||||
|
options
|
||||||
|
) {
|
||||||
|
this.eventBus_ = eventBusService
|
||||||
|
|
||||||
|
this.meilisearchService_ = meilisearchService
|
||||||
|
|
||||||
|
this.productService_ = productService
|
||||||
|
|
||||||
|
this.productIndexName = "medusa-commerce_products"
|
||||||
|
|
||||||
|
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(this.productIndexName, [
|
||||||
|
product,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
retrieveProduct_ = async (product_id) => {
|
||||||
|
const product = await this.productService_.retrieve(product_id, {
|
||||||
|
select: [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"subtitle",
|
||||||
|
"description",
|
||||||
|
"handle",
|
||||||
|
"is_giftcard",
|
||||||
|
"discountable",
|
||||||
|
"thumbnail",
|
||||||
|
"profile_id",
|
||||||
|
"collection_id",
|
||||||
|
"type_id",
|
||||||
|
"origin_country",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
],
|
||||||
|
relations: ["variants", "tags", "type", "collection"],
|
||||||
|
})
|
||||||
|
const transformedProduct = transformProduct(product)
|
||||||
|
return transformedProduct
|
||||||
|
}
|
||||||
|
|
||||||
|
handleProductUpdate = async (data) => {
|
||||||
|
const product = await this.retrieveProduct_(data.id)
|
||||||
|
await this.meilisearchService_.addDocuments(this.productIndexName, [
|
||||||
|
product,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
handleProductDeletion = async (data) => {
|
||||||
|
await this.meilisearchService_.deleteDocument(
|
||||||
|
this.productIndexName,
|
||||||
|
data.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleProductVariantChange = async (data) => {
|
||||||
|
const product = await this.retrieveProduct_(data.product_id)
|
||||||
|
await this.meilisearchService_.addDocuments(this.productIndexName, [
|
||||||
|
product,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProductSearchSubscriber
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const keys = ["sku", "title", "upc", "ean", "mid_code", "hs_code"]
|
||||||
|
const prefix = `variant`
|
||||||
|
|
||||||
|
export const transformProduct = (product) => {
|
||||||
|
const initialObj = keys.reduce((obj, key) => {
|
||||||
|
obj[`${prefix}_${key}`] = []
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
const flattenedFields = product.variants.reduce((obj, variant) => {
|
||||||
|
keys.forEach((k) => variant[k] && obj[`${prefix}_${k}`].push(variant[k]))
|
||||||
|
return obj
|
||||||
|
}, initialObj)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...product,
|
||||||
|
...flattenedFields,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,4 @@ export default async ({ container }) => {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const productService = container.resolve("productService")
|
|
||||||
await productService.loadIntoSearchEngine()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import _ from "lodash"
|
|||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { BaseService } from "medusa-interfaces"
|
import { BaseService } from "medusa-interfaces"
|
||||||
import { Brackets } from "typeorm"
|
import { Brackets } from "typeorm"
|
||||||
import { flattenField } from "../utils/flatten-field"
|
|
||||||
import { INDEX_NS } from "../utils/index-ns"
|
import { INDEX_NS } from "../utils/index-ns"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -748,61 +747,6 @@ class ProductService extends BaseService {
|
|||||||
// const final = await this.runDecorators_(decorated)
|
// const final = await this.runDecorators_(decorated)
|
||||||
return product
|
return product
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all products into the search engine
|
|
||||||
*/
|
|
||||||
|
|
||||||
async loadIntoSearchEngine() {
|
|
||||||
if (this.searchService_.isDefault) return
|
|
||||||
|
|
||||||
const TAKE = 20
|
|
||||||
const totalCount = await this.count()
|
|
||||||
let iterCount = 0,
|
|
||||||
lastSeenId = ""
|
|
||||||
|
|
||||||
while (iterCount < totalCount) {
|
|
||||||
console.log({ lastSeenId })
|
|
||||||
const products = await this.list(
|
|
||||||
{ id: { gte: lastSeenId } },
|
|
||||||
{
|
|
||||||
select: [
|
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"subtitle",
|
|
||||||
"description",
|
|
||||||
"handle",
|
|
||||||
"is_giftcard",
|
|
||||||
"discountable",
|
|
||||||
"thumbnail",
|
|
||||||
"profile_id",
|
|
||||||
"collection_id",
|
|
||||||
"type_id",
|
|
||||||
"origin_country",
|
|
||||||
"created_at",
|
|
||||||
"updated_at",
|
|
||||||
],
|
|
||||||
relations: ["variants", "tags", "type", "collection"],
|
|
||||||
take: TAKE,
|
|
||||||
order: { id: "ASC" },
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const flattenSkus = product => {
|
|
||||||
product.sku = flattenField(product.variants, "sku").filter(Boolean)
|
|
||||||
return product
|
|
||||||
}
|
|
||||||
|
|
||||||
const productsWithSkus = products.map(product => flattenSkus(product))
|
|
||||||
|
|
||||||
await this.searchService_.addDocuments(
|
|
||||||
ProductService.IndexName,
|
|
||||||
productsWithSkus
|
|
||||||
)
|
|
||||||
|
|
||||||
iterCount += TAKE
|
|
||||||
lastSeenId = products.at(-1).id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProductService
|
export default ProductService
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
import ProductService from "../services/product"
|
|
||||||
import ProductVariantService from "../services/product-variant"
|
|
||||||
import { flattenField } from "../utils/flatten-field"
|
|
||||||
|
|
||||||
class ProductSearchSubscriber {
|
|
||||||
constructor({ eventBusService, searchService, productService }, options) {
|
|
||||||
this.eventBus_ = eventBusService
|
|
||||||
|
|
||||||
this.searchService_ = searchService
|
|
||||||
|
|
||||||
this.productService_ = productService
|
|
||||||
|
|
||||||
this.eventBus_.subscribe(
|
|
||||||
ProductService.Events.CREATED,
|
|
||||||
this.handleProductCreation
|
|
||||||
)
|
|
||||||
|
|
||||||
this.eventBus_.subscribe(
|
|
||||||
ProductService.Events.UPDATED,
|
|
||||||
this.handleProductUpdate
|
|
||||||
)
|
|
||||||
|
|
||||||
this.eventBus_.subscribe(
|
|
||||||
ProductService.Events.DELETED,
|
|
||||||
this.handleProductDeletion
|
|
||||||
)
|
|
||||||
|
|
||||||
this.eventBus_.subscribe(
|
|
||||||
ProductVariantService.Events.CREATED,
|
|
||||||
this.handleProductVariantChange
|
|
||||||
)
|
|
||||||
|
|
||||||
this.eventBus_.subscribe(
|
|
||||||
ProductVariantService.Events.UPDATED,
|
|
||||||
this.handleProductVariantChange
|
|
||||||
)
|
|
||||||
|
|
||||||
this.eventBus_.subscribe(
|
|
||||||
ProductVariantService.Events.DELETED,
|
|
||||||
this.handleProductVariantChange
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleProductCreation = async data => {
|
|
||||||
const product = await this.retrieveProduct_(data.id)
|
|
||||||
await this.searchService_.addDocuments(ProductService.IndexName, [product])
|
|
||||||
}
|
|
||||||
|
|
||||||
retrieveProduct_ = async product_id => {
|
|
||||||
const product = await this.productService_.retrieve(product_id, {
|
|
||||||
select: [
|
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"subtitle",
|
|
||||||
"description",
|
|
||||||
"handle",
|
|
||||||
"is_giftcard",
|
|
||||||
"discountable",
|
|
||||||
"thumbnail",
|
|
||||||
"profile_id",
|
|
||||||
"collection_id",
|
|
||||||
"type_id",
|
|
||||||
"origin_country",
|
|
||||||
"created_at",
|
|
||||||
"updated_at",
|
|
||||||
],
|
|
||||||
relations: ["variants", "tags", "type", "collection"],
|
|
||||||
})
|
|
||||||
const skus = flattenField(product.variants, "sku").filter(Boolean)
|
|
||||||
product.sku = skus
|
|
||||||
return product
|
|
||||||
}
|
|
||||||
|
|
||||||
handleProductUpdate = async data => {
|
|
||||||
const product = await this.retrieveProduct_(data.id)
|
|
||||||
await this.searchService_.addDocuments(ProductService.IndexName, [product])
|
|
||||||
}
|
|
||||||
|
|
||||||
handleProductDeletion = async data => {
|
|
||||||
await this.searchService_.deleteDocument(ProductService.IndexName, data.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleProductVariantChange = async data => {
|
|
||||||
const product = await this.retrieveProduct_(data.product_id)
|
|
||||||
await this.searchService_.addDocuments(ProductService.IndexName, [product])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ProductSearchSubscriber
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export const flattenField = (list, field) => {
|
|
||||||
return list.map(el => el[field])
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user