-
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
9fc505a
b330b06
f062a2a
32f96fe
50acc14
e564eae
c01efd4
b458b95
735abc4
39e2b05
3197676
71a91d4
4221392
d6b43fb
e727676
b128e8f
4eb0731
b7deec7
118ac39
2a96ee7
22193e5
e522c0c
3eba24e
36267c3
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 |
|---|---|---|
|
|
@@ -54,13 +54,19 @@ func (StatementFnCallResolution) fnCallResolution() {} | |
| func (r VarOriginFnCallResolution) GetParams() []string { return r.Params } | ||
| func (r StatementFnCallResolution) GetParams() []string { return r.Params } | ||
|
|
||
| const FnSetTxMeta = "set_tx_meta" | ||
| const FnSetAccountMeta = "set_account_meta" | ||
| const FnVarOriginMeta = "meta" | ||
| const FnVarOriginBalance = "balance" | ||
| const FnVarOriginOverdraft = "overdraft" | ||
| const FnVarOriginGetAsset = "get_asset" | ||
| const FnVarOriginGetAmount = "get_amount" | ||
| const ( | ||
| // Statemetn fns | ||
| FnSetTxMeta = "set_tx_meta" | ||
| FnSetAccountMeta = "set_account_meta" | ||
|
|
||
| // Expr fns | ||
| FnVarOriginMeta = "meta" | ||
| FnVarOriginBalance = "balance" | ||
| FnVarOriginOverdraft = "overdraft" | ||
| FnVarOriginGetAsset = "get_asset" | ||
| FnVarOriginGetAmount = "get_amount" | ||
| FnVarOriginScoped = "scoped" | ||
| ) | ||
|
|
||
| var Builtins = map[string]FnCallResolution{ | ||
| FnSetTxMeta: StatementFnCallResolution{ | ||
|
|
@@ -114,6 +120,17 @@ var Builtins = map[string]FnCallResolution{ | |
| }, | ||
| }, | ||
| }, | ||
| FnVarOriginScoped: VarOriginFnCallResolution{ | ||
|
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
NumaryBot marked this conversation as resolved.
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. 🟠 [major] Adding Suggestion: Add a |
||
| Params: []string{TypeAccount, TypeString}, | ||
| Return: TypeAccount, | ||
| Docs: "returns the scoped version of that account. Empty string means no scope. Overwrites the previous scope", | ||
| VersionConstraints: []VersionClause{ | ||
|
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. 🟠 [major] Mid-script function call flag not required for When Suggestion: Either require both flags in the checker registration, or ensure the runtime does not require the mid-script flag for |
||
| { | ||
| Version: parser.NewVersionInterpreter(0, 0, 25), | ||
|
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
|
||
| FeatureFlag: flags.ExperimentalScopedFunction, | ||
|
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
ascandone marked this conversation as resolved.
NumaryBot marked this conversation as resolved.
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. 🟠 [major] Wrong feature flag gates
Suggestion: Change the feature-flag constraint for the |
||
| }, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| type Diagnostic struct { | ||
|
|
||
| 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,12 @@ | ||
|
|
||
| [TestPrettyPrintMeta/renders_plain_values - 1] | ||
| | [36mName [0m | [36mValue [0m | | ||
| | count | 42 | | ||
| | greeting | "hello" | | ||
| --- | ||
|
|
||
| [TestPrettyPrintMeta/renders_a_scoped_account_value_in_its_source_form - 1] | ||
| | [36mName [0m | [36mValue [0m | | ||
| | greeting | "hello" | | ||
| | owner | scoped(alice, "reserve") | | ||
| --- |
| 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,42 @@ 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{} | ||
| }) | ||
| type AccountMetadataRow struct { | ||
| Account string `json:"account"` | ||
| Key string `json:"key"` | ||
| Value string `json:"value"` | ||
| Scope string `json:"scope,omitempty"` | ||
| } | ||
|
|
||
| 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 | ||
| } | ||
|
|
||
| func (m AccountsMetadata) Merge(update AccountsMetadata) { | ||
| for acc, accBalances := range update { | ||
| cachedAcc := utils.MapGetOrPutDefault(m, acc, func() AccountMetadata { | ||
| return AccountMetadata{} | ||
| }) | ||
|
|
||
| for curr, amt := range accBalances { | ||
| cachedAcc[curr] = amt | ||
| // 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 | ||
|
|
||
| // 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) | ||
|
NumaryBot marked this conversation as resolved.
NumaryBot marked this conversation as resolved.
NumaryBot marked this conversation as resolved.
NumaryBot marked this conversation as resolved.
NumaryBot marked this conversation as resolved.
NumaryBot marked this conversation as resolved.
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. 🟠 [major]
Suggestion: Use a frequency-count map: increment counts for each row in slice |
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.