diff --git a/integration-tests/api/__tests__/store/regions.js b/integration-tests/api/__tests__/store/regions.js index 79768ec8c6..bbceaa5fca 100644 --- a/integration-tests/api/__tests__/store/regions.js +++ b/integration-tests/api/__tests__/store/regions.js @@ -1,22 +1,10 @@ const path = require("path") -const { - Region, - ReturnReason, - Order, - Customer, - ShippingProfile, - Product, - ProductVariant, - ShippingOption, - FulfillmentProvider, - LineItem, - Discount, - DiscountRule, -} = require("@medusajs/medusa") +const { Region } = require("@medusajs/medusa") const setupServer = require("../../../environment-helpers/setup-server") const { useApi } = require("../../../environment-helpers/use-api") const { initDb, useDb } = require("../../../environment-helpers/use-db") +const { breaking } = require("../../../helpers/breaking") jest.setTimeout(30000) @@ -76,15 +64,27 @@ describe("/store/carts", () => { const api = useApi() const response = await api.get( - "/store/regions?limit=1&offset=1&expand=currency" + `/store/regions?limit=1&offset=1&${breaking( + () => "expand=currency", + () => "fields=*payment_providers" + )}` ) expect(response.status).toEqual(200) - expect(response.data.regions[0].currency).toEqual( - expect.objectContaining({ - code: "usd", - }) + breaking( + () => { + expect(response.data.regions[0].currency).toEqual( + expect.objectContaining({ + code: "usd", + }) + ) + }, + () => { + expect(response.data.regions[0].payment_providers).toEqual( + expect.arrayContaining([]) + ) + } ) }) }) @@ -109,16 +109,13 @@ describe("/store/carts", () => { it("should retrieve the region from ID", async () => { const api = useApi() - const response = await api.get(`/store/regions/region-id?expand=currency`) + const response = await api.get(`/store/regions/region-id`) expect(response.status).toEqual(200) expect(response.data.region).toEqual( expect.objectContaining({ id: "region-id", - currency: expect.objectContaining({ - code: "usd", - }), }) ) }) @@ -131,10 +128,12 @@ describe("/store/carts", () => { .catch((e) => e) expect(error.response.status).toEqual(404) - expect(error.response.data).toEqual({ type: "not_found", - message: "Region with invalid-region-id was not found", + message: breaking( + () => "Region with invalid-region-id was not found", + () => "Region with id: invalid-region-id was not found" + ), }) }) }) diff --git a/integration-tests/modules/__tests__/payment/payments.spec.ts b/integration-tests/modules/__tests__/payment/payments.spec.ts index 3f4c72a237..42758a41c3 100644 --- a/integration-tests/modules/__tests__/payment/payments.spec.ts +++ b/integration-tests/modules/__tests__/payment/payments.spec.ts @@ -38,11 +38,11 @@ medusaIntegrationTestRunner({ }) let response = await api.get( - `/store/regions/${region.id}/payment-providers` + `/store/regions/${region.id}?fields=*payment_providers` ) expect(response.status).toEqual(200) - expect(response.data.payment_providers).toEqual([]) + expect(response.data.region.payment_providers).toEqual([]) await remoteLink.create([ { @@ -56,11 +56,11 @@ medusaIntegrationTestRunner({ ]) response = await api.get( - `/store/regions/${region.id}/payment-providers` + `/store/regions/${region.id}?fields=*payment_providers` ) expect(response.status).toEqual(200) - expect(response.data.payment_providers).toEqual([ + expect(response.data.region.payment_providers).toEqual([ expect.objectContaining({ id: "pp_system_default", }), diff --git a/packages/medusa/src/api-v2/store/regions/[id]/payment-providers/route.ts b/packages/medusa/src/api-v2/store/regions/[id]/payment-providers/route.ts deleted file mode 100644 index 5ea72ee0be..0000000000 --- a/packages/medusa/src/api-v2/store/regions/[id]/payment-providers/route.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { remoteQueryObjectFromString } from "@medusajs/utils" -import { MedusaRequest, MedusaResponse } from "../../../../../types/routing" - -export const GET = async (req: MedusaRequest, res: MedusaResponse) => { - const remoteQuery = req.scope.resolve("remoteQuery") - - const queryObject = remoteQueryObjectFromString({ - entryPoint: "regions", - fields: ["payment_providers.id", "payment_providers.is_enabled"], - variables: { - id: req.params.id, - }, - }) - - const [region] = await remoteQuery(queryObject) - - res.status(200).json({ - payment_providers: region.payment_providers.filter((pp) => pp.is_enabled), - }) -} diff --git a/packages/medusa/src/api-v2/store/regions/[id]/route.ts b/packages/medusa/src/api-v2/store/regions/[id]/route.ts index bd04de5e2e..546395d311 100644 --- a/packages/medusa/src/api-v2/store/regions/[id]/route.ts +++ b/packages/medusa/src/api-v2/store/regions/[id]/route.ts @@ -1,19 +1,28 @@ -import { remoteQueryObjectFromString } from "@medusajs/utils" +import { + ContainerRegistrationKeys, + MedusaError, + remoteQueryObjectFromString, +} from "@medusajs/utils" import { MedusaRequest, MedusaResponse } from "../../../../types/routing" -import { defaultStoreRegionFields } from "../query-config" export const GET = async (req: MedusaRequest, res: MedusaResponse) => { - const remoteQuery = req.scope.resolve("remoteQuery") - - const variables = { id: req.params.id } - + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const queryObject = remoteQueryObjectFromString({ entryPoint: "region", - variables, - fields: defaultStoreRegionFields, + variables: { + filters: { id: req.params.id }, + }, + fields: req.remoteQueryConfig.fields, }) const [region] = await remoteQuery(queryObject) + if (!region) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Region with id: ${req.params.id} was not found` + ) + } + res.status(200).json({ region }) } diff --git a/packages/medusa/src/api-v2/store/regions/middlewares.ts b/packages/medusa/src/api-v2/store/regions/middlewares.ts index 901ffc5c7e..fe6d727d71 100644 --- a/packages/medusa/src/api-v2/store/regions/middlewares.ts +++ b/packages/medusa/src/api-v2/store/regions/middlewares.ts @@ -1,14 +1,14 @@ -import { transformQuery } from "../../../api/middlewares" import { MiddlewareRoute } from "../../../loaders/helpers/routing/types" +import { validateAndTransformQuery } from "../../utils/validate-query" import * as QueryConfig from "./query-config" -import { StoreGetRegionsParams, StoreRegionsRegionParams } from "./validators" +import { StoreGetRegionParams, StoreGetRegionsParams } from "./validators" export const storeRegionRoutesMiddlewares: MiddlewareRoute[] = [ { method: ["GET"], matcher: "/store/regions", middlewares: [ - transformQuery( + validateAndTransformQuery( StoreGetRegionsParams, QueryConfig.listTransformQueryConfig ), @@ -18,15 +18,10 @@ export const storeRegionRoutesMiddlewares: MiddlewareRoute[] = [ method: ["GET"], matcher: "/store/regions/:id", middlewares: [ - transformQuery( - StoreRegionsRegionParams, + validateAndTransformQuery( + StoreGetRegionParams, QueryConfig.retrieveTransformQueryConfig ), ], }, - { - method: ["GET"], - matcher: "/store/regions/:id/payment-providers", - middlewares: [], - }, ] diff --git a/packages/medusa/src/api-v2/store/regions/query-config.ts b/packages/medusa/src/api-v2/store/regions/query-config.ts index 1eef989e7f..a0e9abad1d 100644 --- a/packages/medusa/src/api-v2/store/regions/query-config.ts +++ b/packages/medusa/src/api-v2/store/regions/query-config.ts @@ -6,22 +6,16 @@ export const defaultStoreRegionFields = [ "updated_at", "deleted_at", "metadata", - "countries.id", - "countries.iso_2", - "countries.iso_3", - "countries.num_code", - "countries.name", - "currency.code", - "currency.symbol", - "currency.symbol_native", - "currency.name", + "*countries", ] export const retrieveTransformQueryConfig = { + defaults: defaultStoreRegionFields, isList: false, } export const listTransformQueryConfig = { + defaults: defaultStoreRegionFields, defaultLimit: 20, isList: true, } diff --git a/packages/medusa/src/api-v2/store/regions/route.ts b/packages/medusa/src/api-v2/store/regions/route.ts index e370bb2027..7c7d4c0885 100644 --- a/packages/medusa/src/api-v2/store/regions/route.ts +++ b/packages/medusa/src/api-v2/store/regions/route.ts @@ -1,20 +1,27 @@ -import { remoteQueryObjectFromString } from "@medusajs/utils" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" import { MedusaRequest, MedusaResponse } from "../../../types/routing" -import { defaultStoreRegionFields } from "./query-config" export const GET = async (req: MedusaRequest, res: MedusaResponse) => { - const remoteQuery = req.scope.resolve("remoteQuery") - - const variables = { filters: req.filterableFields } + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const queryObject = remoteQueryObjectFromString({ entryPoint: "region", - variables, - fields: defaultStoreRegionFields, + variables: { + filters: req.filterableFields, + ...req.remoteQueryConfig.pagination, + }, + fields: req.remoteQueryConfig.fields, }) - // TODO: Add count, offset, limit - const regions = await remoteQuery(queryObject) + const { rows: regions, metadata } = await remoteQuery(queryObject) - res.json({ regions }) + res.json({ + regions, + count: metadata.count, + offset: metadata.skip, + limit: metadata.take, + }) } diff --git a/packages/medusa/src/api-v2/store/regions/validators.ts b/packages/medusa/src/api-v2/store/regions/validators.ts index c784af7568..e634c8c9cd 100644 --- a/packages/medusa/src/api-v2/store/regions/validators.ts +++ b/packages/medusa/src/api-v2/store/regions/validators.ts @@ -1,55 +1,20 @@ -import { OperatorMap } from "@medusajs/types" -import { Type } from "class-transformer" -import { IsOptional, IsString, ValidateNested } from "class-validator" -import { FindParams, extendedFindParamsMixin } from "../../../types/common" -import { OperatorMapValidator } from "../../../types/validators/operator-map" +import { createFindParams, createSelectParams } from "../../utils/validators" +import { z } from "zod" -export class StoreRegionsRegionParams extends FindParams {} +export type StoreGetRegionParamsType = z.infer +export const StoreGetRegionParams = createSelectParams() -/** - * Parameters used to filter and configure the pagination of the retrieved regions. - */ -export class StoreGetRegionsParams extends extendedFindParamsMixin({ +export type StoreGetRegionsParamsType = z.infer +export const StoreGetRegionsParams = createFindParams({ limit: 50, offset: 0, -}) { - /** - * Filter by currency code - */ - @IsString({ each: true }) - @IsOptional() - code?: string | string[] - - /** - * Filter by region name - */ - @IsString({ each: true }) - @IsOptional() - name?: string | string[] - - /** - * Date filters to apply on the regions' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => OperatorMapValidator) - created_at?: OperatorMap - - /** - * Date filters to apply on the regions' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => OperatorMapValidator) - updated_at?: OperatorMap - - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => StoreGetRegionsParams) - $and?: StoreGetRegionsParams[] - - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => StoreGetRegionsParams) - $or?: StoreGetRegionsParams[] -} +}).merge( + z.object({ + q: z.string().optional(), + id: z.union([z.string(), z.array(z.string())]).optional(), + code: z.union([z.string(), z.array(z.string())]).optional(), + name: z.union([z.string(), z.array(z.string())]).optional(), + $and: z.lazy(() => StoreGetRegionsParams.array()).optional(), + $or: z.lazy(() => StoreGetRegionsParams.array()).optional(), + }) +) diff --git a/packages/orchestration/src/joiner/remote-joiner.ts b/packages/orchestration/src/joiner/remote-joiner.ts index 97321a37bd..ebb61f978f 100644 --- a/packages/orchestration/src/joiner/remote-joiner.ts +++ b/packages/orchestration/src/joiner/remote-joiner.ts @@ -869,9 +869,11 @@ export class RemoteJoiner { location: [...currentPath], property, path: fullPath, - isList: fieldAliasIsList || !!serviceConfig.relationships?.find( - (relationship) => relationship.alias === parentFieldAlias - )?.isList, + isList: + fieldAliasIsList || + !!serviceConfig.relationships?.find( + (relationship) => relationship.alias === parentFieldAlias + )?.isList, }) const extMapping = expands as unknown[]