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 11:29:36 +00:00
committed by GitHub
parent 56cbf88115
commit 8ea37d03c9
10 changed files with 106 additions and 45 deletions
+5
View 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 { export default class LineItemAdjustment extends AdjustmentLine {
@ManyToOne({ @ManyToOne({
entity: () => LineItem, entity: () => LineItem,
cascade: [Cascade.REMOVE, Cascade.PERSIST, "soft-remove"] as any, cascade: [Cascade.REMOVE, Cascade.PERSIST],
}) })
item: LineItem item: LineItem
@@ -20,7 +20,7 @@ import ShippingMethod from "./shipping-method"
export default class ShippingMethodAdjustment extends AdjustmentLine { export default class ShippingMethodAdjustment extends AdjustmentLine {
@ManyToOne({ @ManyToOne({
entity: () => ShippingMethod, entity: () => ShippingMethod,
cascade: [Cascade.REMOVE, Cascade.PERSIST, "soft-remove"] as any, cascade: [Cascade.REMOVE, Cascade.PERSIST],
}) })
shipping_method: ShippingMethod shipping_method: ShippingMethod
@@ -1,15 +1,15 @@
import { IPaymentModuleService } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk" import { Modules } from "@medusajs/modules-sdk"
import { IPaymentModuleService } from "@medusajs/types"
import {
moduleIntegrationTestRunner,
SuiteOptions,
} from "medusa-test-utils/dist"
import { import {
createPaymentCollections, createPaymentCollections,
createPayments, createPayments,
createPaymentSessions, createPaymentSessions,
} from "../../../__fixtures__" } from "../../../__fixtures__"
import {
moduleIntegrationTestRunner,
SuiteOptions,
} from "medusa-test-utils/dist"
jest.setTimeout(30000) jest.setTimeout(30000)
@@ -466,7 +466,7 @@ moduleIntegrationTestRunner({
id: expect.any(String), id: expect.any(String),
currency_code: "usd", currency_code: "usd",
amount: 100, amount: 100,
raw_amount: { value: "100.00000000000000000", precision: 20 }, raw_amount: { value: "100", precision: 20 },
provider_id: "system", provider_id: "system",
data: {}, data: {},
status: "authorized", status: "authorized",
+4 -3
View File
@@ -1,6 +1,5 @@
export * from "./alter-columns-helper" export * from "./alter-columns-helper"
export * from "./array-difference" export * from "./array-difference"
export * from "./get-set-difference"
export * from "./build-query" export * from "./build-query"
export * from "./camel-to-snake-case" export * from "./camel-to-snake-case"
export * from "./container" export * from "./container"
@@ -12,8 +11,10 @@ export * from "./errors"
export * from "./generate-entity-id" export * from "./generate-entity-id"
export * from "./generate-linkable-keys-map" export * from "./generate-linkable-keys-map"
export * from "./get-config-file" export * from "./get-config-file"
export * from "./get-duplicates"
export * from "./get-iso-string-from-date" export * from "./get-iso-string-from-date"
export * from "./get-selects-and-relations-from-object-array" export * from "./get-selects-and-relations-from-object-array"
export * from "./get-set-difference"
export * from "./group-by" export * from "./group-by"
export * from "./handle-postgres-database-error" export * from "./handle-postgres-database-error"
export * from "./is-big-number" 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-from-string"
export * from "./remote-query-object-to-string" export * from "./remote-query-object-to-string"
export * from "./remove-nullisih" export * from "./remove-nullisih"
export * from "./remove-undefined"
export * from "./selector-constraints-to-string" export * from "./selector-constraints-to-string"
export * from "./set-metadata" export * from "./set-metadata"
export * from "./simple-hash" export * from "./simple-hash"
@@ -45,7 +47,6 @@ export * from "./to-camel-case"
export * from "./to-kebab-case" export * from "./to-kebab-case"
export * from "./to-pascal-case" export * from "./to-pascal-case"
export * from "./transaction" export * from "./transaction"
export * from "./trim-zeros"
export * from "./upper-case-first" export * from "./upper-case-first"
export * from "./wrap-handler" export * from "./wrap-handler"
export * from "./remove-undefined"
export * from "./get-duplicates"
+15
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
}
@@ -1,6 +1,6 @@
import { MikroOrmBigNumberProperty } from "../big-number-field"
import { BigNumberRawValue } from "@medusajs/types" import { BigNumberRawValue } from "@medusajs/types"
import { BigNumber } from "../../../totals/big-number" import { BigNumber } from "../../../totals/big-number"
import { MikroOrmBigNumberProperty } from "../big-number-field"
describe("@MikroOrmBigNumberProperty", () => { describe("@MikroOrmBigNumberProperty", () => {
it("should correctly assign and update BigNumber values", () => { it("should correctly assign and update BigNumber values", () => {
@@ -9,6 +9,11 @@ describe("@MikroOrmBigNumberProperty", () => {
amount: BigNumber | number amount: BigNumber | number
raw_amount: BigNumberRawValue raw_amount: BigNumberRawValue
@MikroOrmBigNumberProperty({ nullable: true })
nullable_amount: BigNumber | number | null = null
raw_nullable_amount: BigNumberRawValue | null = null
} }
const testAmount = new TestAmount() const testAmount = new TestAmount()
@@ -21,10 +26,20 @@ describe("@MikroOrmBigNumberProperty", () => {
expect(testAmount.amount).toEqual(100) expect(testAmount.amount).toEqual(100)
expect((testAmount as any).amount_).toEqual(100) expect((testAmount as any).amount_).toEqual(100)
expect(testAmount.raw_amount).toEqual({ expect(testAmount.raw_amount).toEqual({
value: "100.00000000000000000", value: "100",
precision: 20, 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 // Update the amount
testAmount.amount = 200 testAmount.amount = 200
@@ -32,7 +47,7 @@ describe("@MikroOrmBigNumberProperty", () => {
expect(testAmount.amount).toEqual(200) expect(testAmount.amount).toEqual(200)
expect((testAmount as any).amount_).toEqual(200) expect((testAmount as any).amount_).toEqual(200)
expect(testAmount.raw_amount).toEqual({ expect(testAmount.raw_amount).toEqual({
value: "200.00000000000000000", value: "200",
precision: 20, precision: 20,
}) })
@@ -42,6 +57,6 @@ describe("@MikroOrmBigNumberProperty", () => {
expect(testAmount.amount).toEqual(300) expect(testAmount.amount).toEqual(300)
expect((testAmount as any).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 { BigNumberInput } from "@medusajs/types"
import { Property } from "@mikro-orm/core"
import { isPresent, trimZeros } from "../../common"
import { BigNumber } from "../../totals/big-number"
export function MikroOrmBigNumberProperty( export function MikroOrmBigNumberProperty(
options: Parameters<typeof Property>[0] & { options: Parameters<typeof Property>[0] & {
@@ -16,21 +17,37 @@ export function MikroOrmBigNumberProperty(
return this[targetColumn] return this[targetColumn]
}, },
set(value: BigNumberInput) { set(value: BigNumberInput) {
if (options?.nullable && !isPresent(value)) {
this[targetColumn] = null
this[rawColumnName] = null
return
}
let bigNumber: BigNumber let bigNumber: BigNumber
if (value instanceof BigNumber) { if (value instanceof BigNumber) {
bigNumber = value bigNumber = value
} else if (this[rawColumnName]) { } else if (this[rawColumnName]) {
const precision = this[rawColumnName].precision const precision = this[rawColumnName].precision
this[rawColumnName].value = new BigNumber(value, {
precision, this[rawColumnName].value = trimZeros(
}).raw!.value new BigNumber(value, {
precision,
}).raw!.value as string
)
bigNumber = new BigNumber(this[rawColumnName]) bigNumber = new BigNumber(this[rawColumnName])
} else { } else {
bigNumber = new BigNumber(value) bigNumber = new BigNumber(value)
} }
this[targetColumn] = bigNumber.numeric 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 () { it("should throw if not correct type", function () {
// @ts-ignore // @ts-ignore
expect(() => new BigNumber([])).toThrow( 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"
) )
}) })
}) })
+23 -23
View File
@@ -8,61 +8,61 @@ export class BigNumber {
private numeric_: number private numeric_: number
private raw_?: BigNumberRawValue private raw_?: BigNumberRawValue
constructor(rawPrice: BigNumberInput, options?: { precision?: number }) { constructor(rawValue: BigNumberInput, options?: { precision?: number }) {
this.setRawPriceOrThrow(rawPrice, options) this.setRawValueOrThrow(rawValue, options)
} }
setRawPriceOrThrow( setRawValueOrThrow(
rawPrice: BigNumberInput, rawValue: BigNumberInput,
{ precision }: { precision?: number } = {} { precision }: { precision?: number } = {}
) { ) {
precision ??= BigNumber.DEFAULT_PRECISION precision ??= BigNumber.DEFAULT_PRECISION
if (BigNumberJS.isBigNumber(rawPrice)) { if (BigNumberJS.isBigNumber(rawValue)) {
/** /**
* Example: * Example:
* const bnUnitPrice = new BigNumberJS("10.99") * const bnUnitValue = new BigNumberJS("10.99")
* const unitPrice = new BigNumber(bnUnitPrice) * const unitValue = new BigNumber(bnUnitValue)
*/ */
this.numeric_ = rawPrice.toNumber() this.numeric_ = rawValue.toNumber()
this.raw_ = { this.raw_ = {
value: rawPrice.toPrecision(precision), value: rawValue.toPrecision(precision),
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.numeric_ = bigNum.toNumber()
this.raw_ = this.raw_ = { this.raw_ = this.raw_ = {
value: bigNum.toPrecision(precision), value: bigNum.toPrecision(precision),
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_ = { this.raw_ = {
...rawPrice, ...rawValue,
precision, 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_ = { this.raw_ = {
value: BigNumberJS(rawPrice as number).toPrecision(precision), value: BigNumberJS(rawValue as number).toPrecision(precision),
precision, precision,
} }
} else { } else {
throw new Error( 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`
) )
} }
} }