fix(medusa): List products by type_id (#2427)
**What** - Fixes `GET /products` in both admin and store API so they no longer accept the param `type?: string`, but instead accept `type_id?: string[]` **Why** - Filtering by type would never return any products as `ptyp_:id` !== `ProductType`. **Testing** - Added an integration test for each endpoint. Closes CORE-695
This commit is contained in:
1 parent
05f921711f
commit
211720f24c
6 files changed
+72
-12
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Changes type to type_id for the list products endpoints in both the Store and Admin API.
|
||||||
@@ -168,6 +168,30 @@ describe("/admin/products", () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns a list of products where type_id is test-type", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/products?type_id[]=test-type", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(5)
|
||||||
|
expect(response.data.products).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
type_id: "test-type",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("doesn't expand collection and types", async () => {
|
it("doesn't expand collection and types", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,24 @@ describe("/store/products", () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("works when filtering by type_id", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get(
|
||||||
|
`/store/products?type_id[]=test-type&fields=id,title,type_id`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(5)
|
||||||
|
expect(response.data.products).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
type_id: "test-type",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("returns only published products", async () => {
|
it("returns only published products", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
|
|||||||
@@ -73,11 +73,19 @@ import { FilterableProductProps } from "../../../../types/product"
|
|||||||
* type: array
|
* type: array
|
||||||
* items:
|
* items:
|
||||||
* type: string
|
* type: string
|
||||||
|
* - in: query
|
||||||
|
* name: type_id
|
||||||
|
* style: form
|
||||||
|
* explode: false
|
||||||
|
* description: Type IDs to filter products by
|
||||||
|
* schema:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: string
|
||||||
* - (query) title {string} title to search for.
|
* - (query) title {string} title to search for.
|
||||||
* - (query) description {string} description to search for.
|
* - (query) description {string} description to search for.
|
||||||
* - (query) handle {string} handle to search for.
|
* - (query) handle {string} handle to search for.
|
||||||
* - (query) is_giftcard {boolean} Search for giftcards using is_giftcard=true.
|
* - (query) is_giftcard {boolean} Search for giftcards using is_giftcard=true.
|
||||||
* - (query) type {string} type ID to search for.
|
|
||||||
* - in: query
|
* - in: query
|
||||||
* name: created_at
|
* name: created_at
|
||||||
* description: Date comparison for when resulting products were created.
|
* description: Date comparison for when resulting products were created.
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import {
|
|||||||
IsNumber,
|
IsNumber,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
ValidateNested
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { omit, pickBy } from "lodash"
|
import { omit, pickBy } from "lodash"
|
||||||
import {
|
import {
|
||||||
CartService,
|
CartService,
|
||||||
ProductService,
|
ProductService,
|
||||||
RegionService
|
RegionService,
|
||||||
} from "../../../../services"
|
} from "../../../../services"
|
||||||
|
|
||||||
import { defaultStoreProductsRelations } from "."
|
import { defaultStoreProductsRelations } from "."
|
||||||
@@ -54,6 +54,15 @@ import { IsType } from "../../../../utils/validators/is-type"
|
|||||||
* items:
|
* items:
|
||||||
* type: string
|
* type: string
|
||||||
* - in: query
|
* - in: query
|
||||||
|
* name: type_id
|
||||||
|
* style: form
|
||||||
|
* explode: false
|
||||||
|
* description: Type IDs to search for
|
||||||
|
* schema:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: string
|
||||||
|
* - in: query
|
||||||
* name: tags
|
* name: tags
|
||||||
* style: form
|
* style: form
|
||||||
* explode: false
|
* explode: false
|
||||||
@@ -66,7 +75,6 @@ import { IsType } from "../../../../utils/validators/is-type"
|
|||||||
* - (query) description {string} description to search for.
|
* - (query) description {string} description to search for.
|
||||||
* - (query) handle {string} handle to search for.
|
* - (query) handle {string} handle to search for.
|
||||||
* - (query) is_giftcard {boolean} Search for giftcards using is_giftcard=true.
|
* - (query) is_giftcard {boolean} Search for giftcards using is_giftcard=true.
|
||||||
* - (query) type {string} type to search for.
|
|
||||||
* - in: query
|
* - in: query
|
||||||
* name: created_at
|
* name: created_at
|
||||||
* description: Date comparison for when resulting products were created.
|
* description: Date comparison for when resulting products were created.
|
||||||
@@ -301,14 +309,11 @@ export class StoreGetProductsParams extends StoreGetProductsPaginationParams {
|
|||||||
@Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase()))
|
@Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase()))
|
||||||
is_giftcard?: boolean
|
is_giftcard?: boolean
|
||||||
|
|
||||||
@IsString()
|
@IsArray()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
type?: string
|
type_id?: string[]
|
||||||
|
|
||||||
@FeatureFlagDecorators(SalesChannelFeatureFlag.key, [
|
@FeatureFlagDecorators(SalesChannelFeatureFlag.key, [IsOptional(), IsArray()])
|
||||||
IsOptional(),
|
|
||||||
IsArray(),
|
|
||||||
])
|
|
||||||
sales_channel_id?: string[]
|
sales_channel_id?: string[]
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ export class FilterableProductProps {
|
|||||||
@Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase()))
|
@Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase()))
|
||||||
is_giftcard?: boolean
|
is_giftcard?: boolean
|
||||||
|
|
||||||
@IsString()
|
@IsArray()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
type?: string
|
type_id?: string[]
|
||||||
|
|
||||||
@FeatureFlagDecorators(SalesChannelFeatureFlag.key, [IsOptional(), IsArray()])
|
@FeatureFlagDecorators(SalesChannelFeatureFlag.key, [IsOptional(), IsArray()])
|
||||||
sales_channel_id?: string[]
|
sales_channel_id?: string[]
|
||||||
|
|||||||
Reference in new issue
Block a user