@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
|
@@ -5,36 +5,32 @@ const query_source_js_1 = require("../query-source.js");
|
|
|
5
5
|
const pqs_query_error_js_1 = require("../errors/pqs-query-error.js");
|
|
6
6
|
const pqs_sql_compiler_js_1 = require("./pqs-sql-compiler.js");
|
|
7
7
|
const pqs_relational_sql_compiler_js_1 = require("./pqs-relational-sql-compiler.js");
|
|
8
|
+
const query_normalizer_js_1 = require("../canonical/query-normalizer.js");
|
|
8
9
|
const pqs_schema_profile_js_1 = require("./pqs-schema-profile.js");
|
|
9
10
|
const read_only_sql_js_1 = require("./read-only-sql.js");
|
|
10
|
-
const
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
const queryRelationForPqs = {
|
|
12
|
+
__contracts: "contracts", __contract_tpe: "contractTypes", __events: "events", __exercises: "exercises",
|
|
13
|
+
__exercise_tpe: "exerciseTypes", __packages: "packages", __transactions: "transactions", __watermark: "watermark",
|
|
14
|
+
};
|
|
15
|
+
function normalizedUniqueAsFindMany(query) {
|
|
16
|
+
return {
|
|
17
|
+
kind: "findMany", relation: query.relation, predicate: query.predicate,
|
|
18
|
+
select: query.select, includes: query.includes,
|
|
19
|
+
orderBy: query.relation === "contracts" ? [{ path: ["contractId"], direction: "asc" }] : [],
|
|
20
|
+
skip: 0, take: 1, activeOnly: false,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
22
23
|
class PqsQueryClient {
|
|
23
24
|
executor;
|
|
24
25
|
profile;
|
|
25
26
|
ready;
|
|
26
27
|
source = query_source_js_1.QuerySource.pqs;
|
|
27
28
|
contracts = {
|
|
28
|
-
findMany: (args = {}) => this.findContractsAsync(args),
|
|
29
|
-
findUnique: (args) => this.findContractsAsync(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
take: 1,
|
|
34
|
-
}).then((rows) => rows[0]),
|
|
35
|
-
count: async (args = {}) => (await this.findContractsAsync(args)).length,
|
|
36
|
-
aggregate: async (args) => this.aggregateContractsAsync(args),
|
|
37
|
-
groupBy: async (args) => this.groupContractsAsync(args),
|
|
29
|
+
findMany: async (args = {}) => await this.findContractsAsync((0, query_normalizer_js_1.normalizeFindMany)("contracts", args)),
|
|
30
|
+
findUnique: async (args) => (await this.findContractsAsync(normalizedUniqueAsFindMany((0, query_normalizer_js_1.normalizeFindUnique)("contracts", args))))[0],
|
|
31
|
+
count: async (args = {}) => this.countContractsAsync((0, query_normalizer_js_1.normalizeCount)("contracts", args)),
|
|
32
|
+
aggregate: async (args) => this.aggregateContractsAsync((0, query_normalizer_js_1.normalizeAggregate)("contracts", args)),
|
|
33
|
+
groupBy: async (args) => this.groupContractsAsync((0, query_normalizer_js_1.normalizeGroupBy)("contracts", args)),
|
|
38
34
|
};
|
|
39
35
|
contractTypes = this.createPhysicalDelegate("__contract_tpe");
|
|
40
36
|
events = this.createPhysicalDelegate("__events");
|
|
@@ -58,105 +54,54 @@ class PqsQueryClient {
|
|
|
58
54
|
throw this.wrap("$queryRaw", cause);
|
|
59
55
|
}
|
|
60
56
|
}
|
|
57
|
+
async cacheContracts(_args) {
|
|
58
|
+
return { source: query_source_js_1.QuerySource.pqs, cached: false };
|
|
59
|
+
}
|
|
60
|
+
async invalidateContractsCache(_args) { }
|
|
61
61
|
createPhysicalDelegate(relation, hasUnique = true) {
|
|
62
|
-
const
|
|
63
|
-
const findMany = async (args = {}) => this.readPhysicalAsync(relation, metadata, args);
|
|
62
|
+
const queryRelation = queryRelationForPqs[relation];
|
|
64
63
|
const delegate = {
|
|
65
|
-
findMany,
|
|
66
|
-
count: async (args = {}) =>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
await this.ready;
|
|
70
|
-
const result = await this.executor.query(`select count(*)::text as count from ${this.profile.relation(relation)}${where}`, values);
|
|
71
|
-
return Number(result.rows[0]?.count ?? 0);
|
|
72
|
-
}
|
|
73
|
-
catch (cause) {
|
|
74
|
-
throw this.wrap(`${relation}.count`, cause);
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
aggregate: async (args) => this.aggregatePhysicalAsync(relation, metadata, args),
|
|
78
|
-
groupBy: async (args) => this.groupPhysicalAsync(relation, args),
|
|
64
|
+
findMany: async (args = {}) => this.readPhysicalAsync(relation, (0, query_normalizer_js_1.normalizeFindMany)(queryRelation, args)),
|
|
65
|
+
count: async (args = {}) => this.countPhysicalAsync(relation, (0, query_normalizer_js_1.normalizeCount)(queryRelation, args)),
|
|
66
|
+
aggregate: async (args) => this.aggregatePhysicalAsync(relation, (0, query_normalizer_js_1.normalizeAggregate)(queryRelation, args)),
|
|
67
|
+
groupBy: async (args) => this.groupPhysicalAsync(relation, (0, query_normalizer_js_1.normalizeGroupBy)(queryRelation, args)),
|
|
79
68
|
};
|
|
80
|
-
|
|
81
|
-
return delegate;
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
69
|
+
return hasUnique ? {
|
|
84
70
|
...delegate,
|
|
85
|
-
findUnique: async (args) =>
|
|
86
|
-
|
|
87
|
-
return findMany({
|
|
88
|
-
where: Object.fromEntries(Object.entries(args.where).map(([field, value]) => [field, { equals: value }])),
|
|
89
|
-
select: args.select,
|
|
90
|
-
include: args.include,
|
|
91
|
-
take: 1,
|
|
92
|
-
}).then((rows) => rows[0]);
|
|
93
|
-
},
|
|
94
|
-
};
|
|
71
|
+
findUnique: async (args) => (await this.readPhysicalAsync(relation, normalizedUniqueAsFindMany((0, query_normalizer_js_1.normalizeFindUnique)(queryRelation, args))))[0],
|
|
72
|
+
} : delegate;
|
|
95
73
|
}
|
|
96
|
-
async
|
|
97
|
-
const
|
|
98
|
-
const filter = this.compileWhere(relation, pqs_schema_profile_js_1.pqsRelationMetadata[relation], args.where, undefined, root);
|
|
99
|
-
const compiled = (0, pqs_relational_sql_compiler_js_1.compilePqsRelationGroupBy)(relation, args, this.profile, filter.values.length);
|
|
100
|
-
const text = filter.where.length === 0 ? compiled.text : compiled.text.replace(" group by ", `${filter.where} group by `);
|
|
74
|
+
async readPhysicalAsync(relation, query) {
|
|
75
|
+
const compiled = (0, pqs_relational_sql_compiler_js_1.compilePqsRelationFindMany)(relation, query, this.profile);
|
|
101
76
|
try {
|
|
102
77
|
await this.ready;
|
|
103
|
-
return (await this.executor.query(text,
|
|
78
|
+
return (await this.executor.query(compiled.text, compiled.values)).rows.map((row) => this.mapPhysicalRow(row, compiled.resultShape));
|
|
104
79
|
}
|
|
105
80
|
catch (cause) {
|
|
106
|
-
throw this.wrap(`${relation}.
|
|
81
|
+
throw this.wrap(`${relation}.findMany`, cause);
|
|
107
82
|
}
|
|
108
83
|
}
|
|
109
|
-
async
|
|
110
|
-
this.
|
|
111
|
-
const selected = this.selectedFields(relation, metadata, args.select);
|
|
112
|
-
const { where, values } = this.compileWhere(relation, metadata, args.where);
|
|
113
|
-
const orderBy = this.compileOrderBy(relation, metadata, args.orderBy);
|
|
114
|
-
const parameters = [...values];
|
|
115
|
-
const add = (value) => {
|
|
116
|
-
parameters.push(value);
|
|
117
|
-
return `$${parameters.length}`;
|
|
118
|
-
};
|
|
119
|
-
const limit = args.take === undefined ? "" : ` limit ${add(args.take)}`;
|
|
120
|
-
const offset = args.skip === undefined ? "" : ` offset ${add(args.skip)}`;
|
|
121
|
-
const selection = selected.map(([field, column]) => `"${column}" as "${field}"`).join(", ");
|
|
122
|
-
const includes = this.compileIncludes(relation, args.include, add);
|
|
123
|
-
const json = this.compileJsonSelections(relation, args.select?.json, add);
|
|
124
|
-
const fullSelection = [selection, ...json.selection, ...includes.selection].filter((value) => value.length > 0).join(", ");
|
|
84
|
+
async countPhysicalAsync(relation, query) {
|
|
85
|
+
const compiled = (0, pqs_relational_sql_compiler_js_1.compilePqsRelationCount)(relation, query, this.profile);
|
|
125
86
|
try {
|
|
126
87
|
await this.ready;
|
|
127
|
-
|
|
128
|
-
return result.rows.map((row) => this.mapPhysicalRow(row, metadata, selected, includes.values, json.fields));
|
|
88
|
+
return Number((await this.executor.query(compiled.text, compiled.values)).rows[0]?.count ?? 0);
|
|
129
89
|
}
|
|
130
90
|
catch (cause) {
|
|
131
|
-
throw this.wrap(`${relation}.
|
|
91
|
+
throw this.wrap(`${relation}.count`, cause);
|
|
132
92
|
}
|
|
133
93
|
}
|
|
134
|
-
async aggregatePhysicalAsync(relation,
|
|
135
|
-
const
|
|
136
|
-
const selected = [];
|
|
137
|
-
if (args.count) {
|
|
138
|
-
selected.push("count(*)::text as count");
|
|
139
|
-
}
|
|
140
|
-
for (const [operation, fields] of [["min", args.min], ["max", args.max], ["sum", args.sum]]) {
|
|
141
|
-
for (const field of fields ?? []) {
|
|
142
|
-
this.assertNumericField(relation, metadata, field);
|
|
143
|
-
selected.push(`${operation}("${metadata.fields[field]}")::text as "${operation}_${field}"`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (selected.length === 0) {
|
|
147
|
-
throw new Error("aggregate must request at least one result");
|
|
148
|
-
}
|
|
94
|
+
async aggregatePhysicalAsync(relation, query) {
|
|
95
|
+
const compiled = (0, pqs_relational_sql_compiler_js_1.compilePqsRelationAggregate)(relation, query, this.profile);
|
|
149
96
|
try {
|
|
150
97
|
await this.ready;
|
|
151
|
-
const row = (await this.executor.query(
|
|
98
|
+
const row = (await this.executor.query(compiled.text, compiled.values)).rows[0] ?? {};
|
|
152
99
|
const result = {};
|
|
153
|
-
if (
|
|
100
|
+
if (query.aggregates.count)
|
|
154
101
|
result.count = Number(row.count ?? 0);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (fields !== undefined) {
|
|
102
|
+
for (const [operation, fields] of [["min", query.aggregates.min], ["max", query.aggregates.max], ["sum", query.aggregates.sum]]) {
|
|
103
|
+
if (fields.length > 0)
|
|
158
104
|
result[operation] = Object.fromEntries(fields.map((field) => [field, nullableString(row[`${operation}_${field}`])]));
|
|
159
|
-
}
|
|
160
105
|
}
|
|
161
106
|
return result;
|
|
162
107
|
}
|
|
@@ -164,403 +109,79 @@ class PqsQueryClient {
|
|
|
164
109
|
throw this.wrap(`${relation}.aggregate`, cause);
|
|
165
110
|
}
|
|
166
111
|
}
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return
|
|
172
|
-
});
|
|
173
|
-
if (relation === "__contracts") {
|
|
174
|
-
const where = this.compileLogicalContractWhere(filters, add, parentExpression);
|
|
175
|
-
return { where: where === "true" ? "" : ` where ${where}`, values };
|
|
176
|
-
}
|
|
177
|
-
const compile = (expression) => {
|
|
178
|
-
const conditions = [];
|
|
179
|
-
for (const [field, filter] of Object.entries(expression ?? {})) {
|
|
180
|
-
if (field === "and" || field === "or") {
|
|
181
|
-
if (!Array.isArray(filter))
|
|
182
|
-
throw new Error(`${field} must be an array`);
|
|
183
|
-
conditions.push(filter.length ? `(${filter.map((child) => compile(child)).join(` ${field} `)})` : field === "and" ? "true" : "false");
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
if (field === "not") {
|
|
187
|
-
if (filter === null || Array.isArray(filter) || typeof filter !== "object")
|
|
188
|
-
throw new Error("not must be an expression");
|
|
189
|
-
conditions.push(`not (${compile(filter)})`);
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
const edge = pqs_schema_profile_js_1.pqsRelationEdges[relation]?.[field];
|
|
193
|
-
if (edge !== undefined) {
|
|
194
|
-
if (filter === null || Array.isArray(filter) || typeof filter !== "object")
|
|
195
|
-
throw new Error(`${field} must be a relation filter`);
|
|
196
|
-
const related = filter;
|
|
197
|
-
const alias = `"${field}"`;
|
|
198
|
-
const relatedCondition = (child) => {
|
|
199
|
-
const where = this.compileWhere(edge.target, pqs_schema_profile_js_1.pqsRelationMetadata[edge.target], child, add, alias).where;
|
|
200
|
-
return where.length === 0 ? "true" : where.slice(" where ".length);
|
|
201
|
-
};
|
|
202
|
-
const join = `${alias}."${edge.targetColumn}" = ${parentExpression}."${edge.sourceColumn}"`;
|
|
203
|
-
if (edge.cardinality === "one") {
|
|
204
|
-
if (Object.keys(related).some((name) => ["some", "none", "every"].includes(name)))
|
|
205
|
-
throw new Error(`${field} is a to-one relation`);
|
|
206
|
-
conditions.push(`exists (select 1 from ${this.profile.relation(edge.target)} ${alias} where ${join} and (${relatedCondition(related)}))`);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
const operators = ["some", "none", "every"].filter((name) => related[name] !== undefined);
|
|
210
|
-
if (operators.length !== 1)
|
|
211
|
-
throw new Error(`${field} requires exactly one of some, none, or every`);
|
|
212
|
-
const operator = operators[0];
|
|
213
|
-
const predicate = related[operator];
|
|
214
|
-
const condition = relatedCondition(predicate);
|
|
215
|
-
const subquery = `select 1 from ${this.profile.relation(edge.target)} ${alias} where ${join} and (${condition})`;
|
|
216
|
-
if (operator === "some")
|
|
217
|
-
conditions.push(`exists (${subquery})`);
|
|
218
|
-
else if (operator === "none")
|
|
219
|
-
conditions.push(`not exists (${subquery})`);
|
|
220
|
-
else
|
|
221
|
-
conditions.push(`not exists (select 1 from ${this.profile.relation(edge.target)} ${alias} where ${join} and not (${condition}))`);
|
|
222
|
-
}
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
const column = this.field(relation, metadata, field);
|
|
226
|
-
if (filter === null || Array.isArray(filter) || typeof filter !== "object")
|
|
227
|
-
throw new Error(`${field} must be a filter`);
|
|
228
|
-
const scalar = filter;
|
|
229
|
-
if (pqs_schema_profile_js_1.PqsSchemaProfileV1.jsonField(relation, field) && scalar.path !== undefined) {
|
|
230
|
-
if (scalar.path.length === 0 || scalar.path.some((segment) => segment.length === 0))
|
|
231
|
-
throw new Error(`${field}.path must be a non-empty JSON path`);
|
|
232
|
-
const expression = `"${column}" #>> ${add(scalar.path)}::text[]`;
|
|
233
|
-
if (scalar.is === null)
|
|
234
|
-
conditions.push(`${expression} is null`);
|
|
235
|
-
if (scalar.isNot === null)
|
|
236
|
-
conditions.push(`${expression} is not null`);
|
|
237
|
-
if (scalar.equals !== undefined)
|
|
238
|
-
conditions.push(`${expression} = ${add(scalar.equals)}`);
|
|
239
|
-
if (scalar.in !== undefined)
|
|
240
|
-
conditions.push(scalar.in.length === 0 ? "false" : `${expression} = any(${add(scalar.in)})`);
|
|
241
|
-
for (const [operator, value] of [["lt", scalar.lt], ["lte", scalar.lte], ["gt", scalar.gt], ["gte", scalar.gte], ["like", scalar.like], ["ilike", scalar.ilike]]) {
|
|
242
|
-
if (value !== undefined)
|
|
243
|
-
conditions.push(`${expression} ${operator === "lte" ? "<=" : operator === "gte" ? ">=" : operator} ${add(value)}`);
|
|
244
|
-
}
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
if (scalar.is === null) {
|
|
248
|
-
conditions.push(`"${column}" is null`);
|
|
249
|
-
}
|
|
250
|
-
if (scalar.isNot === null) {
|
|
251
|
-
conditions.push(`"${column}" is not null`);
|
|
252
|
-
}
|
|
253
|
-
if (scalar.equals !== undefined) {
|
|
254
|
-
conditions.push(`"${column}" = ${add(scalar.equals)}`);
|
|
255
|
-
}
|
|
256
|
-
if (scalar.in !== undefined) {
|
|
257
|
-
conditions.push(scalar.in.length === 0 ? "false" : `"${column}" = any(${add(scalar.in)})`);
|
|
258
|
-
}
|
|
259
|
-
if (scalar.has !== undefined) {
|
|
260
|
-
if (!metadata.arrayFields.includes(field)) {
|
|
261
|
-
throw new Error(`${field} is not an array field of ${relation}`);
|
|
262
|
-
}
|
|
263
|
-
conditions.push(`${add(scalar.has)} = any("${column}")`);
|
|
264
|
-
}
|
|
265
|
-
for (const [operator, value] of [["lt", scalar.lt], ["lte", scalar.lte], ["gt", scalar.gt], ["gte", scalar.gte], ["like", scalar.like], ["ilike", scalar.ilike]]) {
|
|
266
|
-
if (value === undefined)
|
|
267
|
-
continue;
|
|
268
|
-
if ((operator === "like" || operator === "ilike") && !metadata.stringFields?.includes(field))
|
|
269
|
-
throw new Error(`${field} does not support ${operator}`);
|
|
270
|
-
if ((operator !== "like" && operator !== "ilike") && !metadata.numericFields.includes(field) && !metadata.dateFields.includes(field) && !metadata.stringFields?.includes(field))
|
|
271
|
-
throw new Error(`${field} does not support ${operator}`);
|
|
272
|
-
conditions.push(`"${column}" ${operator === "lte" ? "<=" : operator === "gte" ? ">=" : operator} ${add(value)}`);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return conditions.length ? conditions.join(" and ") : "true";
|
|
276
|
-
};
|
|
277
|
-
const where = compile(filters);
|
|
278
|
-
return { where: where === "true" ? "" : ` where ${where}`, values };
|
|
279
|
-
}
|
|
280
|
-
compileLogicalContractWhere(filters, add, alias) {
|
|
281
|
-
const compile = (expression) => {
|
|
282
|
-
const conditions = [];
|
|
283
|
-
for (const [field, filter] of Object.entries(expression ?? {})) {
|
|
284
|
-
if (field === "and" || field === "or") {
|
|
285
|
-
if (!Array.isArray(filter))
|
|
286
|
-
throw new Error(`${field} must be an array`);
|
|
287
|
-
conditions.push(filter.length === 0 ? field === "and" ? "true" : "false" : `(${filter.map((child) => compile(child)).join(` ${field} `)})`);
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
if (field === "not") {
|
|
291
|
-
conditions.push(`not (${compile(filter)})`);
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
if (field === "active") {
|
|
295
|
-
const value = typeof filter === "boolean" ? filter : filter.equals;
|
|
296
|
-
if (typeof value !== "boolean")
|
|
297
|
-
throw new Error("active supports only equals");
|
|
298
|
-
conditions.push(`${alias}."archived_at_ix" is ${value ? "null" : "not null"}`);
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
if (field === "witnesses") {
|
|
302
|
-
const value = filter.has;
|
|
303
|
-
if (typeof value !== "string")
|
|
304
|
-
throw new Error("witnesses supports only has");
|
|
305
|
-
conditions.push(`${add(value)} = any(${alias}."witnesses")`);
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
if (field === "payload") {
|
|
309
|
-
const match = filter.match;
|
|
310
|
-
if (match === undefined || typeof match !== "object" || match === null)
|
|
311
|
-
throw new Error("payload requires match");
|
|
312
|
-
for (const [key, value] of Object.entries(match))
|
|
313
|
-
if (value.equals !== undefined)
|
|
314
|
-
conditions.push(`${alias}."payload" #>> ${add([key])}::text[] = ${add(value.equals)}`);
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
const columns = { contractId: "contract_id", packageId: "creation_package_id", createdEventOffset: "created_at_ix", archivedEventOffset: "archived_at_ix" };
|
|
318
|
-
const column = columns[field];
|
|
319
|
-
if (column === undefined || filter === null || typeof filter !== "object")
|
|
320
|
-
throw new Error(`${field} is not a supported contract filter`);
|
|
321
|
-
const value = filter;
|
|
322
|
-
if (value.equals !== undefined)
|
|
323
|
-
conditions.push(`${alias}."${column}" = ${add(value.equals)}`);
|
|
324
|
-
else if (value.in !== undefined)
|
|
325
|
-
conditions.push(value.in.length === 0 ? "false" : `${alias}."${column}" = any(${add(value.in)})`);
|
|
326
|
-
else
|
|
327
|
-
throw new Error(`${field} requires equals or in`);
|
|
328
|
-
}
|
|
329
|
-
return conditions.length === 0 ? "true" : conditions.join(" and ");
|
|
330
|
-
};
|
|
331
|
-
return compile(filters);
|
|
332
|
-
}
|
|
333
|
-
selectedFields(relation, metadata, select) {
|
|
334
|
-
if (select === undefined) {
|
|
335
|
-
return Object.entries(metadata.fields);
|
|
336
|
-
}
|
|
337
|
-
const selected = Object.entries(select).filter(([field, enabled]) => field !== "json" && enabled === true).map(([field]) => [field, this.field(relation, metadata, field)]);
|
|
338
|
-
if (selected.length === 0 && Object.keys(select.json ?? {}).length === 0) {
|
|
339
|
-
throw new Error("select must include at least one field");
|
|
340
|
-
}
|
|
341
|
-
return selected;
|
|
342
|
-
}
|
|
343
|
-
compileOrderBy(relation, metadata, orderBy) {
|
|
344
|
-
if (orderBy === undefined) {
|
|
345
|
-
return "";
|
|
346
|
-
}
|
|
347
|
-
const entries = orderBy.flatMap((entry) => Object.entries(entry));
|
|
348
|
-
if (entries.length === 0 || entries.some(([, direction]) => direction !== "asc" && direction !== "desc")) {
|
|
349
|
-
throw new Error("orderBy must be a non-empty list of one-field entries");
|
|
350
|
-
}
|
|
351
|
-
return ` order by ${entries.map(([field, direction]) => `"${this.field(relation, metadata, field)}" ${direction}`).join(", ")}`;
|
|
352
|
-
}
|
|
353
|
-
assertUniqueWhere(relation, metadata, where) {
|
|
354
|
-
const fields = Object.keys(where).sort();
|
|
355
|
-
const matches = metadata.uniqueKeys.some((key) => [...key].sort().join("\0") === fields.join("\0"));
|
|
356
|
-
if (!matches) {
|
|
357
|
-
throw new Error(`where is not a stable unique key of ${relation}`);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
assertNumericField(relation, metadata, field) {
|
|
361
|
-
if (!metadata.numericFields.includes(field)) {
|
|
362
|
-
throw new Error(`${field} is not a numeric aggregate field of ${relation}`);
|
|
112
|
+
async groupPhysicalAsync(relation, query) {
|
|
113
|
+
const compiled = (0, pqs_relational_sql_compiler_js_1.compilePqsRelationGroupBy)(relation, query, this.profile);
|
|
114
|
+
try {
|
|
115
|
+
await this.ready;
|
|
116
|
+
return (await this.executor.query(compiled.text, compiled.values)).rows.map((row) => Object.fromEntries(Object.entries(row).map(([name, value]) => [name, name === "count" ? Number(value) : value instanceof Date ? value : value === null ? null : String(value)])));
|
|
363
117
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const column = metadata.fields[field];
|
|
367
|
-
if (column === undefined) {
|
|
368
|
-
throw new Error(`${field} is not a field of ${relation}`);
|
|
118
|
+
catch (cause) {
|
|
119
|
+
throw this.wrap(`${relation}.groupBy`, cause);
|
|
369
120
|
}
|
|
370
|
-
return column;
|
|
371
121
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
122
|
+
mapPhysicalRow(row, shape, scalarSource = row) {
|
|
123
|
+
const metadata = pqs_schema_profile_js_1.pqsRelationMetadata[shape.relation];
|
|
124
|
+
const scalar = Object.fromEntries(shape.fields
|
|
125
|
+
.filter(({ name }) => Object.hasOwn(scalarSource, name) || Object.hasOwn(scalarSource, metadata.fields[name] ?? ""))
|
|
126
|
+
.map(({ name }) => [name, mapPhysicalValue(scalarSource[name] ?? scalarSource[metadata.fields[name] ?? ""], shape.relation, metadata, name)]));
|
|
127
|
+
const projected = Object.fromEntries(shape.json.map((projection) => [projection.name, mapJsonValue(row[projection.name], projection.as)]));
|
|
128
|
+
const included = Object.fromEntries(shape.includes.map((include) => [include.edge, this.mapIncludedPhysicalValue(row[include.edge], include)]));
|
|
129
|
+
return { ...scalar, ...projected, ...included };
|
|
130
|
+
}
|
|
131
|
+
mapIncludedPhysicalValue(value, include) {
|
|
132
|
+
if (include.cardinality === "many") {
|
|
133
|
+
if (value === null || value === undefined)
|
|
134
|
+
return [];
|
|
135
|
+
if (!Array.isArray(value))
|
|
136
|
+
throw new Error(`Invalid included ${include.target} rows`);
|
|
137
|
+
return value.map((entry) => this.mapIncludedPhysicalValue(entry, { ...include, cardinality: "one" }));
|
|
377
138
|
}
|
|
378
|
-
}
|
|
379
|
-
mapPhysicalRow(row, metadata, fields, includes, json = {}) {
|
|
380
|
-
const scalar = Object.fromEntries(fields
|
|
381
|
-
.filter(([field]) => Object.hasOwn(row, field))
|
|
382
|
-
.map(([field]) => [field, mapPhysicalValue(row[field], metadata, field)]));
|
|
383
|
-
const related = Object.fromEntries(Object.entries(includes).map(([name, edge]) => [name, this.mapRelatedValue(row[name], edge.target, edge.options)]));
|
|
384
|
-
const projected = Object.fromEntries(Object.entries(json).map(([name, as]) => [name, mapJsonValue(row[name], as)]));
|
|
385
|
-
return { ...scalar, ...projected, ...related };
|
|
386
|
-
}
|
|
387
|
-
mapRelatedValue(value, relation, options) {
|
|
388
139
|
if (value === null || value === undefined)
|
|
389
|
-
return
|
|
390
|
-
if (Array.isArray(value))
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
throw new Error(`Invalid included ${relation} row`);
|
|
394
|
-
if (relation === "__contracts")
|
|
395
|
-
return this.mapLogicalContractValue(value, options);
|
|
396
|
-
const metadata = pqs_schema_profile_js_1.pqsRelationMetadata[relation];
|
|
397
|
-
const row = value;
|
|
398
|
-
const fields = this.selectedFields(relation, metadata, options.select);
|
|
399
|
-
const nested = Object.fromEntries(Object.entries(options.include ?? {}).map(([name, option]) => {
|
|
400
|
-
const edge = pqs_schema_profile_js_1.pqsRelationEdges[relation]?.[name];
|
|
401
|
-
if (edge === undefined)
|
|
402
|
-
throw new Error(`${name} is not a relation of ${relation}`);
|
|
403
|
-
return [name, { target: edge.target, options: option === true ? {} : option }];
|
|
404
|
-
}));
|
|
405
|
-
const json = Object.fromEntries(Object.entries(options.select?.json ?? {}).map(([name, projection]) => [name, projection.as]));
|
|
406
|
-
const normalized = Object.fromEntries(fields
|
|
407
|
-
.filter(([field, column]) => Object.hasOwn(row, field) || Object.hasOwn(row, column))
|
|
408
|
-
.map(([field, column]) => [field, row[field] ?? row[column]]));
|
|
409
|
-
for (const name of Object.keys(nested))
|
|
410
|
-
normalized[name] = row[name];
|
|
411
|
-
for (const name of Object.keys(json))
|
|
412
|
-
normalized[name] = row[name];
|
|
413
|
-
return this.mapPhysicalRow(normalized, metadata, fields, nested, json);
|
|
414
|
-
}
|
|
415
|
-
mapLogicalContractValue(row, options) {
|
|
416
|
-
const fields = options.select === undefined
|
|
417
|
-
? logicalContractFields
|
|
418
|
-
: Object.entries(options.select).filter(([field, enabled]) => field !== "json" && enabled === true).map(([field]) => {
|
|
419
|
-
if (!logicalContractFields.includes(field))
|
|
420
|
-
throw new Error(`${field} is not a field of __contracts`);
|
|
421
|
-
return field;
|
|
422
|
-
});
|
|
423
|
-
const scalar = Object.fromEntries(fields.filter((field) => Object.hasOwn(row, field)).map((field) => [field, row[field]]));
|
|
424
|
-
const relations = Object.fromEntries(Object.entries(options.include ?? {}).map(([name, option]) => {
|
|
425
|
-
const edge = pqs_schema_profile_js_1.pqsRelationEdges.__contracts?.[name];
|
|
426
|
-
if (edge === undefined)
|
|
427
|
-
throw new Error(`${name} is not a relation of __contracts`);
|
|
428
|
-
return [name, this.mapRelatedValue(row[name], edge.target, option === true ? {} : option)];
|
|
429
|
-
}));
|
|
430
|
-
const json = Object.fromEntries(Object.entries(options.select?.json ?? {}).map(([name, projection]) => [name, mapJsonValue(row[name], projection.as)]));
|
|
431
|
-
return { ...scalar, ...json, ...relations };
|
|
432
|
-
}
|
|
433
|
-
compileIncludes(relation, include, add, parentExpression = this.profile.relation(relation)) {
|
|
434
|
-
const selections = [];
|
|
435
|
-
const values = {};
|
|
436
|
-
for (const [name, option] of Object.entries(include ?? {})) {
|
|
437
|
-
const edge = pqs_schema_profile_js_1.pqsRelationEdges[relation]?.[name];
|
|
438
|
-
if (edge === undefined)
|
|
439
|
-
throw new Error(`${name} is not a relation of ${relation}`);
|
|
440
|
-
const options = option === true ? {} : option;
|
|
441
|
-
if (edge.cardinality === "many" && options.take === undefined)
|
|
442
|
-
throw new Error(`${name} is a to-many relation and requires take`);
|
|
443
|
-
if (options.take !== undefined && (!Number.isInteger(options.take) || options.take < 0))
|
|
444
|
-
throw new Error(`${name}.take must be a non-negative integer`);
|
|
445
|
-
const expression = this.compileIncludedExpression(name, edge.target, edge.sourceColumn, edge.targetColumn, edge.cardinality, options, add, parentExpression);
|
|
446
|
-
selections.push(`${expression} as "${name}"`);
|
|
447
|
-
values[name] = { target: edge.target, options };
|
|
448
|
-
}
|
|
449
|
-
return { selection: selections, values };
|
|
450
|
-
}
|
|
451
|
-
compileJsonSelections(relation, selections, add, tableAlias) {
|
|
452
|
-
const selection = [];
|
|
453
|
-
const fields = {};
|
|
454
|
-
for (const [name, projection] of Object.entries(selections ?? {})) {
|
|
455
|
-
if (!pqs_schema_profile_js_1.PqsSchemaProfileV1.jsonField(relation, projection.field))
|
|
456
|
-
throw new Error(`${projection.field} is not a JSON field of ${relation}`);
|
|
457
|
-
if (projection.path.length === 0 || projection.path.some((segment) => segment.length === 0))
|
|
458
|
-
throw new Error(`${name}.path must be a non-empty JSON path`);
|
|
459
|
-
const column = this.field(relation, pqs_schema_profile_js_1.pqsRelationMetadata[relation], projection.field);
|
|
460
|
-
const text = `${tableAlias === undefined ? "" : `${tableAlias}.`}"${column}" #>> ${add(projection.path)}::text[]`;
|
|
461
|
-
const expression = projection.as === "text" ? text : projection.as === "numeric" ? `(${text})::numeric::text` : projection.as === "boolean" ? `(${text})::boolean` : `(${text})::timestamptz`;
|
|
462
|
-
selection.push(`${expression} as "${name}"`);
|
|
463
|
-
fields[name] = projection.as;
|
|
464
|
-
}
|
|
465
|
-
return { selection, fields };
|
|
466
|
-
}
|
|
467
|
-
compileIncludedExpression(name, target, sourceColumn, targetColumn, cardinality, options, add, parentExpression) {
|
|
468
|
-
const alias = `"${name}"`;
|
|
469
|
-
const targetMetadata = pqs_schema_profile_js_1.pqsRelationMetadata[target];
|
|
470
|
-
const fields = target === "__contracts" ? [] : this.selectedFields(target, targetMetadata, options.select);
|
|
471
|
-
const json = target === "__contracts"
|
|
472
|
-
? this.compileLogicalContractJsonSelections(options.select?.json, add, alias)
|
|
473
|
-
: this.compileJsonSelections(target, options.select?.json, add, alias).selection;
|
|
474
|
-
const nested = this.compileIncludes(target, options.include, add, alias).selection;
|
|
475
|
-
const scalarSelections = target === "__contracts"
|
|
476
|
-
? this.compileLogicalContractSelections(alias, options.select)
|
|
477
|
-
: fields.map(([field, column]) => `'${field}', ${alias}."${column}"`);
|
|
478
|
-
const object = `jsonb_build_object(${[...scalarSelections, ...[...json, ...nested].flatMap((selection) => {
|
|
479
|
-
const match = /^(.*) as "([^"]+)"$/.exec(selection);
|
|
480
|
-
return match === null ? [] : [`'${match[2]}', ${match[1]}`];
|
|
481
|
-
})].join(", ")})`;
|
|
482
|
-
const { where } = this.compileWhere(target, targetMetadata, options.where, add, alias);
|
|
483
|
-
const condition = `${alias}."${targetColumn}" = ${parentExpression}."${sourceColumn}"`;
|
|
484
|
-
const childWhere = where.length === 0 ? ` where ${condition}` : `${where} and ${condition}`;
|
|
485
|
-
if (cardinality === "one")
|
|
486
|
-
return `(select ${object} from ${this.profile.relation(target)} ${alias}${childWhere})`;
|
|
487
|
-
const orderBy = this.compileOrderBy(target, targetMetadata, options.orderBy);
|
|
488
|
-
return `(select coalesce(jsonb_agg("${name}_limited".value), '[]'::jsonb) from (select ${object} as value from ${this.profile.relation(target)} ${alias}${childWhere}${orderBy} limit ${add(options.take)}) "${name}_limited")`;
|
|
489
|
-
}
|
|
490
|
-
compileLogicalContractSelections(alias, select) {
|
|
491
|
-
const selected = select === undefined
|
|
492
|
-
? logicalContractFields
|
|
493
|
-
: Object.entries(select).filter(([field, enabled]) => field !== "json" && enabled === true).map(([field]) => field);
|
|
494
|
-
if (selected.length === 0 && Object.keys(select?.json ?? {}).length === 0)
|
|
495
|
-
throw new Error("select must include at least one field");
|
|
496
|
-
const expressions = {
|
|
497
|
-
contractId: `${alias}."contract_id"`,
|
|
498
|
-
templateId: `jsonb_build_object('packageId', ${alias}."creation_package_id", 'moduleName', (select contract_type."module_name" from ${this.profile.relation("__contract_tpe")} contract_type where contract_type."pk" = ${alias}."tpe_pk"), 'entityName', (select contract_type."entity_name" from ${this.profile.relation("__contract_tpe")} contract_type where contract_type."pk" = ${alias}."tpe_pk"))`,
|
|
499
|
-
packageId: `${alias}."creation_package_id"`,
|
|
500
|
-
payload: `${alias}."payload"`,
|
|
501
|
-
witnesses: `${alias}."witnesses"`,
|
|
502
|
-
createdEventOffset: `${alias}."created_at_ix"::text`,
|
|
503
|
-
createdAt: `(select created_transaction."effective_at" from ${this.profile.relation("__transactions")} created_transaction where created_transaction."ix" = ${alias}."created_at_ix")`,
|
|
504
|
-
archivedEventOffset: `${alias}."archived_at_ix"::text`,
|
|
505
|
-
archivedAt: `(select archived_transaction."effective_at" from ${this.profile.relation("__transactions")} archived_transaction where archived_transaction."ix" = ${alias}."archived_at_ix")`,
|
|
506
|
-
active: `${alias}."archived_at_ix" is null`,
|
|
507
|
-
};
|
|
508
|
-
return selected.map((field) => {
|
|
509
|
-
const expression = expressions[field];
|
|
510
|
-
if (expression === undefined)
|
|
511
|
-
throw new Error(`${field} is not a field of __contracts`);
|
|
512
|
-
return `'${field}', ${expression}`;
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
compileLogicalContractJsonSelections(selections, add, alias) {
|
|
516
|
-
return Object.entries(selections ?? {}).map(([name, projection]) => {
|
|
517
|
-
if (projection.field !== "payload")
|
|
518
|
-
throw new Error(`${projection.field} is not a JSON field of __contracts`);
|
|
519
|
-
if (projection.path.length === 0 || projection.path.some((segment) => segment.length === 0))
|
|
520
|
-
throw new Error(`${name}.path must be a non-empty JSON path`);
|
|
521
|
-
const text = `${alias}."payload" #>> ${add(projection.path)}::text[]`;
|
|
522
|
-
const expression = projection.as === "text" ? text : projection.as === "numeric" ? `(${text})::numeric::text` : projection.as === "boolean" ? `(${text})::boolean` : `(${text})::timestamptz`;
|
|
523
|
-
return `${expression} as "${name}"`;
|
|
524
|
-
});
|
|
140
|
+
return null;
|
|
141
|
+
if (typeof value !== "object" || Array.isArray(value))
|
|
142
|
+
throw new Error(`Invalid included ${include.target} row`);
|
|
143
|
+
return this.mapPhysicalRow(value, include.shape);
|
|
525
144
|
}
|
|
526
|
-
async findContractsAsync(
|
|
527
|
-
const compiled = (0, pqs_sql_compiler_js_1.compileContractFindMany)(
|
|
145
|
+
async findContractsAsync(query) {
|
|
146
|
+
const compiled = (0, pqs_sql_compiler_js_1.compileContractFindMany)(query, this.profile);
|
|
528
147
|
try {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const select = "select" in args ? args.select : undefined;
|
|
532
|
-
if (select === undefined) {
|
|
533
|
-
return rows;
|
|
534
|
-
}
|
|
535
|
-
const fields = Object.entries(select).filter(([field, enabled]) => field !== "json" && enabled === true).map(([field]) => field);
|
|
536
|
-
const json = Object.keys(select.json ?? {});
|
|
537
|
-
if (fields.length === 0 && json.length === 0) {
|
|
538
|
-
throw new Error("select must include at least one field");
|
|
539
|
-
}
|
|
540
|
-
return rows.map((row) => Object.fromEntries([...fields.map((field) => [field, row[field]]), ...json.map((field) => [field, row[field]])]));
|
|
148
|
+
await this.ready;
|
|
149
|
+
return (await this.executor.query(compiled.text, compiled.values)).rows.map((row) => this.mapPhysicalRow(contractRootRow(row), compiled.resultShape, contractRootScalars(row)));
|
|
541
150
|
}
|
|
542
151
|
catch (cause) {
|
|
543
152
|
throw this.wrap("contracts.findMany", cause);
|
|
544
153
|
}
|
|
545
154
|
}
|
|
546
|
-
async
|
|
547
|
-
|
|
548
|
-
|
|
155
|
+
async countContractsAsync(query) {
|
|
156
|
+
const compiled = (0, pqs_sql_compiler_js_1.compileContractCount)(query, this.profile);
|
|
157
|
+
try {
|
|
158
|
+
await this.ready;
|
|
159
|
+
return Number((await this.executor.query(compiled.text, compiled.values)).rows[0]?.count ?? 0);
|
|
549
160
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
if (args.count) {
|
|
553
|
-
result.count = rows.length;
|
|
161
|
+
catch (cause) {
|
|
162
|
+
throw this.wrap("contracts.count", cause);
|
|
554
163
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
164
|
+
}
|
|
165
|
+
async aggregateContractsAsync(normalized) {
|
|
166
|
+
const compiled = (0, pqs_sql_compiler_js_1.compileContractAggregate)(normalized, this.profile);
|
|
167
|
+
try {
|
|
168
|
+
await this.ready;
|
|
169
|
+
const row = (await this.executor.query(compiled.text, compiled.values)).rows[0] ?? {};
|
|
170
|
+
const result = {};
|
|
171
|
+
if (normalized.aggregates.count)
|
|
172
|
+
result.count = Number(row.count ?? 0);
|
|
173
|
+
for (const [operation, fields] of [["min", normalized.aggregates.min], ["max", normalized.aggregates.max], ["sum", normalized.aggregates.sum]]) {
|
|
174
|
+
if (fields.length > 0)
|
|
175
|
+
result[operation] = Object.fromEntries(fields.map((field) => [field, nullableString(row[`${operation}_${field}`])]));
|
|
558
176
|
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
catch (cause) {
|
|
180
|
+
throw this.wrap("contracts.aggregate", cause);
|
|
559
181
|
}
|
|
560
|
-
return result;
|
|
561
182
|
}
|
|
562
|
-
async groupContractsAsync(
|
|
563
|
-
const compiled = (0, pqs_sql_compiler_js_1.compileContractGroupBy)(
|
|
183
|
+
async groupContractsAsync(query) {
|
|
184
|
+
const compiled = (0, pqs_sql_compiler_js_1.compileContractGroupBy)(query, this.profile);
|
|
564
185
|
try {
|
|
565
186
|
await this.ready;
|
|
566
187
|
return (await this.executor.query(compiled.text, compiled.values)).rows.map((row) => Object.fromEntries(Object.entries(row).map(([name, value]) => [name, name === "count" ? Number(value) : value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value instanceof Date ? value : String(value)])));
|
|
@@ -574,22 +195,39 @@ class PqsQueryClient {
|
|
|
574
195
|
}
|
|
575
196
|
}
|
|
576
197
|
exports.PqsQueryClient = PqsQueryClient;
|
|
577
|
-
function mapPhysicalValue(value, metadata, field) {
|
|
578
|
-
if (value === null || value === undefined)
|
|
198
|
+
function mapPhysicalValue(value, relation, metadata, field) {
|
|
199
|
+
if (value === null || value === undefined)
|
|
579
200
|
return value ?? null;
|
|
580
|
-
|
|
581
|
-
|
|
201
|
+
if (relation === "__events" && field === "eventId" && typeof value === "object" && !Array.isArray(value)) {
|
|
202
|
+
const event = value;
|
|
203
|
+
if (event.offset !== undefined && event.node_id !== undefined)
|
|
204
|
+
return `${String(event.offset)}:${String(event.node_id)}`;
|
|
205
|
+
}
|
|
206
|
+
if (relation === "__events" && field === "type") {
|
|
207
|
+
if (value === "create")
|
|
208
|
+
return "created";
|
|
209
|
+
if (value === "exercise")
|
|
210
|
+
return "exercised";
|
|
211
|
+
}
|
|
212
|
+
if (relation === "__transactions" && field === "workflowId" && value === "")
|
|
213
|
+
return null;
|
|
214
|
+
if (relation === "__transactions" && field === "traceContext" && typeof value === "object" && !Array.isArray(value)) {
|
|
215
|
+
const trace = value;
|
|
216
|
+
const traceparent = trace.traceparent ?? trace.trace_parent;
|
|
217
|
+
const tracestate = trace.tracestate ?? trace.trace_state;
|
|
218
|
+
return Object.fromEntries([
|
|
219
|
+
...(traceparent === undefined || traceparent === null || traceparent === "" ? [] : [["traceparent", String(traceparent)]]),
|
|
220
|
+
...(tracestate === undefined || tracestate === null || tracestate === "" ? [] : [["tracestate", String(tracestate)]]),
|
|
221
|
+
]);
|
|
222
|
+
}
|
|
223
|
+
if (metadata.numericFields.includes(field))
|
|
582
224
|
return String(value);
|
|
583
|
-
|
|
584
|
-
else if (metadata.dateFields.includes(field)) {
|
|
225
|
+
if (metadata.dateFields.includes(field))
|
|
585
226
|
return value instanceof Date ? value : new Date(String(value));
|
|
586
|
-
|
|
587
|
-
else if (metadata.binaryFields.includes(field)) {
|
|
227
|
+
if (metadata.binaryFields.includes(field))
|
|
588
228
|
return value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
589
|
-
|
|
590
|
-
else if (metadata.arrayFields.includes(field)) {
|
|
229
|
+
if (metadata.arrayFields.includes(field))
|
|
591
230
|
return Array.isArray(value) ? value.map(String) : [];
|
|
592
|
-
}
|
|
593
231
|
return value;
|
|
594
232
|
}
|
|
595
233
|
function mapJsonValue(value, as) {
|
|
@@ -601,99 +239,30 @@ function mapJsonValue(value, as) {
|
|
|
601
239
|
return value instanceof Date ? value : new Date(String(value));
|
|
602
240
|
return String(value);
|
|
603
241
|
}
|
|
604
|
-
function
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
return null;
|
|
616
|
-
if (typeof value !== "object" || Array.isArray(value))
|
|
617
|
-
throw new Error(`Invalid included ${relation} row`);
|
|
618
|
-
const row = value;
|
|
619
|
-
const metadata = pqs_schema_profile_js_1.pqsRelationMetadata[relation];
|
|
620
|
-
return Object.fromEntries(Object.entries(metadata.fields)
|
|
621
|
-
.filter(([field, column]) => Object.hasOwn(row, field) || Object.hasOwn(row, column))
|
|
622
|
-
.map(([field, column]) => [field, mapPhysicalValue(row[field] ?? row[column], metadata, field)]));
|
|
623
|
-
}
|
|
624
|
-
function mapContractTypeJson(value) {
|
|
625
|
-
const row = mapProfileJsonRow(value, "__contract_tpe");
|
|
626
|
-
return row === null ? undefined : { pk: String(row.pk), payloadType: String(row.payloadType), aliases: stringArray(row.aliases), packageName: String(row.packageName), moduleName: String(row.moduleName), entityName: String(row.entityName), templateFqn: String(row.templateFqn) };
|
|
627
|
-
}
|
|
628
|
-
function mapTransactionJson(value) {
|
|
629
|
-
const row = mapProfileJsonRow(value, "__transactions");
|
|
630
|
-
return row === null ? undefined : { ix: String(row.ix), offset: String(row.offset), transactionId: nullableString(row.transactionId), effectiveAt: nullableDate(row.effectiveAt), workflowId: nullableString(row.workflowId), domainId: nullableString(row.domainId), traceContext: row.traceContext, externalTransactionHash: row.externalTransactionHash instanceof Uint8Array ? row.externalTransactionHash : null, paidTrafficCost: nullableString(row.paidTrafficCost) };
|
|
631
|
-
}
|
|
632
|
-
function mapEventJson(value) {
|
|
633
|
-
const row = mapSelectedProfileJsonRow(value, "__events");
|
|
634
|
-
return row ?? undefined;
|
|
635
|
-
}
|
|
636
|
-
function mapSelectedRelationJson(value, relation) {
|
|
637
|
-
const row = mapSelectedProfileJsonRow(value, relation);
|
|
638
|
-
return row ?? undefined;
|
|
639
|
-
}
|
|
640
|
-
function mapLogicalContractJson(value) {
|
|
641
|
-
if (value === null || value === undefined)
|
|
642
|
-
return undefined;
|
|
643
|
-
if (typeof value !== "object" || Array.isArray(value))
|
|
644
|
-
throw new Error("Invalid included __contracts row");
|
|
645
|
-
return value;
|
|
646
|
-
}
|
|
647
|
-
function mapExerciseJson(value) {
|
|
648
|
-
const raw = value;
|
|
649
|
-
const row = mapSelectedProfileJsonRow(value, "__exercises");
|
|
650
|
-
if (row === null)
|
|
651
|
-
throw new Error("Included exercise cannot be null");
|
|
652
|
-
const base = row;
|
|
653
|
-
const knownFields = new Set(Object.entries(pqs_schema_profile_js_1.pqsRelationMetadata.__exercises.fields).flatMap(([field, column]) => [field, column]));
|
|
654
|
-
const knownRelations = new Set(Object.keys(pqs_schema_profile_js_1.pqsRelationEdges.__exercises ?? {}));
|
|
655
|
-
const projections = Object.fromEntries(Object.entries(raw).filter(([name]) => !knownFields.has(name) && !knownRelations.has(name)));
|
|
656
|
-
return {
|
|
657
|
-
...base,
|
|
658
|
-
...projections,
|
|
659
|
-
...(raw.exerciseType === undefined ? {} : { exerciseType: mapSelectedRelationJson(raw.exerciseType, "__exercise_tpe") }),
|
|
660
|
-
...(raw.contractType === undefined ? {} : { contractType: mapSelectedRelationJson(raw.contractType, "__contract_tpe") }),
|
|
661
|
-
...(raw.event === undefined ? {} : { event: raw.event === null ? null : mapEventJson(raw.event) ?? null }),
|
|
662
|
-
...(raw.transaction === undefined ? {} : { transaction: raw.transaction === null ? null : mapTransactionJson(raw.transaction) ?? null }),
|
|
663
|
-
...(raw.package === undefined ? {} : { package: mapSelectedRelationJson(raw.package, "__packages") }),
|
|
664
|
-
...(raw.contract === undefined ? {} : { contract: mapLogicalContractJson(raw.contract) }),
|
|
242
|
+
function contractRootScalars(row) {
|
|
243
|
+
const scalars = {
|
|
244
|
+
contractId: row.contract_id,
|
|
245
|
+
packageId: row.package_id,
|
|
246
|
+
payload: row.payload,
|
|
247
|
+
witnesses: row.witnesses,
|
|
248
|
+
createdEventOffset: row.created_event_offset,
|
|
249
|
+
createdAt: row.created_at,
|
|
250
|
+
archivedEventOffset: row.archived_event_offset,
|
|
251
|
+
archivedAt: row.archived_at,
|
|
252
|
+
active: row.active,
|
|
665
253
|
};
|
|
254
|
+
if (row.template_package_id !== undefined && row.template_module_name !== undefined && row.template_entity_name !== undefined) {
|
|
255
|
+
scalars.templateId = { packageId: row.template_package_id, moduleName: row.template_module_name, entityName: row.template_entity_name };
|
|
256
|
+
}
|
|
257
|
+
return scalars;
|
|
666
258
|
}
|
|
667
|
-
function
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
...(include?.exercises === undefined ? {} : { exercises: Array.isArray(row.exercises) ? row.exercises.map(mapExerciseJson) : [] }),
|
|
259
|
+
function contractRootRow(row) {
|
|
260
|
+
return {
|
|
261
|
+
...row,
|
|
262
|
+
contractType: row.contractType ?? row.contract_type,
|
|
263
|
+
createdTransaction: row.createdTransaction ?? row.created_transaction,
|
|
264
|
+
archivedTransaction: row.archivedTransaction ?? row.archived_transaction,
|
|
674
265
|
};
|
|
675
|
-
const projections = Object.fromEntries(Object.entries(json ?? {}).map(([name, projection]) => [name, mapJsonValue(row[name], projection.as)]));
|
|
676
|
-
return { ...base, ...relations, ...projections };
|
|
677
|
-
}
|
|
678
|
-
function nullableString(value) {
|
|
679
|
-
return value === null || value === undefined ? null : String(value);
|
|
680
|
-
}
|
|
681
|
-
function nullableDate(value) {
|
|
682
|
-
return value === null || value === undefined ? null : value instanceof Date ? value : new Date(String(value));
|
|
683
|
-
}
|
|
684
|
-
function stringArray(value) {
|
|
685
|
-
return Array.isArray(value) ? value.map(String) : [];
|
|
686
|
-
}
|
|
687
|
-
function getPqsCode(cause) {
|
|
688
|
-
return typeof cause === "object" && cause !== null && "code" in cause && typeof cause.code === "string" ? cause.code : undefined;
|
|
689
|
-
}
|
|
690
|
-
function aggregateNumeric(values, operation) {
|
|
691
|
-
const numbers = values.filter((value) => value !== null).map(BigInt);
|
|
692
|
-
if (numbers.length === 0) {
|
|
693
|
-
return null;
|
|
694
|
-
}
|
|
695
|
-
else if (operation === "sum") {
|
|
696
|
-
return numbers.reduce((total, value) => total + value, 0n).toString();
|
|
697
|
-
}
|
|
698
|
-
return numbers.reduce((result, value) => operation === "min" ? value < result ? value : result : value > result ? value : result).toString();
|
|
699
266
|
}
|
|
267
|
+
function nullableString(value) { return value === null || value === undefined ? null : String(value); }
|
|
268
|
+
function getPqsCode(cause) { return typeof cause === "object" && cause !== null && "code" in cause && typeof cause.code === "string" ? cause.code : undefined; }
|