diff --git a/.gitignore b/.gitignore index 70a4aba..4baca45 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.gem +.gems/ # rbenv .ruby-version diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ae9f7f9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog + +## [2.0.0] + +### Changed + +- `GetLedgerAccountBalance` now returns total `balance` (self + children) instead of `ownBalance`. +- `ListLedgerAccountBalances` and `ListMultiCurrencyLedgerAccountBalances` now accept `consistencyMode` on `childBalance`, `childBalances`, `balance`, and `balances`. + +### Removed + +- `GetLedgerAccountBalanceWithChildRollup` has been removed. + +### Upgrade Guide + +1. Upgrade your schema to use total balance consistency. + - Change `ownBalanceUpdates` to `totalBalanceUpdates` in ledger account consistency config. + - Change `ownBalance` to `totalBalance` in entry conditions. + - A schema can use only one of `ownBalanceUpdates` or `totalBalanceUpdates` for consistency and conditions. + - Deploy the new schema. +2. You can now set `consistencyConfig.totalBalanceUpdates: strong` on any account in the tree to make its balance strongly consistent. +3. Upgrade the Fragment SDK to this version. + - `GetLedgerAccountBalance` now returns total `balance` (self + children) instead of `ownBalance`. + - Change `$ownBalanceConsistencyMode` to `$balanceConsistencyMode` + - Use `GetLedgerAccountBalance` instead of `GetLedgerAccountBalanceWithChildRollup`. diff --git a/Gemfile.lock b/Gemfile.lock index ac2788c..ea5168f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - fragment-dev (1.4.6) + fragment-dev (2.0.0) graphql (>= 2.2.5, < 3.0) graphql-client (~> 0.23.0) sorbet-runtime (~> 0.5) diff --git a/lib/fragment.schema.json b/lib/fragment.schema.json index 7c798a2..1d5e260 100644 --- a/lib/fragment.schema.json +++ b/lib/fragment.schema.json @@ -4951,6 +4951,77 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lines", + "description": "List Ledger Lines across accounts in this Ledger, sorted by `posted` in reverse chronological order.\nSpecify a single Ledger Account via the `ledgerAccount` field, or query across multiple accounts using the `path` filter or `ledgerAccount.in`.", + "args": [ + { + "name": "after", + "description": "Where to start paginating from, when paginating forwards. Send endCursor from a response to get its next page. Learn more about [pagination](https://fragment.dev/docs/query-data#basics-pagination).", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "before", + "description": "Where to start paginating from, when paginating backwards. Send startCursor from a response to get the previous page. Learn more about [pagination](https://fragment.dev/docs/query-data#basics-pagination).", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "filter", + "description": "Filter the Ledger Lines returned. Either the `ledgerAccount` or `path` field is required. Learn more about [querying Ledger Lines](https://fragment.dev/docs/query-data#ledger-lines).", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "LedgerLinesFilterSet", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "first", + "description": "The number of Ledger Lines to return per page, when paginating forwards. Defaults to 20, maximum is 200.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "last", + "description": "The number of Ledger Lines to return per page, when paginating backwards. Defaults to 20, maximum is 200.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "LedgerLinesConnection", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "migrations", "description": "Schema migrations affecting this Ledger.", @@ -6743,6 +6814,18 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "totalBalanceUpdates", + "description": "If set to `strong`, then a Ledger Account's `ownBalance`, `childBalance`, and `balance` fields' updates will be strongly consistent with\nthe API response. This Ledger Account's balance will be updated and\navailable for strongly consistent reads once you receive an API response.\n\nOtherwise if not set or set to `eventual`, updates are applied\nasynchronously and may not be immediately reflected in queries.\n\nSee [Configure consistency](https://fragment.dev/docs/configure-consistency).", + "args": [], + "type": { + "kind": "ENUM", + "name": "BalanceUpdateConsistencyMode", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -7328,7 +7411,7 @@ }, { "name": "earliestPosted", - "description": "Filter by the earliest posted timestamp across all currencies for clearing accounts. This must be used alongside the clearingStatus filter.\nOnly clearing accounts where the minimum posted timestamp (across all currencies) matches this filter will be included.", + "description": "Filter by the earliest posted timestamp across all currencies for clearing accounts. You must also provide clearingStatus in the same filter.\nOnly clearing accounts where the minimum posted timestamp (across all currencies) matches this filter will be included.", "type": { "kind": "INPUT_OBJECT", "name": "DateTimeFilter", @@ -7358,7 +7441,7 @@ }, { "name": "latestPosted", - "description": "Filter by the latest posted timestamp across all currencies for clearing accounts. This must be used alongside the clearingStatus filter.\nOnly clearing accounts where the maximum posted timestamp (across all currencies) matches this filter will be included.", + "description": "Filter by the latest posted timestamp across all currencies for clearing accounts. You must also provide clearingStatus in the same filter.\nOnly clearing accounts where the maximum posted timestamp (across all currencies) matches this filter will be included.", "type": { "kind": "INPUT_OBJECT", "name": "DateTimeFilter", @@ -10177,6 +10260,30 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "tags", + "description": "Tags attached to this Ledger Line.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "LedgerLineTag", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "tx", "description": "The transaction linked to this LedgerLine", @@ -10299,6 +10406,24 @@ }, "defaultValue": null }, + { + "name": "tags", + "description": "A set of tags attached to this Ledger Line.", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "LedgerEntryTagInput", + "ofType": null + } + } + }, + "defaultValue": null + }, { "name": "tx", "description": "Required for reconcileTx to specify the transaction being reconciled, you can specify either the FRAGMENT ID or external ID of the transaction", @@ -10339,6 +10464,49 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "LedgerLineTag", + "description": "A tag attached to a Ledger Line.", + "fields": [ + { + "name": "key", + "description": "The key of this tag.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "SafeString", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "value", + "description": "The value associated with this tag's key.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "SafeString", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "LedgerLinesConnection", @@ -10479,6 +10647,26 @@ }, "defaultValue": null }, + { + "name": "ledgerAccount", + "description": "Specify which Ledger Account to read lines from. Required when querying lines via `Ledger.lines` without a `path` filter. Not allowed when querying via `LedgerAccount.lines`.", + "type": { + "kind": "INPUT_OBJECT", + "name": "LedgerAccountFilter", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "path", + "description": "A filter that string matches the account path. Wildcards ('*') can be used to return lines across multiple accounts.\nTo search for all instances of a a Ledger Account template, use the `matches` filter with an wildcard character in place of the template value e.g. `assets/user:*`. This returns lines from all instances of this template, interleaved by `posted` timestamp.\nTo search for all descendant Ledger Accounts under a given path, use a trailing `/*` in the `matches` filter e.g. `assets/user:user-1>/*`. This returns lines from all descendants at any depth, but not lines from the parent account at `assets/user:user-1>`.\nCannot be combined with `ledgerAccount` filter. Not allowed when querying via `LedgerAccount.lines`. You cannot use wildcards for both descendant and template instance matching in the same query.", + "type": { + "kind": "INPUT_OBJECT", + "name": "StringMatchFilter", + "ofType": null + }, + "defaultValue": null + }, { "name": "posted", "description": "Filter by the posted timestamp of the Ledger Line.", @@ -10499,6 +10687,16 @@ }, "defaultValue": null }, + { + "name": "tag", + "description": "Filter Ledger Lines by tag. Only matches lines that have the specified tags attached directly to them.", + "type": { + "kind": "INPUT_OBJECT", + "name": "TagFilter", + "ofType": null + }, + "defaultValue": null + }, { "name": "type", "description": null, @@ -12071,6 +12269,35 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "ENUM", + "name": "PostLinesAs", + "description": "Controls how lines are posted for a Ledger Entry.\nNew entries created via the dashboard default to `net_amounts`.\nExisting entries without this field set are treated as `raw_lines`.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "net_amounts", + "description": "Lines targeting the same account, currency, and tx are aggregated into a single line with the net amount. Lines that sum to zero are skipped. If all lines sum to zero, no lines are skipped.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "raw_lines", + "description": "Lines are posted as-is without aggregation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "skip_zero_lines", + "description": "Lines with a zero amount are skipped, but lines are not aggregated. If all lines have a zero amount, no lines are skipped.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, { "kind": "OBJECT", "name": "PostedWindow", @@ -13935,6 +14162,16 @@ }, "defaultValue": null }, + { + "name": "postLinesAs", + "description": "Controls how lines are posted. When set to `net_amounts`, all lines targeting the same account, currency, and tx are aggregated into a single line with the net amount, and lines that sum to zero are skipped. When set to `skip_zero_lines`, lines with a zero amount are skipped but not aggregated. In both modes, if all lines are zero, no lines are skipped. When set to `raw_lines`, lines are posted as-is without aggregation. New entries created via the dashboard default to `net_amounts`. Existing entries without this field set are treated as `raw_lines`.", + "type": { + "kind": "ENUM", + "name": "PostLinesAs", + "ofType": null + }, + "defaultValue": null + }, { "name": "status", "description": "The status of this Ledger Entry. Defaults to active.", @@ -14134,6 +14371,24 @@ }, "defaultValue": null }, + { + "name": "tags", + "description": "Tags to attach to this Ledger Line. Supports parameterized values via handlebars syntax.", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "SchemaLedgerEntryTagInput", + "ofType": null + } + } + }, + "defaultValue": null + }, { "name": "tx", "description": "The external transaction to reconcile.\nThis field is required if the Ledger Account being posted to is a Linked Ledger Account. Otherwise, this field is disallowed.\nIt supports parameters in its attributes via handlebars syntax.\n\nSee the docs on [reconciling payments](https://fragment.dev/docs/reconcile-payments).", diff --git a/lib/fragment_client/version.rb b/lib/fragment_client/version.rb index 64dc7e4..c37d2cb 100644 --- a/lib/fragment_client/version.rb +++ b/lib/fragment_client/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module FragmentSDK - VERSION = '1.4.6' + VERSION = '2.0.0' end diff --git a/lib/queries.graphql b/lib/queries.graphql index 8923e07..7804128 100644 --- a/lib/queries.graphql +++ b/lib/queries.graphql @@ -24,9 +24,7 @@ mutation StoreSchema($schema: SchemaInput!) { } } -mutation DeleteSchema( - $schema: SchemaMatchInput! -) { +mutation DeleteSchema($schema: SchemaMatchInput!) { deleteSchema(schema: $schema) { __typename ... on DeleteSchemaResult { @@ -77,9 +75,7 @@ mutation CreateLedger( } } -mutation DeleteLedger( - $ledger: LedgerMatchInput! -) { +mutation DeleteLedger($ledger: LedgerMatchInput!) { deleteLedger(ledger: $ledger) { __typename ... on DeleteLedgerResult { @@ -151,9 +147,7 @@ mutation AddLedgerEntry( } } -mutation ReverseLedgerEntry( - $id: ID! -) { +mutation ReverseLedgerEntry($id: ID!) { reverseLedgerEntry(id: $id) { __typename ... on ReverseLedgerEntryResult { @@ -208,14 +202,8 @@ mutation ReverseLedgerEntry( } } -mutation MigrateLedgerEntry( - $id: ID! - $newLedgerEntry: LedgerEntryInput! -) { - migrateLedgerEntry(input: { - id: $id - newLedgerEntry: $newLedgerEntry - }) { +mutation MigrateLedgerEntry($id: ID!, $newLedgerEntry: LedgerEntryInput!) { + migrateLedgerEntry(input: { id: $id, newLedgerEntry: $newLedgerEntry }) { __typename ... on MigrateLedgerEntryResult { reversingLedgerEntry { @@ -689,6 +677,8 @@ query ListLedgerAccountBalances( $balanceCurrency: CurrencyMatchInput $balanceAt: LastMoment $ownBalanceConsistencyMode: ReadBalanceConsistencyMode + $childBalanceConsistencyMode: ReadBalanceConsistencyMode + $balanceConsistencyMode: ReadBalanceConsistencyMode ) { ledger(ledger: { ik: $ledgerIk }) { id @@ -707,8 +697,16 @@ query ListLedgerAccountBalances( at: $balanceAt consistencyMode: $ownBalanceConsistencyMode ) - childBalance(currency: $balanceCurrency, at: $balanceAt) - balance(currency: $balanceCurrency, at: $balanceAt) + childBalance( + currency: $balanceCurrency + at: $balanceAt + consistencyMode: $childBalanceConsistencyMode + ) + balance( + currency: $balanceCurrency + at: $balanceAt + consistencyMode: $balanceConsistencyMode + ) } pageInfo { hasNextPage @@ -727,6 +725,8 @@ query ListMultiCurrencyLedgerAccountBalances( $before: String $balanceAt: LastMoment $ownBalancesConsistencyMode: ReadBalanceConsistencyMode + $childBalancesConsistencyMode: ReadBalanceConsistencyMode + $balancesConsistencyMode: ReadBalanceConsistencyMode ) { ledger(ledger: { ik: $ledgerIk }) { id @@ -752,7 +752,10 @@ query ListMultiCurrencyLedgerAccountBalances( amount } } - childBalances(at: $balanceAt) { + childBalances( + at: $balanceAt + consistencyMode: $childBalancesConsistencyMode + ) { nodes { currency { code @@ -761,7 +764,7 @@ query ListMultiCurrencyLedgerAccountBalances( amount } } - balances(at: $balanceAt) { + balances(at: $balanceAt, consistencyMode: $balancesConsistencyMode) { nodes { currency { code @@ -815,24 +818,7 @@ query GetLedgerAccountBalance( $ledgerIk: SafeString! $balanceCurrency: CurrencyMatchInput $balanceAt: LastMoment - $ownBalanceConsistencyMode: ReadBalanceConsistencyMode -) { - ledgerAccount(ledgerAccount: { ledger: { ik: $ledgerIk }, path: $path }) { - id - path - ownBalance( - currency: $balanceCurrency - at: $balanceAt - consistencyMode: $ownBalanceConsistencyMode - ) - } -} - -query GetLedgerAccountBalanceWithChildRollup( - $path: String! - $ledgerIk: SafeString! - $balanceCurrency: CurrencyMatchInput - $balanceAt: LastMoment + $balanceConsistencyMode: ReadBalanceConsistencyMode ) { ledgerAccount(ledgerAccount: { ledger: { ik: $ledgerIk }, path: $path }) { id @@ -840,11 +826,11 @@ query GetLedgerAccountBalanceWithChildRollup( balance( currency: $balanceCurrency at: $balanceAt + consistencyMode: $balanceConsistencyMode ) } } - query GetSchema($key: SafeString!, $version: Int) { schema(schema: { key: $key, version: $version }) { key @@ -912,21 +898,23 @@ query ListLedgerEntryGroupBalances( $last: Int $filter: LedgerEntryGroupBalanceFilterSet ) { - ledgerEntryGroup(ledgerEntryGroup: { - ledger: { ik: $ledgerIk }, - key: $groupKey, - value: $groupValue, - }) { + ledgerEntryGroup( + ledgerEntryGroup: { + ledger: { ik: $ledgerIk } + key: $groupKey + value: $groupValue + } + ) { key value created balances( - after: $after, - before: $before, - first: $first, - last: $last, - filter: $filter, - ){ + after: $after + before: $before + first: $first + last: $last + filter: $filter + ) { nodes { account { path @@ -1020,12 +1008,8 @@ query GetEntriesToMigrateForLedgerEntryDataMigration( ledger(ledger: { ik: $ledgerIk }) { ledgerEntryDataMigrations( filter: { - entryType: { - equalTo: $entryType - } - typeVersion: { - equalTo: $typeVersion - } + entryType: { equalTo: $entryType } + typeVersion: { equalTo: $typeVersion } } ) { nodes { @@ -1049,7 +1033,7 @@ query GetEntriesToMigrateForLedgerEntryDataMigration( id amount account { - path + path } } } @@ -1136,18 +1120,14 @@ query GetEntriesToMigrateForLedgerAccountDataMigration( ) { ledger(ledger: { ik: $ledgerIk }) { ledgerAccountDataMigrations( - filter: { - accountPath: { - equalTo: $accountPath - } - } + filter: { accountPath: { equalTo: $accountPath } } ) { nodes { ledgerEntries( - first: $first - after: $after - last: $last - before: $before + first: $first + after: $after + last: $last + before: $before ) { nodes { id @@ -1181,17 +1161,17 @@ query GetEntriesToMigrateForLedgerAccountDataMigration( } mutation CreateCustomCurrency( - $id: SafeString!, - $name: String!, - $precision: Int!, - $customCode: String!, + $id: SafeString! + $name: String! + $precision: Int! + $customCode: String! ) { createCustomCurrency( customCurrency: { - customCurrencyId: $id, - name: $name, - precision: $precision, - customCode: $customCode, + customCurrencyId: $id + name: $name + precision: $precision + customCode: $customCode } ) { ... on CreateCustomCurrencyResult {