feat(medusa): Allow to query product tags by condition id (#2340)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(medusa): Allow to query product tags by condition id
|
||||||
@@ -4,9 +4,9 @@ exports[`/admin/product-tags GET /admin/product-tags returns a list of product t
|
|||||||
Array [
|
Array [
|
||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"id": "tag1",
|
"id": "tag4",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"value": "123",
|
"value": "1234",
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
@@ -16,9 +16,9 @@ Array [
|
|||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"id": "tag4",
|
"id": "tag1",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"value": "1234",
|
"value": "123",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
@@ -27,9 +27,9 @@ exports[`/admin/product-tags GET /admin/product-tags returns a list of product t
|
|||||||
Array [
|
Array [
|
||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"id": "tag1",
|
"id": "tag4",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"value": "123",
|
"value": "1234",
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
@@ -39,9 +39,9 @@ Array [
|
|||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"id": "tag4",
|
"id": "tag1",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"value": "1234",
|
"value": "123",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
const path = require("path")
|
const path = require("path")
|
||||||
|
|
||||||
|
const { IdMap } = require("medusa-test-utils")
|
||||||
|
|
||||||
const setupServer = require("../../../helpers/setup-server")
|
const setupServer = require("../../../helpers/setup-server")
|
||||||
const { useApi } = require("../../../helpers/use-api")
|
const { useApi } = require("../../../helpers/use-api")
|
||||||
const { initDb, useDb } = require("../../../helpers/use-db")
|
const { initDb, useDb } = require("../../../helpers/use-db")
|
||||||
|
|
||||||
const adminSeeder = require("../../helpers/admin-seeder")
|
const adminSeeder = require("../../helpers/admin-seeder")
|
||||||
const productSeeder = require("../../helpers/product-seeder")
|
const productSeeder = require("../../helpers/product-seeder")
|
||||||
|
const {
|
||||||
|
DiscountConditionType,
|
||||||
|
DiscountConditionOperator,
|
||||||
|
} = require("@medusajs/medusa")
|
||||||
|
const { simpleDiscountFactory } = require("../../factories")
|
||||||
|
const { DiscountRuleType, AllocationType } = require("@medusajs/medusa/dist")
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
|
const adminReqConfig = {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
describe("/admin/product-tags", () => {
|
describe("/admin/product-tags", () => {
|
||||||
let medusaProcess
|
let medusaProcess
|
||||||
let dbConnection
|
let dbConnection
|
||||||
@@ -28,8 +42,8 @@ describe("/admin/product-tags", () => {
|
|||||||
|
|
||||||
describe("GET /admin/product-tags", () => {
|
describe("GET /admin/product-tags", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await productSeeder(dbConnection)
|
|
||||||
await adminSeeder(dbConnection)
|
await adminSeeder(dbConnection)
|
||||||
|
await productSeeder(dbConnection)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
@@ -41,11 +55,7 @@ describe("/admin/product-tags", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const res = await api
|
const res = await api
|
||||||
.get("/admin/product-tags", {
|
.get("/admin/product-tags", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
})
|
})
|
||||||
@@ -68,11 +78,7 @@ describe("/admin/product-tags", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const res = await api
|
const res = await api
|
||||||
.get("/admin/product-tags?q=123", {
|
.get("/admin/product-tags?q=123", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
})
|
})
|
||||||
@@ -95,5 +101,78 @@ describe("/admin/product-tags", () => {
|
|||||||
tagMatch,
|
tagMatch,
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns a list of product tags filtered by discount condition id", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const resTags = await api.get("/admin/product-tags", adminReqConfig)
|
||||||
|
|
||||||
|
const tag1 = resTags.data.product_tags[0]
|
||||||
|
const tag2 = resTags.data.product_tags[2]
|
||||||
|
|
||||||
|
const buildDiscountData = (code, conditionId, tags) => {
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
rule: {
|
||||||
|
type: DiscountRuleType.PERCENTAGE,
|
||||||
|
value: 10,
|
||||||
|
allocation: AllocationType.TOTAL,
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
id: conditionId,
|
||||||
|
type: DiscountConditionType.PRODUCT_TAGS,
|
||||||
|
operator: DiscountConditionOperator.IN,
|
||||||
|
product_tags: tags,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const discountConditionId = IdMap.getId("discount-condition-tag-1")
|
||||||
|
await simpleDiscountFactory(
|
||||||
|
dbConnection,
|
||||||
|
buildDiscountData("code-1", discountConditionId, [tag1.id])
|
||||||
|
)
|
||||||
|
|
||||||
|
const discountConditionId2 = IdMap.getId("discount-condition-tag-2")
|
||||||
|
await simpleDiscountFactory(
|
||||||
|
dbConnection,
|
||||||
|
buildDiscountData("code-2", discountConditionId2, [tag2.id])
|
||||||
|
)
|
||||||
|
|
||||||
|
let res = await api.get(
|
||||||
|
`/admin/product-tags?discount_condition_id=${discountConditionId}`,
|
||||||
|
adminReqConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.product_tags).toHaveLength(1)
|
||||||
|
expect(res.data.product_tags).toEqual(
|
||||||
|
expect.arrayContaining([expect.objectContaining({ id: tag1.id })])
|
||||||
|
)
|
||||||
|
|
||||||
|
res = await api.get(
|
||||||
|
`/admin/product-tags?discount_condition_id=${discountConditionId2}`,
|
||||||
|
adminReqConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.product_tags).toHaveLength(1)
|
||||||
|
expect(res.data.product_tags).toEqual(
|
||||||
|
expect.arrayContaining([expect.objectContaining({ id: tag2.id })])
|
||||||
|
)
|
||||||
|
|
||||||
|
res = await api.get(`/admin/product-tags`, adminReqConfig)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.product_tags).toHaveLength(3)
|
||||||
|
expect(res.data.product_tags).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: tag1.id }),
|
||||||
|
expect.objectContaining({ id: tag2.id }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
import { Order } from "../../../.."
|
import { Order } from "../../../.."
|
||||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
|
||||||
import {
|
import {
|
||||||
DeleteResponse,
|
DeleteResponse,
|
||||||
FindParams,
|
FindParams,
|
||||||
PaginatedResponse,
|
PaginatedResponse,
|
||||||
} from "../../../../types/common"
|
} from "../../../../types/common"
|
||||||
import { FlagRouter } from "../../../../utils/flag-router"
|
|
||||||
import middlewares, { transformQuery } from "../../../middlewares"
|
import middlewares, { transformQuery } from "../../../middlewares"
|
||||||
import { AdminGetOrdersParams } from "./list-orders"
|
import { AdminGetOrdersParams } from "./list-orders"
|
||||||
|
import { FlagRouter } from "../../../../utils/flag-router"
|
||||||
|
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,25 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import { ProductTag } from "../../../.."
|
import { ProductTag } from "../../../.."
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import middlewares from "../../../middlewares"
|
import middlewares, { transformQuery } from "../../../middlewares"
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
|
import { AdminGetProductTagsParams } from "./list-product-tags"
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
|
|
||||||
export default (app) => {
|
export default (app) => {
|
||||||
app.use("/product-tags", route)
|
app.use("/product-tags", route)
|
||||||
|
|
||||||
route.get("/", middlewares.wrap(require("./list-product-tags").default))
|
route.get(
|
||||||
|
"/",
|
||||||
|
transformQuery(AdminGetProductTagsParams, {
|
||||||
|
defaultFields: defaultAdminProductTagsFields,
|
||||||
|
defaultRelations: defaultAdminProductTagsRelations,
|
||||||
|
allowedFields: allowedAdminProductTagsFields,
|
||||||
|
isList: true,
|
||||||
|
}),
|
||||||
|
middlewares.wrap(require("./list-product-tags").default)
|
||||||
|
)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
DateComparisonOperator,
|
DateComparisonOperator,
|
||||||
FindConfig,
|
|
||||||
StringComparisonOperator,
|
StringComparisonOperator,
|
||||||
} from "../../../../types/common"
|
} from "../../../../types/common"
|
||||||
import { IsNumber, IsOptional, IsString } from "class-validator"
|
import { IsNumber, IsOptional, IsString } from "class-validator"
|
||||||
import {
|
|
||||||
allowedAdminProductTagsFields,
|
|
||||||
defaultAdminProductTagsFields,
|
|
||||||
defaultAdminProductTagsRelations,
|
|
||||||
} from "."
|
|
||||||
import { identity, omit, pickBy } from "lodash"
|
|
||||||
|
|
||||||
import { IsType } from "../../../../utils/validators/is-type"
|
import { IsType } from "../../../../utils/validators/is-type"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { ProductTag } from "../../../../models/product-tag"
|
|
||||||
import ProductTagService from "../../../../services/product-tag"
|
import ProductTagService from "../../../../services/product-tag"
|
||||||
import { Type } from "class-transformer"
|
import { Type } from "class-transformer"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { Request, Response } from "express"
|
||||||
import { isDefined } from "../../../../utils"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /product-tags
|
* @oas [get] /product-tags
|
||||||
@@ -29,6 +19,7 @@ import { isDefined } from "../../../../utils"
|
|||||||
* - (query) limit=10 {integer} The number of tags to return.
|
* - (query) limit=10 {integer} The number of tags to return.
|
||||||
* - (query) offset=0 {integer} The number of items to skip before the results.
|
* - (query) offset=0 {integer} The number of items to skip before the results.
|
||||||
* - (query) order {string} The field to sort items by.
|
* - (query) order {string} The field to sort items by.
|
||||||
|
* - (query) discount_condition_id {string} The discount condition id on which to filter the tags.
|
||||||
* - in: query
|
* - in: query
|
||||||
* name: value
|
* name: value
|
||||||
* style: form
|
* style: form
|
||||||
@@ -144,48 +135,21 @@ import { isDefined } from "../../../../utils"
|
|||||||
* "500":
|
* "500":
|
||||||
* $ref: "#/components/responses/500_error"
|
* $ref: "#/components/responses/500_error"
|
||||||
*/
|
*/
|
||||||
export default async (req, res) => {
|
export default async (req: Request, res: Response) => {
|
||||||
const validated = await validator(AdminGetProductTagsParams, req.query)
|
|
||||||
|
|
||||||
const tagService: ProductTagService = req.scope.resolve("productTagService")
|
const tagService: ProductTagService = req.scope.resolve("productTagService")
|
||||||
|
const { listConfig, filterableFields } = req
|
||||||
const listConfig: FindConfig<ProductTag> = {
|
const { skip, take } = req.listConfig
|
||||||
select: defaultAdminProductTagsFields as (keyof ProductTag)[],
|
|
||||||
relations: defaultAdminProductTagsRelations,
|
|
||||||
skip: validated.offset,
|
|
||||||
take: validated.limit,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(validated.order)) {
|
|
||||||
let orderField = validated.order
|
|
||||||
if (validated.order.startsWith("-")) {
|
|
||||||
const [, field] = validated.order.split("-")
|
|
||||||
orderField = field
|
|
||||||
listConfig.order = { [field]: "DESC" }
|
|
||||||
} else {
|
|
||||||
listConfig.order = { [validated.order]: "ASC" }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowedAdminProductTagsFields.includes(orderField)) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
"Order field must be a valid product tag field"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const filterableFields = omit(validated, ["limit", "offset"])
|
|
||||||
|
|
||||||
const [tags, count] = await tagService.listAndCount(
|
const [tags, count] = await tagService.listAndCount(
|
||||||
pickBy(filterableFields, identity),
|
filterableFields,
|
||||||
listConfig
|
listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
product_tags: tags,
|
product_tags: tags,
|
||||||
count,
|
count,
|
||||||
offset: validated.offset,
|
offset: skip,
|
||||||
limit: validated.limit,
|
limit: take,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,18 +165,17 @@ export class AdminGetProductTagsPaginationParams {
|
|||||||
offset = 0
|
offset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
export class AdminGetProductTagsParams extends AdminGetProductTagsPaginationParams {
|
export class AdminGetProductTagsParams extends AdminGetProductTagsPaginationParams {
|
||||||
@IsType([String, [String], StringComparisonOperator])
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@IsType([String, [String], StringComparisonOperator])
|
||||||
id?: string | string[] | StringComparisonOperator
|
id?: string | string[] | StringComparisonOperator
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
q?: string
|
q?: string
|
||||||
|
|
||||||
@IsType([String, [String], StringComparisonOperator])
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@IsType([String, [String], StringComparisonOperator])
|
||||||
value?: string | string[] | StringComparisonOperator
|
value?: string | string[] | StringComparisonOperator
|
||||||
|
|
||||||
@IsType([DateComparisonOperator])
|
@IsType([DateComparisonOperator])
|
||||||
@@ -226,4 +189,8 @@ export class AdminGetProductTagsParams extends AdminGetProductTagsPaginationPara
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
order?: string
|
order?: string
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
discount_condition_id?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,38 @@
|
|||||||
import { EntityRepository, In, Repository } from "typeorm"
|
import { EntityRepository, In, Repository } from "typeorm"
|
||||||
import { ProductTag } from "../models/product-tag"
|
import { ProductTag } from "../models/product-tag"
|
||||||
|
import { ExtendedFindConfig } from "../types/common"
|
||||||
|
|
||||||
type UpsertTagsInput = (Partial<ProductTag> & {
|
type UpsertTagsInput = (Partial<ProductTag> & {
|
||||||
value: string
|
value: string
|
||||||
})[]
|
})[]
|
||||||
|
|
||||||
|
type ProductTagSelector = Partial<ProductTag> & {
|
||||||
|
q?: string
|
||||||
|
discount_condition_id?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DefaultWithoutRelations = Omit<
|
||||||
|
ExtendedFindConfig<ProductTag, ProductTagSelector>,
|
||||||
|
"relations"
|
||||||
|
>
|
||||||
|
|
||||||
|
export type FindWithoutRelationsOptions = DefaultWithoutRelations & {
|
||||||
|
where: DefaultWithoutRelations["where"] & {
|
||||||
|
discount_condition_id?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EntityRepository(ProductTag)
|
@EntityRepository(ProductTag)
|
||||||
export class ProductTagRepository extends Repository<ProductTag> {
|
export class ProductTagRepository extends Repository<ProductTag> {
|
||||||
public async listTagsByUsage(count = 10): Promise<ProductTag[]> {
|
public async listTagsByUsage(count = 10): Promise<ProductTag[]> {
|
||||||
return await this.query(
|
return await this.query(
|
||||||
`
|
`
|
||||||
SELECT id, COUNT(pts.product_tag_id) as usage_count, pt.value
|
SELECT id, COUNT(pts.product_tag_id) as usage_count, pt.value
|
||||||
FROM product_tag pt
|
FROM product_tag pt
|
||||||
LEFT JOIN product_tags pts ON pt.id = pts.product_tag_id
|
LEFT JOIN product_tags pts ON pt.id = pts.product_tag_id
|
||||||
GROUP BY id
|
GROUP BY id
|
||||||
ORDER BY usage_count DESC
|
ORDER BY usage_count DESC
|
||||||
LIMIT $1
|
LIMIT $1
|
||||||
`,
|
`,
|
||||||
[count]
|
[count]
|
||||||
)
|
)
|
||||||
@@ -47,4 +64,33 @@ export class ProductTagRepository extends Repository<ProductTag> {
|
|||||||
|
|
||||||
return upsertedTags
|
return upsertedTags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findAndCountByDiscountConditionId(
|
||||||
|
conditionId: string,
|
||||||
|
query: ExtendedFindConfig<ProductTag, Partial<ProductTag>>
|
||||||
|
) {
|
||||||
|
const qb = this.createQueryBuilder("pt")
|
||||||
|
|
||||||
|
if (query?.select) {
|
||||||
|
qb.select(query.select.map((select) => `pt.${select}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.skip) {
|
||||||
|
qb.skip(query.skip)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.take) {
|
||||||
|
qb.take(query.take)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await qb
|
||||||
|
.where(query.where)
|
||||||
|
.innerJoin(
|
||||||
|
"discount_condition_product_tag",
|
||||||
|
"dc_pt",
|
||||||
|
`dc_pt.product_tag_id = pt.id AND dc_pt.condition_id = :dcId`,
|
||||||
|
{ dcId: conditionId }
|
||||||
|
)
|
||||||
|
.getManyAndCount()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { EntityManager, ILike, SelectQueryBuilder } from "typeorm"
|
import { EntityManager, ILike } from "typeorm"
|
||||||
import { ProductTag } from "../models"
|
import { ProductTag } from "../models"
|
||||||
import { ProductTagRepository } from "../repositories/product-tag"
|
import { ProductTagRepository } from "../repositories/product-tag"
|
||||||
import { FindConfig } from "../types/common"
|
import { FindConfig } from "../types/common"
|
||||||
import { FilterableProductTagProps } from "../types/product"
|
|
||||||
import { TransactionBaseService } from "../interfaces"
|
import { TransactionBaseService } from "../interfaces"
|
||||||
import { buildQuery } from "../utils"
|
import { buildQuery, isString } from "../utils"
|
||||||
|
|
||||||
type ProductTagConstructorProps = {
|
type ProductTagConstructorProps = {
|
||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
@@ -70,13 +69,14 @@ class ProductTagService extends TransactionBaseService {
|
|||||||
* @return the result of the find operation
|
* @return the result of the find operation
|
||||||
*/
|
*/
|
||||||
async list(
|
async list(
|
||||||
selector: FilterableProductTagProps = {},
|
selector: Partial<ProductTag> & {
|
||||||
|
q?: string
|
||||||
|
discount_condition_id?: string
|
||||||
|
} = {},
|
||||||
config: FindConfig<ProductTag> = { skip: 0, take: 20 }
|
config: FindConfig<ProductTag> = { skip: 0, take: 20 }
|
||||||
): Promise<ProductTag[]> {
|
): Promise<ProductTag[]> {
|
||||||
const tagRepo = this.manager_.getCustomRepository(this.tagRepo_)
|
const [tags] = await this.listAndCount(selector, config)
|
||||||
|
return tags
|
||||||
const query = buildQuery(selector, config)
|
|
||||||
return await tagRepo.find(query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,13 +86,16 @@ class ProductTagService extends TransactionBaseService {
|
|||||||
* @return the result of the find operation
|
* @return the result of the find operation
|
||||||
*/
|
*/
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector: FilterableProductTagProps = {},
|
selector: Partial<ProductTag> & {
|
||||||
|
q?: string
|
||||||
|
discount_condition_id?: string
|
||||||
|
} = {},
|
||||||
config: FindConfig<ProductTag> = { skip: 0, take: 20 }
|
config: FindConfig<ProductTag> = { skip: 0, take: 20 }
|
||||||
): Promise<[ProductTag[], number]> {
|
): Promise<[ProductTag[], number]> {
|
||||||
const tagRepo = this.manager_.getCustomRepository(this.tagRepo_)
|
const tagRepo = this.manager_.getCustomRepository(this.tagRepo_)
|
||||||
|
|
||||||
let q: string | undefined = undefined
|
let q: string | undefined
|
||||||
if ("q" in selector) {
|
if (isString(selector.q)) {
|
||||||
q = selector.q
|
q = selector.q
|
||||||
delete selector.q
|
delete selector.q
|
||||||
}
|
}
|
||||||
@@ -100,13 +103,16 @@ class ProductTagService extends TransactionBaseService {
|
|||||||
const query = buildQuery(selector, config)
|
const query = buildQuery(selector, config)
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
const where = query.where
|
query.where.value = ILike(`%${q}%`)
|
||||||
|
}
|
||||||
|
|
||||||
delete where.value
|
if (query.where.discount_condition_id) {
|
||||||
|
const discountConditionId = query.where.discount_condition_id as string
|
||||||
query.where = (qb: SelectQueryBuilder<ProductTag>): void => {
|
delete query.where.discount_condition_id
|
||||||
qb.where(where).andWhere([{ value: ILike(`%${q}%`) }])
|
return await tagRepo.findAndCountByDiscountConditionId(
|
||||||
}
|
discountConditionId,
|
||||||
|
query
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await tagRepo.findAndCount(query)
|
return await tagRepo.findAndCount(query)
|
||||||
|
|||||||
@@ -12,11 +12,7 @@ import { Product, ProductOptionValue, ProductStatus } from "../models"
|
|||||||
import { FeatureFlagDecorators } from "../utils/feature-flag-decorators"
|
import { FeatureFlagDecorators } from "../utils/feature-flag-decorators"
|
||||||
import { optionalBooleanMapper } from "../utils/validators/is-boolean"
|
import { optionalBooleanMapper } from "../utils/validators/is-boolean"
|
||||||
import { IsType } from "../utils/validators/is-type"
|
import { IsType } from "../utils/validators/is-type"
|
||||||
import {
|
import { DateComparisonOperator, FindConfig } from "./common"
|
||||||
DateComparisonOperator,
|
|
||||||
FindConfig,
|
|
||||||
StringComparisonOperator,
|
|
||||||
} from "./common"
|
|
||||||
import { PriceListLoadConfig } from "./price-list"
|
import { PriceListLoadConfig } from "./price-list"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,28 +83,6 @@ export class FilterableProductProps {
|
|||||||
deleted_at?: DateComparisonOperator
|
deleted_at?: DateComparisonOperator
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FilterableProductTagProps {
|
|
||||||
@IsOptional()
|
|
||||||
@IsType([String, [String], StringComparisonOperator])
|
|
||||||
id?: string | string[] | StringComparisonOperator
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsType([String, [String], StringComparisonOperator])
|
|
||||||
value?: string | string[] | StringComparisonOperator
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsType([DateComparisonOperator])
|
|
||||||
created_at?: DateComparisonOperator
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsType([DateComparisonOperator])
|
|
||||||
updated_at?: DateComparisonOperator
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
@IsOptional()
|
|
||||||
q?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service Level DTOs
|
* Service Level DTOs
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user