diff --git a/packages/region/src/services/region-module.ts b/packages/region/src/services/region-module.ts index ad779ee581..997cca7f3a 100644 --- a/packages/region/src/services/region-module.ts +++ b/packages/region/src/services/region-module.ts @@ -23,11 +23,13 @@ import { MedusaError, ModulesSdkUtils, promiseAll, + DefaultsUtils, + removeUndefined, + getDuplicates, } from "@medusajs/utils" import { Country, Currency, Region } from "@models" -import { DefaultsUtils } from "@medusajs/utils" import { CreateCountryDTO, CreateCurrencyDTO } from "@types" import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" @@ -304,7 +306,7 @@ export default class RegionModuleService< if (uniqueCountries.length !== countries.length) { throw new MedusaError( MedusaError.Types.INVALID_DATA, - `Countries with codes: "${getDuplicateEntries(countries).join( + `Countries with codes: "${getDuplicates(countries).join( ", " )}" are already assigned to a region` ) @@ -413,25 +415,3 @@ export default class RegionModuleService< } } } - -// microORM complains if undefined fields are present in the passed data object -const removeUndefined = >(obj: T): T => { - return Object.fromEntries( - Object.entries(obj).filter(([_, v]) => v !== undefined) - ) as T -} - -const getDuplicateEntries = (collection: string[]): string[] => { - const uniqueElements = new Set() - const duplicates: string[] = [] - - collection.forEach((item) => { - if (uniqueElements.has(item)) { - duplicates.push(item) - } else { - uniqueElements.add(item) - } - }) - - return duplicates -} diff --git a/packages/utils/src/common/__tests__/get-duplicates.spec.ts b/packages/utils/src/common/__tests__/get-duplicates.spec.ts new file mode 100644 index 0000000000..4d6ba1c3ad --- /dev/null +++ b/packages/utils/src/common/__tests__/get-duplicates.spec.ts @@ -0,0 +1,20 @@ +import { getDuplicates } from "../get-duplicates" + +describe("getDuplicates", function () { + it("should return an empty array if there are no duplicates", function () { + const output = getDuplicates(["foo", "bar", "baz"]) + expect(output).toHaveLength(0) + }) + + it("should return a singular duplicate", function () { + const output = getDuplicates(["foo", "bar", "baz", "baz", "baz"]) + expect(output).toHaveLength(1) + expect(output[0]).toEqual("baz") + }) + + it("should return all duplicates in the array", function () { + const output = getDuplicates(["foo", "bar", "bar", "baz", "baz", "baz"]) + expect(output).toHaveLength(2) + expect(output).toEqual(expect.arrayContaining(["baz", "bar"])) + }) +}) diff --git a/packages/utils/src/common/__tests__/remove-undefined.spec.ts b/packages/utils/src/common/__tests__/remove-undefined.spec.ts new file mode 100644 index 0000000000..e888ead587 --- /dev/null +++ b/packages/utils/src/common/__tests__/remove-undefined.spec.ts @@ -0,0 +1,22 @@ +import { removeUndefined } from "../remove-undefined" + +describe("removeUndefined", function () { + it("should remove all undefined fields from an object", function () { + const withUndefined = { + foo: undefined, + bar: "baz", + foo2: null, + } + expect(withUndefined.hasOwnProperty("foo")).toBe(true) + + const output = removeUndefined(withUndefined) + expect(output.hasOwnProperty("foo")).toBe(false) + expect(output.hasOwnProperty("bar")).toBe(true) + expect(output.hasOwnProperty("foo2")).toBe(true) + }) + + it("should return an empty object as-is", function () { + const output = removeUndefined({}) + expect(output).toEqual({}) + }) +}) diff --git a/packages/utils/src/common/get-duplicates.ts b/packages/utils/src/common/get-duplicates.ts new file mode 100644 index 0000000000..8d20a5be1a --- /dev/null +++ b/packages/utils/src/common/get-duplicates.ts @@ -0,0 +1,16 @@ +// This function is intentionally not generic, as we will likely need a comparator function in that case, which will make it more complex than necessary +// Revisit if there is such use-case in the future +export const getDuplicates = (collection: string[]): string[] => { + const uniqueElements = new Set() + const duplicates = new Set() + + collection.forEach((item) => { + if (uniqueElements.has(item)) { + duplicates.add(item) + } else { + uniqueElements.add(item) + } + }) + + return Array.from(duplicates) +} diff --git a/packages/utils/src/common/index.ts b/packages/utils/src/common/index.ts index 230ce46dcc..5305c8d5df 100644 --- a/packages/utils/src/common/index.ts +++ b/packages/utils/src/common/index.ts @@ -47,3 +47,5 @@ export * from "./to-pascal-case" export * from "./transaction" export * from "./upper-case-first" export * from "./wrap-handler" +export * from "./remove-undefined" +export * from "./get-duplicates" diff --git a/packages/utils/src/common/remove-undefined.ts b/packages/utils/src/common/remove-undefined.ts new file mode 100644 index 0000000000..adade4e036 --- /dev/null +++ b/packages/utils/src/common/remove-undefined.ts @@ -0,0 +1,4 @@ +// useful in cases where presence of undefined is not desired (eg. in microORM operations) +export const removeUndefined = >(obj: T): T => { + return JSON.parse(JSON.stringify(obj)) as T +}