-
Notifications
You must be signed in to change notification settings - Fork 7
feat: scoped accounts #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c07d256
ff72060
f5a8ea6
95ccd08
a1f8795
71a2121
9435a4b
07f2e1d
3b5b118
94b8e9c
4696bc0
70e2ae8
1335270
ac4d566
fc3bbf4
c0851b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
|
|
||
| [TestPrettyPrintAccountsMetadata/without_scope_(no_Scope_column) - 1] | ||
| | [36mAccount[0m | [36mName[0m | [36mValue [0m | | ||
| | alice | kyc | verified | | ||
| | bob | tier | gold | | ||
| --- | ||
|
|
||
| [TestPrettyPrintAccountsMetadata/with_scope_(Scope_column_shown) - 1] | ||
| | [36mAccount[0m | [36mScope[0m | [36mName[0m | [36mValue [0m | | ||
| | alice | eu | kyc | pending | | ||
| | alice | | kyc | verified | | ||
| | bob | | tier | gold | | ||
| --- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
|
|
||
| [TestPrettyPrintPostings/no_scope,_no_color_(no_optional_columns) - 1] | ||
| | [36mSource[0m | [36mDestination[0m | [36mAsset[0m | [36mAmount[0m | | ||
| | world | alice | EUR/2 | 100 | | ||
| --- | ||
|
|
||
| [TestPrettyPrintPostings/only_source_scope_(only_Source_Scope_column_shown) - 1] | ||
| | [36mSource[0m | [36mSource Scope[0m | [36mDestination[0m | [36mAsset[0m | [36mAmount[0m | | ||
| | src | x | dest | USD | 10 | | ||
| | world | | dest | USD | 5 | | ||
| --- | ||
|
|
||
| [TestPrettyPrintPostings/both_scopes_(both_Scope_columns_shown) - 1] | ||
| | [36mSource[0m | [36mSource Scope[0m | [36mDestination[0m | [36mDestination Scope[0m | [36mAsset[0m | [36mAmount[0m | | ||
| | src | x | dest | y | USD | 10 | | ||
| --- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,50 +4,66 @@ import ( | |
| "github.com/formancehq/numscript/internal/utils" | ||
| ) | ||
|
|
||
| type AccountMetadata = map[string]string | ||
| type AccountsMetadata map[string]AccountMetadata | ||
|
|
||
| func (m AccountsMetadata) fetchAccountMetadata(account string) AccountMetadata { | ||
| return utils.MapGetOrPutDefault(m, account, func() AccountMetadata { | ||
| return AccountMetadata{} | ||
| }) | ||
| } | ||
|
|
||
| func (m AccountsMetadata) DeepClone() AccountsMetadata { | ||
| cloned := make(AccountsMetadata) | ||
| for account, accountBalances := range m { | ||
| for asset, metadataValue := range accountBalances { | ||
| clonedAccountBalances := cloned.fetchAccountMetadata(account) | ||
| utils.MapGetOrPutDefault(clonedAccountBalances, asset, func() string { | ||
| return metadataValue | ||
| }) | ||
| } | ||
| } | ||
| return cloned | ||
| type AccountMetadataRow struct { | ||
| Account string `json:"account"` | ||
| Key string `json:"key"` | ||
| Value string `json:"value"` | ||
| Scope string `json:"scope,omitempty"` | ||
| } | ||
|
|
||
| func (m AccountsMetadata) Merge(update AccountsMetadata) { | ||
| for acc, accBalances := range update { | ||
| cachedAcc := utils.MapGetOrPutDefault(m, acc, func() AccountMetadata { | ||
| return AccountMetadata{} | ||
| }) | ||
| // AccountsMetadata is the external, serialized representation of account | ||
| // metadata. The runtime works with the in-memory InternalAccountsMetadata and | ||
| // converts to this at the boundaries (store queries, execution result). | ||
| type AccountsMetadata []AccountMetadataRow | ||
|
|
||
| for curr, amt := range accBalances { | ||
| cachedAcc[curr] = amt | ||
| // FirstDuplicate returns the first row whose (account, key, scope) key already | ||
| // appeared earlier in the list, if any. That triple is the identity of a | ||
| // metadata entry and the value is its content, so a repeated key is an | ||
| // ambiguous, malformed input. | ||
| func (rows AccountsMetadata) FirstDuplicate() (AccountMetadataRow, bool) { | ||
| seen := make(map[[3]string]struct{}, len(rows)) | ||
| for _, row := range rows { | ||
| key := [3]string{row.Account, row.Key, row.Scope} | ||
| if _, ok := seen[key]; ok { | ||
| return row, true | ||
| } | ||
| seen[key] = struct{}{} | ||
| } | ||
| return AccountMetadataRow{}, false | ||
| } | ||
|
|
||
| func (m AccountsMetadata) PrettyPrint() string { | ||
| header := []string{"Account", "Name", "Value"} | ||
| // the Scope column is dropped automatically when no entry has a scope | ||
| header := []string{"Account", "Scope", "Name", "Value"} | ||
|
|
||
| var rows [][]string | ||
| for account, accMetadata := range m { | ||
| for name, value := range accMetadata { | ||
| row := []string{account, name, value} | ||
| rows = append(rows, row) | ||
| } | ||
| for _, row := range m { | ||
| rows = append(rows, []string{row.Account, row.Scope, row.Key, row.Value}) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 [minor] Keep required metadata value column when values are empty If account metadata entries all have an empty string value, |
||
| } | ||
|
|
||
| return utils.CsvPretty(header, rows, true) | ||
| return utils.CsvPrettyOmitEmptyCols(header, rows, true) | ||
| } | ||
|
|
||
| // CompareAccountsMetadata reports whether two metadata lists hold the same rows, | ||
| // ignoring order but respecting multiplicity. A duplicated row in one list must | ||
| // be matched by the same number of occurrences in the other, so e.g. [x, x] is | ||
| // not considered equal to [x, y]. | ||
| func CompareAccountsMetadata(a AccountsMetadata, b AccountsMetadata) bool { | ||
| if len(a) != len(b) { | ||
| return false | ||
| } | ||
| // AccountMetadataRow is an all-string (comparable) struct, so it can key the | ||
| // multiset directly. | ||
| counts := make(map[AccountMetadataRow]int, len(a)) | ||
| for _, row := range a { | ||
|
ascandone marked this conversation as resolved.
|
||
| counts[row]++ | ||
| } | ||
| for _, row := range b { | ||
| counts[row]-- | ||
| if counts[row] < 0 { | ||
| return false | ||
| } | ||
| } | ||
| // equal lengths + every b row consumed a distinct a row => exact multiset match | ||
| return true | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.