Skip to content

Commit

Permalink
feat: Update signature of region module to match latest spec (medusaj…
Browse files Browse the repository at this point in the history
  • Loading branch information
sradevski authored Feb 23, 2024
1 parent c86e27b commit 5b85c31
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 85 deletions.
6 changes: 3 additions & 3 deletions packages/core-flows/src/region/steps/update-regions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
FilterableRegionProps,
IRegionModuleService,
UpdatableRegionFields,
UpdateRegionDTO,
} from "@medusajs/types"
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"

type UpdateRegionsStepInput = {
selector: FilterableRegionProps
update: UpdatableRegionFields
update: UpdateRegionDTO
}

export const updateRegionsStepId = "update-region"
Expand Down Expand Up @@ -42,7 +42,7 @@ export const updateRegionsStep = createStep(
ModuleRegistrationName.REGION
)

await service.update(
await service.upsert(
prevData.map((r) => ({
id: r.id,
name: r.name,
Expand Down
4 changes: 2 additions & 2 deletions packages/core-flows/src/region/workflows/update-regions.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {
FilterableRegionProps,
RegionDTO,
UpdatableRegionFields,
UpdateRegionDTO,
} from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { updateRegionsStep } from "../steps"

type UpdateRegionsStepInput = {
selector: FilterableRegionProps
update: UpdatableRegionFields
update: UpdateRegionDTO
}

type WorkflowInput = UpdateRegionsStepInput
Expand Down
4 changes: 2 additions & 2 deletions packages/medusa/src/api-v2/admin/regions/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
deleteRegionsWorkflow,
updateRegionsWorkflow,
} from "@medusajs/core-flows"
import { UpdatableRegionFields } from "@medusajs/types"
import { UpdateRegionDTO } from "@medusajs/types"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
import { defaultAdminRegionFields } from "../query-config"
Expand All @@ -27,7 +27,7 @@ export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
const { result, errors } = await updateRegionsWorkflow(req.scope).run({
input: {
selector: { id: req.params.id },
update: req.validatedBody as UpdatableRegionFields,
update: req.validatedBody as UpdateRegionDTO,
},
throwOnError: false,
})
Expand Down
62 changes: 62 additions & 0 deletions packages/region/integration-tests/__tests__/region-module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,68 @@ describe("Region Module Service", () => {
)
})

it("should upsert the region successfully", async () => {
const createdRegion = await service.upsert({
name: "North America",
currency_code: "USD",
countries: ["us", "ca"],
})

await service.upsert({
id: createdRegion.id,
name: "Americas",
currency_code: "MXN",
countries: ["us", "mx"],
})

const latestRegion = await service.retrieve(createdRegion.id, {
relations: ["currency", "countries"],
})

expect(latestRegion).toMatchObject({
id: createdRegion.id,
name: "Americas",
currency_code: "mxn",
})
expect(latestRegion.countries.map((c) => c.iso_2)).toEqual(["mx", "us"])
})

it("should allow mixing create and update operations in upsert", async () => {
const createdRegion = await service.upsert({
name: "North America",
currency_code: "USD",
countries: ["us", "ca"],
})

const upserted = await service.upsert([
{
id: createdRegion.id,
name: "Americas",
currency_code: "USD",
countries: ["us", "ca"],
},
{
name: "Central America",
currency_code: "MXN",
countries: ["mx"],
},
])

expect(upserted).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: createdRegion.id,
name: "Americas",
currency_code: "usd",
}),
expect.objectContaining({
name: "Central America",
currency_code: "mxn",
}),
])
)
})

it("should update the region successfully", async () => {
const createdRegion = await service.create({
name: "North America",
Expand Down
106 changes: 64 additions & 42 deletions packages/region/src/services/region-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ import {
RegionCountryDTO,
RegionCurrencyDTO,
RegionDTO,
UpdatableRegionFields,
UpdateRegionDTO,
UpsertRegionDTO,
} from "@medusajs/types"
import {
arrayDifference,
InjectManager,
InjectTransactionManager,
isObject,
isString,
MedusaContext,
MedusaError,
Expand All @@ -30,7 +29,7 @@ import {

import { Country, Currency, Region } from "@models"

import { CreateCountryDTO, CreateCurrencyDTO } from "@types"
import { CreateCountryDTO, CreateCurrencyDTO, UpdateRegionInput } from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"

const COUNTRIES_LIMIT = 1000
Expand Down Expand Up @@ -143,54 +142,64 @@ export default class RegionModuleService<
return await this.regionService_.create(normalizedDbRegions, sharedContext)
}

async update(
selector: FilterableRegionProps,
data: UpdatableRegionFields,
async upsert(
data: UpsertRegionDTO[],
sharedContext?: Context
): Promise<RegionDTO[]>
async update(
regionId: string,
data: UpdatableRegionFields,
async upsert(
data: UpsertRegionDTO,
sharedContext?: Context
): Promise<RegionDTO>
async update(data: UpdateRegionDTO[]): Promise<RegionDTO[]>
@InjectManager("baseRepository_")
async update(
idOrSelectorOrData: string | FilterableRegionProps | UpdateRegionDTO[],
data?: UpdatableRegionFields,
@InjectTransactionManager("baseRepository_")
async upsert(
data: UpsertRegionDTO | UpsertRegionDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<RegionDTO | RegionDTO[]> {
const updateResult = await this.update_(
idOrSelectorOrData,
data,
sharedContext
const input = Array.isArray(data) ? data : [data]
const forUpdate = input.filter(
(region): region is UpdateRegionInput => !!region.id
)
const forCreate = input.filter(
(region): region is CreateRegionDTO => !region.id
)

const regions = await this.baseRepository_.serialize<
RegionDTO[] | RegionDTO
>(updateResult)

return isString(idOrSelectorOrData) ? regions[0] : regions
}
const operations: Promise<Region[]>[] = []

@InjectTransactionManager("baseRepository_")
protected async update_(
idOrSelectorOrData: string | FilterableRegionProps | UpdateRegionDTO[],
data?: UpdatableRegionFields,
@MedusaContext() sharedContext: Context = {}
): Promise<Region[]> {
let normalizedInput: UpdateRegionDTO[] = []
if (isString(idOrSelectorOrData)) {
normalizedInput = [{ id: idOrSelectorOrData, ...data }]
if (forCreate.length) {
operations.push(this.create_(forCreate, sharedContext))
}

if (Array.isArray(idOrSelectorOrData)) {
normalizedInput = idOrSelectorOrData
if (forUpdate.length) {
operations.push(this.update_(forUpdate, sharedContext))
}

if (isObject(idOrSelectorOrData)) {
const result = (await promiseAll(operations)).flat()
return await this.baseRepository_.serialize<RegionDTO[] | RegionDTO>(
Array.isArray(data) ? result : result[0]
)
}

async update(
id: string,
data: UpdateRegionDTO,
sharedContext?: Context
): Promise<RegionDTO>
async update(
selector: FilterableRegionProps,
data: UpdateRegionDTO,
sharedContext?: Context
): Promise<RegionDTO[]>
@InjectManager("baseRepository_")
async update(
idOrSelector: string | FilterableRegionProps,
data: UpdateRegionDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<RegionDTO | RegionDTO[]> {
let normalizedInput: UpdateRegionInput[] = []
if (isString(idOrSelector)) {
normalizedInput = [{ id: idOrSelector, ...data }]
} else {
const regions = await this.regionService_.list(
idOrSelectorOrData,
idOrSelector,
{},
sharedContext
)
Expand All @@ -200,7 +209,22 @@ export default class RegionModuleService<
...data,
}))
}
normalizedInput = RegionModuleService.normalizeInput(normalizedInput)

const updateResult = await this.update_(normalizedInput, sharedContext)

const regions = await this.baseRepository_.serialize<
RegionDTO[] | RegionDTO
>(updateResult)

return isString(idOrSelector) ? regions[0] : regions
}

@InjectTransactionManager("baseRepository_")
protected async update_(
data: UpdateRegionInput[],
@MedusaContext() sharedContext: Context = {}
): Promise<Region[]> {
const normalizedInput = RegionModuleService.normalizeInput(data)

// If countries are being updated for a region, first make previously set countries' region to null to get to a clean slate.
// Somewhat less efficient, but region operations will be very rare, so it is better to go with a simple solution
Expand Down Expand Up @@ -245,9 +269,7 @@ export default class RegionModuleService<
return await this.regionService_.update(normalizedDbRegions, sharedContext)
}

private static normalizeInput<T extends UpdatableRegionFields>(
regions: T[]
): T[] {
private static normalizeInput<T extends UpdateRegionDTO>(regions: T[]): T[] {
return regions.map((region) =>
removeUndefined({
...region,
Expand Down
4 changes: 3 additions & 1 deletion packages/region/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Logger } from "@medusajs/types"
import { Logger, UpdateRegionDTO } from "@medusajs/types"
import { Country } from "@models"

export type InitializeModuleInjectableDependencies = {
Expand All @@ -24,3 +24,5 @@ export type CreateCountryDTO = {
name: string
display_name: string
}

export type UpdateRegionInput = UpdateRegionDTO & { id: string }
18 changes: 6 additions & 12 deletions packages/types/src/region/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,13 @@ export interface CreateRegionDTO {
metadata?: Record<string, unknown>
}

/**
* The attributes to update in the region.
*/
export interface UpdateRegionDTO {
export interface UpsertRegionDTO {
/**
* The ID of the region.
* The id of the region in the case of an update
*/
id: string
id?: string
/**
* The name of the region.
* The target name of the region
*/
name?: string
/**
Expand All @@ -48,12 +45,9 @@ export interface UpdateRegionDTO {
metadata?: Record<string, unknown>
}

/**
* The updatable fields of a region.
*/
export interface UpdatableRegionFields {
export interface UpdateRegionDTO {
/**
* The name of the region.
* The target name of the region
*/
name?: string
/**
Expand Down
Loading

0 comments on commit 5b85c31

Please sign in to comment.