fix: storefront product filtering (#1189)
* fix: allow multiple ids in list + expand, fields param * fix: add filtering by title * fix: adds integration test * fix: adds integration test of product variant filtering * fix: integration tests * fix: unit tests * fix: refactor query param parsing
This commit is contained in:
@@ -33,6 +33,8 @@ describe("GET /admin/products/:id", () => {
|
||||
"id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"status",
|
||||
"external_id",
|
||||
"description",
|
||||
"handle",
|
||||
"is_giftcard",
|
||||
@@ -51,6 +53,7 @@ describe("GET /admin/products/:id", () => {
|
||||
"material",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"metadata",
|
||||
],
|
||||
relations: [
|
||||
|
||||
@@ -73,6 +73,8 @@ export const defaultAdminProductFields = [
|
||||
"id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"status",
|
||||
"external_id",
|
||||
"description",
|
||||
"handle",
|
||||
"is_giftcard",
|
||||
@@ -91,6 +93,7 @@ export const defaultAdminProductFields = [
|
||||
"material",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"metadata",
|
||||
]
|
||||
|
||||
@@ -98,6 +101,8 @@ export const allowedAdminProductFields = [
|
||||
"id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"status",
|
||||
"external_id",
|
||||
"description",
|
||||
"handle",
|
||||
"is_giftcard",
|
||||
@@ -116,6 +121,7 @@ export const allowedAdminProductFields = [
|
||||
"material",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"metadata",
|
||||
]
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ import {
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { omit, pickBy, identity } from "lodash"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { defaultStoreProductsRelations } from "."
|
||||
import { ProductService } from "../../../../services"
|
||||
import { DateComparisonOperator } from "../../../../types/common"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
||||
|
||||
/**
|
||||
@@ -64,6 +64,8 @@ export default async (req, res) => {
|
||||
const validated = await validator(StoreGetProductsParams, req.query)
|
||||
|
||||
const filterableFields: StoreGetProductsParams = omit(validated, [
|
||||
"fields",
|
||||
"expand",
|
||||
"limit",
|
||||
"offset",
|
||||
])
|
||||
@@ -71,8 +73,23 @@ export default async (req, res) => {
|
||||
// get only published products for store endpoint
|
||||
filterableFields["status"] = ["published"]
|
||||
|
||||
let includeFields: string[] = []
|
||||
if (validated.fields) {
|
||||
const set = new Set(validated.fields.split(","))
|
||||
set.add("id")
|
||||
includeFields = [...set]
|
||||
}
|
||||
|
||||
let expandFields: string[] = []
|
||||
if (validated.expand) {
|
||||
expandFields = validated.expand.split(",")
|
||||
}
|
||||
|
||||
const listConfig = {
|
||||
relations: defaultStoreProductsRelations,
|
||||
select: includeFields.length ? includeFields : undefined,
|
||||
relations: expandFields.length
|
||||
? expandFields
|
||||
: defaultStoreProductsRelations,
|
||||
skip: validated.offset,
|
||||
take: validated.limit,
|
||||
}
|
||||
@@ -91,6 +108,14 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
export class StoreGetProductsPaginationParams {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
fields?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
expand?: string
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@@ -103,9 +128,9 @@ export class StoreGetProductsPaginationParams {
|
||||
}
|
||||
|
||||
export class StoreGetProductsParams extends StoreGetProductsPaginationParams {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
id?: string
|
||||
@IsType([String, [String]])
|
||||
id?: string | string[]
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { Type } from "class-transformer"
|
||||
import { omit } from "lodash"
|
||||
import { IsInt, IsOptional, IsString } from "class-validator"
|
||||
import { defaultStoreVariantRelations } from "."
|
||||
import { FilterableProductVariantProps } from "../../../../types/product-variant"
|
||||
import ProductVariantService from "../../../../services/product-variant"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import { NumericalComparisonOperator } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [get] /variants
|
||||
@@ -29,17 +33,14 @@ import { validator } from "../../../../utils/validator"
|
||||
* $ref: "#/components/schemas/product_variant"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { limit, offset, expand, ids } = await validator(
|
||||
StoreGetVariantsParams,
|
||||
req.query
|
||||
)
|
||||
const validated = await validator(StoreGetVariantsParams, req.query)
|
||||
const { expand, offset, limit } = validated
|
||||
|
||||
let expandFields: string[] = []
|
||||
if (expand) {
|
||||
expandFields = expand.split(",")
|
||||
}
|
||||
|
||||
let selector = {}
|
||||
const listConfig = {
|
||||
relations: expandFields.length
|
||||
? expandFields
|
||||
@@ -48,14 +49,21 @@ export default async (req, res) => {
|
||||
take: limit,
|
||||
}
|
||||
|
||||
if (ids) {
|
||||
selector = { id: ids.split(",") }
|
||||
const filterableFields: FilterableProductVariantProps = omit(validated, [
|
||||
"ids",
|
||||
"limit",
|
||||
"offset",
|
||||
"expand",
|
||||
])
|
||||
|
||||
if (validated.ids) {
|
||||
filterableFields.id = validated.ids.split(",")
|
||||
}
|
||||
|
||||
const variantService: ProductVariantService = req.scope.resolve(
|
||||
"productVariantService"
|
||||
)
|
||||
const variants = await variantService.list(selector, listConfig)
|
||||
const variants = await variantService.list(filterableFields, listConfig)
|
||||
|
||||
res.json({ variants })
|
||||
}
|
||||
@@ -78,4 +86,16 @@ export class StoreGetVariantsParams {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
ids?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
id?: string | string[]
|
||||
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
title?: string | string[]
|
||||
|
||||
@IsOptional()
|
||||
@IsType([Number, NumericalComparisonOperator])
|
||||
inventory_quantity?: number | NumericalComparisonOperator
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user