Feat(medusa, medusa-js, medusa-react): Include sales channels in related queries as an optional expand parameter (#1816)
**What** - Add `transformQuery` to get endpoints for product, order and cart - ensure that the default relations (when getting a singular entity) includes sales channels when enabled - Add `EmptyQueryParams` class in common types to prevent query parameters while using `transformQuery` - update product-, order- and cartFactory to include sales channels if provided - remove `packages/medusa/src/controllers/products/admin-list-products.ts` **Testing** - expands sales channel for single order - expands sales channels for orders with expand parameter - returns single product with sales channel - expands sales channels for products with expand parameter - returns cart with sales channel for single cart Fixes CORE-293 Co-authored-by: Sebastian Rindom <7554214+srindom@users.noreply.github.com> Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com>
This commit is contained in:
co-authored by
Sebastian Rindom
Adrien de Peretti
parent
fb4cfc3c3c
commit
19f35ba6aa
@@ -1,40 +1,59 @@
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import { Column, ColumnOptions, Entity, EntityOptions } from "typeorm"
|
||||
import featureFlagsLoader from "../loaders/feature-flags"
|
||||
import path from "path"
|
||||
import { ConfigModule } from "../types/global"
|
||||
import { FlagRouter } from "./flag-router"
|
||||
|
||||
/**
|
||||
* If that file is required in a non node environment then the setImmediate timer does not exists.
|
||||
* This can happen when a client package require a server based package and that one of the import
|
||||
* require to import that file which is using the setImmediate.
|
||||
* In order to take care of those cases, the setImmediate timer will use the one provided by the api (node)
|
||||
* if possible and will provide a mock in a browser like environment.
|
||||
*/
|
||||
let setImmediate_
|
||||
try {
|
||||
setImmediate_ = setImmediate
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
"[feature-flag-decorator.ts] setImmediate will use a mock, this happen when this file is required in a browser environment and should not impact you"
|
||||
)
|
||||
setImmediate_ = ((callback: () => void | Promise<void>) => callback())
|
||||
}
|
||||
|
||||
export function FeatureFlagColumn(
|
||||
featureFlag: string,
|
||||
columnOptions: ColumnOptions = {}
|
||||
): PropertyDecorator {
|
||||
const featureFlagRouter = getFeatureFlagRouter()
|
||||
return function (target, propertyName) {
|
||||
setImmediate_((): any => {
|
||||
const featureFlagRouter = getFeatureFlagRouter()
|
||||
|
||||
if (!featureFlagRouter.isFeatureEnabled(featureFlag)) {
|
||||
return (): void => {
|
||||
// noop
|
||||
}
|
||||
if (!featureFlagRouter.isFeatureEnabled(featureFlag)) {
|
||||
return
|
||||
}
|
||||
|
||||
Column(columnOptions)(target, propertyName)
|
||||
})
|
||||
}
|
||||
|
||||
return Column(columnOptions)
|
||||
}
|
||||
|
||||
export function FeatureFlagDecorators(
|
||||
featureFlag: string,
|
||||
decorators: PropertyDecorator[]
|
||||
): PropertyDecorator {
|
||||
const featureFlagRouter = getFeatureFlagRouter()
|
||||
return function (target, propertyName) {
|
||||
setImmediate_((): any => {
|
||||
const featureFlagRouter = getFeatureFlagRouter()
|
||||
|
||||
if (!featureFlagRouter.isFeatureEnabled(featureFlag)) {
|
||||
return (): void => {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
return (target: Object, propertyKey: string | symbol): void => {
|
||||
decorators.forEach((decorator) => {
|
||||
decorator(target, propertyKey)
|
||||
if (!featureFlagRouter.isFeatureEnabled(featureFlag)) {
|
||||
return
|
||||
}
|
||||
|
||||
decorators.forEach((decorator: PropertyDecorator) => {
|
||||
decorator(target, propertyName)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -44,12 +63,10 @@ export function FeatureFlagEntity(
|
||||
name?: string,
|
||||
options?: EntityOptions
|
||||
): ClassDecorator {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
return function (target: Function): void {
|
||||
target["isFeatureEnabled"] = function (): boolean {
|
||||
const featureFlagRouter = getFeatureFlagRouter()
|
||||
|
||||
// const featureFlagRouter = featureFlagsLoader(configModule)
|
||||
return featureFlagRouter.isFeatureEnabled(featureFlag)
|
||||
}
|
||||
Entity(name, options)(target)
|
||||
|
||||
@@ -27,14 +27,14 @@ export function getRetrieveConfig<TModel extends BaseEntity>(
|
||||
): FindConfig<TModel> {
|
||||
let includeFields: (keyof TModel)[] = []
|
||||
if (typeof fields !== "undefined") {
|
||||
includeFields = Array
|
||||
.from(new Set([...fields, "id"]))
|
||||
.map(field => (typeof field === "string") ? field.trim() : field) as (keyof TModel)[]
|
||||
includeFields = Array.from(new Set([...fields, "id"])).map((field) =>
|
||||
typeof field === "string" ? field.trim() : field
|
||||
) as (keyof TModel)[]
|
||||
}
|
||||
|
||||
let expandFields: string[] = []
|
||||
if (typeof expand !== "undefined") {
|
||||
expandFields = expand.map(expandRelation => expandRelation.trim())
|
||||
expandFields = expand.map((expandRelation) => expandRelation.trim())
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -106,7 +106,10 @@ export function prepareListQuery<
|
||||
orderBy = { [order]: "ASC" }
|
||||
}
|
||||
|
||||
if (queryConfig?.allowedFields?.length && !queryConfig?.allowedFields.includes(orderField)) {
|
||||
if (
|
||||
queryConfig?.allowedFields?.length &&
|
||||
!queryConfig?.allowedFields.includes(orderField)
|
||||
) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Order field ${orderField} is not valid`
|
||||
|
||||
Reference in New Issue
Block a user