feat(product): return parents tree (#6944)

*What*

include option `include_ancestors_tree` to list products including the parent tree.
This commit is contained in:
Carlos R. L. Rodrigues authored and GitHub committed 2024-04-05 16:46:55 +00:00
1 parent 8ecfa4b6f5
commit 09a2220569
7 files changed
+602 -51

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
---
"@medusajs/product": patch
"@medusajs/types": patch
---
Add parents to product categories
@@ -65,3 +65,127 @@ export const productCategoriesRankData = [
rank: 2, rank: 2,
}, },
] ]
export const eletronicsCategoriesData = eval(`[
{
id: "electronics",
name: "Electronics",
parent_category_id: null,
},
{
id: "computers",
name: "Computers & Accessories",
parent_category_id: "electronics",
},
{
id: "desktops",
name: "Desktops",
parent_category_id: "computers",
},
{
id: "gaming-desktops",
name: "Gaming Desktops",
parent_category_id: "desktops",
},
{
id: "office-desktops",
name: "Office Desktops",
parent_category_id: "desktops",
},
{
id: "laptops",
name: "Laptops",
parent_category_id: "computers",
},
{
id: "gaming-laptops",
name: "Gaming Laptops",
parent_category_id: "laptops",
},
{
id: "budget-gaming",
name: "Budget Gaming Laptops",
parent_category_id: "gaming-laptops",
},
{
id: "high-performance",
name: "High Performance Gaming Laptops",
parent_category_id: "gaming-laptops",
},
{
id: "vr-ready",
name: "VR-Ready High Performance Gaming Laptops",
parent_category_id: "high-performance",
},
{
id: "4k-gaming",
name: "4K Gaming Laptops",
parent_category_id: "high-performance",
},
{
id: "ultrabooks",
name: "Ultrabooks",
parent_category_id: "laptops",
},
{
id: "thin-light",
name: "Thin & Light Ultrabooks",
parent_category_id: "ultrabooks",
},
{
id: "convertible-ultrabooks",
name: "Convertible Ultrabooks",
parent_category_id: "ultrabooks",
},
{
id: "touchscreen-ultrabooks",
name: "Touchscreen Ultrabooks",
parent_category_id: "convertible-ultrabooks",
},
{
id: "detachable-ultrabooks",
name: "Detachable Ultrabooks",
parent_category_id: "convertible-ultrabooks",
},
{
id: "mobile",
name: "Mobile Phones & Accessories",
parent_category_id: "electronics",
},
{
id: "smartphones",
name: "Smartphones",
parent_category_id: "mobile",
},
{
id: "android-phones",
name: "Android Phones",
parent_category_id: "smartphones",
},
{
id: "flagship-phones",
name: "Flagship Smartphones",
parent_category_id: "android-phones",
},
{
id: "budget-phones",
name: "Budget Smartphones",
parent_category_id: "android-phones",
},
{
id: "iphones",
name: "iPhones",
parent_category_id: "smartphones",
},
{
id: "pro-phones",
name: "Pro Models",
parent_category_id: "iphones",
},
{
id: "mini-phones",
name: "Mini Models",
parent_category_id: "iphones",
},
]`)
@@ -1,13 +1,14 @@
import { ProductCategoryService } from "@services" import { ProductCategoryService } from "@services"
import { Modules } from "@medusajs/modules-sdk"
import { IProductModuleService } from "@medusajs/types"
import { SuiteOptions, moduleIntegrationTestRunner } from "medusa-test-utils"
import { createProductCategories } from "../../../__fixtures__/product-category" import { createProductCategories } from "../../../__fixtures__/product-category"
import { import {
eletronicsCategoriesData,
productCategoriesData, productCategoriesData,
productCategoriesRankData, productCategoriesRankData,
} from "../../../__fixtures__/product-category/data" } from "../../../__fixtures__/product-category/data"
import { Modules } from "@medusajs/modules-sdk"
import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils"
import { IProductModuleService } from "@medusajs/types"
jest.setTimeout(30000) jest.setTimeout(30000)
@@ -138,14 +139,12 @@ moduleIntegrationTestRunner({
handle: "category-1", handle: "category-1",
mpath: "category-0.category-1.", mpath: "category-0.category-1.",
parent_category_id: "category-0", parent_category_id: "category-0",
parent_category: "category-0",
category_children: [ category_children: [
expect.objectContaining({ expect.objectContaining({
id: "category-1-a", id: "category-1-a",
handle: "category-1-a", handle: "category-1-a",
mpath: "category-0.category-1.category-1-a.", mpath: "category-0.category-1.category-1-a.",
parent_category_id: "category-1", parent_category_id: "category-1",
parent_category: "category-1",
category_children: [], category_children: [],
}), }),
expect.objectContaining({ expect.objectContaining({
@@ -153,7 +152,6 @@ moduleIntegrationTestRunner({
handle: "category-1-b", handle: "category-1-b",
mpath: "category-0.category-1.category-1-b.", mpath: "category-0.category-1.category-1-b.",
parent_category_id: "category-1", parent_category_id: "category-1",
parent_category: "category-1",
category_children: [ category_children: [
expect.objectContaining({ expect.objectContaining({
id: "category-1-b-1", id: "category-1-b-1",
@@ -161,7 +159,6 @@ moduleIntegrationTestRunner({
mpath: mpath:
"category-0.category-1.category-1-b.category-1-b-1.", "category-0.category-1.category-1-b.category-1-b-1.",
parent_category_id: "category-1-b", parent_category_id: "category-1-b",
parent_category: "category-1-b",
category_children: [], category_children: [],
}), }),
], ],
@@ -173,6 +170,365 @@ moduleIntegrationTestRunner({
]) ])
}) })
it("includes the entire list of descendants when include_descendants_tree is true for multiple results", async () => {
const productCategoryResults = await service.list(
{
parent_category_id: "category-1",
include_descendants_tree: true,
},
{
select: ["id", "handle"],
}
)
const serializedObject = JSON.parse(
JSON.stringify(productCategoryResults)
)
expect(serializedObject).toEqual([
{
id: "category-1-a",
handle: "category-1-a",
mpath: "category-0.category-1.category-1-a.",
parent_category_id: "category-1",
category_children: [],
},
{
id: "category-1-b",
handle: "category-1-b",
mpath: "category-0.category-1.category-1-b.",
parent_category_id: "category-1",
category_children: [
{
id: "category-1-b-1",
handle: "category-1-b-1",
mpath: "category-0.category-1.category-1-b.category-1-b-1.",
parent_category_id: "category-1-b",
category_children: [],
},
],
},
])
})
it("includes the entire list of parents when include_ancestors_tree is true", async () => {
await createProductCategories(
MikroOrmWrapper.forkManager(),
eletronicsCategoriesData
)
const productCategoryResults = await service.list(
{
id: "4k-gaming",
include_ancestors_tree: true,
},
{
select: ["id", "handle"],
}
)
const serializedObject = JSON.parse(
JSON.stringify(productCategoryResults)
)
expect(serializedObject).toEqual([
{
id: "4k-gaming",
handle: "4k-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.high-performance.4k-gaming.",
parent_category_id: "high-performance",
parent_category: {
id: "high-performance",
parent_category_id: "gaming-laptops",
handle: "high-performance-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.high-performance.",
parent_category: {
id: "gaming-laptops",
handle: "gaming-laptops",
mpath: "electronics.computers.laptops.gaming-laptops.",
parent_category_id: "laptops",
parent_category: {
id: "laptops",
parent_category_id: "computers",
handle: "laptops",
mpath: "electronics.computers.laptops.",
parent_category: {
id: "computers",
handle: "computers-&-accessories",
mpath: "electronics.computers.",
parent_category_id: "electronics",
parent_category: {
id: "electronics",
parent_category_id: null,
handle: "electronics",
mpath: "electronics.",
parent_category: null,
},
},
},
},
},
},
])
})
it("includes the entire list of descendants when include_descendants_tree is true", async () => {
await createProductCategories(
MikroOrmWrapper.forkManager(),
eletronicsCategoriesData
)
const productCategoryResults = await service.list(
{
id: "gaming-laptops",
include_descendants_tree: true,
},
{
select: ["id", "handle"],
}
)
const serializedObject = JSON.parse(
JSON.stringify(productCategoryResults)
)
expect(serializedObject).toEqual([
{
id: "gaming-laptops",
handle: "gaming-laptops",
mpath: "electronics.computers.laptops.gaming-laptops.",
parent_category_id: "laptops",
category_children: [
{
id: "budget-gaming",
handle: "budget-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.budget-gaming.",
parent_category_id: "gaming-laptops",
category_children: [],
},
{
id: "high-performance",
handle: "high-performance-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.high-performance.",
parent_category_id: "gaming-laptops",
category_children: [
{
id: "4k-gaming",
handle: "4k-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.high-performance.4k-gaming.",
parent_category_id: "high-performance",
category_children: [],
},
{
id: "vr-ready",
handle: "vr-ready-high-performance-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.high-performance.vr-ready.",
parent_category_id: "high-performance",
category_children: [],
},
],
},
],
},
])
})
it("includes the entire list of descendants an parents when include_descendants_tree and include_ancestors_tree are true", async () => {
await createProductCategories(
MikroOrmWrapper.forkManager(),
eletronicsCategoriesData
)
const productCategoryResults = await service.list(
{
id: "gaming-laptops",
include_descendants_tree: true,
include_ancestors_tree: true,
},
{
select: ["id", "handle"],
}
)
const serializedObject = JSON.parse(
JSON.stringify(productCategoryResults)
)
expect(serializedObject).toEqual([
{
id: "gaming-laptops",
handle: "gaming-laptops",
mpath: "electronics.computers.laptops.gaming-laptops.",
parent_category_id: "laptops",
parent_category: {
id: "laptops",
handle: "laptops",
mpath: "electronics.computers.laptops.",
parent_category_id: "computers",
parent_category: {
id: "computers",
handle: "computers-&-accessories",
mpath: "electronics.computers.",
parent_category_id: "electronics",
parent_category: {
id: "electronics",
handle: "electronics",
mpath: "electronics.",
parent_category_id: null,
parent_category: null,
},
},
},
category_children: [
{
id: "budget-gaming",
handle: "budget-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.budget-gaming.",
parent_category_id: "gaming-laptops",
},
{
id: "high-performance",
handle: "high-performance-gaming-laptops",
mpath:
"electronics.computers.laptops.gaming-laptops.high-performance.",
parent_category_id: "gaming-laptops",
},
],
},
])
})
it("includes the entire list of parents when include_ancestors_tree is true for multiple results", async () => {
const productCategoryResults = await service.list(
{
parent_category_id: "category-1",
include_ancestors_tree: true,
},
{
select: ["id", "handle"],
}
)
const serializedObject = JSON.parse(
JSON.stringify(productCategoryResults)
)
expect(serializedObject).toEqual([
{
id: "category-1-a",
handle: "category-1-a",
mpath: "category-0.category-1.category-1-a.",
parent_category_id: "category-1",
parent_category: {
id: "category-1",
handle: "category-1",
mpath: "category-0.category-1.",
parent_category_id: "category-0",
parent_category: {
id: "category-0",
handle: "category-0",
mpath: "category-0.",
parent_category_id: null,
parent_category: null,
},
},
},
{
id: "category-1-b",
handle: "category-1-b",
mpath: "category-0.category-1.category-1-b.",
parent_category_id: "category-1",
parent_category: {
id: "category-1",
handle: "category-1",
mpath: "category-0.category-1.",
parent_category_id: "category-0",
parent_category: {
id: "category-0",
handle: "category-0",
mpath: "category-0.",
parent_category_id: null,
parent_category: null,
},
},
},
])
})
it("includes the entire list of descendants an parents when include_descendants_tree and include_ancestors_tree are true for multiple results", async () => {
const productCategoryResults = await service.list(
{
parent_category_id: "category-1",
include_descendants_tree: true,
include_ancestors_tree: true,
},
{
select: ["id", "handle"],
}
)
const serializedObject = JSON.parse(
JSON.stringify(productCategoryResults)
)
expect(serializedObject).toEqual([
{
id: "category-1-a",
handle: "category-1-a",
mpath: "category-0.category-1.category-1-a.",
parent_category_id: "category-1",
parent_category: {
id: "category-1",
handle: "category-1",
mpath: "category-0.category-1.",
parent_category_id: "category-0",
parent_category: {
id: "category-0",
handle: "category-0",
mpath: "category-0.",
parent_category_id: null,
parent_category: null,
},
},
category_children: [],
},
{
id: "category-1-b",
handle: "category-1-b",
mpath: "category-0.category-1.category-1-b.",
parent_category_id: "category-1",
parent_category: {
id: "category-1",
handle: "category-1",
mpath: "category-0.category-1.",
parent_category_id: "category-0",
parent_category: {
id: "category-0",
handle: "category-0",
mpath: "category-0.",
parent_category_id: null,
parent_category: null,
},
},
category_children: [
{
id: "category-1-b-1",
handle: "category-1-b-1",
mpath: "category-0.category-1.category-1-b.category-1-b-1.",
parent_category_id: "category-1-b",
},
],
},
])
})
it("scopes children when include_descendants_tree is true", async () => { it("scopes children when include_descendants_tree is true", async () => {
const productCategoryResults = await service.list( const productCategoryResults = await service.list(
{ {
@@ -202,14 +558,12 @@ moduleIntegrationTestRunner({
handle: "category-1", handle: "category-1",
mpath: "category-0.category-1.", mpath: "category-0.category-1.",
parent_category_id: "category-0", parent_category_id: "category-0",
parent_category: "category-0",
category_children: [ category_children: [
expect.objectContaining({ expect.objectContaining({
id: "category-1-a", id: "category-1-a",
handle: "category-1-a", handle: "category-1-a",
mpath: "category-0.category-1.category-1-a.", mpath: "category-0.category-1.category-1-a.",
parent_category_id: "category-1", parent_category_id: "category-1",
parent_category: "category-1",
category_children: [], category_children: [],
}), }),
], ],
@@ -456,14 +810,12 @@ moduleIntegrationTestRunner({
handle: "category-1", handle: "category-1",
mpath: "category-0.category-1.", mpath: "category-0.category-1.",
parent_category_id: "category-0", parent_category_id: "category-0",
parent_category: "category-0",
category_children: [ category_children: [
expect.objectContaining({ expect.objectContaining({
id: "category-1-a", id: "category-1-a",
handle: "category-1-a", handle: "category-1-a",
mpath: "category-0.category-1.category-1-a.", mpath: "category-0.category-1.category-1-a.",
parent_category_id: "category-1", parent_category_id: "category-1",
parent_category: "category-1",
category_children: [], category_children: [],
}), }),
expect.objectContaining({ expect.objectContaining({
@@ -471,7 +823,6 @@ moduleIntegrationTestRunner({
handle: "category-1-b", handle: "category-1-b",
mpath: "category-0.category-1.category-1-b.", mpath: "category-0.category-1.category-1-b.",
parent_category_id: "category-1", parent_category_id: "category-1",
parent_category: "category-1",
category_children: [ category_children: [
expect.objectContaining({ expect.objectContaining({
id: "category-1-b-1", id: "category-1-b-1",
@@ -479,7 +830,6 @@ moduleIntegrationTestRunner({
mpath: mpath:
"category-0.category-1.category-1-b.category-1-b-1.", "category-0.category-1.category-1-b.category-1-b-1.",
parent_category_id: "category-1-b", parent_category_id: "category-1-b",
parent_category: "category-1-b",
category_children: [], category_children: [],
}), }),
], ],
@@ -522,14 +872,12 @@ moduleIntegrationTestRunner({
handle: "category-1", handle: "category-1",
mpath: "category-0.category-1.", mpath: "category-0.category-1.",
parent_category_id: "category-0", parent_category_id: "category-0",
parent_category: "category-0",
category_children: [ category_children: [
expect.objectContaining({ expect.objectContaining({
id: "category-1-a", id: "category-1-a",
handle: "category-1-a", handle: "category-1-a",
mpath: "category-0.category-1.category-1-a.", mpath: "category-0.category-1.category-1-a.",
parent_category_id: "category-1", parent_category_id: "category-1",
parent_category: "category-1",
category_children: [], category_children: [],
}), }),
], ],
@@ -1,14 +1,17 @@
import { import {
Context,
DAL,
ProductCategoryTransformOptions,
ProductTypes,
} from "@medusajs/types"
import { DALUtils, MedusaError, isDefined } from "@medusajs/utils"
import {
LoadStrategy,
FilterQuery as MikroFilterQuery, FilterQuery as MikroFilterQuery,
FindOptions as MikroOptions, FindOptions as MikroOptions,
LoadStrategy,
} from "@mikro-orm/core" } from "@mikro-orm/core"
import { ProductCategory } from "@models"
import { Context, DAL, ProductCategoryTransformOptions } from "@medusajs/types"
import groupBy from "lodash/groupBy"
import { SqlEntityManager } from "@mikro-orm/postgresql" import { SqlEntityManager } from "@mikro-orm/postgresql"
import { DALUtils, isDefined, MedusaError } from "@medusajs/utils" import { ProductCategory } from "@models"
import { ProductTypes } from "@medusajs/types"
export type ReorderConditions = { export type ReorderConditions = {
targetCategoryId: string targetCategoryId: string
@@ -34,13 +37,13 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
const manager = super.getActiveManager<SqlEntityManager>(context) const manager = super.getActiveManager<SqlEntityManager>(context)
const findOptions_ = { ...findOptions } const findOptions_ = { ...findOptions }
const { includeDescendantsTree } = transformOptions const { includeDescendantsTree, includeParentsTree } = transformOptions
findOptions_.options ??= {} findOptions_.options ??= {}
const fields = (findOptions_.options.fields ??= []) const fields = (findOptions_.options.fields ??= [])
// Ref: Building descendants // Ref: Building descendants
// mpath and parent_category_id needs to be added to the query for the tree building to be done accurately // mpath and parent_category_id needs to be added to the query for the tree building to be done accurately
if (includeDescendantsTree) { if (includeDescendantsTree || includeParentsTree) {
fields.indexOf("mpath") === -1 && fields.push("mpath") fields.indexOf("mpath") === -1 && fields.push("mpath")
fields.indexOf("parent_category_id") === -1 && fields.indexOf("parent_category_id") === -1 &&
fields.push("parent_category_id") fields.push("parent_category_id")
@@ -56,29 +59,61 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
findOptions_.options as MikroOptions<ProductCategory> findOptions_.options as MikroOptions<ProductCategory>
) )
if (!includeDescendantsTree) { if (!includeDescendantsTree && !includeParentsTree) {
return productCategories return productCategories
} }
return this.buildProductCategoriesWithDescendants( return this.buildProductCategoriesWithTree(
{
descendants: includeDescendantsTree,
parents: includeParentsTree,
},
productCategories, productCategories,
findOptions_ findOptions_
) )
} }
async buildProductCategoriesWithDescendants( async buildProductCategoriesWithTree(
include: {
descendants?: boolean
parents?: boolean
},
productCategories: ProductCategory[], productCategories: ProductCategory[],
findOptions: DAL.FindOptions<ProductCategory> = { where: {} }, findOptions: DAL.FindOptions<ProductCategory> = { where: {} },
context: Context = {} context: Context = {}
): Promise<ProductCategory[]> { ): Promise<ProductCategory[]> {
const manager = super.getActiveManager<SqlEntityManager>(context) const manager = super.getActiveManager<SqlEntityManager>(context)
for (let productCategory of productCategories) { const hasPopulateParentCategory = (
findOptions.options?.populate ?? ([] as any)
).find((pop) => pop.field === "parent_category")
include.parents = include.parents || hasPopulateParentCategory
const mpaths: any[] = []
const parentMpaths = new Set()
for (const cat of productCategories) {
if (include.descendants) {
mpaths.push({ mpath: { $like: `${cat.mpath}%` } })
}
if (include.parents) {
let parent = ""
cat.mpath?.split(".").forEach((mpath) => {
if (mpath === "") {
return
}
parentMpaths.add(parent + mpath + ".")
parent += mpath + "."
})
}
}
mpaths.push({ mpath: Array.from(parentMpaths) })
const whereOptions = { const whereOptions = {
...findOptions.where, ...findOptions.where,
mpath: { $or: mpaths,
$like: `${productCategory.mpath}%`,
},
} }
if ("parent_category_id" in whereOptions) { if ("parent_category_id" in whereOptions) {
@@ -89,32 +124,53 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
delete whereOptions.id delete whereOptions.id
} }
const descendantsForCategory = await manager.find( let allCategories = await manager.find(
ProductCategory, ProductCategory,
whereOptions as MikroFilterQuery<ProductCategory>, whereOptions as MikroFilterQuery<ProductCategory>,
findOptions.options as MikroOptions<ProductCategory> findOptions.options as MikroOptions<ProductCategory>
) )
const descendantsByParentId = groupBy( allCategories = JSON.parse(JSON.stringify(allCategories))
descendantsForCategory,
(pc) => pc.parent_category_id const categoriesById = new Map(allCategories.map((cat) => [cat.id, cat]))
allCategories.forEach((cat: any) => {
if (cat.parent_category_id) {
cat.parent_category = categoriesById.get(cat.parent_category_id)
}
})
const populateChildren = (category, level = 0) => {
const categories = allCategories.filter(
(child) => child.parent_category_id === category.id
) )
const addChildrenToCategory = (category, children) => { if (include.descendants) {
category.category_children = (children || []).map((categoryChild) => { category.category_children = categories.map((child) => {
const moreChildren = descendantsByParentId[categoryChild.id] || [] return populateChildren(categoriesById.get(child.id), level + 1)
return addChildrenToCategory(categoryChild, moreChildren)
}) })
}
if (level === 0) {
return category
}
if (include.parents) {
delete category.category_children
}
if (include.descendants) {
delete category.parent_category
}
return category return category
} }
const children = descendantsByParentId[productCategory.id] || [] const populatedProductCategories = productCategories.map((cat) => {
productCategory = addChildrenToCategory(productCategory, children) const fullCategory = categoriesById.get(cat.id)
} return populateChildren(fullCategory)
})
return productCategories return populatedProductCategories
} }
async findAndCount( async findAndCount(
@@ -125,7 +181,7 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
const manager = super.getActiveManager<SqlEntityManager>(context) const manager = super.getActiveManager<SqlEntityManager>(context)
const findOptions_ = { ...findOptions } const findOptions_ = { ...findOptions }
const { includeDescendantsTree } = transformOptions const { includeDescendantsTree, includeParentsTree } = transformOptions
findOptions_.options ??= {} findOptions_.options ??= {}
const fields = (findOptions_.options.fields ??= []) const fields = (findOptions_.options.fields ??= [])
@@ -146,13 +202,20 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
findOptions_.where as MikroFilterQuery<ProductCategory>, findOptions_.where as MikroFilterQuery<ProductCategory>,
findOptions_.options as MikroOptions<ProductCategory> findOptions_.options as MikroOptions<ProductCategory>
) )
if (!includeDescendantsTree) { if (!includeDescendantsTree) {
return [productCategories, count] return [productCategories, count]
} }
if (!includeDescendantsTree && !includeParentsTree) {
return [productCategories, count]
}
return [ return [
await this.buildProductCategoriesWithDescendants( await this.buildProductCategoriesWithTree(
{
descendants: includeDescendantsTree,
parents: includeParentsTree,
},
productCategories, productCategories,
findOptions_ findOptions_
), ),
@@ -1,14 +1,14 @@
import { ProductCategory } from "@models"
import { ProductCategoryRepository } from "@repositories"
import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types" import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types"
import { import {
InjectManager, InjectManager,
InjectTransactionManager, InjectTransactionManager,
isDefined,
MedusaContext, MedusaContext,
MedusaError, MedusaError,
ModulesSdkUtils, ModulesSdkUtils,
isDefined,
} from "@medusajs/utils" } from "@medusajs/utils"
import { ProductCategory } from "@models"
import { ProductCategoryRepository } from "@repositories"
type InjectedDependencies = { type InjectedDependencies = {
productCategoryRepository: DAL.TreeRepositoryService productCategoryRepository: DAL.TreeRepositoryService
@@ -71,8 +71,10 @@ export default class ProductCategoryService<
): Promise<TEntity[]> { ): Promise<TEntity[]> {
const transformOptions = { const transformOptions = {
includeDescendantsTree: filters?.include_descendants_tree || false, includeDescendantsTree: filters?.include_descendants_tree || false,
includeParentsTree: filters?.include_ancestors_tree || false,
} }
delete filters.include_descendants_tree delete filters.include_descendants_tree
delete filters.include_ancestors_tree
const queryOptions = ModulesSdkUtils.buildQuery<ProductCategory>( const queryOptions = ModulesSdkUtils.buildQuery<ProductCategory>(
filters, filters,
@@ -95,8 +97,10 @@ export default class ProductCategoryService<
): Promise<[TEntity[], number]> { ): Promise<[TEntity[], number]> {
const transformOptions = { const transformOptions = {
includeDescendantsTree: filters?.include_descendants_tree || false, includeDescendantsTree: filters?.include_descendants_tree || false,
includeParentsTree: filters?.include_ancestors_tree || false,
} }
delete filters.include_descendants_tree delete filters.include_descendants_tree
delete filters.include_ancestors_tree
const queryOptions = ModulesSdkUtils.buildQuery<ProductCategory>( const queryOptions = ModulesSdkUtils.buildQuery<ProductCategory>(
filters, filters,
@@ -1,5 +1,7 @@
import { RepositoryTransformOptions } from '../common' import { RepositoryTransformOptions } from "../common"
export interface ProductCategoryTransformOptions extends RepositoryTransformOptions { export interface ProductCategoryTransformOptions
extends RepositoryTransformOptions {
includeDescendantsTree?: boolean includeDescendantsTree?: boolean
includeParentsTree?: boolean
} }
+4
View File
@@ -915,6 +915,10 @@ export interface FilterableProductCategoryProps
* Whether to include children of retrieved product categories. * Whether to include children of retrieved product categories.
*/ */
include_descendants_tree?: boolean include_descendants_tree?: boolean
/**
* Whether to include parents of retrieved product categories.
*/
include_ancestors_tree?: boolean
} }
/** /**