From 8141e12a3da0ed0b3bb9058682ada6b7241a3f11 Mon Sep 17 00:00:00 2001 From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com> Date: Thu, 10 Feb 2022 09:15:07 +0100 Subject: [PATCH] add pagination and date filtering to regions (#976) --- .../api/__tests__/admin/region.js | 94 ++++++++++++++++++- .../api/routes/admin/regions/list-regions.ts | 52 ++++++++-- 2 files changed, 138 insertions(+), 8 deletions(-) diff --git a/integration-tests/api/__tests__/admin/region.js b/integration-tests/api/__tests__/admin/region.js index 1853f8d3df..bc7970baa5 100644 --- a/integration-tests/api/__tests__/admin/region.js +++ b/integration-tests/api/__tests__/admin/region.js @@ -1,5 +1,5 @@ const path = require("path") -const { Region, FulfillmentProvider } = require("@medusajs/medusa") +const { Region } = require("@medusajs/medusa") const setupServer = require("../../../helpers/setup-server") const { useApi } = require("../../../helpers/use-api") @@ -8,7 +8,7 @@ const adminSeeder = require("../../helpers/admin-seeder") jest.setTimeout(30000) -describe("/admin/discounts", () => { +describe("/admin/regions", () => { let medusaProcess let dbConnection @@ -24,6 +24,96 @@ describe("/admin/discounts", () => { medusaProcess.kill() }) + describe("GET /admin/regions", () => { + beforeAll(async () => { + const manager = dbConnection.manager + await adminSeeder(dbConnection) + await manager.insert(Region, { + id: "test-region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + }) + await manager.insert(Region, { + id: "test-region-deleted", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + deleted_at: new Date(), + }) + await manager.insert(Region, { + id: "test-region-updated", + name: "Test Region updated", + currency_code: "usd", + tax_rate: 0, + updated_at: new Date(), + }) + await manager.insert(Region, { + id: "test-region-updated-1", + name: "Test Region updated 1", + currency_code: "usd", + tax_rate: 0, + updated_at: new Date("10/10/2000"), + }) + }) + + afterAll(async () => { + const db = useDb() + await db.teardown() + }) + + it("only returns non-deleted regions", async () => { + const api = useApi() + + const response = await api + .get(`/admin/regions`, { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.log(err) + }) + + expect(response.data.regions).toEqual([ + expect.objectContaining({ + id: "test-region-updated-1", + }), + expect.objectContaining({ + id: "test-region", + }), + expect.objectContaining({ + id: "test-region-updated", + }), + ]) + expect(response.status).toEqual(200) + }) + + it("filters correctly on update", async () => { + const api = useApi() + + const response = await api + .get(`/admin/regions?updated_at[gt]=10-10-2005`, { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.log(err) + }) + + expect(response.data.regions).toEqual([ + expect.objectContaining({ + id: "test-region", + }), + expect.objectContaining({ + id: "test-region-updated", + }), + ]) + expect(response.status).toEqual(200) + }) + }) + describe("DELETE /admin/regions/:id", () => { beforeEach(async () => { const manager = dbConnection.manager diff --git a/packages/medusa/src/api/routes/admin/regions/list-regions.ts b/packages/medusa/src/api/routes/admin/regions/list-regions.ts index cc2591705b..56aec531ab 100644 --- a/packages/medusa/src/api/routes/admin/regions/list-regions.ts +++ b/packages/medusa/src/api/routes/admin/regions/list-regions.ts @@ -2,8 +2,10 @@ import { validator } from "../../../../utils/validator" import { Region } from "../../../.." import RegionService from "../../../../services/region" import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." -import { IsInt, IsOptional } from "class-validator" +import { IsInt, IsOptional, ValidateNested } from "class-validator" import { Type } from "class-transformer" +import _, { identity } from "lodash" +import { DateComparisonOperator } from "../../../../types/common" /** * @oas [get] /regions @@ -12,18 +14,36 @@ import { Type } from "class-transformer" * description: "Retrieves a list of Regions." * x-authenticated: true * parameters: - * - in: path + * - in: query * name: limit * schema: * type: integer * required: false * description: limit the number of regions in response - * - in: path + * - in: query * name: offset * schema: * type: integer * required: false * description: Offset of regions in response (used for pagination) + * - in: query + * name: created_at + * schema: + * type: DateComparisonOperator + * required: false + * description: Date comparison for when resulting region was created, i.e. less than, greater than etc. + * - in: query + * name: updated_at + * schema: + * type: DateComparisonOperator + * required: false + * description: Date comparison for when resulting region was updated, i.e. less than, greater than etc. + * - in: query + * name: deleted_at + * schema: + * type: DateComparisonOperator + * required: false + * description: Date comparison for when resulting region was deleted, i.e. less than, greater than etc. * tags: * - Region * responses: @@ -43,7 +63,7 @@ export default async (req, res) => { const regionService: RegionService = req.scope.resolve("regionService") - const selector = {} + const filterableFields = _.omit(validated, ["limit", "offset"]) const listConfig = { select: defaultAdminRegionFields, @@ -52,7 +72,10 @@ export default async (req, res) => { take: validated.limit, } - const regions: Region[] = await regionService.list(selector, listConfig) + const regions: Region[] = await regionService.list( + _.pickBy(filterableFields, identity), + listConfig + ) res.json({ regions, @@ -62,7 +85,7 @@ export default async (req, res) => { }) } -export class AdminGetRegionsParams { +export class AdminGetRegionsPaginationParams { @IsInt() @IsOptional() @Type(() => Number) @@ -73,3 +96,20 @@ export class AdminGetRegionsParams { @Type(() => Number) offset?: number = 0 } + +export class AdminGetRegionsParams extends AdminGetRegionsPaginationParams { + @IsOptional() + @ValidateNested() + @Type(() => DateComparisonOperator) + created_at?: DateComparisonOperator + + @IsOptional() + @ValidateNested() + @Type(() => DateComparisonOperator) + updated_at?: DateComparisonOperator + + @ValidateNested() + @IsOptional() + @Type(() => DateComparisonOperator) + deleted_at?: DateComparisonOperator +}