@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
|
@@ -1,141 +1,172 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.compilePqsRelationFindMany = compilePqsRelationFindMany;
|
|
4
|
+
exports.compilePqsRelationCount = compilePqsRelationCount;
|
|
5
|
+
exports.compilePqsRelationAggregate = compilePqsRelationAggregate;
|
|
4
6
|
exports.compilePqsRelationGroupBy = compilePqsRelationGroupBy;
|
|
5
7
|
const pqs_schema_profile_js_1 = require("./pqs-schema-profile.js");
|
|
6
8
|
const pqs_schema_profile_js_2 = require("./pqs-schema-profile.js");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
const pqs_sql_compiler_js_1 = require("./pqs-sql-compiler.js");
|
|
10
|
+
const pqs_sql_syntax_js_1 = require("./pqs-sql-syntax.js");
|
|
11
|
+
const pqs_result_shape_js_1 = require("./pqs-result-shape.js");
|
|
12
|
+
function compilePqsRelationFindMany(relation, query, profile) {
|
|
13
|
+
assertCanonicalPhysicalFindMany(relation, query);
|
|
9
14
|
const metadata = pqs_schema_profile_js_1.pqsRelationMetadata[relation];
|
|
15
|
+
const source = logicalTypeRootSource(relation, profile);
|
|
10
16
|
const values = [];
|
|
11
17
|
const add = (value) => {
|
|
12
18
|
values.push(value);
|
|
13
19
|
return `$${values.length}`;
|
|
14
20
|
};
|
|
15
|
-
const fields =
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
21
|
+
const fields = selectedCanonicalFields(relation, metadata, query.select?.fields, (query.select?.json.length ?? 0) > 0);
|
|
22
|
+
const predicate = query.predicate === undefined ? "" : (0, pqs_sql_compiler_js_1.compileCanonicalPhysicalPredicate)(relation, query.predicate, "", profile, add);
|
|
23
|
+
const where = predicate.length === 0 ? "" : ` where ${predicate}`;
|
|
24
|
+
const orderBy = compileCanonicalOrderBy(relation, metadata, query.orderBy, profile);
|
|
25
|
+
const limit = query.take === undefined ? "" : ` limit ${add(query.take)}`;
|
|
26
|
+
const offset = query.skip === 0 ? "" : ` offset ${add(query.skip)}`;
|
|
27
|
+
const included = (0, pqs_sql_compiler_js_1.compileCanonicalPhysicalIncludes)(relation, source.reference, query.includes, profile, add);
|
|
28
|
+
const json = compileCanonicalJsonSelections(relation, query.select, profile, add);
|
|
29
|
+
const shape = (0, pqs_result_shape_js_1.compilePqsResultShape)(relation, "many", query.select, query.includes);
|
|
20
30
|
return {
|
|
21
|
-
text:
|
|
31
|
+
text: `${source.withClause}select ${[...fields.map(([field]) => `${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, field, "", profile)} as "${field}"`), ...json, ...included.map((include) => include.selection)].join(", ")} from ${source.relation}${where}${orderBy}${limit}${offset}`,
|
|
22
32
|
values,
|
|
33
|
+
resultShape: shape,
|
|
23
34
|
};
|
|
24
35
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
36
|
+
function compilePqsRelationCount(relation, query, profile) {
|
|
37
|
+
assertCanonicalPhysicalQuery(relation, query, "count");
|
|
38
|
+
const source = logicalTypeRootSource(relation, profile);
|
|
39
|
+
const values = [];
|
|
40
|
+
const add = (value) => {
|
|
41
|
+
values.push(value);
|
|
42
|
+
return `$${values.length}`;
|
|
43
|
+
};
|
|
44
|
+
const predicate = query.predicate === undefined ? "" : ` where ${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalPredicate)(relation, query.predicate, "", profile, add)}`;
|
|
45
|
+
return { text: `${source.withClause}select count(*)::text as count from ${source.relation}${predicate}`, values };
|
|
46
|
+
}
|
|
47
|
+
function compilePqsRelationAggregate(relation, query, profile) {
|
|
48
|
+
assertCanonicalPhysicalQuery(relation, query, "aggregate");
|
|
49
|
+
const metadata = pqs_schema_profile_js_1.pqsRelationMetadata[relation];
|
|
50
|
+
const source = logicalTypeRootSource(relation, profile);
|
|
51
|
+
const values = [];
|
|
52
|
+
const add = (value) => {
|
|
53
|
+
values.push(value);
|
|
54
|
+
return `$${values.length}`;
|
|
55
|
+
};
|
|
56
|
+
const selected = [];
|
|
57
|
+
if (query.aggregates.count)
|
|
58
|
+
selected.push("count(*)::text as count");
|
|
59
|
+
for (const [operation, fields] of [["min", query.aggregates.min], ["max", query.aggregates.max], ["sum", query.aggregates.sum]]) {
|
|
60
|
+
for (const name of fields) {
|
|
61
|
+
if (!metadata.numericFields.includes(name))
|
|
62
|
+
throw new Error(`${name} is not a numeric aggregate field of ${relation}`);
|
|
63
|
+
selected.push(`${operation}(${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, name, "", profile)})::text as "${operation}_${name}"`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (selected.length === 0)
|
|
67
|
+
throw new Error("aggregate must request at least one result");
|
|
68
|
+
const predicate = query.predicate === undefined ? "" : ` where ${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalPredicate)(relation, query.predicate, "", profile, add)}`;
|
|
69
|
+
return { text: `${source.withClause}select ${selected.join(", ")} from ${source.relation}${predicate}`, values };
|
|
70
|
+
}
|
|
71
|
+
function compilePqsRelationGroupBy(relation, query, profile) {
|
|
72
|
+
assertCanonicalPhysicalQuery(relation, query, "groupBy");
|
|
73
|
+
if (query.by.length === 0 || (!query.aggregates.count && query.aggregates.min.length === 0 && query.aggregates.max.length === 0 && query.aggregates.sum.length === 0))
|
|
27
74
|
throw new Error("groupBy requires a key and aggregate");
|
|
28
75
|
const metadata = pqs_schema_profile_js_1.pqsRelationMetadata[relation];
|
|
76
|
+
const source = logicalTypeRootSource(relation, profile);
|
|
29
77
|
const root = relation === "__events" ? "event" : "root";
|
|
30
78
|
const joins = [];
|
|
31
79
|
const expressions = [];
|
|
32
80
|
const selected = [];
|
|
33
81
|
const values = [];
|
|
34
|
-
const add = (value) => { values.push(value); return `$${
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
82
|
+
const add = (value) => { values.push(value); return `$${values.length}`; };
|
|
83
|
+
const predicate = query.predicate === undefined ? "" : ` where ${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalPredicate)(relation, query.predicate, `"${root}"`, profile, add)}`;
|
|
84
|
+
for (const key of query.by) {
|
|
85
|
+
if (key.kind === "field") {
|
|
86
|
+
const fieldName = key.path[0];
|
|
87
|
+
const column = field(relation, metadata, fieldName);
|
|
88
|
+
const expression = metadata.arrayFields.includes(fieldName)
|
|
89
|
+
? `"${fieldName}".value`
|
|
90
|
+
: (0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, fieldName, `"${root}"`, profile);
|
|
91
|
+
if (metadata.arrayFields.includes(fieldName))
|
|
92
|
+
joins.push(`cross join lateral unnest("${root}"."${column}") as "${fieldName}"(value)`);
|
|
43
93
|
expressions.push(expression);
|
|
44
|
-
selected.push(`${expression} as "${
|
|
94
|
+
selected.push(`${expression} as "${fieldName}"`);
|
|
45
95
|
continue;
|
|
46
96
|
}
|
|
47
|
-
if (key ===
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const projection = nested;
|
|
52
|
-
if (typeof projection.name !== "string" || !Array.isArray(projection.path) || !projection.path.every((segment) => typeof segment === "string" && segment.length > 0) || !["text", "numeric", "boolean", "timestamp"].includes(String(projection.as)) || !pqs_schema_profile_js_1.PqsSchemaProfileV1.jsonField(relation, edgeName))
|
|
53
|
-
throw new Error("invalid profiled JSON group key");
|
|
54
|
-
const column = field(relation, metadata, edgeName);
|
|
55
|
-
const text = `"${root}"."${column}" #>> ${add(projection.path)}::text[]`;
|
|
56
|
-
const expression = projection.as === "text" ? text : projection.as === "numeric" ? `(${text})::numeric` : projection.as === "boolean" ? `(${text})::boolean` : `(${text})::timestamptz`;
|
|
97
|
+
if (key.kind === "json") {
|
|
98
|
+
field(relation, metadata, key.field);
|
|
99
|
+
const text = `${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, key.field, `"${root}"`, profile)} #>> ${add(key.path)}::text[]`;
|
|
100
|
+
const expression = key.as === "text" ? text : key.as === "numeric" ? `(${text})::numeric` : key.as === "boolean" ? `(${text})::boolean` : `(${text})::timestamptz`;
|
|
57
101
|
expressions.push(expression);
|
|
58
|
-
selected.push(`${expression} as
|
|
102
|
+
selected.push(`${expression} as ${(0, pqs_sql_syntax_js_1.quotePqsIdentifier)(key.name)}`);
|
|
59
103
|
continue;
|
|
60
104
|
}
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
throw new Error("invalid profiled time bucket");
|
|
65
|
-
const column = field(relation, metadata, edgeName);
|
|
66
|
-
const expression = `date_trunc('${bucket}', "${root}"."${column}")`;
|
|
105
|
+
if (key.kind === "bucket" && key.path.length === 1) {
|
|
106
|
+
field(relation, metadata, key.path[0]);
|
|
107
|
+
const expression = `date_trunc('${key.bucket}', ${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, key.path[0], `"${root}"`, profile)})`;
|
|
67
108
|
expressions.push(expression);
|
|
68
|
-
selected.push(`${expression} as "${
|
|
109
|
+
selected.push(`${expression} as "${key.path[0]}_${key.bucket}"`);
|
|
69
110
|
continue;
|
|
70
111
|
}
|
|
112
|
+
const edgeName = key.path[0];
|
|
113
|
+
const fieldName = key.path[1];
|
|
71
114
|
const edge = pqs_schema_profile_js_2.pqsRelationEdges[relation]?.[edgeName];
|
|
72
|
-
if (edge === undefined || edge.cardinality !== "one"
|
|
115
|
+
if (edge === undefined || edge.cardinality !== "one")
|
|
73
116
|
throw new Error("group key must follow a profiled to-one edge");
|
|
74
|
-
|
|
75
|
-
const bucket = bucketValue !== null && typeof bucketValue === "object" ? bucketValue.bucket : undefined;
|
|
76
|
-
if (typeof bucket !== "string" || !["hour", "day", "week", "month"].includes(bucket) || !pqs_schema_profile_js_1.PqsSchemaProfileV1.bucketField(edge.target, fieldName))
|
|
77
|
-
throw new Error("invalid profiled time bucket");
|
|
78
|
-
const targetColumn = field(edge.target, pqs_schema_profile_js_1.pqsRelationMetadata[edge.target], fieldName);
|
|
117
|
+
field(edge.target, pqs_schema_profile_js_1.pqsRelationMetadata[edge.target], fieldName);
|
|
79
118
|
joins.push(`join ${profile.relation(edge.target)} "${edgeName}" on "${edgeName}"."${edge.targetColumn}" = "${root}"."${edge.sourceColumn}"`);
|
|
80
|
-
const expression = `date_trunc('${bucket}',
|
|
119
|
+
const expression = `date_trunc('${key.bucket}', ${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(edge.target, fieldName, `"${edgeName}"`, profile)})`;
|
|
81
120
|
expressions.push(expression);
|
|
82
|
-
selected.push(`${expression} as "${edgeName}_${fieldName}_${bucket}"`);
|
|
121
|
+
selected.push(`${expression} as "${edgeName}_${fieldName}_${key.bucket}"`);
|
|
83
122
|
}
|
|
84
|
-
if (
|
|
123
|
+
if (query.aggregates.count)
|
|
85
124
|
selected.push("count(*)::text as count");
|
|
86
|
-
for (const [operation, fields] of [["min",
|
|
87
|
-
for (const name of fields
|
|
125
|
+
for (const [operation, fields] of [["min", query.aggregates.min], ["max", query.aggregates.max], ["sum", query.aggregates.sum]])
|
|
126
|
+
for (const name of fields) {
|
|
88
127
|
if (!metadata.numericFields.includes(name))
|
|
89
128
|
throw new Error(`${name} is not a numeric aggregate field of ${relation}`);
|
|
90
|
-
|
|
129
|
+
field(relation, metadata, name);
|
|
130
|
+
selected.push(`${operation}(${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, name, `"${root}"`, profile)})::text as "${operation}_${name}"`);
|
|
91
131
|
}
|
|
92
|
-
return { text:
|
|
132
|
+
return { text: `${source.withClause}select ${selected.join(", ")} from ${source.relation} "${root}"${joins.length === 0 ? "" : ` ${joins.join(" ")}`}${predicate} group by ${expressions.join(", ")}`, values };
|
|
133
|
+
}
|
|
134
|
+
function logicalTypeRootSource(relation, profile) {
|
|
135
|
+
if (relation !== "__contract_tpe" && relation !== "__exercise_tpe") {
|
|
136
|
+
const physical = profile.relation(relation);
|
|
137
|
+
return { withClause: "", relation: physical, reference: physical };
|
|
138
|
+
}
|
|
139
|
+
const publicKey = (0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, "pk", '"physical_type"', profile);
|
|
140
|
+
const logicalRelation = '"logical_type_root"';
|
|
141
|
+
return {
|
|
142
|
+
withClause: `with ${logicalRelation} as (select distinct on (${publicKey}) "physical_type".* from ${profile.relation(relation)} "physical_type" order by ${publicKey}, "physical_type"."pk" asc) `,
|
|
143
|
+
relation: logicalRelation,
|
|
144
|
+
reference: logicalRelation,
|
|
145
|
+
};
|
|
93
146
|
}
|
|
94
|
-
function
|
|
95
|
-
const fields =
|
|
96
|
-
|
|
97
|
-
: Object.entries(select).filter(([, enabled]) => enabled).map(([name]) => [name, field(relation, metadata, name)]);
|
|
98
|
-
if (fields.length === 0)
|
|
147
|
+
function selectedCanonicalFields(relation, metadata, selected, allowEmpty = false) {
|
|
148
|
+
const fields = selected === undefined ? Object.entries(metadata.fields) : selected.map((name) => [name, field(relation, metadata, name)]);
|
|
149
|
+
if (fields.length === 0 && !allowEmpty)
|
|
99
150
|
throw new Error("select must include at least one field");
|
|
100
151
|
return fields;
|
|
101
152
|
}
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
conditions.push(`"${column}" = ${add(operand)}`);
|
|
112
|
-
else if (operator === "in" && Array.isArray(operand))
|
|
113
|
-
conditions.push(operand.length === 0 ? "false" : `"${column}" = any(${add(operand)})`);
|
|
114
|
-
else if (operator === "is" && operand === null)
|
|
115
|
-
conditions.push(`"${column}" is null`);
|
|
116
|
-
else if (operator === "isNot" && operand === null)
|
|
117
|
-
conditions.push(`"${column}" is not null`);
|
|
118
|
-
else if (["lt", "lte", "gt", "gte", "like", "ilike"].includes(operator)) {
|
|
119
|
-
const sql = { lt: "<", lte: "<=", gt: ">", gte: ">=", like: "like", ilike: "ilike" }[operator];
|
|
120
|
-
conditions.push(`"${column}" ${sql} ${add(operand)}`);
|
|
121
|
-
}
|
|
122
|
-
else
|
|
123
|
-
throw new Error(`${operator} is not supported for ${name}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return conditions.length === 0 ? "" : ` where ${conditions.join(" and ")}`;
|
|
153
|
+
function compileCanonicalJsonSelections(relation, selection, profile, add) {
|
|
154
|
+
return (selection?.json ?? []).map((projection) => {
|
|
155
|
+
if (!pqs_schema_profile_js_1.PqsSchemaProfileV1.jsonField(relation, projection.field))
|
|
156
|
+
throw new Error(`${projection.field} is not a JSON field of ${relation}`);
|
|
157
|
+
field(relation, pqs_schema_profile_js_1.pqsRelationMetadata[relation], projection.field);
|
|
158
|
+
const text = `${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, projection.field, "", profile)} #>> ${add(projection.path)}::text[]`;
|
|
159
|
+
const expression = projection.as === "text" ? text : projection.as === "numeric" ? `(${text})::numeric::text` : projection.as === "boolean" ? `(${text})::boolean` : `(${text})::timestamptz`;
|
|
160
|
+
return `${expression} as ${(0, pqs_sql_syntax_js_1.quotePqsIdentifier)(projection.name)}`;
|
|
161
|
+
});
|
|
127
162
|
}
|
|
128
|
-
function
|
|
129
|
-
if (orderBy ===
|
|
163
|
+
function compileCanonicalOrderBy(relation, metadata, orderBy, profile) {
|
|
164
|
+
if (orderBy.length === 0)
|
|
130
165
|
return "";
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const stableKey = metadata.uniqueKeys[0]?.[0];
|
|
136
|
-
if (stableKey !== undefined && !ordered.some(([column]) => column === metadata.fields[stableKey]))
|
|
137
|
-
ordered.push([metadata.fields[stableKey], "asc"]);
|
|
138
|
-
return ` order by ${ordered.map(([column, direction]) => `"${column}" ${direction}`).join(", ")}`;
|
|
166
|
+
return ` order by ${orderBy.map((order) => {
|
|
167
|
+
field(relation, metadata, order.path[0]);
|
|
168
|
+
return `${(0, pqs_sql_compiler_js_1.compileCanonicalPhysicalField)(relation, order.path[0], "", profile)} ${order.direction}`;
|
|
169
|
+
}).join(", ")}`;
|
|
139
170
|
}
|
|
140
171
|
function field(relation, metadata, name) {
|
|
141
172
|
const column = metadata.fields[name];
|
|
@@ -143,8 +174,20 @@ function field(relation, metadata, name) {
|
|
|
143
174
|
throw new Error(`${name} is not a field of ${relation}`);
|
|
144
175
|
return column;
|
|
145
176
|
}
|
|
146
|
-
function
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
177
|
+
function assertCanonicalPhysicalFindMany(relation, query) {
|
|
178
|
+
if (query === null || typeof query !== "object" || query.kind !== "findMany" || !Array.isArray(query.includes) || !Array.isArray(query.orderBy)) {
|
|
179
|
+
throw new Error("compilePqsRelationFindMany requires a canonical findMany query");
|
|
180
|
+
}
|
|
181
|
+
if (relationForCanonical(query.relation) !== relation)
|
|
182
|
+
throw new Error(`Canonical relation ${query.relation} does not match ${relation}`);
|
|
183
|
+
}
|
|
184
|
+
function assertCanonicalPhysicalQuery(relation, query, kind) {
|
|
185
|
+
if (query === null || typeof query !== "object" || query.kind !== kind) {
|
|
186
|
+
throw new Error(`compilePqsRelation${kind[0].toUpperCase()}${kind.slice(1)} requires a canonical ${kind} query`);
|
|
187
|
+
}
|
|
188
|
+
if (relationForCanonical(query.relation) !== relation)
|
|
189
|
+
throw new Error(`Canonical relation ${query.relation} does not match ${relation}`);
|
|
190
|
+
}
|
|
191
|
+
function relationForCanonical(relation) {
|
|
192
|
+
return { contracts: "__contracts", contractTypes: "__contract_tpe", events: "__events", exercises: "__exercises", exerciseTypes: "__exercise_tpe", packages: "__packages", transactions: "__transactions", watermark: "__watermark" }[relation];
|
|
150
193
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compilePqsResultShape = compilePqsResultShape;
|
|
4
|
+
const pqs_schema_profile_js_1 = require("./pqs-schema-profile.js");
|
|
5
|
+
function compilePqsResultShape(relation, cardinality, selection, includes) {
|
|
6
|
+
const fields = relation === "__contracts"
|
|
7
|
+
? selection?.fields ?? ["contractId", "templateId", "packageId", "payload", "witnesses", "createdEventOffset", "createdAt", "archivedEventOffset", "archivedAt", "active"]
|
|
8
|
+
: selection?.fields ?? Object.keys(pqs_schema_profile_js_1.pqsRelationMetadata[relation].fields);
|
|
9
|
+
const shape = {
|
|
10
|
+
relation,
|
|
11
|
+
cardinality,
|
|
12
|
+
fields: fields.map((name) => Object.freeze({ name })),
|
|
13
|
+
json: (selection?.json ?? []).map((projection) => Object.freeze({ ...projection, path: Object.freeze([...projection.path]) })),
|
|
14
|
+
includes: includes.map((include) => {
|
|
15
|
+
const edge = pqs_schema_profile_js_1.pqsRelationEdges[relation]?.[include.edge];
|
|
16
|
+
if (edge === undefined || edge.target !== relationForCanonical(include.relation) || edge.cardinality !== include.cardinality)
|
|
17
|
+
throw new Error(`Invalid canonical include ${include.edge}`);
|
|
18
|
+
return Object.freeze({ edge: include.edge, target: edge.target, cardinality: include.cardinality, shape: compilePqsResultShape(edge.target, include.cardinality, include.select, include.includes) });
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
Object.freeze(shape.fields);
|
|
22
|
+
Object.freeze(shape.json);
|
|
23
|
+
Object.freeze(shape.includes);
|
|
24
|
+
return Object.freeze(shape);
|
|
25
|
+
}
|
|
26
|
+
function relationForCanonical(relation) {
|
|
27
|
+
return { contracts: "__contracts", contractTypes: "__contract_tpe", events: "__events", exercises: "__exercises", exerciseTypes: "__exercise_tpe", packages: "__packages", transactions: "__transactions", watermark: "__watermark" }[relation];
|
|
28
|
+
}
|
|
@@ -4,6 +4,7 @@ exports.PqsSchemaProfileV1 = exports.requiredPqsColumns = exports.pqsRelationMet
|
|
|
4
4
|
exports.validatePqsSchemaAsync = validatePqsSchemaAsync;
|
|
5
5
|
exports.assertPqsSchemaIdentifier = assertPqsSchemaIdentifier;
|
|
6
6
|
const pqs_schema_profile_error_js_1 = require("../errors/pqs-schema-profile-error.js");
|
|
7
|
+
const query_schema_js_1 = require("../canonical/query-schema.js");
|
|
7
8
|
const schemaIdentifier = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
8
9
|
exports.requiredPqsRelations = [
|
|
9
10
|
"__contracts",
|
|
@@ -15,56 +16,56 @@ exports.requiredPqsRelations = [
|
|
|
15
16
|
"__transactions",
|
|
16
17
|
"__watermark",
|
|
17
18
|
];
|
|
18
|
-
|
|
19
|
-
__contracts:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
exercises: { target: "__exercises", sourceColumn: "pk", targetColumn: "contract_tpe_pk", cardinality: "many", nullable: false },
|
|
28
|
-
},
|
|
29
|
-
__events: {
|
|
30
|
-
transaction: { target: "__transactions", sourceColumn: "tx_ix", targetColumn: "ix", cardinality: "one", nullable: false },
|
|
31
|
-
exercises: { target: "__exercises", sourceColumn: "pk", targetColumn: "exercise_event_pk", cardinality: "many", nullable: false },
|
|
32
|
-
},
|
|
33
|
-
__exercises: {
|
|
34
|
-
exerciseType: { target: "__exercise_tpe", sourceColumn: "tpe_pk", targetColumn: "pk", cardinality: "one", nullable: false },
|
|
35
|
-
contractType: { target: "__contract_tpe", sourceColumn: "contract_tpe_pk", targetColumn: "pk", cardinality: "one", nullable: false },
|
|
36
|
-
event: { target: "__events", sourceColumn: "exercise_event_pk", targetColumn: "pk", cardinality: "one", nullable: true },
|
|
37
|
-
transaction: { target: "__transactions", sourceColumn: "exercised_at_ix", targetColumn: "ix", cardinality: "one", nullable: true },
|
|
38
|
-
package: { target: "__packages", sourceColumn: "package_pk", targetColumn: "pk", cardinality: "one", nullable: false },
|
|
39
|
-
contract: { target: "__contracts", sourceColumn: "contract_id", targetColumn: "contract_id", cardinality: "one", nullable: false },
|
|
40
|
-
},
|
|
41
|
-
__exercise_tpe: { exercises: { target: "__exercises", sourceColumn: "pk", targetColumn: "tpe_pk", cardinality: "many", nullable: false } },
|
|
42
|
-
__packages: { exercises: { target: "__exercises", sourceColumn: "pk", targetColumn: "package_pk", cardinality: "many", nullable: false } },
|
|
43
|
-
__transactions: {
|
|
44
|
-
events: { target: "__events", sourceColumn: "ix", targetColumn: "tx_ix", cardinality: "many", nullable: false },
|
|
45
|
-
createdContracts: { target: "__contracts", sourceColumn: "ix", targetColumn: "created_at_ix", cardinality: "many", nullable: false },
|
|
46
|
-
archivedContracts: { target: "__contracts", sourceColumn: "ix", targetColumn: "archived_at_ix", cardinality: "many", nullable: false },
|
|
47
|
-
exercises: { target: "__exercises", sourceColumn: "ix", targetColumn: "exercised_at_ix", cardinality: "many", nullable: false },
|
|
48
|
-
},
|
|
19
|
+
const queryRelationByPqsRelation = {
|
|
20
|
+
__contracts: "contracts",
|
|
21
|
+
__contract_tpe: "contractTypes",
|
|
22
|
+
__events: "events",
|
|
23
|
+
__exercises: "exercises",
|
|
24
|
+
__exercise_tpe: "exerciseTypes",
|
|
25
|
+
__packages: "packages",
|
|
26
|
+
__transactions: "transactions",
|
|
27
|
+
__watermark: "watermark",
|
|
49
28
|
};
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
29
|
+
const pqsRelationByQueryRelation = {
|
|
30
|
+
contracts: "__contracts",
|
|
31
|
+
contractTypes: "__contract_tpe",
|
|
32
|
+
events: "__events",
|
|
33
|
+
exercises: "__exercises",
|
|
34
|
+
exerciseTypes: "__exercise_tpe",
|
|
35
|
+
packages: "__packages",
|
|
36
|
+
transactions: "__transactions",
|
|
37
|
+
watermark: "__watermark",
|
|
54
38
|
};
|
|
55
|
-
const
|
|
56
|
-
|
|
39
|
+
const pqsEdgeColumns = {
|
|
40
|
+
__contracts: { contractType: { sourceColumn: "tpe_pk", targetColumn: "pk" }, createdTransaction: { sourceColumn: "created_at_ix", targetColumn: "ix" }, archivedTransaction: { sourceColumn: "archived_at_ix", targetColumn: "ix" }, exercises: { sourceColumn: "contract_id", targetColumn: "contract_id" } },
|
|
41
|
+
__contract_tpe: { contracts: { sourceColumn: "pk", targetColumn: "tpe_pk" }, exercises: { sourceColumn: "pk", targetColumn: "contract_tpe_pk" } },
|
|
42
|
+
__events: { transaction: { sourceColumn: "tx_ix", targetColumn: "ix" }, exercises: { sourceColumn: "pk", targetColumn: "exercise_event_pk" } },
|
|
43
|
+
__exercises: { exerciseType: { sourceColumn: "tpe_pk", targetColumn: "pk" }, contractType: { sourceColumn: "contract_tpe_pk", targetColumn: "pk" }, event: { sourceColumn: "exercise_event_pk", targetColumn: "pk" }, transaction: { sourceColumn: "exercised_at_ix", targetColumn: "ix" }, package: { sourceColumn: "package_pk", targetColumn: "pk" }, contract: { sourceColumn: "contract_id", targetColumn: "contract_id" } },
|
|
44
|
+
__exercise_tpe: { exercises: { sourceColumn: "pk", targetColumn: "tpe_pk" } },
|
|
45
|
+
__packages: { exercises: { sourceColumn: "pk", targetColumn: "package_pk" } },
|
|
46
|
+
__transactions: { events: { sourceColumn: "ix", targetColumn: "tx_ix" }, createdContracts: { sourceColumn: "ix", targetColumn: "created_at_ix" }, archivedContracts: { sourceColumn: "ix", targetColumn: "archived_at_ix" }, exercises: { sourceColumn: "ix", targetColumn: "exercised_at_ix" } },
|
|
57
47
|
};
|
|
58
|
-
exports.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
48
|
+
exports.pqsRelationEdges = Object.fromEntries(exports.requiredPqsRelations.map((relation) => [relation, Object.fromEntries(Object.entries(query_schema_js_1.queryRelationEdges[queryRelationByPqsRelation[relation]] ?? {}).map(([name, edge]) => {
|
|
49
|
+
const columns = pqsEdgeColumns[relation]?.[name];
|
|
50
|
+
if (columns === undefined) {
|
|
51
|
+
throw new Error(`Missing physical PQS edge mapping for ${relation}.${name}`);
|
|
52
|
+
}
|
|
53
|
+
return [name, { target: pqsRelationByQueryRelation[edge.target], ...columns, cardinality: edge.cardinality, nullable: edge.nullable }];
|
|
54
|
+
}))]));
|
|
55
|
+
const pqsFields = {
|
|
56
|
+
__contracts: {},
|
|
57
|
+
__contract_tpe: { pk: "pk", payloadType: "payload_type", aliases: "aliases", packageName: "package_name", moduleName: "module_name", entityName: "entity_name", templateFqn: "template_fqn" },
|
|
58
|
+
__events: { pk: "pk", txIx: "tx_ix", eventId: "event_id", type: "type" },
|
|
59
|
+
__exercises: { tpePk: "tpe_pk", contractTpePk: "contract_tpe_pk", exerciseEventPk: "exercise_event_pk", exercisedAtIx: "exercised_at_ix", contractId: "contract_id", argument: "argument", result: "result", redactionId: "redaction_id", packagePk: "package_pk", controllers: "controllers", lastDescendantNodeId: "last_descendant_node_id", witnesses: "witnesses" },
|
|
60
|
+
__exercise_tpe: { pk: "pk", choice: "choice", consuming: "consuming", aliases: "aliases", packageName: "package_name", moduleName: "module_name", entityName: "entity_name", templateFqn: "template_fqn", choiceFqn: "choice_fqn" },
|
|
61
|
+
__packages: { pk: "pk", name: "name", version: "version", id: "id" },
|
|
62
|
+
__transactions: { ix: "ix", offset: "offset", transactionId: "transaction_id", effectiveAt: "effective_at", workflowId: "workflow_id", domainId: "domain_id", traceContext: "trace_context", externalTransactionHash: "external_transaction_hash", paidTrafficCost: "paid_traffic_cost" },
|
|
63
|
+
__watermark: { singleton: "singleton", ix: "ix", offset: "offset", instanceId: "instance_id" },
|
|
67
64
|
};
|
|
65
|
+
exports.pqsRelationMetadata = Object.fromEntries(exports.requiredPqsRelations.map((relation) => {
|
|
66
|
+
const logical = query_schema_js_1.queryRelationMetadata[queryRelationByPqsRelation[relation]];
|
|
67
|
+
return [relation, { fields: pqsFields[relation], uniqueKeys: logical.uniqueKeys, numericFields: logical.numericFields, arrayFields: logical.arrayFields, dateFields: logical.dateFields, binaryFields: logical.binaryFields, stringFields: logical.stringFields }];
|
|
68
|
+
}));
|
|
68
69
|
exports.requiredPqsColumns = {
|
|
69
70
|
__contracts: [
|
|
70
71
|
"tpe_pk",
|
|
@@ -145,10 +146,10 @@ class PqsSchemaProfileV1 {
|
|
|
145
146
|
return `${quoteIdentifier(this.schema)}.${quoteIdentifier(relation)}`;
|
|
146
147
|
}
|
|
147
148
|
static jsonField(relation, field) {
|
|
148
|
-
return
|
|
149
|
+
return query_schema_js_1.queryRelationMetadata[queryRelationByPqsRelation[relation]].jsonFields.includes(field);
|
|
149
150
|
}
|
|
150
151
|
static bucketField(relation, field) {
|
|
151
|
-
return
|
|
152
|
+
return query_schema_js_1.queryRelationMetadata[queryRelationByPqsRelation[relation]].bucketFields.includes(field);
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
exports.PqsSchemaProfileV1 = PqsSchemaProfileV1;
|