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:
Riqwan Thamir
2024-02-26 16:59:36 +05:30
committed by GitHub
parent 56cbf88115
commit 8ea37d03c9
10 changed files with 106 additions and 45 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/utils": patch
---
fix(utils): bignumber util considers nullable options when setting value

View File

@@ -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

View File

@@ -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

View File

@@ -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",

View File

@@ -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"

View 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
}

View File

@@ -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 })
})
})

View File

@@ -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
},
})

View File

@@ -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"
)
})
})

View File

@@ -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`
)
}
}