feat(utils): Support free text configuration (#6942)
**What** - Add support for searchable entity properties to configure default free text search when providing a `q` filter - `@Searchable` decorator to mark a property or relation to be searchable form the current entity FIXES CORE-1910
This commit is contained in:
1 parent
a0005faa14
commit
21990fcd4b
19 files changed
+424
-205
No files matched your search
@@ -234,6 +234,31 @@ moduleIntegrationTestRunner({
|
||||
})
|
||||
|
||||
describe("list", () => {
|
||||
it("should list all product that match the free text search", async () => {
|
||||
const data = buildProductOnlyData({
|
||||
title: "test product",
|
||||
})
|
||||
const data2 = buildProductOnlyData({
|
||||
title: "space X",
|
||||
})
|
||||
|
||||
const products = await service.create([data, data2])
|
||||
|
||||
const result = await service.list({
|
||||
q: "test",
|
||||
})
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].title).toEqual("test product")
|
||||
|
||||
const result2 = await service.list({
|
||||
q: "space",
|
||||
})
|
||||
|
||||
expect(result2).toHaveLength(1)
|
||||
expect(result2[0].title).toEqual("space X")
|
||||
})
|
||||
|
||||
describe("soft deleted", function () {
|
||||
let product
|
||||
|
||||
|
||||
@@ -4,17 +4,18 @@ import {
|
||||
Entity,
|
||||
Filter,
|
||||
Index,
|
||||
OnInit,
|
||||
OneToMany,
|
||||
OnInit,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
import {
|
||||
DALUtils,
|
||||
createPsqlIndexStatementHelper,
|
||||
DALUtils,
|
||||
generateEntityId,
|
||||
kebabCase,
|
||||
Searchable,
|
||||
} from "@medusajs/utils"
|
||||
import Product from "./product"
|
||||
|
||||
@@ -34,6 +35,7 @@ class ProductCollection {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id!: string
|
||||
|
||||
@Searchable()
|
||||
@Property({ columnType: "text" })
|
||||
title: string
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {
|
||||
DALUtils,
|
||||
createPsqlIndexStatementHelper,
|
||||
DALUtils,
|
||||
generateEntityId,
|
||||
optionalNumericSerializer,
|
||||
Searchable,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
@@ -12,8 +13,8 @@ import {
|
||||
Filter,
|
||||
Index,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
OneToMany,
|
||||
OnInit,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
@@ -76,9 +77,11 @@ class ProductVariant {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id!: string
|
||||
|
||||
@Searchable()
|
||||
@Property({ columnType: "text" })
|
||||
title: string
|
||||
|
||||
@Searchable()
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
sku?: string | null
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
generateEntityId,
|
||||
kebabCase,
|
||||
ProductUtils,
|
||||
Searchable,
|
||||
} from "@medusajs/utils"
|
||||
import ProductCategory from "./product-category"
|
||||
import ProductCollection from "./product-collection"
|
||||
@@ -64,6 +65,7 @@ class Product {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id!: string
|
||||
|
||||
@Searchable()
|
||||
@Property({ columnType: "text" })
|
||||
title: string
|
||||
|
||||
@@ -73,7 +75,11 @@ class Product {
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
subtitle?: string | null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
@Searchable()
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
description?: string | null
|
||||
|
||||
@Property({ columnType: "boolean", default: false })
|
||||
@@ -91,6 +97,7 @@ class Product {
|
||||
})
|
||||
options = new Collection<ProductOption>(this)
|
||||
|
||||
@Searchable()
|
||||
@OneToMany(() => ProductVariant, (variant) => variant.product, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
@@ -120,6 +127,7 @@ class Product {
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
material?: string | null
|
||||
|
||||
@Searchable()
|
||||
@ManyToOne(() => ProductCollection, {
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
|
||||
@@ -15,40 +15,6 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
|
||||
super(...arguments)
|
||||
}
|
||||
|
||||
async find(
|
||||
findOptions: DAL.FindOptions<Product & { q?: string }> = { where: {} },
|
||||
context: Context = {}
|
||||
): Promise<Product[]> {
|
||||
const findOptions_ = { ...findOptions }
|
||||
findOptions_.options ??= {}
|
||||
|
||||
await this.mutateNotInCategoriesConstraints(findOptions_)
|
||||
|
||||
this.applyFreeTextSearchFilters<Product>(
|
||||
findOptions_,
|
||||
this.getFreeTextSearchConstraints
|
||||
)
|
||||
|
||||
return await super.find(findOptions_, context)
|
||||
}
|
||||
|
||||
async findAndCount(
|
||||
findOptions: DAL.FindOptions<Product & { q?: string }> = { where: {} },
|
||||
context: Context = {}
|
||||
): Promise<[Product[], number]> {
|
||||
const findOptions_ = { ...findOptions }
|
||||
findOptions_.options ??= {}
|
||||
|
||||
await this.mutateNotInCategoriesConstraints(findOptions_)
|
||||
|
||||
this.applyFreeTextSearchFilters<Product>(
|
||||
findOptions_,
|
||||
this.getFreeTextSearchConstraints
|
||||
)
|
||||
|
||||
return await super.findAndCount(findOptions_, context)
|
||||
}
|
||||
|
||||
/**
|
||||
* In order to be able to have a strict not in categories, and prevent a product
|
||||
* to be return in the case it also belongs to other categories, we need to
|
||||
@@ -88,42 +54,4 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Pr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected getFreeTextSearchConstraints(q: string) {
|
||||
return [
|
||||
{
|
||||
description: {
|
||||
$ilike: `%${q}%`,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: {
|
||||
$ilike: `%${q}%`,
|
||||
},
|
||||
},
|
||||
{
|
||||
collection: {
|
||||
title: {
|
||||
$ilike: `%${q}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
variants: {
|
||||
$or: [
|
||||
{
|
||||
title: {
|
||||
$ilike: `%${q}%`,
|
||||
},
|
||||
},
|
||||
{
|
||||
sku: {
|
||||
$ilike: `%${q}%`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user