-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add BigNumber implementation (#6253)
> This is a proposal - not necessarily the end result - to kick off the discussion about the implementation of the new totals utilities ### What Introduces a BigNumber class implementation, enabling us to work with high-precision numeric values. **Scope** - Introduce the BigNumber class - Remain somewhat backward-compatible (in behavior) - Establish a foundation for handling high-precision values in more complex scenarios **Not in scope** - The implementation will not address complex use cases. However, the concept introduced now should be open for extensibility, so this can be added later without major changes to the calculation logic ### How There are significant changes to three areas in this PR: - Schemas - (De)-Serialization - Totals calculations **Schemas** Domains that need high-precision values will have two DB columns for each value in the database: a standard numeric column and a raw value column. The standard column is for basic operations like sorting and filtering in the database and is what should be publicly exposed in our API. The raw value is initially used solely for precise calculations and is stored as a JSONB column. Keeping it as JSONB is flexible and will allow us to extend the concept in future iterations. As of now, the raw value will only require a single property `value`. **(De)-Serialization** We cast the raw JSONB value to a `BigNumberRawValue` when reading from the database. We serialize the standard value to a `BigNumber` when reading from the database. We use the standard numeric value to construct the raw value upon writing to the database. For example, the unit price and raw unit price on line items will be inserted as follows: ```ts @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "cali") const asBigNumber = new BigNumber(this.raw_unit_price ?? this.unit_price) this.unit_price = asBigNumber.numeric this.raw_unit_price = asBigNumber.raw } ``` **Totals calculations** For totals calculations, we will use the [`bignumber.js`](https://github.com/MikeMcl/bignumber.js/) library. The library ships with a `BigNumber` class with arithmetic methods for precise calculations. When we need to perform a calculation, we construct the BigNumber class from the library using the raw value from the database. Let's have a look at an oversimplified example: ```ts // create cart with line items const [createdCart] = await service.create([ { currency_code: "eur", items: [ // li_1234 { title: "test", quantity: 2, unit_price: 100, }, // li_4321 { title: "test", quantity: 3, // raw price creation unit_price: 200, }, ], }, ]) ``` ```ts // calculating line item totals import BN from "bignumber.js" const lineItem1 = await service.retrieveLineItem("li_1234") const lineItem2 = await service.retrieveLineItem("li_4321") const bnUnitPrice1 = new BN(lineItem1.unit_price.raw) const bnUnitPrice2 = new BN(lineItem2.unit_price.raw) const line1Total = bnUnitPrice1.multipliedBy(lineItem1.quantity) const line2Total = bnUnitPrice2.multipliedBy(lineItem2.quantity) const total = line1Total.plus(line2Total) ``` **A note on backward compatibility** Our BigNumber implementation is built to support the existing behavior of numeric values in the database. So even though we serialize the value to a BigNumber, you will still be able to treat it as a standard number, as we've always done. For example, the following works perfectly fine: ```ts const lineItem = await service.createLineItem({ title: "test", quantity: 2, unit_price: 100, }) console.log(lineItem.unit_price) // will print `100` ``` However, the type of `unit_price` will be `number | BigNumber`.
- Loading branch information
1 parent
dc88fd3
commit 94062d2
Showing
24 changed files
with
529 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
export { default as CartModuleService } from "./cart-module" | ||
export { default as CartModuleService } from "./cart-module"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import BigNumber from "bignumber.js" | ||
|
||
export type BigNumberRawValue = { | ||
value: string | number | ||
[key: string]: unknown | ||
} | ||
|
||
export type BigNumberRawPriceInput = | ||
| BigNumberRawValue | ||
| number | ||
| string | ||
| BigNumber |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./big-number"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { BigNumberRawValue } from "@medusajs/types" | ||
import { isObject } from "./is-object" | ||
|
||
export function isBigNumber(obj: any): obj is BigNumberRawValue { | ||
return isObject(obj) && "value" in obj | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.