Для работы с деньгами heap-таблицы поддерживают специальный тип поля Money , который представляет собой семантически корректное представление денежных сумм. Обладает следующими свойствами:
Хранит сумму вместе с валютой.
Значения представлены в виде экземпляров специального класса Money , который предоставляет методы для корректных с точки зрения округления и валюты операций над деньгами.
Методы фильтрации и сортировки таблицы поддерживают специальный синтаксис и семантику для денежного типа
Фильтрация по денежному типу поддерживает несколько вариантов:
По деньгам в целом - сумма с учётом валюты. Наиболее "безопасный" вариант.
По сумме без учёта валюты. Можно выстрелить себе в ногу, но в умелых руках может быть полезно.
Отдельно по валюте.
Если у в таблице объявлено поле money: Heap.Money()
, то вы можете "сравнивать" его в фильтрации:
С объектом класса Money
import { Money } from '@app/heap'
await table.findAll(ctx, { where: { money: new Money(10, 'RUB')} }
С парой сумма+валюта вида [10, 'RUB']
await table.findAll(ctx, { where: { money: { $lte: [1000, 'RUB'] } } }
С нулём. Сравнение с любыми другими значениями суммы без валюты небезопасно.
await table.findAll(ctx, { where: { money: { $gt: 0 } } }
В этом режиме (когда мы при фильтрации "обращаемся" непосредственно к полю), поиск происходит в рамках фиксированной валюты из правой части фильтра, за исключением сравнения с нулём в третьем варианте.
В этом режиме не поддерживается IN-фильтрация, когда в правой части указан массив со списком значений. Если необходимо сравнить со списком значений, можно использовать сравнение с псевдо-полем amount
(см. ниже).
Для случаев, когда разработчик знает, что делает, поля типа Heap.Money
поддерживают фильтрацию отдельно по сумме, отдельно по валюте, а также их комбинации. Для этого в фильтре можно использовать специальные дочерние псевдо-поля amount
и currency
. Для каждого из них поддерживается IN-фильтрация по списку значений, но для currency
не поддерживаются стандартные операторы сравнения.
Только сумма:
await table.findBy(ctx, { money: { amount: { $gt: 100 } } })
await table.findAll(ctx, { where: { money: { amount: [10, 20, 30, 40] } } })
Только валюта:
await table.findBy(ctx, { money: { currency: 'USD' } })
await table.findAll(ctx, { where: { money: { currency: ['RUB', 'EUR'] } } })
Когда указаны оба поля, это сооветствует двум условиям, объединённым через AND
:
await table.findBy(ctx, { money: { amount: [10, 20, 30, 40] currency: 'USD' } })
await table.findAll(ctx, { where: { money: { amount: { $lt: 1000 }, currency: ['USD', 'EUR'] } } })
Если поле с типом Heap.Money используется в свойстве order
метода findAll
, то действуют следующие принципы:
Сортировка по сумме без учёта валюты, а также по отдельно по валюте не имеет практического смысла и поэтому не поддерживается. Если необходимо получить строго упорядоченный по сумме список, следует отфильтровать его по одной валюте с помошью псевдо-поля currency
.
await table.findAll(ctx, { where: { money: { currency: 'USD' } },
order: { money: 'desc' } })
Автоматическое приведение значений к единой валюте для корректной сортировки также не поддерживается, но легко выполнимо в обычном js-коде, если имеются курсы обмена валют.