-
Notifications
You must be signed in to change notification settings - Fork 188
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce compare function (#266)
Co-authored-by: Sarah Dayan <[email protected]>
- Loading branch information
1 parent
107607d
commit 53f84c2
Showing
10 changed files
with
271 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* eslint-disable functional/no-expression-statement */ | ||
import { UNEQUAL_CURRENCIES_MESSAGE } from '../checks'; | ||
import { assert } from '../helpers'; | ||
import { compare as cmp } from '../utils'; | ||
|
||
import { haveSameCurrency } from './haveSameCurrency'; | ||
import { normalizeScale } from './normalizeScale'; | ||
|
||
import type { Dinero } from '../types'; | ||
import type { Dependencies } from './types'; | ||
|
||
export type CompareParams<TAmount> = readonly [ | ||
dineroObject: Dinero<TAmount>, | ||
comparator: Dinero<TAmount> | ||
]; | ||
|
||
export type UnsafeCompareDependencies<TAmount> = Dependencies<TAmount>; | ||
|
||
export function unsafeCompare<TAmount>({ | ||
calculator, | ||
}: UnsafeCompareDependencies<TAmount>) { | ||
const compareFn = cmp(calculator); | ||
|
||
return function compare( | ||
...[dineroObject, comparator]: CompareParams<TAmount> | ||
) { | ||
const dineroObjects = [dineroObject, comparator]; | ||
|
||
const [subjectAmount, comparatorAmount] = dineroObjects.map((d) => { | ||
const { amount } = d.toJSON(); | ||
|
||
return amount; | ||
}); | ||
|
||
return compareFn(subjectAmount, comparatorAmount); | ||
}; | ||
} | ||
|
||
export type SafeCompareDependencies<TAmount> = Dependencies<TAmount>; | ||
|
||
export function safeCompare<TAmount>({ | ||
calculator, | ||
}: SafeCompareDependencies<TAmount>) { | ||
const normalizeFn = normalizeScale({ calculator }); | ||
const compareFn = unsafeCompare({ | ||
calculator, | ||
}); | ||
|
||
return function compare( | ||
...[dineroObject, comparator]: CompareParams<TAmount> | ||
) { | ||
const condition = haveSameCurrency([dineroObject, comparator]); | ||
assert(condition, UNEQUAL_CURRENCIES_MESSAGE); | ||
|
||
const [subjectAmount, comparatorAmount] = normalizeFn([ | ||
dineroObject, | ||
comparator, | ||
]); | ||
|
||
return compareFn(subjectAmount, comparatorAmount); | ||
}; | ||
} |
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,50 @@ | ||
import { compare as cmp } from '@dinero.js/calculator-number'; | ||
|
||
import { compare } from '../compare'; | ||
|
||
const compareFn = compare({ compare: cmp }); | ||
|
||
describe('compare', () => { | ||
describe('inferiority', () => { | ||
it('returns -1 when the first number is less than the other with positive numbers', () => { | ||
expect(compareFn(1, 2)).toBe(-1); | ||
}); | ||
it('returns -1 when the first number is less than the other with negative numbers', () => { | ||
expect(compareFn(-3, -2)).toBe(-1); | ||
}); | ||
it('returns -1 when the first number is less than the other with floats', () => { | ||
expect(compareFn(1.2, 2.2)).toBe(-1); | ||
}); | ||
it('returns -1 when the first number is less than the other with numbers in scientific notation', () => { | ||
expect(compareFn(2e5, 3e5)).toBe(-1); | ||
}); | ||
}); | ||
describe('equality', () => { | ||
it('returns 0 when the first number is equal to the other with positive numbers', () => { | ||
expect(compareFn(4, 4)).toBe(0); | ||
}); | ||
it('returns 0 when the first number is equal to the other with negative numbers', () => { | ||
expect(compareFn(-2, -2)).toBe(0); | ||
}); | ||
it('returns 0 when the first number is equal to the other with floats', () => { | ||
expect(compareFn(3.2, 3.2)).toBe(0); | ||
}); | ||
it('returns 0 when the first number is equal to the other with numbers in scientific notation', () => { | ||
expect(compareFn(3e5, 3e5)).toBe(0); | ||
}); | ||
}); | ||
describe('superiority', () => { | ||
it('returns 1 when the first number is greater than the other with positive numbers', () => { | ||
expect(compareFn(4, 3)).toBe(1); | ||
}); | ||
it('returns 1 when the first number is greater than the other with negative numbers', () => { | ||
expect(compareFn(-2, -3)).toBe(1); | ||
}); | ||
it('returns 1 when the first number is greater than the other with floats', () => { | ||
expect(compareFn(3.2, 2.2)).toBe(1); | ||
}); | ||
it('returns 1 when the first number is greater than the other with numbers in scientific notation', () => { | ||
expect(compareFn(3e5, 2e5)).toBe(1); | ||
}); | ||
}); | ||
}); |
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,16 @@ | ||
import type { Calculator } from '../types'; | ||
|
||
type ComparisonCalculator<TAmount> = Pick<Calculator<TAmount>, 'compare'>; | ||
|
||
/** | ||
* Returns a compare function. | ||
* | ||
* @param calculator - The calculator to use. | ||
* | ||
* @returns The compare function. | ||
*/ | ||
export function compare<TAmount>(calculator: ComparisonCalculator<TAmount>) { | ||
return (subject: TAmount, comparator: TAmount) => { | ||
return calculator.compare(subject, comparator); | ||
}; | ||
} |
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,40 @@ | ||
import { EUR, USD } from '@dinero.js/currencies'; | ||
|
||
import { dinero, compare } from '../../..'; | ||
|
||
describe('compare', () => { | ||
it('returns -1 when the first amount is less than the other', () => { | ||
const d1 = dinero({ amount: 500, currency: USD }); | ||
const d2 = dinero({ amount: 800, currency: USD }); | ||
|
||
expect(compare(d1, d2)).toBe(-1); | ||
}); | ||
it('returns 0 when amounts are equal', () => { | ||
const d1 = dinero({ amount: 500, currency: USD }); | ||
const d2 = dinero({ amount: 500, currency: USD }); | ||
|
||
expect(compare(d1, d2)).toBe(0); | ||
}); | ||
it('returns 1 when the first amount is greater than the other', () => { | ||
const d1 = dinero({ amount: 800, currency: USD }); | ||
const d2 = dinero({ amount: 500, currency: USD }); | ||
|
||
expect(compare(d1, d2)).toBe(1); | ||
}); | ||
it('normalizes the result to the highest scale', () => { | ||
const d1 = dinero({ amount: 5000, currency: USD, scale: 3 }); | ||
const d2 = dinero({ amount: 800, currency: USD }); | ||
|
||
expect(compare(d1, d2)).toBe(-1); | ||
}); | ||
it('throws when using different currencies', () => { | ||
const d1 = dinero({ amount: 800, currency: USD }); | ||
const d2 = dinero({ amount: 500, currency: EUR }); | ||
|
||
expect(() => { | ||
compare(d1, d2); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"[Dinero.js] Objects must have the same currency."` | ||
); | ||
}); | ||
}); |
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,20 @@ | ||
import { safeCompare } from '@dinero.js/core'; | ||
|
||
import type { CompareParams } from '@dinero.js/core'; | ||
|
||
/** | ||
* Compare the value of a Dinero object relative to another. | ||
* | ||
* @param dineroObject - The Dinero object to compare. | ||
* @param comparator - The Dinero object to compare to. | ||
* | ||
* @returns One of -1, 0, or 1 depending on whether the first Dinero object is less than, equal to, or greater than the other. | ||
*/ | ||
export function compare<TAmount>( | ||
...[dineroObject, comparator]: CompareParams<TAmount> | ||
) { | ||
const { calculator } = dineroObject; | ||
const compareFn = safeCompare({ calculator }); | ||
|
||
return compareFn(dineroObject, comparator); | ||
} |
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,79 @@ | ||
--- | ||
title: compare | ||
description: Compare the value of a Dinero object relative to another. | ||
returns: number | ||
--- | ||
|
||
Compare the value of a Dinero object relative to another. This is useful for sorting Dinero objects. | ||
|
||
Possible return values are: | ||
- `-1` if the first Dinero object is less than the other | ||
- `1` if the first Dinero object is greater than the other | ||
- `0` if both objects are equal | ||
|
||
**You can only compare objects that share the same currency.** The function also normalizes objects to the same scale (the highest) before comparing them. | ||
|
||
## Parameters | ||
|
||
<Parameters> | ||
|
||
<Parameter name="dineroObject" type="Dinero<TAmount>" required={true}> | ||
|
||
The first Dinero object to compare. | ||
|
||
</Parameter> | ||
|
||
<Parameter name="comparator" type="Dinero<TAmount>" required={true}> | ||
|
||
The second Dinero object to compare. | ||
|
||
</Parameter> | ||
|
||
</Parameters> | ||
|
||
## Code examples | ||
|
||
### Compare two objects | ||
|
||
```js | ||
import { dinero, compare } from 'dinero.js'; | ||
import { USD } from '@dinero.js/currencies'; | ||
|
||
const d1 = dinero({ amount: 800, currency: USD }); | ||
const d2 = dinero({ amount: 500, currency: USD }); | ||
|
||
compare(d1, d2); // 1 | ||
``` | ||
|
||
### Compare two objects after normalization | ||
|
||
```js | ||
import { dinero, compare } from 'dinero.js'; | ||
import { USD } from '@dinero.js/currencies'; | ||
|
||
const d1 = dinero({ amount: 5000, currency: USD, scale: 3 }); | ||
const d2 = dinero({ amount: 800, currency: USD }); | ||
|
||
compare(d1, d2); // -1 | ||
|
||
const d3 = dinero({ amount: 5000, currency: USD, scale: 3 }); | ||
const d4 = dinero({ amount: 500, currency: USD }); | ||
|
||
compare(d3, d4); // 0 | ||
``` | ||
|
||
### Sort arrays of objects | ||
|
||
One of the main use cases of the `compare` function is to sort Dinero objects. For example, you can use it with [`Array.prototype.sort`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort). | ||
|
||
```js | ||
import { dinero, compare } from 'dinero.js'; | ||
import { USD } from '@dinero.js/currencies'; | ||
|
||
const d1 = dinero({ amount: 900, currency: USD }); | ||
const d2 = dinero({ amount: 500, currency: USD }); | ||
const d3 = dinero({ amount: 800, currency: USD }); | ||
|
||
const lowToHigh = [d1, d2, d3].sort(compare); | ||
const highToLow = [d1, d2, d3].sort((a, b) => compare(b, a)); | ||
``` |
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
53f84c2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: