fix(utils): bignumber util considers nullable options when setting value (#6499)
what: - when setting null for nullable columns, big number utils should not throw error - remove circular soft delete depenedencies for cart module - trims zeros on big number values
This commit is contained in:
5
.changeset/itchy-bags-play.md
Normal file
5
.changeset/itchy-bags-play.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/utils": patch
|
||||
---
|
||||
|
||||
fix(utils): bignumber util considers nullable options when setting value
|
||||
@@ -24,7 +24,7 @@ import LineItem from "./line-item"
|
||||
export default class LineItemAdjustment extends AdjustmentLine {
|
||||
@ManyToOne({
|
||||
entity: () => LineItem,
|
||||
cascade: [Cascade.REMOVE, Cascade.PERSIST, "soft-remove"] as any,
|
||||
cascade: [Cascade.REMOVE, Cascade.PERSIST],
|
||||
})
|
||||
item: LineItem
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import ShippingMethod from "./shipping-method"
|
||||
export default class ShippingMethodAdjustment extends AdjustmentLine {
|
||||
@ManyToOne({
|
||||
entity: () => ShippingMethod,
|
||||
cascade: [Cascade.REMOVE, Cascade.PERSIST, "soft-remove"] as any,
|
||||
cascade: [Cascade.REMOVE, Cascade.PERSIST],
|
||||
})
|
||||
shipping_method: ShippingMethod
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { IPaymentModuleService } from "@medusajs/types"
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { IPaymentModuleService } from "@medusajs/types"
|
||||
|
||||
import {
|
||||
moduleIntegrationTestRunner,
|
||||
SuiteOptions,
|
||||
} from "medusa-test-utils/dist"
|
||||
import {
|
||||
createPaymentCollections,
|
||||
createPayments,
|
||||
createPaymentSessions,
|
||||
} from "../../../__fixtures__"
|
||||
import {
|
||||
moduleIntegrationTestRunner,
|
||||
SuiteOptions,
|
||||
} from "medusa-test-utils/dist"
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
@@ -466,7 +466,7 @@ moduleIntegrationTestRunner({
|
||||
id: expect.any(String),
|
||||
currency_code: "usd",
|
||||
amount: 100,
|
||||
raw_amount: { value: "100.00000000000000000", precision: 20 },
|
||||
raw_amount: { value: "100", precision: 20 },
|
||||
provider_id: "system",
|
||||
data: {},
|
||||
status: "authorized",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
export * from "./alter-columns-helper"
|
||||
export * from "./array-difference"
|
||||
export * from "./get-set-difference"
|
||||
export * from "./build-query"
|
||||
export * from "./camel-to-snake-case"
|
||||
export * from "./container"
|
||||
@@ -12,8 +11,10 @@ export * from "./errors"
|
||||
export * from "./generate-entity-id"
|
||||
export * from "./generate-linkable-keys-map"
|
||||
export * from "./get-config-file"
|
||||
export * from "./get-duplicates"
|
||||
export * from "./get-iso-string-from-date"
|
||||
export * from "./get-selects-and-relations-from-object-array"
|
||||
export * from "./get-set-difference"
|
||||
export * from "./group-by"
|
||||
export * from "./handle-postgres-database-error"
|
||||
export * from "./is-big-number"
|
||||
@@ -35,6 +36,7 @@ export * from "./promise-all"
|
||||
export * from "./remote-query-object-from-string"
|
||||
export * from "./remote-query-object-to-string"
|
||||
export * from "./remove-nullisih"
|
||||
export * from "./remove-undefined"
|
||||
export * from "./selector-constraints-to-string"
|
||||
export * from "./set-metadata"
|
||||
export * from "./simple-hash"
|
||||
@@ -45,7 +47,6 @@ export * from "./to-camel-case"
|
||||
export * from "./to-kebab-case"
|
||||
export * from "./to-pascal-case"
|
||||
export * from "./transaction"
|
||||
export * from "./trim-zeros"
|
||||
export * from "./upper-case-first"
|
||||
export * from "./wrap-handler"
|
||||
export * from "./remove-undefined"
|
||||
export * from "./get-duplicates"
|
||||
|
||||
15
packages/utils/src/common/trim-zeros.ts
Normal file
15
packages/utils/src/common/trim-zeros.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export function trimZeros(value: string) {
|
||||
const [whole, fraction] = value.split(".")
|
||||
|
||||
if (fraction) {
|
||||
const decimal = fraction.replace(/0+$/, "")
|
||||
|
||||
if (!decimal) {
|
||||
return whole
|
||||
}
|
||||
|
||||
return `${whole}.${decimal}`
|
||||
}
|
||||
|
||||
return whole
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MikroOrmBigNumberProperty } from "../big-number-field"
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import { BigNumber } from "../../../totals/big-number"
|
||||
import { MikroOrmBigNumberProperty } from "../big-number-field"
|
||||
|
||||
describe("@MikroOrmBigNumberProperty", () => {
|
||||
it("should correctly assign and update BigNumber values", () => {
|
||||
@@ -9,6 +9,11 @@ describe("@MikroOrmBigNumberProperty", () => {
|
||||
amount: BigNumber | number
|
||||
|
||||
raw_amount: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty({ nullable: true })
|
||||
nullable_amount: BigNumber | number | null = null
|
||||
|
||||
raw_nullable_amount: BigNumberRawValue | null = null
|
||||
}
|
||||
|
||||
const testAmount = new TestAmount()
|
||||
@@ -21,10 +26,20 @@ describe("@MikroOrmBigNumberProperty", () => {
|
||||
expect(testAmount.amount).toEqual(100)
|
||||
expect((testAmount as any).amount_).toEqual(100)
|
||||
expect(testAmount.raw_amount).toEqual({
|
||||
value: "100.00000000000000000",
|
||||
value: "100",
|
||||
precision: 20,
|
||||
})
|
||||
|
||||
try {
|
||||
;(testAmount as any).amount = null
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual(
|
||||
"Invalid BigNumber value: null. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
)
|
||||
}
|
||||
|
||||
testAmount.nullable_amount = null
|
||||
expect(testAmount.nullable_amount).toEqual(null)
|
||||
// Update the amount
|
||||
|
||||
testAmount.amount = 200
|
||||
@@ -32,7 +47,7 @@ describe("@MikroOrmBigNumberProperty", () => {
|
||||
expect(testAmount.amount).toEqual(200)
|
||||
expect((testAmount as any).amount_).toEqual(200)
|
||||
expect(testAmount.raw_amount).toEqual({
|
||||
value: "200.00000000000000000",
|
||||
value: "200",
|
||||
precision: 20,
|
||||
})
|
||||
|
||||
@@ -42,6 +57,6 @@ describe("@MikroOrmBigNumberProperty", () => {
|
||||
|
||||
expect(testAmount.amount).toEqual(300)
|
||||
expect((testAmount as any).amount_).toEqual(300)
|
||||
expect(testAmount.raw_amount).toEqual({ value: "300.00", precision: 5 })
|
||||
expect(testAmount.raw_amount).toEqual({ value: "300", precision: 5 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BigNumber } from "../../totals/big-number"
|
||||
import { Property } from "@mikro-orm/core"
|
||||
import { BigNumberInput } from "@medusajs/types"
|
||||
import { Property } from "@mikro-orm/core"
|
||||
import { isPresent, trimZeros } from "../../common"
|
||||
import { BigNumber } from "../../totals/big-number"
|
||||
|
||||
export function MikroOrmBigNumberProperty(
|
||||
options: Parameters<typeof Property>[0] & {
|
||||
@@ -16,21 +17,37 @@ export function MikroOrmBigNumberProperty(
|
||||
return this[targetColumn]
|
||||
},
|
||||
set(value: BigNumberInput) {
|
||||
if (options?.nullable && !isPresent(value)) {
|
||||
this[targetColumn] = null
|
||||
this[rawColumnName] = null
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let bigNumber: BigNumber
|
||||
|
||||
if (value instanceof BigNumber) {
|
||||
bigNumber = value
|
||||
} else if (this[rawColumnName]) {
|
||||
const precision = this[rawColumnName].precision
|
||||
this[rawColumnName].value = new BigNumber(value, {
|
||||
|
||||
this[rawColumnName].value = trimZeros(
|
||||
new BigNumber(value, {
|
||||
precision,
|
||||
}).raw!.value
|
||||
}).raw!.value as string
|
||||
)
|
||||
|
||||
bigNumber = new BigNumber(this[rawColumnName])
|
||||
} else {
|
||||
bigNumber = new BigNumber(value)
|
||||
}
|
||||
|
||||
this[targetColumn] = bigNumber.numeric
|
||||
this[rawColumnName] = bigNumber.raw
|
||||
|
||||
const raw = bigNumber.raw!
|
||||
raw.value = trimZeros(raw.value as string)
|
||||
|
||||
this[rawColumnName] = raw
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -29,7 +29,15 @@ describe("BigNumber", function () {
|
||||
it("should throw if not correct type", function () {
|
||||
// @ts-ignore
|
||||
expect(() => new BigNumber([])).toThrow(
|
||||
"Invalid BigNumber value. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
"Invalid BigNumber value: . Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
)
|
||||
|
||||
expect(() => new BigNumber(null as any)).toThrow(
|
||||
"Invalid BigNumber value: null. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
)
|
||||
|
||||
expect(() => new BigNumber(undefined as any)).toThrow(
|
||||
"Invalid BigNumber value: undefined. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -8,61 +8,61 @@ export class BigNumber {
|
||||
private numeric_: number
|
||||
private raw_?: BigNumberRawValue
|
||||
|
||||
constructor(rawPrice: BigNumberInput, options?: { precision?: number }) {
|
||||
this.setRawPriceOrThrow(rawPrice, options)
|
||||
constructor(rawValue: BigNumberInput, options?: { precision?: number }) {
|
||||
this.setRawValueOrThrow(rawValue, options)
|
||||
}
|
||||
|
||||
setRawPriceOrThrow(
|
||||
rawPrice: BigNumberInput,
|
||||
setRawValueOrThrow(
|
||||
rawValue: BigNumberInput,
|
||||
{ precision }: { precision?: number } = {}
|
||||
) {
|
||||
precision ??= BigNumber.DEFAULT_PRECISION
|
||||
|
||||
if (BigNumberJS.isBigNumber(rawPrice)) {
|
||||
if (BigNumberJS.isBigNumber(rawValue)) {
|
||||
/**
|
||||
* Example:
|
||||
* const bnUnitPrice = new BigNumberJS("10.99")
|
||||
* const unitPrice = new BigNumber(bnUnitPrice)
|
||||
* const bnUnitValue = new BigNumberJS("10.99")
|
||||
* const unitValue = new BigNumber(bnUnitValue)
|
||||
*/
|
||||
this.numeric_ = rawPrice.toNumber()
|
||||
this.numeric_ = rawValue.toNumber()
|
||||
this.raw_ = {
|
||||
value: rawPrice.toPrecision(precision),
|
||||
value: rawValue.toPrecision(precision),
|
||||
precision,
|
||||
}
|
||||
} else if (isString(rawPrice)) {
|
||||
} else if (isString(rawValue)) {
|
||||
/**
|
||||
* Example: const unitPrice = "1234.1234"
|
||||
* Example: const unitValue = "1234.1234"
|
||||
*/
|
||||
const bigNum = new BigNumberJS(rawPrice)
|
||||
const bigNum = new BigNumberJS(rawValue)
|
||||
|
||||
this.numeric_ = bigNum.toNumber()
|
||||
this.raw_ = this.raw_ = {
|
||||
value: bigNum.toPrecision(precision),
|
||||
precision,
|
||||
}
|
||||
} else if (isBigNumber(rawPrice)) {
|
||||
} else if (isBigNumber(rawValue)) {
|
||||
/**
|
||||
* Example: const unitPrice = { value: "1234.1234" }
|
||||
* Example: const unitValue = { value: "1234.1234" }
|
||||
*/
|
||||
this.numeric_ = BigNumberJS(rawPrice.value).toNumber()
|
||||
|
||||
const definedPrecision = rawValue.precision ?? precision
|
||||
this.numeric_ = BigNumberJS(rawValue.value).toNumber()
|
||||
this.raw_ = {
|
||||
...rawPrice,
|
||||
precision,
|
||||
...rawValue,
|
||||
precision: definedPrecision,
|
||||
}
|
||||
} else if (typeof rawPrice === `number` && !Number.isNaN(rawPrice)) {
|
||||
} else if (typeof rawValue === `number` && !Number.isNaN(rawValue)) {
|
||||
/**
|
||||
* Example: const unitPrice = 1234
|
||||
* Example: const unitValue = 1234
|
||||
*/
|
||||
this.numeric_ = rawPrice as number
|
||||
this.numeric_ = rawValue as number
|
||||
|
||||
this.raw_ = {
|
||||
value: BigNumberJS(rawPrice as number).toPrecision(precision),
|
||||
value: BigNumberJS(rawValue as number).toPrecision(precision),
|
||||
precision,
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
"Invalid BigNumber value. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
`Invalid BigNumber value: ${rawValue}. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user