@distrohelena/canton-typescript-sdk 0.1.36 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -34
- package/dist/cjs/core/types/requests/{submit-command-request.js → submit-commands-request.js} +10 -6
- package/dist/cjs/index.js +10 -8
- package/dist/cjs/query/canonical/in-memory-query-evaluator.js +291 -0
- package/dist/cjs/query/canonical/public-identity.js +41 -0
- package/dist/cjs/query/canonical/query-ast.js +2 -0
- package/dist/cjs/query/canonical/query-dataset.js +351 -0
- package/dist/cjs/query/canonical/query-normalizer.js +655 -0
- package/dist/cjs/query/canonical/query-schema.js +86 -0
- package/dist/cjs/query/canton-manager.js +14 -5
- package/dist/cjs/query/errors/query-snapshot-incomplete-error.js +19 -0
- package/dist/cjs/query/grpc/grpc-contract-cache.js +484 -0
- package/dist/cjs/query/grpc/grpc-package-relation-reader.js +218 -0
- package/dist/cjs/query/grpc/grpc-query-client.js +249 -0
- package/dist/cjs/query/grpc/grpc-query-snapshot-reader.js +238 -0
- package/dist/cjs/query/grpc/grpc-query-value-mapper.js +204 -0
- package/dist/cjs/query/grpc/grpc-relation-mapper.js +794 -0
- package/dist/cjs/query/pqs/pqs-query-client.js +151 -582
- package/dist/cjs/query/pqs/pqs-relational-sql-compiler.js +138 -95
- package/dist/cjs/query/pqs/pqs-result-shape.js +28 -0
- package/dist/cjs/query/pqs/pqs-schema-profile.js +49 -48
- package/dist/cjs/query/pqs/pqs-sql-compiler.js +343 -289
- package/dist/cjs/query/pqs/pqs-sql-syntax.js +10 -0
- package/dist/cjs/services/command/command-service-client.js +16 -3
- package/dist/cjs/services/commands/command-payload-builder.js +1 -1
- package/dist/cjs/services/commands/command-submission-pipeline.js +21 -6
- package/dist/cjs/testing/runtime/declarative-action-executor.js +3 -3
- package/dist/cjs/transports/grpc/grpc-transport.js +2 -2
- package/dist/cjs/transports/grpc/mappers/commands-mapper.js +6 -6
- package/dist/cjs/transports/grpc/mappers/interactive-command-mapper.js +1 -1
- package/dist/cjs/transports/json/json-transport.js +1 -1
- package/dist/cjs/transports/json/mappers/commands-mapper.js +3 -3
- package/dist/core/transports/transport.interface.d.ts +4 -4
- package/dist/core/types/prepared-command-submission.d.ts +3 -3
- package/dist/core/types/requests/{submit-command-request.d.ts → submit-commands-request.d.ts} +8 -4
- package/dist/core/types/requests/{submit-command-request.js → submit-commands-request.js} +8 -4
- package/dist/index.d.ts +5 -2
- package/dist/index.js +2 -1
- package/dist/query/canonical/in-memory-query-evaluator.d.ts +22 -0
- package/dist/query/canonical/in-memory-query-evaluator.js +287 -0
- package/dist/query/canonical/public-identity.d.ts +14 -0
- package/dist/query/canonical/public-identity.js +35 -0
- package/dist/query/canonical/query-ast.d.ts +104 -0
- package/dist/query/canonical/query-ast.js +1 -0
- package/dist/query/canonical/query-dataset.d.ts +63 -0
- package/dist/query/canonical/query-dataset.js +343 -0
- package/dist/query/canonical/query-normalizer.d.ts +10 -0
- package/dist/query/canonical/query-normalizer.js +646 -0
- package/dist/query/canonical/query-schema.d.ts +25 -0
- package/dist/query/canonical/query-schema.js +83 -0
- package/dist/query/canton-manager.js +14 -5
- package/dist/query/errors/query-snapshot-incomplete-error.d.ts +14 -0
- package/dist/query/errors/query-snapshot-incomplete-error.js +15 -0
- package/dist/query/grpc/grpc-contract-cache.d.ts +27 -0
- package/dist/query/grpc/grpc-contract-cache.js +479 -0
- package/dist/query/grpc/grpc-package-relation-reader.d.ts +43 -0
- package/dist/query/grpc/grpc-package-relation-reader.js +213 -0
- package/dist/query/grpc/grpc-query-client.d.ts +42 -0
- package/dist/query/grpc/grpc-query-client.js +245 -0
- package/dist/query/grpc/grpc-query-snapshot-reader.d.ts +33 -0
- package/dist/query/grpc/grpc-query-snapshot-reader.js +233 -0
- package/dist/query/grpc/grpc-query-value-mapper.d.ts +15 -0
- package/dist/query/grpc/grpc-query-value-mapper.js +195 -0
- package/dist/query/grpc/grpc-relation-mapper.d.ts +67 -0
- package/dist/query/grpc/grpc-relation-mapper.js +789 -0
- package/dist/query/pqs/pqs-query-client.d.ts +10 -20
- package/dist/query/pqs/pqs-query-client.js +154 -585
- package/dist/query/pqs/pqs-relational-sql-compiler.d.ts +9 -17
- package/dist/query/pqs/pqs-relational-sql-compiler.js +136 -95
- package/dist/query/pqs/pqs-result-shape.d.ts +25 -0
- package/dist/query/pqs/pqs-result-shape.js +25 -0
- package/dist/query/pqs/pqs-schema-profile.js +49 -48
- package/dist/query/pqs/pqs-sql-compiler.d.ts +18 -3
- package/dist/query/pqs/pqs-sql-compiler.js +337 -288
- package/dist/query/pqs/pqs-sql-syntax.d.ts +2 -0
- package/dist/query/pqs/pqs-sql-syntax.js +6 -0
- package/dist/query/query-client.d.ts +15 -0
- package/dist/services/command/command-service-client.d.ts +9 -4
- package/dist/services/command/command-service-client.js +16 -3
- package/dist/services/command-submission/command-submission-service-client.d.ts +2 -2
- package/dist/services/commands/command-payload-builder.d.ts +2 -2
- package/dist/services/commands/command-payload-builder.js +1 -1
- package/dist/services/commands/command-submission-pipeline.d.ts +5 -4
- package/dist/services/commands/command-submission-pipeline.js +21 -6
- package/dist/testing/runtime/declarative-action-executor.js +3 -3
- package/dist/transports/grpc/grpc-transport.d.ts +4 -4
- package/dist/transports/grpc/grpc-transport.js +3 -3
- package/dist/transports/grpc/mappers/commands-mapper.d.ts +3 -3
- package/dist/transports/grpc/mappers/commands-mapper.js +4 -4
- package/dist/transports/grpc/mappers/interactive-command-mapper.d.ts +3 -3
- package/dist/transports/grpc/mappers/interactive-command-mapper.js +1 -1
- package/dist/transports/json/json-transport.d.ts +2 -2
- package/dist/transports/json/json-transport.js +2 -2
- package/dist/transports/json/mappers/commands-mapper.d.ts +2 -2
- package/dist/transports/json/mappers/commands-mapper.js +2 -2
- package/package.json +4 -3
- package/dist/cjs/query/grpc/grpc-contract-query-client.js +0 -178
- package/dist/query/grpc/grpc-contract-query-client.d.ts +0 -33
- package/dist/query/grpc/grpc-contract-query-client.js +0 -174
package/README.md
CHANGED
|
@@ -132,7 +132,7 @@ npm run example:topology:party-hosting
|
|
|
132
132
|
|
|
133
133
|
### Workflow examples
|
|
134
134
|
|
|
135
|
-
The
|
|
135
|
+
The eight stateful workflow examples are standalone proofs, not a sequence:
|
|
136
136
|
each uploads or verifies the fixture DAR, resolves a party, reads the
|
|
137
137
|
participant status, and creates its own run-scoped data. First make a Canton
|
|
138
138
|
participant available and verify the source with `npm run examples:check`; the
|
|
@@ -149,14 +149,33 @@ npm run example:workflow:command-completion
|
|
|
149
149
|
npm run example:workflow:contract-lifecycle-audit
|
|
150
150
|
npm run example:workflow:update-lookup-reconciliation
|
|
151
151
|
npm run example:workflow:pruning-preflight
|
|
152
|
+
npm run example:workflow:participant-local
|
|
152
153
|
```
|
|
153
154
|
|
|
154
|
-
Those
|
|
155
|
+
Those eight established stateful workflows intentionally leave durable state behind. A missing `SDK_EXAMPLE_PARTY`
|
|
155
156
|
causes fallback party allocation, which creates durable topology state; every
|
|
156
157
|
one also creates durable contracts. Set `SDK_EXAMPLE_PARTY` to an existing
|
|
157
158
|
party to rerun the established workflows against that party and avoid fallback
|
|
158
159
|
allocation. The fixture DAR remains installed after a run.
|
|
159
160
|
|
|
161
|
+
The participant-local command-submission workflow
|
|
162
|
+
(`npm run example:workflow:participant-local`) is a standalone gRPC-only proof
|
|
163
|
+
of the ordinary participant submission authorization route. It uses the normal
|
|
164
|
+
`SDK_EXAMPLE_*` endpoint, authentication, party, and timeout configuration:
|
|
165
|
+
`SDK_EXAMPLE_LEDGER_ENDPOINT`, `SDK_EXAMPLE_LEDGER_ADMIN_ENDPOINT`,
|
|
166
|
+
`SDK_EXAMPLE_PARTICIPANT_ADMIN_ENDPOINT`, `SDK_EXAMPLE_BEARER_TOKEN`,
|
|
167
|
+
`SDK_EXAMPLE_LEDGER_BEARER_TOKEN`, `SDK_EXAMPLE_LEDGER_ADMIN_BEARER_TOKEN`,
|
|
168
|
+
`SDK_EXAMPLE_PARTICIPANT_ADMIN_BEARER_TOKEN`, `SDK_EXAMPLE_PARTY`,
|
|
169
|
+
`SDK_EXAMPLE_PARTY_PREFIX`, `SDK_EXAMPLE_TIMEOUT_MS`, and
|
|
170
|
+
`SDK_EXAMPLE_TLS_ROOT_CERTIFICATE`. It configures a command signer that throws
|
|
171
|
+
if touched, then successfully creates and finds one exact active Message through
|
|
172
|
+
`commandService.submitParticipantLocalAndWaitAsync`; that success proves the
|
|
173
|
+
configured external signer was bypassed. An explicit party is reused, while
|
|
174
|
+
fallback allocation creates durable topology; the fixture upload leaves a
|
|
175
|
+
durable DAR and the proof leaves a durable contract. The unchanged
|
|
176
|
+
implementation uses the common compatibility path on Participant 3.5.7 and
|
|
177
|
+
the isolated Participant 3.5.8 sidecar.
|
|
178
|
+
|
|
160
179
|
The completion-correlation workflow (`npm run example:workflow:command-completion`)
|
|
161
180
|
is a standalone successful proof that creates durable Message state. It uses the
|
|
162
181
|
same normal `SDK_EXAMPLE_*` configuration: `SDK_EXAMPLE_LEDGER_ENDPOINT`,
|
|
@@ -185,16 +204,17 @@ The update-lookup reconciliation workflow (`npm run example:workflow:update-look
|
|
|
185
204
|
|
|
186
205
|
The pruning-preflight workflow (`npm run example:workflow:pruning-preflight`) is a standalone gRPC-only, read-only operator check. It requires `SDK_EXAMPLE_OFFSET` to be a canonical positive decimal integer and uses the normal endpoint, authentication, and timeout variables: `SDK_EXAMPLE_LEDGER_ENDPOINT`, `SDK_EXAMPLE_LEDGER_ADMIN_ENDPOINT`, `SDK_EXAMPLE_PARTICIPANT_ADMIN_ENDPOINT`, `SDK_EXAMPLE_BEARER_TOKEN`, `SDK_EXAMPLE_LEDGER_BEARER_TOKEN`, `SDK_EXAMPLE_LEDGER_ADMIN_BEARER_TOKEN`, `SDK_EXAMPLE_PARTICIPANT_ADMIN_BEARER_TOKEN`, and `SDK_EXAMPLE_TIMEOUT_MS`. The participant-admin credential is required for the schedule and safe-pruning context reads. Its safe-pruning context request sends the saved ledger end and a validated current timestamp encoded in `beforeOrAt`; it leaves commitment-state absent. It does not mutate the participant or create durable state: no party, DAR, command, update query, schedule change, or pruning request is made. The later participant watermark classifies the supplied offset as `alreadyPruned`, `beyondLedgerEnd`, or `notObservedPruned`; all-divulged watermarks and schedule/safe-pruning context are reported separately and do not alter that result. `notObservedPruned` is not proven queryable, because pruning can race after the later observation and other query preconditions can still fail. The unchanged implementation is supported on Participant 3.5.7 and the isolated Participant 3.5.8 sidecar.
|
|
187
206
|
|
|
188
|
-
Each of the
|
|
207
|
+
Each of the eight established stateful workflows prints its actor plus the full participant version returned by the
|
|
189
208
|
authenticated status API, its parsed release core, and its selected path:
|
|
190
209
|
`Participant version:`, `Release core:`, and `Compatibility path:`. The current
|
|
191
210
|
stateful-workflow implementation uses one common-code path for release cores 3.5.7 and 3.5.8. It
|
|
192
211
|
adds a version-specific behavioral difference only after live evidence proves
|
|
193
212
|
one; it does not infer compatibility from a container tag or endpoint.
|
|
194
213
|
|
|
195
|
-
- `example:workflow:atomic` first proves that
|
|
196
|
-
|
|
197
|
-
and
|
|
214
|
+
- `example:workflow:atomic` first proves that a two-command batch with an
|
|
215
|
+
invalid second command is rejected without creating its valid first Message,
|
|
216
|
+
then proves that two independent creates commit atomically and remain active
|
|
217
|
+
with their exact payloads.
|
|
198
218
|
- `example:workflow:retry` submits a caller-controlled command ID with a
|
|
199
219
|
deduplication duration, retries the exact same request, classifies the
|
|
200
220
|
duplicate outcome, and proves that exactly one matching contract is active.
|
|
@@ -212,7 +232,7 @@ request and is not a retry proof. The resume example treats the saved offset as
|
|
|
212
232
|
exclusive, so its resumed stream must observe only updates after the saved
|
|
213
233
|
ledger end.
|
|
214
234
|
|
|
215
|
-
The
|
|
235
|
+
The eight established stateful workflow sources and unit contracts were developed
|
|
216
236
|
and live-tested against authenticated Participant 3.5.7 and the isolated
|
|
217
237
|
Participant 3.5.8. Both final-tree matrices selected the same unchanged implementation and common
|
|
218
238
|
compatibility path. The normalized outcome comparison is identical: atomic
|
|
@@ -220,7 +240,7 @@ reports `invalidChoice` before its replacement proof, retry reports
|
|
|
220
240
|
`duplicateCommand` with one active contract, resume reports `idle-timeout` and
|
|
221
241
|
a post-offset update, and stale-contract reports `staleContract`.
|
|
222
242
|
|
|
223
|
-
For those
|
|
243
|
+
For those eight established stateful workflows, the best multi-version path reads the authenticated full version, parses its
|
|
224
244
|
release core, and uses data-only structured compatibility for observed
|
|
225
245
|
outcomes. A behavioral difference is introduced only after live proof; it is
|
|
226
246
|
never inferred from a container tag, endpoint, or prose error message. For the
|
|
@@ -682,53 +702,103 @@ signature format and algorithm. This convenience operation is gRPC-only.
|
|
|
682
702
|
|
|
683
703
|
## Canton Manager queries
|
|
684
704
|
|
|
685
|
-
`CantonManager` keeps gRPC as the write path and selects
|
|
686
|
-
at initialization.
|
|
687
|
-
|
|
705
|
+
`CantonManager` keeps gRPC as the write path and selects one typed-query source
|
|
706
|
+
at initialization. The same typed query function works with either gRPC or
|
|
707
|
+
PQS; source selection changes how the data is read, not the query grammar.
|
|
688
708
|
|
|
689
709
|
```ts
|
|
690
710
|
import {
|
|
711
|
+
CantonClientOptions,
|
|
691
712
|
CantonManager,
|
|
713
|
+
CreateCommand,
|
|
714
|
+
DamlRecord,
|
|
692
715
|
MemoryQueryCache,
|
|
693
716
|
QuerySource,
|
|
717
|
+
SubmitCommandsRequest,
|
|
694
718
|
TransportKind,
|
|
695
719
|
} from "@distrohelena/canton-typescript-sdk";
|
|
696
720
|
|
|
697
|
-
const
|
|
698
|
-
grpc: {
|
|
699
|
-
|
|
721
|
+
const options = {
|
|
722
|
+
grpc: new CantonClientOptions({
|
|
723
|
+
transportKind: TransportKind.grpc,
|
|
724
|
+
ledgerEndpoint: "localhost:6865",
|
|
725
|
+
}),
|
|
700
726
|
pqs: { connectionString: process.env.PQS_URL!, schema: "public" },
|
|
701
727
|
cache: { store: new MemoryQueryCache(), ttlMs: 5_000 },
|
|
702
|
-
}
|
|
728
|
+
};
|
|
703
729
|
|
|
704
|
-
const
|
|
705
|
-
where: { templateId: { equals: "
|
|
730
|
+
const readIous = (manager: CantonManager) => manager.query.contracts.findMany({
|
|
731
|
+
where: { templateId: { moduleName: { equals: "Main" }, entityName: { equals: "Iou" } } },
|
|
732
|
+
orderBy: [{ createdAt: "desc" }],
|
|
706
733
|
take: 50,
|
|
707
734
|
});
|
|
708
735
|
|
|
709
|
-
|
|
710
|
-
|
|
736
|
+
const pqsManager = new CantonManager({ ...options, querySource: QuerySource.pqs });
|
|
737
|
+
const grpcManager = new CantonManager({ ...options, querySource: QuerySource.grpc });
|
|
738
|
+
const pqsContracts = await readIous(pqsManager);
|
|
739
|
+
const grpcContracts = await readIous(grpcManager);
|
|
740
|
+
|
|
741
|
+
// gRPC caching is explicit and point-in-time; ordinary reads never populate it.
|
|
742
|
+
await grpcManager.query.cacheContracts({ parties: ["Alice"] });
|
|
743
|
+
await grpcManager.query.invalidateContractsCache({ parties: ["Alice"] });
|
|
744
|
+
|
|
745
|
+
// A SubmitCommandsRequest contains a non-empty ordered atomic command batch:
|
|
746
|
+
// all commands commit together, or none of them do.
|
|
747
|
+
await grpcManager.grpc.commandService.submitAndWaitAsync(
|
|
748
|
+
new SubmitCommandsRequest({
|
|
749
|
+
applicationId: "example-app",
|
|
750
|
+
actAs: ["Alice"],
|
|
751
|
+
commands: [
|
|
752
|
+
new CreateCommand({
|
|
753
|
+
templateId: { packageId: "", moduleName: "Main", entityName: "Message" },
|
|
754
|
+
createArguments: new DamlRecord({ author: "Alice", body: "Hello" }),
|
|
755
|
+
}),
|
|
756
|
+
],
|
|
757
|
+
}),
|
|
758
|
+
);
|
|
759
|
+
await Promise.all([pqsManager.disposeAsync(), grpcManager.disposeAsync()]);
|
|
711
760
|
```
|
|
712
761
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
762
|
+
To migrate a prior singleton submission, pass `commands: [previousCommand]`.
|
|
763
|
+
There is no compatibility alias; put multiple independent commands in that
|
|
764
|
+
array in their required atomic order.
|
|
765
|
+
|
|
766
|
+
An options object may contain both `grpc` and `pqs`; the PQS setting is used
|
|
767
|
+
only when `querySource` is `pqs`. Both sources expose `contracts`,
|
|
768
|
+
`contractTypes`, `events`, `exercises`, `exerciseTypes`, `packages`,
|
|
769
|
+
`transactions`, and `watermark`, including filters, includes, ordering,
|
|
770
|
+
pagination, projections, grouping, and aggregates. Literal parity requires
|
|
771
|
+
PQS and gRPC to observe the same participant-visible data; independently
|
|
772
|
+
configured participants can legitimately see different contracts.
|
|
773
|
+
|
|
774
|
+
`cacheContracts` is a gRPC-only explicit prewarm of active contracts for one
|
|
775
|
+
party scope. It needs a cache store and a positive TTL; reads may use a valid
|
|
776
|
+
entry but never renew it. A cached gRPC result is internally consistent at its
|
|
777
|
+
`activeAtOffset`, so it can be stale until expiry, refresh, or
|
|
778
|
+
`invalidateContractsCache`. Under PQS the same lifecycle calls are safe no-ops
|
|
779
|
+
and `cacheContracts` returns `{ source: QuerySource.pqs, cached: false }`.
|
|
780
|
+
|
|
781
|
+
Typed-query `pk`/`ix` values are canonical and source-independent. Transaction
|
|
782
|
+
and watermark keys are ledger offsets; event, package, contract-type, and
|
|
783
|
+
exercise-type keys are lossless positive-decimal encodings of their stable
|
|
784
|
+
semantic identities. PQS physical keys are retained only for internal joins.
|
|
785
|
+
If pruning has removed history needed by a gRPC typed query, it rejects with
|
|
786
|
+
`QuerySnapshotIncompleteError` rather than returning partial rows, groups, or
|
|
787
|
+
aggregates.
|
|
788
|
+
|
|
789
|
+
Raw SQL is the sole PQS-only query operation: use
|
|
790
|
+
`pqsManager.query.$queryRaw(...)` for one read-only statement with positional
|
|
791
|
+
parameters and a read-only PostgreSQL role. `$queryRaw` on a gRPC manager
|
|
792
|
+
rejects with `QueryCapabilityError`.
|
|
793
|
+
|
|
794
|
+
The typed relation delegates use a Prisma-like surface: `findMany({ where,
|
|
724
795
|
select, orderBy, skip, take })`, `findUnique({ where, select })`, `count`, and
|
|
725
796
|
`aggregate({ count, min, max, sum })`. Filters support `equals`, `in`,
|
|
726
797
|
`{ is: null }`, `{ isNot: null }`, and `{ has: party }` on array fields.
|
|
727
|
-
Ordering accepts one
|
|
798
|
+
Ordering accepts an ordered list of one-field entries, so multi-field ordering
|
|
799
|
+
uses `[{ createdAt: "desc" }, { contractId: "asc" }]`. `exercises` intentionally has no `findUnique`
|
|
728
800
|
because the v1 PQS profile does not declare a stable key. The manager validates
|
|
729
|
-
the selected PQS schema profile before its first query.
|
|
730
|
-
active-contract `findMany`, `findUnique`, and `count` subset is available;
|
|
731
|
-
unsupported query features reject with `QueryCapabilityError`.
|
|
801
|
+
the selected PQS schema profile before its first PQS query.
|
|
732
802
|
|
|
733
803
|
- Ledger endpoint:
|
|
734
804
|
- `versionService.getLedgerApiVersionAsync(...)`: `json`, `grpc`
|
package/dist/cjs/core/types/requests/{submit-command-request.js → submit-commands-request.js}
RENAMED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.SubmitCommandsRequest = void 0;
|
|
4
4
|
const validation_error_js_1 = require("../../errors/validation-error.js");
|
|
5
5
|
const ledgerStringPattern = /^[A-Za-z0-9#:\-_/ ]+$/;
|
|
6
6
|
const canonicalOffsetPattern = /^(0|[1-9][0-9]*)$/;
|
|
7
7
|
const maximumInt64Offset = "9223372036854775807";
|
|
8
|
-
class
|
|
8
|
+
class SubmitCommandsRequest {
|
|
9
9
|
applicationId;
|
|
10
10
|
userId;
|
|
11
11
|
actAs;
|
|
12
12
|
readAs;
|
|
13
|
-
|
|
13
|
+
commands;
|
|
14
14
|
commandId;
|
|
15
15
|
deduplicationPeriod;
|
|
16
16
|
disclosedContracts;
|
|
17
17
|
synchronizerId;
|
|
18
18
|
constructor(init) {
|
|
19
|
-
|
|
19
|
+
const commands = init.commands;
|
|
20
|
+
if (!Array.isArray(commands) || commands.length === 0) {
|
|
21
|
+
throw new validation_error_js_1.ValidationError("submit requests require at least one command");
|
|
22
|
+
}
|
|
23
|
+
else if (init.actAs.length === 0) {
|
|
20
24
|
throw new validation_error_js_1.ValidationError("submit requests require at least one actAs party");
|
|
21
25
|
}
|
|
22
26
|
else if (init.commandId !== undefined &&
|
|
@@ -30,14 +34,14 @@ class SubmitCommandRequest {
|
|
|
30
34
|
this.userId = init.userId;
|
|
31
35
|
this.actAs = init.actAs;
|
|
32
36
|
this.readAs = init.readAs ?? [];
|
|
33
|
-
this.
|
|
37
|
+
this.commands = Object.freeze([...commands]);
|
|
34
38
|
this.commandId = init.commandId;
|
|
35
39
|
this.deduplicationPeriod = deduplicationPeriod;
|
|
36
40
|
this.disclosedContracts = init.disclosedContracts ?? [];
|
|
37
41
|
this.synchronizerId = init.synchronizerId;
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
|
-
exports.
|
|
44
|
+
exports.SubmitCommandsRequest = SubmitCommandsRequest;
|
|
41
45
|
function freezeDeduplicationPeriod(value) {
|
|
42
46
|
if (value === undefined) {
|
|
43
47
|
return undefined;
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.
|
|
5
|
-
exports.
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
8
|
-
exports.EndpointNotConfiguredError = exports.ObjectDisposedError = exports.NotSupportedError = exports.ConflictError = exports.TimeoutError = exports.SigningError = exports.GrpcTransportError = exports.TransportError = exports.AuthorizationError = exports.AuthenticationError = exports.ActiveContractsTraversalError = exports.ValidationError = exports.CantonError = exports.SynchronizerTime = exports.ParticipantNodeStatus = exports.PartyDetails = exports.UploadDarFileResponse = exports.GrantUserRightsResponse = exports.SubmitCommandResponse = exports.TopologyListPartiesResponse = exports.TopologyListVettedPackagesResponse = exports.ListVettedPackagesResponse = exports.ListUsersResponse = exports.ListUserRightsResponse = exports.ListSynchronizerTrustCertificateResponse = exports.ListSynchronizerParametersStateResponse = exports.ListSequencingParametersStateResponse = exports.ListSequencerSynchronizerStateResponse = exports.ListPartyToParticipantResponse = exports.ListPartyToKeyMappingResponse = exports.ListPartyHostingLimitsResponse = exports.ListParticipantSynchronizerPermissionResponse = exports.ListKeyOwnersResponse = exports.ListKnownPartiesResponse = exports.ListKnownPackagesResponse = exports.ListIdentityProviderConfigsResponse = exports.ListDarsResponse = exports.ListPackagesResponse = exports.ListOwnerToKeyMappingResponse = exports.ListNamespaceDelegationResponse = exports.ListMediatorSynchronizerStateResponse = exports.ListLsuSequencerConnectionSuccessorResponse = exports.ListLsuAnnouncementResponse = void 0;
|
|
3
|
+
exports.ExternalPartySignatureFormat = exports.ExternalPartySignature = exports.ExternalPartyOnboardingTransaction = exports.ExternalPartyCryptoKeyFormat = exports.TransportKind = exports.TransportCapability = exports.SignCommandResult = exports.SignCommandRequest = exports.BearerTokenAuthProvider = exports.SynchronizerConnectivityServiceClient = exports.VersionServiceClient = exports.UserManagementServiceClient = exports.UpdateServiceClient = exports.TrafficControlServiceClient = exports.TopologyManagerWriteServiceClient = exports.TopologyManagerReadServiceClient = exports.TopologyAggregationServiceClient = exports.StateServiceClient = exports.ResourceManagementServiceClient = exports.PruningServiceClient = exports.PartyManagementServiceClient = exports.ParticipantStatusServiceClient = exports.ParticipantRepairServiceClient = exports.ParticipantPackageServiceClient = exports.ParticipantPartyManagementServiceClient = exports.ParticipantInspectionServiceClient = exports.PackageServiceClient = exports.PackageManagementServiceClient = exports.IdentityProviderConfigServiceClient = exports.IdentityInitializationServiceClient = exports.HealthServiceClient = exports.EventQueryServiceClient = exports.ContractServiceClient = exports.CommandSubmissionServiceClient = exports.CommandServiceClient = exports.CommandInspectionServiceClient = exports.CommandCompletionServiceClient = exports.ExternalPartyActivationResponse = exports.ExternalPartyActivationRequest = exports.ExternalPartyActivationClient = exports.CantonClientOptions = exports.CantonHashingClient = exports.PqsSchemaProfileError = exports.PqsQueryError = exports.QuerySnapshotIncompleteError = exports.QueryCapabilityError = exports.MemoryQueryCache = exports.QuerySource = exports.CantonManager = exports.CantonClient = void 0;
|
|
4
|
+
exports.PackageReference = exports.PackageMetadataFilter = exports.ActiveContractsTraversalOptions = exports.OperationDeadline = exports.RequestOptions = exports.ReceivedAcsCommitmentState = exports.ReceivedAcsCommitmentPerSynchronizer = exports.ReceivedAcsCommitment = exports.PruningSchedule = exports.ParticipantPruningSchedule = exports.PendingOperationMetadata = exports.PackageStatus = exports.CantonHashPurpose = exports.HashFunction = exports.PackageFormat = exports.OffsetCheckpoint = exports.ObjectMeta = exports.LedgerUser = exports.KnownPackageDetails = exports.IdentityProviderConfig = exports.UserRightKind = exports.EventStreamKind = exports.DamlParty = exports.DamlNumeric = exports.ContractCreated = exports.ContractArchived = exports.CounterParticipantInfo = exports.CommitmentTimeRange = exports.CommitmentInterval = exports.Completion = exports.CommandUpdateSummary = exports.CommandTiming = exports.CommandStatus = exports.CommandState = exports.CommandRequestStatistics = exports.CommandInspectionContract = exports.ConnectedSynchronizerStatus = exports.ConnectedSynchronizer = exports.ConnectedSynchronizerHealth = exports.AdminTopologyQueueStatus = exports.AdminNotInitializedStatus = exports.AdminNotInitializedExternalInputKind = exports.AdminNodeStatus = exports.AdminComponentStatus = exports.AdminComponentHealthKind = exports.SubmissionMode = exports.GrpcChannelSecurity = exports.ExternalPartySigningPublicKey = exports.ExternalPartySigningKeySpec = exports.ExternalPartySigningAlgorithmSpec = void 0;
|
|
5
|
+
exports.TopologyPublicKey = exports.TopologyPartyResult = exports.TopologyPartyParticipantSynchronizerPermission = exports.TopologyPartyParticipant = exports.TopologyMappingResult = exports.TopologyMappingOperation = exports.TopologyMappingCode = exports.TopologyKeyOwnerResult = exports.MultiTopologyTransactionSignature = exports.GeneratedTopologyTransaction = exports.TopologyEncryptionPublicKey = exports.ExternalTopologySignature = exports.TopologyDuration = exports.TopologyBaseResult = exports.TopologyBaseQuery = exports.SynchronizerTrustCertificate = exports.SequencerSynchronizerState = exports.PartyToParticipantParticipant = exports.PartyToParticipantOnboarding = exports.PartyToParticipant = exports.PartyToKeyMapping = exports.PartyHostingLimits = exports.ParticipantSynchronizerPermission = exports.ParticipantSynchronizerLimits = exports.ParticipantPermission = exports.OwnerToKeyMapping = exports.OnboardingRestriction = exports.NamespaceDelegationRestrictionKind = exports.NamespaceDelegationRestriction = exports.NamespaceDelegation = exports.MediatorSynchronizerState = exports.LsuSequencerConnectionSuccessor = exports.LsuSequencerConnection = exports.LsuAnnouncement = exports.DynamicSynchronizerParameters = exports.DynamicSequencingParameters = exports.DecentralizedNamespaceDefinition = exports.AcsCommitmentsCatchUpConfig = exports.WaitCommitmentsSetup = exports.TopologyStateFilter = exports.SynchronizerTimeRange = exports.SlowCounterParticipantSynchronizerConfig = exports.SentAcsCommitmentState = exports.SentAcsCommitmentPerSynchronizer = exports.SentAcsCommitment = exports.SdkCommand = exports.SafeToPruneCommitmentState = exports.ParticipantPackageDescription = exports.ParticipantModuleDescription = exports.ParticipantDarDescription = void 0;
|
|
6
|
+
exports.ListAllRequest = exports.ListPackagesRequest = exports.GetCommandStatusRequest = exports.GetActiveContractsRequest = exports.GetActiveContractsPageRequest = exports.GetDarRequest = exports.GetDarContentsRequest = exports.AssembleSignedTopologyTransactionsRequest = exports.SubmitCommandTransactionResponse = exports.DamlRecord = exports.DamlEnum = exports.DamlVariant = exports.DamlGenMap = exports.DamlTextMap = exports.DamlTimestamp = exports.DamlDate = exports.DamlUnit = exports.DamlContractId = exports.PreparedCommandSubmission = exports.DisclosedContract = exports.AllocatePartyRequest = exports.CreateExternalPartyRequest = exports.PreparedDecentralizedParty = exports.FinalizeDecentralizedPartyRequest = exports.CreateDecentralizedPartyRequest = exports.ExerciseCommand = exports.ExerciseByKeyCommand = exports.CreateCommand = exports.CreateAndExerciseCommand = exports.SignedTopologyTransaction = exports.PreparedTopologyTransaction = exports.VettedPackages = exports.VettedPackage = exports.TrafficControlParameters = exports.TopologyVettedPackages = exports.TopologyVettedPackage = exports.TopologyTransactions = exports.TopologyTransactionItem = exports.TopologyTransactionSignature = exports.TopologyTimeRange = exports.TopologyStoreTemporary = exports.TopologyStoreSynchronizer = exports.TopologyStoreKind = exports.TopologyStoreId = exports.TopologyStoreAuthorized = exports.TopologySigningPublicKey = exports.TopologySigningKeysWithThreshold = exports.TopologySignatureFormat = exports.TopologySignatureDelegation = exports.TopologyForceFlag = void 0;
|
|
7
|
+
exports.ListAllResponse = exports.GetUserResponse = exports.GetPartiesResponse = exports.GetPackageStatusResponse = exports.GetPackageResponse = exports.GetLedgerEndResponse = exports.GetLatestPrunedOffsetsResponse = exports.GetIdentityProviderConfigResponse = exports.GetCommandStatusResponse = exports.GetConnectedSynchronizersResponse = exports.GetActiveContractsPageResponse = exports.GetDarResponse = exports.GetDarContentsResponse = exports.AllocatePartyResponse = exports.UploadDarFileRequest = exports.GrantUserRightsRequest = exports.WaitForPartyHostingRequest = exports.TopologyListPartiesRequest = exports.SubmitCommandsRequest = exports.ListUsersRequest = exports.ListUserRightsRequest = exports.ListKeyOwnersRequest = exports.ListIdentityProviderConfigsRequest = exports.ListDarsRequest = exports.ListKnownPackagesRequest = exports.ListKnownPartiesRequest = exports.TopologyListVettedPackagesRequest = exports.ListSynchronizerTrustCertificateRequest = exports.ListSynchronizerParametersStateRequest = exports.ListSequencingParametersStateRequest = exports.ListSequencerSynchronizerStateRequest = exports.ListPartyToParticipantRequest = exports.ListPartyToKeyMappingRequest = exports.ListVettedPackagesRequest = exports.ListPartyHostingLimitsRequest = exports.ListParticipantSynchronizerPermissionRequest = exports.ListOwnerToKeyMappingRequest = exports.ListNamespaceDelegationRequest = exports.ListMediatorSynchronizerStateRequest = exports.ListLsuSequencerConnectionSuccessorRequest = exports.ListLsuAnnouncementRequest = exports.GetUserRequest = exports.GetPartiesRequest = exports.GetLedgerEndRequest = exports.GetLatestPrunedOffsetsRequest = exports.GetConnectedSynchronizersRequest = exports.GetPackageStatusRequest = exports.GetPackageRequest = exports.GetIdentityProviderConfigRequest = exports.ListDecentralizedNamespaceDefinitionRequest = void 0;
|
|
8
|
+
exports.EndpointNotConfiguredError = exports.ObjectDisposedError = exports.NotSupportedError = exports.ConflictError = exports.TimeoutError = exports.SigningError = exports.GrpcTransportError = exports.TransportError = exports.AuthorizationError = exports.AuthenticationError = exports.ActiveContractsTraversalError = exports.ValidationError = exports.CantonError = exports.SynchronizerTime = exports.ParticipantNodeStatus = exports.PartyDetails = exports.UploadDarFileResponse = exports.GrantUserRightsResponse = exports.SubmitCommandResponse = exports.TopologyListPartiesResponse = exports.TopologyListVettedPackagesResponse = exports.ListVettedPackagesResponse = exports.ListUsersResponse = exports.ListUserRightsResponse = exports.ListSynchronizerTrustCertificateResponse = exports.ListSynchronizerParametersStateResponse = exports.ListSequencingParametersStateResponse = exports.ListSequencerSynchronizerStateResponse = exports.ListPartyToParticipantResponse = exports.ListPartyToKeyMappingResponse = exports.ListPartyHostingLimitsResponse = exports.ListParticipantSynchronizerPermissionResponse = exports.ListKeyOwnersResponse = exports.ListKnownPartiesResponse = exports.ListKnownPackagesResponse = exports.ListIdentityProviderConfigsResponse = exports.ListDarsResponse = exports.ListPackagesResponse = exports.ListOwnerToKeyMappingResponse = exports.ListNamespaceDelegationResponse = exports.ListMediatorSynchronizerStateResponse = exports.ListLsuSequencerConnectionSuccessorResponse = exports.ListLsuAnnouncementResponse = exports.ListDecentralizedNamespaceDefinitionResponse = void 0;
|
|
9
9
|
var canton_client_js_1 = require("./client/canton-client.js");
|
|
10
10
|
Object.defineProperty(exports, "CantonClient", { enumerable: true, get: function () { return canton_client_js_1.CantonClient; } });
|
|
11
11
|
var canton_manager_js_1 = require("./query/canton-manager.js");
|
|
@@ -16,6 +16,8 @@ var memory_query_cache_js_1 = require("./query/cache/memory-query-cache.js");
|
|
|
16
16
|
Object.defineProperty(exports, "MemoryQueryCache", { enumerable: true, get: function () { return memory_query_cache_js_1.MemoryQueryCache; } });
|
|
17
17
|
var query_capability_error_js_1 = require("./query/errors/query-capability-error.js");
|
|
18
18
|
Object.defineProperty(exports, "QueryCapabilityError", { enumerable: true, get: function () { return query_capability_error_js_1.QueryCapabilityError; } });
|
|
19
|
+
var query_snapshot_incomplete_error_js_1 = require("./query/errors/query-snapshot-incomplete-error.js");
|
|
20
|
+
Object.defineProperty(exports, "QuerySnapshotIncompleteError", { enumerable: true, get: function () { return query_snapshot_incomplete_error_js_1.QuerySnapshotIncompleteError; } });
|
|
19
21
|
var pqs_query_error_js_1 = require("./query/errors/pqs-query-error.js");
|
|
20
22
|
Object.defineProperty(exports, "PqsQueryError", { enumerable: true, get: function () { return pqs_query_error_js_1.PqsQueryError; } });
|
|
21
23
|
var pqs_schema_profile_error_js_1 = require("./query/errors/pqs-schema-profile-error.js");
|
|
@@ -458,8 +460,8 @@ var list_user_rights_request_js_1 = require("./core/types/requests/list-user-rig
|
|
|
458
460
|
Object.defineProperty(exports, "ListUserRightsRequest", { enumerable: true, get: function () { return list_user_rights_request_js_1.ListUserRightsRequest; } });
|
|
459
461
|
var list_users_request_js_1 = require("./core/types/requests/list-users-request.js");
|
|
460
462
|
Object.defineProperty(exports, "ListUsersRequest", { enumerable: true, get: function () { return list_users_request_js_1.ListUsersRequest; } });
|
|
461
|
-
var
|
|
462
|
-
Object.defineProperty(exports, "
|
|
463
|
+
var submit_commands_request_js_1 = require("./core/types/requests/submit-commands-request.js");
|
|
464
|
+
Object.defineProperty(exports, "SubmitCommandsRequest", { enumerable: true, get: function () { return submit_commands_request_js_1.SubmitCommandsRequest; } });
|
|
463
465
|
var topology_list_parties_request_js_1 = require("./core/types/requests/topology-list-parties-request.js");
|
|
464
466
|
Object.defineProperty(exports, "TopologyListPartiesRequest", { enumerable: true, get: function () { return topology_list_parties_request_js_1.TopologyListPartiesRequest; } });
|
|
465
467
|
var wait_for_party_hosting_request_js_1 = require("./core/types/requests/wait-for-party-hosting-request.js");
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryQueryEvaluator = void 0;
|
|
4
|
+
const query_dataset_js_1 = require("./query-dataset.js");
|
|
5
|
+
const query_schema_js_1 = require("./query-schema.js");
|
|
6
|
+
/** Reference evaluator for normalized canonical plans; it intentionally has no transport concerns. */
|
|
7
|
+
class InMemoryQueryEvaluator {
|
|
8
|
+
execute(dataset, query) {
|
|
9
|
+
const compiled = (0, query_dataset_js_1.createQueryDataset)(dataset);
|
|
10
|
+
switch (query.kind) {
|
|
11
|
+
case "findMany": return freeze(this.findMany(compiled, query));
|
|
12
|
+
case "findUnique": return freeze(this.findMany(compiled, { kind: "findMany", relation: query.relation, predicate: query.predicate, select: query.select, includes: query.includes, orderBy: [], skip: 0, take: 1, activeOnly: false })[0]);
|
|
13
|
+
case "count": return this.filtered(compiled, query.relation, query.predicate, query.parties, query.activeOnly).length;
|
|
14
|
+
case "aggregate": return freeze(this.aggregate(this.filtered(compiled, query.relation, query.predicate), query));
|
|
15
|
+
case "groupBy": return freeze(this.groupBy(compiled, query));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
findMany(dataset, query) {
|
|
19
|
+
const rows = this.order(this.filtered(dataset, query.relation, query.predicate, query.parties, query.activeOnly), query.orderBy)
|
|
20
|
+
.slice(query.skip, query.take === undefined ? undefined : query.skip + query.take);
|
|
21
|
+
return rows.map((row) => this.shape(dataset, query.relation, row, query.select, query.includes));
|
|
22
|
+
}
|
|
23
|
+
filtered(dataset, relation, predicate, parties, activeOnly = false) {
|
|
24
|
+
return dataset.rows[relation].filter((row) => (!activeOnly || row.active === true)
|
|
25
|
+
&& (parties === undefined || (Array.isArray(row.witnesses) && row.witnesses.some((party) => parties.includes(String(party)))))
|
|
26
|
+
&& (predicate === undefined || this.matches(dataset, relation, row, predicate)));
|
|
27
|
+
}
|
|
28
|
+
matches(dataset, relation, row, predicate) {
|
|
29
|
+
switch (predicate.kind) {
|
|
30
|
+
case "and": return predicate.children.every((child) => this.matches(dataset, relation, row, child));
|
|
31
|
+
case "or": return predicate.children.some((child) => this.matches(dataset, relation, row, child));
|
|
32
|
+
case "not": return !this.matches(dataset, relation, row, predicate.child);
|
|
33
|
+
case "relation": {
|
|
34
|
+
const edge = query_schema_js_1.queryRelationEdges[relation]?.[predicate.edge];
|
|
35
|
+
if (edge === undefined) {
|
|
36
|
+
throw new Error(`Unknown ${relation}.${predicate.edge} edge`);
|
|
37
|
+
}
|
|
38
|
+
const related = this.related(dataset, relation, row, predicate.edge);
|
|
39
|
+
const result = related.map((target) => this.matches(dataset, edge.target, target, predicate.predicate));
|
|
40
|
+
return predicate.quantifier === "one" ? result[0] === true : predicate.quantifier === "some" ? result.some(Boolean) : predicate.quantifier === "none" ? !result.some(Boolean) : result.every(Boolean);
|
|
41
|
+
}
|
|
42
|
+
case "scalar": {
|
|
43
|
+
const actual = at(row, predicate.path);
|
|
44
|
+
const expected = predicate.value;
|
|
45
|
+
switch (predicate.operator) {
|
|
46
|
+
case "equals": return actual !== null && actual !== undefined && expected !== null && expected !== undefined && equal(actual, expected);
|
|
47
|
+
case "in": return actual !== null && actual !== undefined && Array.isArray(expected) && expected.some((candidate) => candidate !== null && candidate !== undefined && equal(actual, candidate));
|
|
48
|
+
case "is": return actual === null || actual === undefined;
|
|
49
|
+
case "isNot": return actual !== null && actual !== undefined;
|
|
50
|
+
case "lt": return compare(actual, expected) < 0;
|
|
51
|
+
case "lte": return compare(actual, expected) <= 0;
|
|
52
|
+
case "gt": return compare(actual, expected) > 0;
|
|
53
|
+
case "gte": return compare(actual, expected) >= 0;
|
|
54
|
+
case "like": return typeof actual === "string" && typeof expected === "string" && sqlLike(actual, expected, false);
|
|
55
|
+
case "ilike": return typeof actual === "string" && typeof expected === "string" && sqlLike(actual, expected, true);
|
|
56
|
+
case "has": return Array.isArray(actual) && actual.some((entry) => equal(entry, expected));
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
related(dataset, relation, row, edge) {
|
|
63
|
+
return [...(0, query_dataset_js_1.relatedQueryRows)(dataset, relation, row, edge)];
|
|
64
|
+
}
|
|
65
|
+
shape(dataset, relation, row, selection, includes) {
|
|
66
|
+
const fields = selection?.fields ?? Object.keys(row);
|
|
67
|
+
const result = Object.fromEntries(fields.filter((field) => Object.hasOwn(row, field)).map((field) => [field, clone(row[field])]));
|
|
68
|
+
for (const projection of selection?.json ?? []) {
|
|
69
|
+
result[projection.name] = project(at(row, [projection.field, ...projection.path]), projection.as);
|
|
70
|
+
}
|
|
71
|
+
for (const include of includes) {
|
|
72
|
+
const targets = this.related(dataset, relation, row, include.edge).filter((target) => include.predicate === undefined || this.matches(dataset, include.relation, target, include.predicate));
|
|
73
|
+
const bounded = this.order(targets, include.orderBy).slice(include.skip, include.take === undefined ? undefined : include.skip + include.take)
|
|
74
|
+
.map((target) => this.shape(dataset, include.relation, target, include.select, include.includes));
|
|
75
|
+
result[include.edge] = include.cardinality === "many" ? bounded : (bounded[0] ?? null);
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
order(rows, orderBy) {
|
|
80
|
+
return rows.map((row, index) => ({ row, index })).sort((left, right) => {
|
|
81
|
+
for (const order of orderBy) {
|
|
82
|
+
const compared = postgresCompare(at(left.row, order.path), at(right.row, order.path), order.direction);
|
|
83
|
+
if (compared !== 0) {
|
|
84
|
+
return compared;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return left.index - right.index;
|
|
88
|
+
}).map(({ row }) => row);
|
|
89
|
+
}
|
|
90
|
+
aggregate(rows, query) {
|
|
91
|
+
const metadata = query_schema_js_1.queryRelationMetadata[query.relation];
|
|
92
|
+
const result = {};
|
|
93
|
+
if (query.aggregates.count) {
|
|
94
|
+
result.count = rows.length;
|
|
95
|
+
}
|
|
96
|
+
for (const operation of ["min", "max", "sum"]) {
|
|
97
|
+
if (query.aggregates[operation].length > 0) {
|
|
98
|
+
for (const field of query.aggregates[operation]) {
|
|
99
|
+
if (!metadata.numericFields.includes(field)) {
|
|
100
|
+
throw new Error(`${field} is not a numeric aggregate field of ${query.relation}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
result[operation] = Object.fromEntries(query.aggregates[operation].map((field) => [field, aggregate(rows.map((row) => at(row, [field])), operation)]));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
groupBy(dataset, query) {
|
|
109
|
+
const groups = new Map();
|
|
110
|
+
for (const row of this.filtered(dataset, query.relation, query.predicate)) {
|
|
111
|
+
const keyVariants = query.by.map((key) => this.groupValues(dataset, query.relation, row, key));
|
|
112
|
+
for (const keys of cartesian(keyVariants)) {
|
|
113
|
+
const identity = JSON.stringify(keys.map(keyIdentity));
|
|
114
|
+
const group = groups.get(identity) ?? { keys, rows: [] };
|
|
115
|
+
group.rows.push(row);
|
|
116
|
+
groups.set(identity, group);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return [...groups.values()].map(({ keys, rows }) => {
|
|
120
|
+
const result = Object.fromEntries(query.by.map((key, index) => [groupName(key), clone(keys[index])]));
|
|
121
|
+
if (query.aggregates.count) {
|
|
122
|
+
result.count = rows.length;
|
|
123
|
+
}
|
|
124
|
+
for (const operation of ["min", "max", "sum"]) {
|
|
125
|
+
for (const field of query.aggregates[operation]) {
|
|
126
|
+
result[`${operation}_${field}`] = aggregate(rows.map((row) => at(row, [field])), operation);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
groupValues(dataset, relation, row, key) {
|
|
133
|
+
if (key.kind === "field") {
|
|
134
|
+
const value = at(row, key.path);
|
|
135
|
+
return Array.isArray(value) ? value : [value];
|
|
136
|
+
}
|
|
137
|
+
else if (key.kind === "json") {
|
|
138
|
+
return [project(at(row, [key.field, ...key.path]), key.as)];
|
|
139
|
+
}
|
|
140
|
+
else if (key.kind !== "bucket") {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
const value = key.path.length === 1 ? at(row, key.path) : this.related(dataset, relation, row, key.path[0])[0] && at(this.related(dataset, relation, row, key.path[0])[0], [key.path[1]]);
|
|
144
|
+
return [bucket(value, key.bucket)];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.InMemoryQueryEvaluator = InMemoryQueryEvaluator;
|
|
148
|
+
function at(value, path) {
|
|
149
|
+
let current = value;
|
|
150
|
+
for (const key of path) {
|
|
151
|
+
if (current === null || current === undefined || typeof current !== "object") {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
current = current[key];
|
|
155
|
+
}
|
|
156
|
+
return current;
|
|
157
|
+
}
|
|
158
|
+
function clone(value) {
|
|
159
|
+
return (0, query_dataset_js_1.immutableQueryValue)(value);
|
|
160
|
+
}
|
|
161
|
+
function freeze(value) {
|
|
162
|
+
if (value === null || typeof value !== "object" || value instanceof Date || value instanceof Uint8Array) {
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
else if (Object.isFrozen(value)) {
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
for (const child of Object.values(value)) {
|
|
169
|
+
freeze(child);
|
|
170
|
+
}
|
|
171
|
+
return Object.freeze(value);
|
|
172
|
+
}
|
|
173
|
+
function equal(left, right) {
|
|
174
|
+
if (left instanceof Date) {
|
|
175
|
+
return left.toISOString() === (right instanceof Date ? right.toISOString() : String(right));
|
|
176
|
+
}
|
|
177
|
+
else if (right instanceof Date) {
|
|
178
|
+
return String(left) === right.toISOString();
|
|
179
|
+
}
|
|
180
|
+
else if (left instanceof Uint8Array || right instanceof Uint8Array) {
|
|
181
|
+
return JSON.stringify(Array.from(left)) === JSON.stringify(Array.from(right));
|
|
182
|
+
}
|
|
183
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
184
|
+
}
|
|
185
|
+
function compare(left, right) {
|
|
186
|
+
if (left === null || left === undefined || right === null || right === undefined) {
|
|
187
|
+
return Number.NaN;
|
|
188
|
+
}
|
|
189
|
+
else if (left instanceof Date || right instanceof Date) {
|
|
190
|
+
const leftTime = left instanceof Date ? left.getTime() : new Date(String(left)).getTime();
|
|
191
|
+
const rightTime = right instanceof Date ? right.getTime() : new Date(String(right)).getTime();
|
|
192
|
+
return !Number.isFinite(leftTime) || !Number.isFinite(rightTime) ? Number.NaN : leftTime < rightTime ? -1 : leftTime > rightTime ? 1 : 0;
|
|
193
|
+
}
|
|
194
|
+
const leftValue = numeric(left) ?? String(left);
|
|
195
|
+
const rightValue = numeric(right) ?? String(right);
|
|
196
|
+
return leftValue < rightValue ? -1 : leftValue > rightValue ? 1 : 0;
|
|
197
|
+
}
|
|
198
|
+
function numeric(value) {
|
|
199
|
+
return typeof value === "string" && /^-?\d+$/.test(value) ? BigInt(value) : typeof value === "number" && Number.isFinite(value) ? BigInt(value) : undefined;
|
|
200
|
+
}
|
|
201
|
+
function postgresCompare(left, right, direction) {
|
|
202
|
+
const leftNull = left === null || left === undefined;
|
|
203
|
+
const rightNull = right === null || right === undefined;
|
|
204
|
+
if (leftNull || rightNull) {
|
|
205
|
+
if (leftNull && rightNull) {
|
|
206
|
+
return 0;
|
|
207
|
+
}
|
|
208
|
+
return leftNull ? (direction === "asc" ? 1 : -1) : (direction === "asc" ? -1 : 1);
|
|
209
|
+
}
|
|
210
|
+
const result = compare(left, right);
|
|
211
|
+
return direction === "asc" ? result : -result;
|
|
212
|
+
}
|
|
213
|
+
function sqlLike(value, pattern, insensitive) {
|
|
214
|
+
let expression = "^";
|
|
215
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
216
|
+
const character = pattern[index];
|
|
217
|
+
if (character === "\\" && index + 1 < pattern.length) {
|
|
218
|
+
expression += escapeRegex(pattern[++index]);
|
|
219
|
+
}
|
|
220
|
+
else if (character === "%") {
|
|
221
|
+
expression += ".*";
|
|
222
|
+
}
|
|
223
|
+
else if (character === "_") {
|
|
224
|
+
expression += ".";
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
expression += escapeRegex(character);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return new RegExp(`${expression}$`, insensitive ? "isu" : "su").test(value);
|
|
231
|
+
}
|
|
232
|
+
function escapeRegex(value) {
|
|
233
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
234
|
+
}
|
|
235
|
+
function project(value, as) {
|
|
236
|
+
if (value === null || value === undefined) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
else if (as === "boolean") {
|
|
240
|
+
return value === true || value === "true";
|
|
241
|
+
}
|
|
242
|
+
else if (as === "timestamp") {
|
|
243
|
+
return (0, query_dataset_js_1.immutableQueryValue)(value instanceof Date ? value : new Date(String(value)));
|
|
244
|
+
}
|
|
245
|
+
return String(value);
|
|
246
|
+
}
|
|
247
|
+
function aggregate(values, operation) {
|
|
248
|
+
const present = values.filter((value) => value !== null && value !== undefined);
|
|
249
|
+
if (present.length === 0) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
const numbers = present.map((value) => BigInt(String(value)));
|
|
253
|
+
if (operation === "sum") {
|
|
254
|
+
return numbers.reduce((total, value) => total + value, 0n).toString();
|
|
255
|
+
}
|
|
256
|
+
return numbers.reduce((winner, value) => operation === "min" ? value < winner ? value : winner : value > winner ? value : winner).toString();
|
|
257
|
+
}
|
|
258
|
+
function cartesian(parts) {
|
|
259
|
+
return parts.reduce((all, part) => all.flatMap((prefix) => part.map((value) => [...prefix, value])), [[]]);
|
|
260
|
+
}
|
|
261
|
+
function keyIdentity(value) {
|
|
262
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
263
|
+
}
|
|
264
|
+
function groupName(key) {
|
|
265
|
+
return key.kind === "field" ? key.path.join("_") : key.kind === "json" ? key.name : key.path.join("_") + "_" + key.bucket;
|
|
266
|
+
}
|
|
267
|
+
function bucket(value, unit) {
|
|
268
|
+
if (value === null || value === undefined) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const date = value instanceof Date ? new Date(value.getTime()) : new Date(String(value));
|
|
272
|
+
if (Number.isNaN(date.getTime())) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
else if (unit === "hour") {
|
|
276
|
+
date.setUTCMinutes(0, 0, 0);
|
|
277
|
+
}
|
|
278
|
+
else if (unit === "day") {
|
|
279
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
280
|
+
}
|
|
281
|
+
else if (unit === "month") {
|
|
282
|
+
date.setUTCDate(1);
|
|
283
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const day = date.getUTCDay() || 7;
|
|
287
|
+
date.setUTCDate(date.getUTCDate() - day + 1);
|
|
288
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
289
|
+
}
|
|
290
|
+
return date;
|
|
291
|
+
}
|