feat(medusa,product,types): product type & tag store missing endpoints (#11057)
* wip: tag endpoints * feat: types, product types * feat: tests * fix: update product type schema
This commit is contained in:
1 parent
1d7eeb53ae
commit
d4cbc6218c
22 files changed
+507
-3
No files matched your search
@@ -0,0 +1,75 @@
|
|||||||
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import {
|
||||||
|
createAdminUser,
|
||||||
|
adminHeaders,
|
||||||
|
generatePublishableKey,
|
||||||
|
generateStoreHeaders,
|
||||||
|
} from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env: {},
|
||||||
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
|
let tag1
|
||||||
|
let tag2
|
||||||
|
let publishableKey
|
||||||
|
let storeHeaders
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const container = getContainer()
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
|
||||||
|
publishableKey = await generatePublishableKey(container)
|
||||||
|
storeHeaders = generateStoreHeaders({ publishableKey })
|
||||||
|
|
||||||
|
tag1 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-types",
|
||||||
|
{
|
||||||
|
value: "test1",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_type
|
||||||
|
|
||||||
|
tag2 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-types",
|
||||||
|
{
|
||||||
|
value: "test2",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_type
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("GET /store/product-types", () => {
|
||||||
|
it("returns a list of product types", async () => {
|
||||||
|
const res = await api.get("/store/product-types", storeHeaders)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.product_types).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
value: "test1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
value: "test2",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of product types matching free text search param", async () => {
|
||||||
|
const res = await api.get("/store/product-types?q=1", storeHeaders)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.product_types.length).toEqual(1)
|
||||||
|
expect(res.data.product_types).toEqual(
|
||||||
|
expect.arrayContaining([expect.objectContaining({ value: "test1" })])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||||
|
import {
|
||||||
|
createAdminUser,
|
||||||
|
adminHeaders,
|
||||||
|
generatePublishableKey,
|
||||||
|
generateStoreHeaders,
|
||||||
|
} from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env: {},
|
||||||
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
|
let tag1
|
||||||
|
let tag2
|
||||||
|
let publishableKey
|
||||||
|
let storeHeaders
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const container = getContainer()
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
|
||||||
|
publishableKey = await generatePublishableKey(container)
|
||||||
|
storeHeaders = generateStoreHeaders({ publishableKey })
|
||||||
|
|
||||||
|
tag1 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-tags",
|
||||||
|
{
|
||||||
|
value: "test1",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_tag
|
||||||
|
|
||||||
|
tag2 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-tags",
|
||||||
|
{
|
||||||
|
value: "test2",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_tag
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("GET /store/product-tags", () => {
|
||||||
|
it("returns a list of product tags", async () => {
|
||||||
|
const res = await api.get("/store/product-tags", storeHeaders)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.product_tags).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
value: "test1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
value: "test2",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of product tags matching free text search param", async () => {
|
||||||
|
const res = await api.get("/admin/product-tags?q=1", adminHeaders)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.product_tags.length).toEqual(1)
|
||||||
|
expect(res.data.product_tags).toEqual(
|
||||||
|
expect.arrayContaining([expect.objectContaining({ value: "test1" })])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -4,6 +4,9 @@ import {
|
|||||||
} from "../common"
|
} from "../common"
|
||||||
|
|
||||||
export interface StoreProductCategoryListParams
|
export interface StoreProductCategoryListParams
|
||||||
extends Omit<BaseProductCategoryListParams, "is_internal" | "is_active" | "deleted_at"> {}
|
extends Omit<
|
||||||
|
BaseProductCategoryListParams,
|
||||||
|
"is_internal" | "is_active" | "deleted_at"
|
||||||
|
> {}
|
||||||
|
|
||||||
export interface StoreProductCategoryParams extends BaseProductCategoryParams {}
|
export interface StoreProductCategoryParams extends BaseProductCategoryParams {}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from "./entities"
|
export * from "./entities"
|
||||||
export * from "./queries"
|
export * from "./queries"
|
||||||
|
export * from "./responses"
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { PaginatedResponse } from "../../common"
|
||||||
|
import { StoreProductTag } from "./entities"
|
||||||
|
|
||||||
|
export interface StoreProductTagResponse {
|
||||||
|
/**
|
||||||
|
* The tag's details.
|
||||||
|
*/
|
||||||
|
product_tag: StoreProductTag
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StoreProductTagListResponse
|
||||||
|
extends PaginatedResponse<{
|
||||||
|
/**
|
||||||
|
* The paginated list of tags.
|
||||||
|
*/
|
||||||
|
product_tags: StoreProductTag[]
|
||||||
|
}> {}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { OperatorMap } from "../../dal"
|
||||||
|
import { FindParams } from "../common"
|
||||||
|
|
||||||
export interface BaseProductType {
|
export interface BaseProductType {
|
||||||
/**
|
/**
|
||||||
* The product type's ID.
|
* The product type's ID.
|
||||||
@@ -24,3 +27,26 @@ export interface BaseProductType {
|
|||||||
*/
|
*/
|
||||||
metadata?: Record<string, unknown> | null
|
metadata?: Record<string, unknown> | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BaseProductTypeListParams extends FindParams {
|
||||||
|
/**
|
||||||
|
* Query or keyword to apply on the type's searchable fields.
|
||||||
|
*/
|
||||||
|
q?: string
|
||||||
|
/**
|
||||||
|
* Filter by type ID(s).
|
||||||
|
*/
|
||||||
|
id?: string | string[]
|
||||||
|
/**
|
||||||
|
* Filter by value(s).
|
||||||
|
*/
|
||||||
|
value?: string | string[]
|
||||||
|
/**
|
||||||
|
* Apply filters on the creation date.
|
||||||
|
*/
|
||||||
|
created_at?: OperatorMap<string>
|
||||||
|
/**
|
||||||
|
* Apply filters on the update date.
|
||||||
|
*/
|
||||||
|
updated_at?: OperatorMap<string>
|
||||||
|
}
|
||||||
@@ -1 +1,3 @@
|
|||||||
export * from "./entities"
|
export * from "./entities"
|
||||||
|
export * from "./queries"
|
||||||
|
export * from "./responses"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { BaseFilterable } from "../../../dal"
|
||||||
|
import { SelectParams } from "../../common"
|
||||||
|
import { BaseProductTypeListParams } from "../common"
|
||||||
|
|
||||||
|
export interface StoreProductTypeListParams
|
||||||
|
extends BaseProductTypeListParams,
|
||||||
|
BaseFilterable<StoreProductTypeListParams> {}
|
||||||
|
|
||||||
|
export interface StoreProductTypeParams extends SelectParams {}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { PaginatedResponse } from "../../common"
|
||||||
|
import { StoreProductType } from "./entities"
|
||||||
|
|
||||||
|
export interface StoreProductTypeResponse {
|
||||||
|
/**
|
||||||
|
* The type's details.
|
||||||
|
*/
|
||||||
|
product_type: StoreProductType
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StoreProductTypeListResponse
|
||||||
|
extends PaginatedResponse<{
|
||||||
|
/**
|
||||||
|
* The paginated list of types.
|
||||||
|
*/
|
||||||
|
product_types: StoreProductType[]
|
||||||
|
}> {}
|
||||||
@@ -54,6 +54,8 @@ import { storePaymentCollectionsMiddlewares } from "./store/payment-collections/
|
|||||||
import { storePaymentProvidersMiddlewares } from "./store/payment-providers/middlewares"
|
import { storePaymentProvidersMiddlewares } from "./store/payment-providers/middlewares"
|
||||||
import { storeProductCategoryRoutesMiddlewares } from "./store/product-categories/middlewares"
|
import { storeProductCategoryRoutesMiddlewares } from "./store/product-categories/middlewares"
|
||||||
import { storeProductRoutesMiddlewares } from "./store/products/middlewares"
|
import { storeProductRoutesMiddlewares } from "./store/products/middlewares"
|
||||||
|
import { storeProductTagRoutesMiddlewares } from "./store/product-tags/middlewares"
|
||||||
|
import { storeProductTypeRoutesMiddlewares } from "./store/product-types/middlewares"
|
||||||
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
|
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
|
||||||
import { storeReturnReasonRoutesMiddlewares } from "./store/return-reasons/middlewares"
|
import { storeReturnReasonRoutesMiddlewares } from "./store/return-reasons/middlewares"
|
||||||
import { storeShippingOptionRoutesMiddlewares } from "./store/shipping-options/middlewares"
|
import { storeShippingOptionRoutesMiddlewares } from "./store/shipping-options/middlewares"
|
||||||
@@ -69,6 +71,8 @@ export default defineMiddlewares([
|
|||||||
...storeCartRoutesMiddlewares,
|
...storeCartRoutesMiddlewares,
|
||||||
...storeCollectionRoutesMiddlewares,
|
...storeCollectionRoutesMiddlewares,
|
||||||
...storeProductCategoryRoutesMiddlewares,
|
...storeProductCategoryRoutesMiddlewares,
|
||||||
|
...storeProductTagRoutesMiddlewares,
|
||||||
|
...storeProductTypeRoutesMiddlewares,
|
||||||
...storePaymentProvidersMiddlewares,
|
...storePaymentProvidersMiddlewares,
|
||||||
...storeShippingOptionRoutesMiddlewares,
|
...storeShippingOptionRoutesMiddlewares,
|
||||||
...storePaymentCollectionsMiddlewares,
|
...storePaymentCollectionsMiddlewares,
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { StoreProductTagResponse } from "@medusajs/framework/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
MedusaError,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
|
||||||
|
import { StoreProductTagParamsType } from "../validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreProductTagParamsType>,
|
||||||
|
res: MedusaResponse<StoreProductTagResponse>
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
|
const { data } = await query.graph({
|
||||||
|
entity: "product_tag",
|
||||||
|
filters: {
|
||||||
|
id: req.params.id,
|
||||||
|
},
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!data.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Product tag with id: ${req.params.id} was not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
res.json({ product_tag: data[0] })
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { MiddlewareRoute } from "@medusajs/framework/http"
|
||||||
|
import { validateAndTransformQuery } from "@medusajs/framework"
|
||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
import { StoreProductTagsParams, StoreProductTagParams } from "./validators"
|
||||||
|
|
||||||
|
export const storeProductTagRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/product-tags",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreProductTagsParams,
|
||||||
|
QueryConfig.listProductTagConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/product-tags/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreProductTagParams,
|
||||||
|
QueryConfig.retrieveProductTagConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export const defaults = [
|
||||||
|
"id",
|
||||||
|
"value",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"metadata",
|
||||||
|
"*products",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveProductTagConfig = {
|
||||||
|
defaults,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listProductTagConfig = {
|
||||||
|
defaults,
|
||||||
|
defaultLimit: 50,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { StoreProductTagListResponse } from "@medusajs/framework/types"
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import { StoreProductTagsParamsType } from "./validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreProductTagsParamsType>,
|
||||||
|
res: MedusaResponse<StoreProductTagListResponse>
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
|
const { data: product_tags, metadata } = await query.graph({
|
||||||
|
entity: "product_tag",
|
||||||
|
filters: req.filterableFields,
|
||||||
|
pagination: req.queryConfig.pagination,
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
product_tags,
|
||||||
|
count: metadata?.count ?? 0,
|
||||||
|
offset: metadata?.skip ?? 0,
|
||||||
|
limit: metadata?.take ?? 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { applyAndAndOrOperators } from "../../utils/common-validators"
|
||||||
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../utils/validators"
|
||||||
|
|
||||||
|
export type StoreProductTagParamsType = z.infer<typeof StoreProductTagParams>
|
||||||
|
|
||||||
|
export const StoreProductTagParams = createSelectParams().merge(z.object({}))
|
||||||
|
|
||||||
|
export const StoreProductTagsParamsFields = z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
value: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type StoreProductTagsParamsType = z.infer<typeof StoreProductTagsParams>
|
||||||
|
export const StoreProductTagsParams = createFindParams({
|
||||||
|
offset: 0,
|
||||||
|
limit: 50,
|
||||||
|
})
|
||||||
|
.merge(StoreProductTagsParamsFields)
|
||||||
|
.merge(applyAndAndOrOperators(StoreProductTagsParamsFields))
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { StoreProductTypeResponse } from "@medusajs/framework/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
MedusaError,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
|
||||||
|
import { StoreProductTypeParamsType } from "../validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreProductTypeParamsType>,
|
||||||
|
res: MedusaResponse<StoreProductTypeResponse>
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
|
const { data } = await query.graph({
|
||||||
|
entity: "product_type",
|
||||||
|
filters: {
|
||||||
|
id: req.params.id,
|
||||||
|
},
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!data.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Product type with id: ${req.params.id} was not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
res.json({ product_type: data[0] })
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { MiddlewareRoute } from "@medusajs/framework/http"
|
||||||
|
import { validateAndTransformQuery } from "@medusajs/framework"
|
||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
|
||||||
|
import { StoreProductTypesParams } from "./validators"
|
||||||
|
|
||||||
|
export const storeProductTypeRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/product-types",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreProductTypesParams,
|
||||||
|
QueryConfig.listProductTypeConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/product-types/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreProductTypesParams,
|
||||||
|
QueryConfig.retrieveProductTypeConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export const defaults = [
|
||||||
|
"id",
|
||||||
|
"value",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"metadata",
|
||||||
|
"*products",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveProductTypeConfig = {
|
||||||
|
defaults,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listProductTypeConfig = {
|
||||||
|
defaults,
|
||||||
|
defaultLimit: 50,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { StoreProductTypeListResponse } from "@medusajs/framework/types"
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "@medusajs/framework/http"
|
||||||
|
import { StoreProductTypesParamsType } from "./validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreProductTypesParamsType>,
|
||||||
|
res: MedusaResponse<StoreProductTypeListResponse>
|
||||||
|
) => {
|
||||||
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
|
const { data: product_types, metadata } = await query.graph({
|
||||||
|
entity: "product_type",
|
||||||
|
filters: req.filterableFields,
|
||||||
|
pagination: req.queryConfig.pagination,
|
||||||
|
fields: req.queryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
product_types,
|
||||||
|
count: metadata?.count ?? 0,
|
||||||
|
offset: metadata?.skip ?? 0,
|
||||||
|
limit: metadata?.take ?? 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { applyAndAndOrOperators } from "../../utils/common-validators"
|
||||||
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../utils/validators"
|
||||||
|
|
||||||
|
export type StoreProductTypeParamsType = z.infer<typeof StoreProductTypeParams>
|
||||||
|
|
||||||
|
export const StoreProductTypeParams = createSelectParams().merge(z.object({}))
|
||||||
|
|
||||||
|
export const StoreProductTypesParamsFields = z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
value: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type StoreProductTypesParamsType = z.infer<
|
||||||
|
typeof StoreProductTypesParams
|
||||||
|
>
|
||||||
|
export const StoreProductTypesParams = createFindParams({
|
||||||
|
offset: 0,
|
||||||
|
limit: 50,
|
||||||
|
})
|
||||||
|
.merge(StoreProductTypesParamsFields)
|
||||||
|
.merge(applyAndAndOrOperators(StoreProductTypesParamsFields))
|
||||||
@@ -6,7 +6,7 @@ const ProductType = model
|
|||||||
id: model.id({ prefix: "ptyp" }).primaryKey(),
|
id: model.id({ prefix: "ptyp" }).primaryKey(),
|
||||||
value: model.text().searchable(),
|
value: model.text().searchable(),
|
||||||
metadata: model.json().nullable(),
|
metadata: model.json().nullable(),
|
||||||
product: model.hasMany(() => Product, {
|
products: model.hasMany(() => Product, {
|
||||||
mappedBy: "type",
|
mappedBy: "type",
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const Product = model
|
|||||||
}),
|
}),
|
||||||
type: model
|
type: model
|
||||||
.belongsTo(() => ProductType, {
|
.belongsTo(() => ProductType, {
|
||||||
mappedBy: "product",
|
mappedBy: "products",
|
||||||
})
|
})
|
||||||
.nullable(),
|
.nullable(),
|
||||||
tags: model.manyToMany(() => ProductTag, {
|
tags: model.manyToMany(() => ProductTag, {
|
||||||
|
|||||||
Reference in new issue
Block a user