fix: Retrieve ancestors and/or descendants on product categories (#7226)
This commit is contained in:
1 parent
520867b074
commit
1366e2efad
11 files changed
+158
-390
No files matched your search
@@ -369,6 +369,7 @@ export class RemoteJoiner {
|
||||
uniqueIds,
|
||||
relationship
|
||||
)
|
||||
|
||||
const isObj = isDefined(response.path)
|
||||
let resData = isObj ? response.data[response.path!] : response.data
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../types/routing"
|
||||
import { refetchCategory } from "../../helpers"
|
||||
import { refetchEntity } from "../../../../utils/refetch-entity"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<LinkMethodRequest>,
|
||||
@@ -24,11 +24,11 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const category = await refetchCategory(
|
||||
req.params.id,
|
||||
const category = await refetchEntity(
|
||||
"product_category",
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields,
|
||||
req.filterableFields
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ product_category: category })
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
import { refetchCategory } from "../helpers"
|
||||
import { refetchEntities } from "../../../utils/refetch-entity"
|
||||
import {
|
||||
AdminProductCategoryParamsType,
|
||||
AdminUpdateProductCategoryType,
|
||||
@@ -14,11 +14,11 @@ export const GET = async (
|
||||
req: AuthenticatedMedusaRequest<AdminProductCategoryParamsType>,
|
||||
res: MedusaResponse<AdminProductCategoryResponse>
|
||||
) => {
|
||||
const category = await refetchCategory(
|
||||
req.params.id,
|
||||
const [category] = await refetchEntities(
|
||||
"product_category",
|
||||
{ id: req.params.id, ...req.filterableFields },
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields,
|
||||
req.filterableFields
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.json({ product_category: category })
|
||||
@@ -40,11 +40,11 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const category = await refetchCategory(
|
||||
req.params.id,
|
||||
const [category] = await refetchEntities(
|
||||
"product_category",
|
||||
{ id, ...req.filterableFields },
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields,
|
||||
req.filterableFields
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ product_category: category })
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const refetchCategory = async (
|
||||
categoryId: string,
|
||||
scope: MedusaContainer,
|
||||
fields: string[],
|
||||
filterableFields: Record<string, any> = {}
|
||||
) => {
|
||||
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "product_category",
|
||||
variables: {
|
||||
filters: { ...filterableFields, id: categoryId },
|
||||
},
|
||||
fields: fields,
|
||||
})
|
||||
|
||||
const categorys = await remoteQuery(queryObject)
|
||||
return categorys[0]
|
||||
}
|
||||
@@ -10,17 +10,36 @@ export const defaults = [
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"metadata",
|
||||
"*parent_category",
|
||||
"*category_children",
|
||||
"parent_category",
|
||||
"category_children",
|
||||
]
|
||||
|
||||
export const allowed = [
|
||||
"id",
|
||||
"name",
|
||||
"description",
|
||||
"handle",
|
||||
"is_active",
|
||||
"is_internal",
|
||||
"rank",
|
||||
"parent_category_id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"metadata",
|
||||
"category_children",
|
||||
"parent_category",
|
||||
"products",
|
||||
]
|
||||
|
||||
export const retrieveProductCategoryConfig = {
|
||||
defaults,
|
||||
allowed,
|
||||
isList: false,
|
||||
}
|
||||
|
||||
export const listProductCategoryConfig = {
|
||||
defaults,
|
||||
allowed,
|
||||
defaultLimit: 50,
|
||||
isList: true,
|
||||
}
|
||||
@@ -3,15 +3,11 @@ import {
|
||||
AdminProductCategoryListResponse,
|
||||
AdminProductCategoryResponse,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../types/routing"
|
||||
import { refetchCategory } from "./helpers"
|
||||
import { refetchEntities } from "../../utils/refetch-entity"
|
||||
import {
|
||||
AdminCreateProductCategoryType,
|
||||
AdminProductCategoriesParamsType,
|
||||
@@ -21,18 +17,13 @@ export const GET = async (
|
||||
req: AuthenticatedMedusaRequest<AdminProductCategoriesParamsType>,
|
||||
res: MedusaResponse<AdminProductCategoryListResponse>
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "product_category",
|
||||
variables: {
|
||||
filters: req.filterableFields,
|
||||
...req.remoteQueryConfig.pagination,
|
||||
},
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
const { rows: product_categories, metadata } = await remoteQuery(queryObject)
|
||||
const { rows: product_categories, metadata } = await refetchEntities(
|
||||
"product_category",
|
||||
req.filterableFields,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields,
|
||||
req.remoteQueryConfig.pagination
|
||||
)
|
||||
|
||||
res.json({
|
||||
product_categories,
|
||||
@@ -57,11 +48,11 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const category = await refetchCategory(
|
||||
result.id,
|
||||
const [category] = await refetchEntities(
|
||||
"product_category",
|
||||
{ id: result.id, ...req.filterableFields },
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields,
|
||||
req.filterableFields
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ product_category: category })
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import { StoreProductCategoryResponse } from "@medusajs/types"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
import { refetchCategory } from "../helpers"
|
||||
import { refetchEntities } from "../../../utils/refetch-entity"
|
||||
import { StoreProductCategoryParamsType } from "../validators"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest<StoreProductCategoryParamsType>,
|
||||
res: MedusaResponse<StoreProductCategoryResponse>
|
||||
) => {
|
||||
const category = await refetchCategory(
|
||||
req.params.id,
|
||||
const category = await refetchEntities(
|
||||
"product_category",
|
||||
{ id: req.params.id, ...req.filterableFields },
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields,
|
||||
req.filterableFields
|
||||
req.remoteQueryConfig.pagination
|
||||
)
|
||||
|
||||
if (!category) {
|
||||
|
||||
@@ -9,7 +9,8 @@ export const refetchEntities = async (
|
||||
entryPoint: string,
|
||||
idOrFilter: string | object,
|
||||
scope: MedusaContainer,
|
||||
fields: string[]
|
||||
fields: string[],
|
||||
pagination: object = {}
|
||||
) => {
|
||||
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const filters = isString(idOrFilter) ? { id: idOrFilter } : idOrFilter
|
||||
@@ -23,7 +24,7 @@ export const refetchEntities = async (
|
||||
delete filters.context
|
||||
}
|
||||
|
||||
let variables = { filters, ...context }
|
||||
let variables = { filters, ...context, ...pagination }
|
||||
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint,
|
||||
|
||||
@@ -4,11 +4,11 @@ import {
|
||||
stringToSelectRelationObject,
|
||||
} from "@medusajs/utils"
|
||||
import { pick } from "lodash"
|
||||
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||
import { MedusaError, isDefined } from "medusa-core-utils"
|
||||
import { BaseEntity } from "../interfaces"
|
||||
import { FindConfig, QueryConfig, RequestQueryFields } from "../types/common"
|
||||
import { featureFlagRouter } from "../loaders/feature-flags"
|
||||
import MedusaV2 from "../loaders/feature-flags/medusa-v2"
|
||||
import { FindConfig, QueryConfig, RequestQueryFields } from "../types/common"
|
||||
|
||||
export function pickByConfig<TModel extends BaseEntity>(
|
||||
obj: TModel | TModel[],
|
||||
|
||||
@@ -29,6 +29,51 @@ export const tempReorderRank = 99999
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeRepository<ProductCategory> {
|
||||
buildFindOptions(
|
||||
findOptions: DAL.FindOptions<ProductCategory> = { where: {} },
|
||||
familyOptions: ProductCategoryTransformOptions = {}
|
||||
) {
|
||||
const findOptions_ = { ...findOptions }
|
||||
findOptions_.options ??= {}
|
||||
|
||||
const fields = (findOptions_.options.fields ??= [])
|
||||
const populate = (findOptions_.options.populate ??= [])
|
||||
|
||||
// Ref: Building descendants
|
||||
// mpath and parent_category_id needs to be added to the query for the tree building to be done accurately
|
||||
if (
|
||||
familyOptions.includeDescendantsTree ||
|
||||
familyOptions.includeAncestorsTree
|
||||
) {
|
||||
fields.indexOf("mpath") === -1 && fields.push("mpath")
|
||||
fields.indexOf("parent_category_id") === -1 &&
|
||||
fields.push("parent_category_id")
|
||||
}
|
||||
|
||||
const shouldExpandParent =
|
||||
familyOptions.includeAncestorsTree || fields.includes("parent_category")
|
||||
|
||||
if (shouldExpandParent) {
|
||||
populate.indexOf("parent_category") === -1 &&
|
||||
populate.push("parent_category")
|
||||
}
|
||||
|
||||
const shouldExpandChildren =
|
||||
familyOptions.includeDescendantsTree ||
|
||||
fields.includes("category_children")
|
||||
|
||||
if (shouldExpandChildren) {
|
||||
populate.indexOf("category_children") === -1 &&
|
||||
populate.push("category_children")
|
||||
}
|
||||
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
|
||||
return findOptions_
|
||||
}
|
||||
|
||||
async find(
|
||||
findOptions: DAL.FindOptions<ProductCategory> = { where: {} },
|
||||
transformOptions: ProductCategoryTransformOptions = {},
|
||||
@@ -36,22 +81,7 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
|
||||
): Promise<ProductCategory[]> {
|
||||
const manager = super.getActiveManager<SqlEntityManager>(context)
|
||||
|
||||
const findOptions_ = { ...findOptions }
|
||||
const { includeDescendantsTree, includeAncestorsTree } = transformOptions
|
||||
findOptions_.options ??= {}
|
||||
const fields = (findOptions_.options.fields ??= [])
|
||||
|
||||
// Ref: Building descendants
|
||||
// mpath and parent_category_id needs to be added to the query for the tree building to be done accurately
|
||||
if (includeDescendantsTree || includeAncestorsTree) {
|
||||
fields.indexOf("mpath") === -1 && fields.push("mpath")
|
||||
fields.indexOf("parent_category_id") === -1 &&
|
||||
fields.push("parent_category_id")
|
||||
}
|
||||
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
const findOptions_ = this.buildFindOptions(findOptions, transformOptions)
|
||||
|
||||
const productCategories = await manager.find(
|
||||
ProductCategory,
|
||||
@@ -59,14 +89,17 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
|
||||
findOptions_.options as MikroOptions<ProductCategory>
|
||||
)
|
||||
|
||||
if (!includeDescendantsTree && !includeAncestorsTree) {
|
||||
if (
|
||||
!transformOptions.includeDescendantsTree &&
|
||||
!transformOptions.includeAncestorsTree
|
||||
) {
|
||||
return productCategories
|
||||
}
|
||||
|
||||
return this.buildProductCategoriesWithTree(
|
||||
return await this.buildProductCategoriesWithTree(
|
||||
{
|
||||
descendants: includeDescendantsTree,
|
||||
ancestors: includeAncestorsTree,
|
||||
descendants: transformOptions.includeDescendantsTree,
|
||||
ancestors: transformOptions.includeAncestorsTree,
|
||||
},
|
||||
productCategories,
|
||||
findOptions_
|
||||
@@ -84,12 +117,6 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
|
||||
): Promise<ProductCategory[]> {
|
||||
const manager = super.getActiveManager<SqlEntityManager>(context)
|
||||
|
||||
const hasPopulateParentCategory = (
|
||||
findOptions.options?.populate ?? ([] as any)
|
||||
).find((pop) => pop.field === "parent_category")
|
||||
|
||||
include.ancestors = include.ancestors || hasPopulateParentCategory
|
||||
|
||||
const mpaths: any[] = []
|
||||
const parentMpaths = new Set()
|
||||
for (const cat of productCategories) {
|
||||
@@ -179,42 +206,27 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
|
||||
context: Context = {}
|
||||
): Promise<[ProductCategory[], number]> {
|
||||
const manager = super.getActiveManager<SqlEntityManager>(context)
|
||||
|
||||
const findOptions_ = { ...findOptions }
|
||||
const { includeDescendantsTree, includeAncestorsTree } = transformOptions
|
||||
findOptions_.options ??= {}
|
||||
const fields = (findOptions_.options.fields ??= [])
|
||||
|
||||
// Ref: Building descendants
|
||||
// mpath and parent_category_id needs to be added to the query for the tree building to be done accurately
|
||||
if (includeDescendantsTree) {
|
||||
fields.indexOf("mpath") === -1 && fields.push("mpath")
|
||||
fields.indexOf("parent_category_id") === -1 &&
|
||||
fields.push("parent_category_id")
|
||||
}
|
||||
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
|
||||
const findOptions_ = this.buildFindOptions(findOptions, transformOptions)
|
||||
|
||||
const [productCategories, count] = await manager.findAndCount(
|
||||
ProductCategory,
|
||||
findOptions_.where as MikroFilterQuery<ProductCategory>,
|
||||
findOptions_.options as MikroOptions<ProductCategory>
|
||||
)
|
||||
if (!includeDescendantsTree) {
|
||||
return [productCategories, count]
|
||||
}
|
||||
|
||||
if (!includeDescendantsTree && !includeAncestorsTree) {
|
||||
if (
|
||||
!transformOptions.includeDescendantsTree &&
|
||||
!transformOptions.includeAncestorsTree
|
||||
) {
|
||||
return [productCategories, count]
|
||||
}
|
||||
|
||||
return [
|
||||
await this.buildProductCategoriesWithTree(
|
||||
{
|
||||
descendants: includeDescendantsTree,
|
||||
ancestors: includeAncestorsTree,
|
||||
descendants: transformOptions.includeDescendantsTree,
|
||||
ancestors: transformOptions.includeAncestorsTree,
|
||||
},
|
||||
productCategories,
|
||||
findOptions_
|
||||
|
||||
Reference in new issue
Block a user