@rocicorp/zero 1.12.0-canary.10 → 1.12.0-canary.12
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/out/analyze-query/src/zql-chain.js +9 -1
- package/out/analyze-query/src/zql-chain.js.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js +61 -20
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/z2s/src/compiler.d.ts +1 -1
- package/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +339 -2
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts +8 -0
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +58 -11
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/bindings.js +4 -4
- package/out/zero-cache/src/auth/write-authorizer.js +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +4 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +13 -0
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/db/create.js +1 -1
- package/out/zero-cache/src/scripts/decommission.js +1 -1
- package/out/zero-cache/src/server/replicator.js +4 -2
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +8 -5
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/serving-checkpointer.js +41 -0
- package/out/zero-cache/src/server/serving-checkpointer.js.map +1 -0
- package/out/zero-cache/src/server/worker-urls.d.ts +1 -0
- package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
- package/out/zero-cache/src/server/worker-urls.js +2 -1
- package/out/zero-cache/src/server/worker-urls.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +6 -0
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +13 -1
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +19 -0
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +53 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +1 -1
- package/out/zero-cache/src/services/replicator/serving-checkpointer.js +85 -0
- package/out/zero-cache/src/services/replicator/serving-checkpointer.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +101 -13
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.js +2 -2
- package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +1 -1
- package/out/zero-cache/src/types/processes.js +4 -4
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/row-key.js +8 -1
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/workers/connection.js +2 -2
- package/out/zero-cache/src/workers/replicator.js +9 -4
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-client/src/client/bindings.d.ts +1 -1
- package/out/zero-client/src/client/bindings.d.ts.map +1 -1
- package/out/zero-client/src/client/bindings.js +4 -4
- package/out/zero-client/src/client/context.d.ts +7 -1
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/context.js +7 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +171 -2
- package/out/zero-client/src/client/crud-impl.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +42 -3
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts +62 -2
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +152 -31
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/keys.d.ts +33 -0
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.js +43 -4
- package/out/zero-client/src/client/keys.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js +29 -1
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-rep.js +2 -15
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.js +1 -1
- package/out/zero-client/src/mod.d.ts +3 -3
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-protocol/src/aggregate-table.d.ts +15 -0
- package/out/zero-protocol/src/aggregate-table.d.ts.map +1 -0
- package/out/zero-protocol/src/aggregate-table.js +5 -0
- package/out/zero-protocol/src/aggregate-table.js.map +1 -0
- package/out/zero-protocol/src/ast.d.ts +141 -5
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +244 -18
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +29 -29
- package/out/zero-protocol/src/inspect-down.d.ts +81 -81
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.d.ts.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.js +38 -0
- package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
- package/out/zero-react/src/bindings.js +4 -4
- package/out/zero-react/src/use-query.d.ts +3 -1
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +4 -2
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.js +2 -0
- package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
- package/out/zero-schema/src/name-mapper.d.ts.map +1 -1
- package/out/zero-schema/src/name-mapper.js +7 -4
- package/out/zero-schema/src/name-mapper.js.map +1 -1
- package/out/zero-server/src/custom.js +1 -1
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +13 -2
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-solid/src/bindings.js +4 -4
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +3 -3
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-types/src/format.d.ts +13 -0
- package/out/zero-types/src/format.d.ts.map +1 -1
- package/out/zero-types/src/format.js.map +1 -1
- package/out/zero-types/src/name-mapper.d.ts +14 -0
- package/out/zero-types/src/name-mapper.d.ts.map +1 -1
- package/out/zero-types/src/name-mapper.js +12 -0
- package/out/zero-types/src/name-mapper.js.map +1 -1
- package/out/zero-types/src/schema-value.d.ts +2 -0
- package/out/zero-types/src/schema-value.d.ts.map +1 -1
- package/out/zero-types/src/schema-value.js +15 -0
- package/out/zero-types/src/schema-value.js.map +1 -0
- package/out/zero-types/src/server-schema.d.ts +18 -0
- package/out/zero-types/src/server-schema.d.ts.map +1 -1
- package/out/zql/src/builder/builder.d.ts +126 -1
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +281 -11
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/builder/filter.d.ts +1 -1
- package/out/zql/src/builder/filter.d.ts.map +1 -1
- package/out/zql/src/builder/filter.js +41 -3
- package/out/zql/src/builder/filter.js.map +1 -1
- package/out/zql/src/ivm/aggregate.d.ts +188 -0
- package/out/zql/src/ivm/aggregate.d.ts.map +1 -0
- package/out/zql/src/ivm/aggregate.js +470 -0
- package/out/zql/src/ivm/aggregate.js.map +1 -0
- package/out/zql/src/ivm/array-view.d.ts +1 -1
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +3 -3
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.js +2 -2
- package/out/zql/src/ivm/constraint.d.ts.map +1 -1
- package/out/zql/src/ivm/constraint.js +2 -1
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.js +1 -1
- package/out/zql/src/ivm/fan-in.js +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +3 -2
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/group-by.d.ts +98 -0
- package/out/zql/src/ivm/group-by.d.ts.map +1 -0
- package/out/zql/src/ivm/group-by.js +384 -0
- package/out/zql/src/ivm/group-by.js.map +1 -0
- package/out/zql/src/ivm/join-index.d.ts.map +1 -1
- package/out/zql/src/ivm/join-index.js +2 -1
- package/out/zql/src/ivm/join-index.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +2 -1
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.js +1 -1
- package/out/zql/src/ivm/lift-field.d.ts +54 -0
- package/out/zql/src/ivm/lift-field.d.ts.map +1 -0
- package/out/zql/src/ivm/lift-field.js +168 -0
- package/out/zql/src/ivm/lift-field.js.map +1 -0
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +2 -0
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +9 -4
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +1 -1
- package/out/zql/src/ivm/schema.d.ts +1 -0
- package/out/zql/src/ivm/schema.d.ts.map +1 -1
- package/out/zql/src/ivm/source.d.ts +21 -0
- package/out/zql/src/ivm/source.d.ts.map +1 -1
- package/out/zql/src/ivm/source.js.map +1 -1
- package/out/zql/src/ivm/take.js +1 -1
- package/out/zql/src/ivm/union-fan-in.js +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts +5 -0
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +23 -3
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/planner/planner-debug.d.ts +1 -1
- package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
- package/out/zql/src/planner/planner-debug.js +4 -0
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/query/expression.d.ts +50 -3
- package/out/zql/src/query/expression.d.ts.map +1 -1
- package/out/zql/src/query/expression.js +62 -6
- package/out/zql/src/query/expression.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts +8 -0
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +13 -5
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +17 -3
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +239 -7
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query.d.ts +319 -7
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zqlite/src/pending-delta.d.ts.map +1 -1
- package/out/zqlite/src/pending-delta.js +4 -3
- package/out/zqlite/src/pending-delta.js.map +1 -1
- package/out/zqlite/src/query-builder.d.ts +12 -1
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +114 -13
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +37 -3
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
package/out/z2s/src/compiler.js
CHANGED
|
@@ -3,16 +3,22 @@ import { hasOwn } from "../../shared/src/has-own.js";
|
|
|
3
3
|
import "../../shared/src/json.js";
|
|
4
4
|
import { last, zip } from "../../shared/src/arrays.js";
|
|
5
5
|
import { must } from "../../shared/src/must.js";
|
|
6
|
+
import { isLikeOperator, isNegatedOperator, jsonLiteralType } from "../../zero-protocol/src/ast.js";
|
|
6
7
|
import { clientToServer } from "../../zero-schema/src/name-mapper.js";
|
|
7
8
|
import { completeOrdering } from "../../zql/src/query/complete-ordering.js";
|
|
9
|
+
import { groupOrdering } from "../../zql/src/ivm/group-by.js";
|
|
8
10
|
import { parse } from "../../shared/src/bigint-json.js";
|
|
9
|
-
import {
|
|
11
|
+
import { isPgTextRepresentedType } from "../../zero-cache/src/types/pg-data-type.js";
|
|
12
|
+
import { isBuiltinTypeSchema, pgTypeForLiteralType, sql, sqlConvertColumnArg, sqlConvertPluralLiteralArg, sqlConvertSingularLiteralArg } from "./sql.js";
|
|
10
13
|
//#region ../z2s/src/compiler.ts
|
|
11
14
|
var ZQL_RESULT_KEY = "zql_result";
|
|
12
15
|
var ZQL_RESULT_KEY_IDENT = sql.ident(ZQL_RESULT_KEY);
|
|
13
16
|
var ZQL_RESULT_TABLE_KEY = "zql_root";
|
|
14
17
|
var ZQL_RESULT_TABLE_IDENT = sql.ident(ZQL_RESULT_TABLE_KEY);
|
|
15
18
|
function compile(serverSchema, zqlSchema, ast, format) {
|
|
19
|
+
assert(ast.groupBy === void 0 || ast.aggregate?.distinct === void 0, "a count of distinct values per group is not supported yet");
|
|
20
|
+
assert(ast.groupBy === void 0 || ast.aggregate === void 0 || !ast.groupBy.includes(ast.aggregate.fn), () => `groupBy(): the column "${ast.aggregate?.fn}" has the same name as the ${ast.aggregate?.fn}() value`);
|
|
21
|
+
assert(ast.groupBy === void 0 && ast.aggregate?.distinct === void 0 || ast.start === void 0 && ast.limit === void 0, "groupBy and a count of distinct values do not support start or limit");
|
|
16
22
|
ast = completeOrdering(ast, (tableName) => zqlSchema.tables[tableName].primaryKey);
|
|
17
23
|
const spec = {
|
|
18
24
|
aliasCount: 0,
|
|
@@ -22,10 +28,157 @@ function compile(serverSchema, zqlSchema, ast, format) {
|
|
|
22
28
|
},
|
|
23
29
|
zql: zqlSchema.tables
|
|
24
30
|
};
|
|
31
|
+
if (ast.groupBy) {
|
|
32
|
+
const groups = ast.aggregate ? selectGroups(spec, ast, ast.aggregate) : selectDistinct(spec, ast);
|
|
33
|
+
return sql`SELECT ${toJSON(ZQL_RESULT_TABLE_KEY)}::text AS ${ZQL_RESULT_KEY_IDENT}
|
|
34
|
+
FROM (${groups}) ${ZQL_RESULT_TABLE_IDENT}`;
|
|
35
|
+
}
|
|
36
|
+
if (ast.aggregate) {
|
|
37
|
+
if (ast.aggregate.distinct) {
|
|
38
|
+
const groups = selectDistinct(spec, {
|
|
39
|
+
...ast,
|
|
40
|
+
groupBy: ast.aggregate.distinct,
|
|
41
|
+
aggregate: void 0
|
|
42
|
+
});
|
|
43
|
+
return sql`SELECT to_json(COUNT(*))::text AS ${ZQL_RESULT_KEY_IDENT}
|
|
44
|
+
FROM (${groups}) ${ZQL_RESULT_TABLE_IDENT}`;
|
|
45
|
+
}
|
|
46
|
+
const bounded = ast.limit !== void 0 || ast.start !== void 0;
|
|
47
|
+
const inner = select(spec, {
|
|
48
|
+
...ast,
|
|
49
|
+
aggregate: void 0,
|
|
50
|
+
related: void 0,
|
|
51
|
+
orderBy: bounded ? ast.orderBy : void 0
|
|
52
|
+
}, void 0);
|
|
53
|
+
return sql`SELECT COALESCE(to_json(${aggregateExpr(spec, ast.table, ast.aggregate)}), 'null'::json)::text AS ${ZQL_RESULT_KEY_IDENT}
|
|
54
|
+
FROM (${inner}) ${ZQL_RESULT_TABLE_IDENT}`;
|
|
55
|
+
}
|
|
25
56
|
return sql`SELECT
|
|
26
57
|
${toJSON(ZQL_RESULT_TABLE_KEY, format?.singular)}::text AS ${ZQL_RESULT_KEY_IDENT}
|
|
27
58
|
FROM (${select(spec, ast, format)}) ${ZQL_RESULT_TABLE_IDENT}`;
|
|
28
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* The groups of `ast.groupBy` among the rows that pass `ast.where`, each with
|
|
62
|
+
* the aggregate under the function's name (`count`, `sum`, …), in the order a
|
|
63
|
+
* grouped query's rows have (see `groupOrdering`). Like a top-level
|
|
64
|
+
* aggregate, it reduces the normalized projection {@link select} gives, so a
|
|
65
|
+
* timestamp comes back in epoch milliseconds, and groups by those values.
|
|
66
|
+
*/
|
|
67
|
+
function selectGroups(spec, ast, agg) {
|
|
68
|
+
const inner = select(spec, {
|
|
69
|
+
...ast,
|
|
70
|
+
groupBy: void 0,
|
|
71
|
+
aggregate: void 0,
|
|
72
|
+
related: void 0,
|
|
73
|
+
orderBy: void 0
|
|
74
|
+
}, void 0);
|
|
75
|
+
const cols = must(ast.groupBy).map((col) => sql.ident(col));
|
|
76
|
+
return sql`SELECT ${sql.join(cols, ",")}, ${aggregateExpr(spec, ast.table, agg)} AS ${sql.ident(agg.fn)}
|
|
77
|
+
FROM (${inner}) ${sql.ident("zql_group")}
|
|
78
|
+
GROUP BY ${sql.join(cols, ", ")}
|
|
79
|
+
ORDER BY ${sql.join(groupOrdering(ast).map(([col, dir]) => {
|
|
80
|
+
const value = orderedValue(spec, ast.table, col, sql.ident(col));
|
|
81
|
+
return dir === "asc" ? sql`${value} ASC NULLS FIRST` : sql`${value} DESC NULLS LAST`;
|
|
82
|
+
}), ", ")}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The distinct values of `ast.groupBy` among the rows that pass `ast.where`,
|
|
86
|
+
* one row of those columns each, in the order a distinct query's rows have
|
|
87
|
+
* (see `groupOrdering`). It groups by the columns rather than selecting
|
|
88
|
+
* DISTINCT, which would need the converted values {@link selectIdent} selects
|
|
89
|
+
* to appear in the ORDER BY too. Like the IVM operator, it ignores `related`.
|
|
90
|
+
*/
|
|
91
|
+
function selectDistinct(spec, ast) {
|
|
92
|
+
const table = makeTable(spec, ast.table);
|
|
93
|
+
const columns = must(ast.groupBy).map((zql) => ({
|
|
94
|
+
table,
|
|
95
|
+
zql
|
|
96
|
+
}));
|
|
97
|
+
return sql`SELECT ${sql.join(columns.map((c) => selectIdent(spec.server, c)), ",")}
|
|
98
|
+
FROM ${fromIdent(spec.server, table)}
|
|
99
|
+
${ast.where ? sql`WHERE ${where(spec, ast.where, table)}` : sql``}
|
|
100
|
+
GROUP BY ${sql.join(columns.map((c) => colIdent(spec.server, c)), ", ")}
|
|
101
|
+
ORDER BY ${sql.join(groupOrdering(ast).map(([col, dir]) => {
|
|
102
|
+
const value = orderedValue(spec, ast.table, col, colIdent(spec.server, {
|
|
103
|
+
table,
|
|
104
|
+
zql: col
|
|
105
|
+
}));
|
|
106
|
+
return dir === "asc" ? sql`${value} ASC NULLS FIRST` : sql`${value} DESC NULLS LAST`;
|
|
107
|
+
}), ", ")}`;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The SQL aggregate for `aggregate`, over a subquery that exposes the
|
|
111
|
+
* aggregated column by its client name (as {@link select} does).
|
|
112
|
+
*
|
|
113
|
+
* `COUNT(*)` is left as Postgres's 64-bit count: the result parser rejects a
|
|
114
|
+
* value outside the safe integer range rather than rounding it.
|
|
115
|
+
*
|
|
116
|
+
* `SUM`/`AVG` add the values as float8, as the IVM operator adds JS numbers:
|
|
117
|
+
* Postgres would otherwise sum a `real` in float4 and a `numeric` exactly.
|
|
118
|
+
*
|
|
119
|
+
* `MIN`/`MAX` of an enum, or of a type Zero represents as text (`uuid`,
|
|
120
|
+
* `inet`, …), compare that text byte by byte, as the IVM operator compares
|
|
121
|
+
* strings. Otherwise an enum would use its declaration order, an `inet` its
|
|
122
|
+
* network order, and a `uuid` would fail (it has no `MIN`).
|
|
123
|
+
*/
|
|
124
|
+
function aggregateExpr(spec, zqlTable, agg) {
|
|
125
|
+
assert(agg.distinct === void 0, "a count of distinct values is not supported in a relationship yet");
|
|
126
|
+
const { fn, field, path } = agg;
|
|
127
|
+
if (path !== void 0) return jsonAggregateExpr(spec, zqlTable, agg, path);
|
|
128
|
+
switch (fn) {
|
|
129
|
+
case "count": return sql`COUNT(*)`;
|
|
130
|
+
case "sum": return sql`SUM(${sql.ident(must(field))}::float8)`;
|
|
131
|
+
case "avg": return sql`AVG(${sql.ident(must(field))}::float8)`;
|
|
132
|
+
case "min": return sql`MIN(${orderedAggregateArg(spec, zqlTable, must(field))})`;
|
|
133
|
+
case "max": return sql`MAX(${orderedAggregateArg(spec, zqlTable, must(field))})`;
|
|
134
|
+
default: unreachable(fn);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The SQL aggregate over the JSON leaf at `path` inside the (client-named)
|
|
139
|
+
* json column `field` of the subquery. Only leaves the aggregate takes count
|
|
140
|
+
* (see `aggregateValue`): numbers for `sum`/`avg`, numbers and strings for
|
|
141
|
+
* `min`/`max`, each gated on `jsonb_typeof` so a mismatched leaf is SQL NULL
|
|
142
|
+
* (skipped) rather than a cast error.
|
|
143
|
+
*
|
|
144
|
+
* `min`/`max` reduce numbers and strings separately and combine them with the
|
|
145
|
+
* client's cross-type order, numbers before strings (`compareAggregateValues`),
|
|
146
|
+
* instead of Postgres's jsonb order, which puts strings first. The result is
|
|
147
|
+
* jsonb so either type comes back as itself.
|
|
148
|
+
*/
|
|
149
|
+
function jsonAggregateExpr(spec, zqlTable, { fn, field }, path) {
|
|
150
|
+
const name = must(field);
|
|
151
|
+
const { type, isArray } = getServerColumn(spec.server, {
|
|
152
|
+
zql: zqlTable,
|
|
153
|
+
alias: zqlTable
|
|
154
|
+
}, name);
|
|
155
|
+
assert(isArray || type === "json" || type === "jsonb", () => `JSON path on non-JSON column "${name}" of type ${type}`);
|
|
156
|
+
const { raw, jsonType } = jsonNavigate(jsonBase(sql.ident(name), type, isArray), path);
|
|
157
|
+
const num = sql`(CASE WHEN ${jsonType} = 'number' THEN ${raw}::float8 END)`;
|
|
158
|
+
const str = sql`(CASE WHEN ${jsonType} = 'string' THEN ${raw} END)`;
|
|
159
|
+
switch (fn) {
|
|
160
|
+
case "sum": return sql`SUM(${num})::float8`;
|
|
161
|
+
case "avg": return sql`AVG(${num})::float8`;
|
|
162
|
+
case "min": return sql`COALESCE(to_jsonb(MIN(${num})), to_jsonb(MIN(${str})))`;
|
|
163
|
+
case "max": return sql`COALESCE(to_jsonb(MAX(${str})), to_jsonb(MAX(${num})))`;
|
|
164
|
+
case "count": throw new Error("count() takes no JSON path");
|
|
165
|
+
default: unreachable(fn);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function orderedAggregateArg(spec, zqlTable, field) {
|
|
169
|
+
return orderedValue(spec, zqlTable, field, sql.ident(field));
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* `value`, the value of `zqlTable`'s column `field`, in a form Postgres
|
|
173
|
+
* orders as the IVM does: an enum, or a type Zero represents as text, by that
|
|
174
|
+
* text byte by byte. Otherwise an enum would use its declaration order and an
|
|
175
|
+
* `inet` its network order.
|
|
176
|
+
*/
|
|
177
|
+
function orderedValue(spec, zqlTable, field, value) {
|
|
178
|
+
const { server } = spec;
|
|
179
|
+
const column = server.schema[server.mapper.tableName(zqlTable)][server.mapper.columnName(zqlTable, field)];
|
|
180
|
+
return column.isEnum || isPgTextRepresentedType(column.type) ? sql`format('%s', ${value}) COLLATE "C"` : value;
|
|
181
|
+
}
|
|
29
182
|
function select(spec, ast, format, correlate) {
|
|
30
183
|
const table = makeTable(spec, ast.table);
|
|
31
184
|
const selectionSet = related(spec, ast.related ?? [], format, table);
|
|
@@ -95,6 +248,36 @@ function related(spec, relationships, format, parentTable) {
|
|
|
95
248
|
}
|
|
96
249
|
function relationshipSubquery(spec, relationship, format, parentTable) {
|
|
97
250
|
const innerAlias = `inner_${relationship.subquery.alias}`;
|
|
251
|
+
if (relationship.aggregate) {
|
|
252
|
+
const { field } = relationship.aggregate;
|
|
253
|
+
const isJunction = !!relationship.subquery.related?.length;
|
|
254
|
+
const aggExpr = aggregateExpr(spec, isJunction ? must(relationship.subquery.related)[0].subquery.table : relationship.subquery.table, relationship.aggregate);
|
|
255
|
+
let inner;
|
|
256
|
+
if (isJunction) {
|
|
257
|
+
const { join, participatingTables } = makeJunctionJoin(spec, relationship);
|
|
258
|
+
const lastTable = must(last(participatingTables)).table;
|
|
259
|
+
const destWhere = relationship.subquery.related[0].subquery.where;
|
|
260
|
+
inner = sql`SELECT ${field ? selectIdent(spec.server, {
|
|
261
|
+
table: lastTable,
|
|
262
|
+
zql: field
|
|
263
|
+
}) : sql`NULL`} FROM ${join} WHERE (${makeCorrelator(spec, relationship.correlation.parentField.map((f) => ({
|
|
264
|
+
table: parentTable,
|
|
265
|
+
zql: f
|
|
266
|
+
})), relationship.correlation.childField)(participatingTables[0].table)})${destWhere ? sql` AND (${where(spec, destWhere, lastTable)})` : sql``}`;
|
|
267
|
+
} else {
|
|
268
|
+
const { subquery } = relationship;
|
|
269
|
+
inner = select(spec, subquery.limit !== void 0 || subquery.start !== void 0 ? subquery : {
|
|
270
|
+
...subquery,
|
|
271
|
+
orderBy: void 0
|
|
272
|
+
}, void 0, makeCorrelator(spec, relationship.correlation.parentField.map((f) => ({
|
|
273
|
+
table: parentTable,
|
|
274
|
+
zql: f
|
|
275
|
+
})), relationship.correlation.childField));
|
|
276
|
+
}
|
|
277
|
+
return sql`(
|
|
278
|
+
SELECT ${aggExpr} FROM (${inner}) ${sql.ident(innerAlias)}
|
|
279
|
+
) as ${sql.ident(relationship.subquery.alias)}`;
|
|
280
|
+
}
|
|
98
281
|
if (relationship.hidden) {
|
|
99
282
|
const { join, participatingTables } = makeJunctionJoin(spec, relationship);
|
|
100
283
|
const lastTable = must(last(participatingTables)).table;
|
|
@@ -151,6 +334,10 @@ function makeCorrelator(spec, parentFields, childZqlFields) {
|
|
|
151
334
|
};
|
|
152
335
|
}
|
|
153
336
|
function simple(spec, condition, table) {
|
|
337
|
+
if (condition.left.type === "json") {
|
|
338
|
+
const special = jsonPathCondition(spec, condition.left, condition, table);
|
|
339
|
+
if (special) return special;
|
|
340
|
+
}
|
|
154
341
|
switch (condition.op) {
|
|
155
342
|
case "ILIKE":
|
|
156
343
|
case "LIKE":
|
|
@@ -210,6 +397,7 @@ function valueComparison(spec, valuePos, table, otherValuePos, plural) {
|
|
|
210
397
|
};
|
|
211
398
|
return colIdent(spec.server, qualified);
|
|
212
399
|
}
|
|
400
|
+
case "json": return jsonPathLeaf(spec, valuePos, table, otherValuePos);
|
|
213
401
|
case "literal": return literalValueComparison(spec, valuePos, table, otherValuePos, plural);
|
|
214
402
|
case "static": throw new Error("Static parameters must be bound to a value before compiling to SQL");
|
|
215
403
|
default: unreachable(valuePosType);
|
|
@@ -219,6 +407,12 @@ function literalValueComparison(spec, valuePos, table, otherValuePos, plural) {
|
|
|
219
407
|
const otherType = otherValuePos.type;
|
|
220
408
|
switch (otherType) {
|
|
221
409
|
case "column": return sqlConvertColumnArg(getServerColumn(spec.server, table, otherValuePos.name), valuePos.value, plural, true);
|
|
410
|
+
case "json": {
|
|
411
|
+
assert(plural === Array.isArray(valuePos.value), "Expected plural flag to match whether value is an array");
|
|
412
|
+
const { value } = valuePos;
|
|
413
|
+
if (Array.isArray(value)) return sqlConvertPluralLiteralArg(jsonLiteralType(value) ?? "string", value);
|
|
414
|
+
return sqlConvertSingularLiteralArg(value);
|
|
415
|
+
}
|
|
222
416
|
case "literal":
|
|
223
417
|
assert(plural === Array.isArray(valuePos.value), "Expected plural flag to match whether value is an array");
|
|
224
418
|
if (Array.isArray(valuePos.value)) {
|
|
@@ -232,6 +426,149 @@ function literalValueComparison(spec, valuePos, table, otherValuePos, plural) {
|
|
|
232
426
|
default: unreachable(otherType);
|
|
233
427
|
}
|
|
234
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* The two SQL pieces every JSON path comparison is built from: the leaf's text
|
|
431
|
+
* (`raw`, SQL NULL for a missing key or a JSON null) and its JSON type
|
|
432
|
+
* (`jsonType`, via `jsonb_typeof`).
|
|
433
|
+
*
|
|
434
|
+
* Navigation chains `->` with a *typed* operand per segment (a text operand
|
|
435
|
+
* for an object key, an integer operand for an array index), so Postgres
|
|
436
|
+
* applies the same strict rule as the in-memory reader and SQLite: a string
|
|
437
|
+
* segment never indexes an array and a number never reads an object key. (A
|
|
438
|
+
* `#>>` text[] path would instead resolve a digit string by the container's
|
|
439
|
+
* runtime type, including `'-1'` from the end.) The last step uses `->>` for
|
|
440
|
+
* the text form.
|
|
441
|
+
*
|
|
442
|
+
* The base is the column as jsonb: a `json` column is cast, and a Postgres
|
|
443
|
+
* array column (which zero maps to a `json()` column and the replica stores
|
|
444
|
+
* as JSON text) is converted with `to_jsonb`.
|
|
445
|
+
*/
|
|
446
|
+
function jsonPathParts(spec, ref, table) {
|
|
447
|
+
const { name } = ref.value;
|
|
448
|
+
const col = colIdent(spec.server, {
|
|
449
|
+
table,
|
|
450
|
+
zql: name
|
|
451
|
+
});
|
|
452
|
+
const { type, isArray } = getServerColumn(spec.server, table, name);
|
|
453
|
+
assert(isArray || type === "json" || type === "jsonb", () => `JSON path on non-JSON column "${name}" of type ${type}`);
|
|
454
|
+
return jsonNavigate(jsonBase(col, type, isArray), ref.path);
|
|
455
|
+
}
|
|
456
|
+
/** A json/jsonb/array column (or an expression of one) as jsonb. */
|
|
457
|
+
function jsonBase(col, type, isArray) {
|
|
458
|
+
return isArray ? sql`to_jsonb(${col})` : type === "json" ? sql`${col}::jsonb` : col;
|
|
459
|
+
}
|
|
460
|
+
/** Navigates `path` from the jsonb `base`; see {@link jsonPathParts}. */
|
|
461
|
+
function jsonNavigate(base, path) {
|
|
462
|
+
let obj = base;
|
|
463
|
+
const operand = (seg) => typeof seg === "number" ? sql.__dangerous__rawValue(String(seg)) : sqlConvertSingularLiteralArg(seg);
|
|
464
|
+
const last = path.length - 1;
|
|
465
|
+
for (let i = 0; i < last; i++) obj = sql`(${obj} -> ${operand(path[i])})`;
|
|
466
|
+
const leaf = operand(path[last]);
|
|
467
|
+
return {
|
|
468
|
+
value: sql`(${obj} -> ${leaf})`,
|
|
469
|
+
raw: sql`(${obj} ->> ${leaf})`,
|
|
470
|
+
jsonType: sql`jsonb_typeof(${obj} -> ${leaf})`
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* The JS type the leaf must have to be compared against the literal on the
|
|
475
|
+
* other side (`jsonLiteralType`, shared across engines). It is also the
|
|
476
|
+
* `jsonb_typeof` name and the key into `pgTypeForLiteralType` for the cast, so
|
|
477
|
+
* the leaf's cast and the literal's own cast cannot drift. `undefined` for a
|
|
478
|
+
* `null` literal (`IS NULL`: a missing key and a JSON null must both read as
|
|
479
|
+
* SQL NULL), an empty list, or a non-literal.
|
|
480
|
+
*/
|
|
481
|
+
function leafType(other) {
|
|
482
|
+
return other.type === "literal" ? jsonLiteralType(other.value) : void 0;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Compiles a JSON path reference to its text form, cast to the comparison type
|
|
486
|
+
* derived from the literal on the other side (`leafType`) so it lines up with
|
|
487
|
+
* that literal's own cast.
|
|
488
|
+
*
|
|
489
|
+
* `->>` maps **both** a missing key and a JSON `null` to SQL `NULL`, matching
|
|
490
|
+
* the SQLite `json_extract` pushdown and the in-memory predicate, so `IS NULL`
|
|
491
|
+
* agrees across all three.
|
|
492
|
+
*
|
|
493
|
+
* The cast is gated on the leaf's JSON type (`CASE WHEN jsonb_typeof(...)`), so a
|
|
494
|
+
* leaf of a different type than the literal is SQL NULL, i.e. a non-match. This
|
|
495
|
+
* is the type-strict comparison documented on {@link JsonPathReference}: `->>`
|
|
496
|
+
* renders a numeric `42` as the text `'42'`, so an ungated text comparison
|
|
497
|
+
* would wrongly match it against the string `'42'`. For `number`/`boolean` the
|
|
498
|
+
* gate is also what keeps the cast from throwing: Postgres errors when casting
|
|
499
|
+
* non-conforming text (a string `"n/a"`, an object's JSON text) to
|
|
500
|
+
* `double precision`/`boolean`, which would fail the whole query on one
|
|
501
|
+
* mismatched row. Negated operators need a different form; see
|
|
502
|
+
* `jsonPathCondition`.
|
|
503
|
+
*/
|
|
504
|
+
function jsonPathLeaf(spec, ref, table, other) {
|
|
505
|
+
const { raw, jsonType } = jsonPathParts(spec, ref, table);
|
|
506
|
+
const t = leafType(other);
|
|
507
|
+
if (t === void 0) return raw;
|
|
508
|
+
return sql`(CASE WHEN ${jsonType} = ${sqlConvertSingularLiteralArg(t)} THEN ${raw}::${sql.__dangerous__rawValue(pgTypeForLiteralType(t))} END)`;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* The comparisons on a JSON path left operand that cannot go through the
|
|
512
|
+
* generic operator rendering with the gated leaf (`jsonPathLeaf`); returns
|
|
513
|
+
* `undefined` for the ones that can.
|
|
514
|
+
*
|
|
515
|
+
* - `IN`/`NOT IN` with a `null` literal is constant-false, as in the
|
|
516
|
+
* in-memory predicate (the generic forms would assert, or match every
|
|
517
|
+
* non-null leaf).
|
|
518
|
+
* - `=`/`IN` against a string or boolean literal compare the leaf *as jsonb*:
|
|
519
|
+
* jsonb equality is type-strict by itself (`"42"` never equals `42`, a JSON
|
|
520
|
+
* `null` never equals a string) and a missing key is SQL NULL, so the
|
|
521
|
+
* `jsonb_typeof` gate is unnecessary. Without the `CASE` around the
|
|
522
|
+
* extraction, an expression index on `(col -> 'key')` can serve the
|
|
523
|
+
* predicate. Numbers keep the gated `double precision` form: jsonb compares
|
|
524
|
+
* numbers exactly (`numeric`), which would diverge from the client's and
|
|
525
|
+
* SQLite's IEEE-754 equality above 2^53 or beyond double precision.
|
|
526
|
+
* - An empty `NOT IN` list matches every non-null leaf: SQL's
|
|
527
|
+
* `NOT (x = ANY('{}'))` is TRUE even for a NULL leaf, whereas the
|
|
528
|
+
* predicate's null guard excludes it.
|
|
529
|
+
* - The LIKE family compares text, so the leaf must be a string whatever the
|
|
530
|
+
* literal's type, and the pattern is the literal's text form, as in the
|
|
531
|
+
* in-memory predicate (`String(pattern)`) and SQLite. Deriving the leaf type
|
|
532
|
+
* from a numeric or boolean literal instead would cast the leaf to
|
|
533
|
+
* `double precision`/`boolean` and hand Postgres a LIKE it cannot execute.
|
|
534
|
+
* - The negated operators (`!=`, `NOT LIKE`, `NOT ILIKE`, `NOT IN`): the gate
|
|
535
|
+
* makes a mismatched leaf SQL NULL, which a positive comparison correctly
|
|
536
|
+
* excludes. But NULL also excludes under a negated operator, where a
|
|
537
|
+
* mismatch must *match* (JS `42 !== '42'` is true). `jsonb_typeof` is NULL
|
|
538
|
+
* for a missing key and `'null'` for a JSON null, so one `COALESCE` covers
|
|
539
|
+
* the null guard without a second extraction: a null/missing leaf is
|
|
540
|
+
* false, the same type is the real (negated) comparison, another type is
|
|
541
|
+
* true.
|
|
542
|
+
*/
|
|
543
|
+
function jsonPathCondition(spec, left, condition, table) {
|
|
544
|
+
const { op } = condition;
|
|
545
|
+
let { right } = condition;
|
|
546
|
+
if ((op === "IN" || op === "NOT IN") && right.type === "literal" && right.value === null) return sql`false`;
|
|
547
|
+
if (isLikeOperator(op) && right.type === "literal" && right.value !== null && !Array.isArray(right.value)) {
|
|
548
|
+
right = {
|
|
549
|
+
type: "literal",
|
|
550
|
+
value: String(right.value)
|
|
551
|
+
};
|
|
552
|
+
if (!isNegatedOperator(op)) return sql`${valueComparison(spec, left, table, right, false)} ${sql.__dangerous__rawValue(op)} ${valueComparison(spec, right, table, left, false)}`;
|
|
553
|
+
}
|
|
554
|
+
if ((op === "=" || op === "IN") && right.type === "literal") {
|
|
555
|
+
const t = leafType(right);
|
|
556
|
+
if (t === "string" || t === "boolean") {
|
|
557
|
+
const { value } = jsonPathParts(spec, left, table);
|
|
558
|
+
const lit = valueComparison(spec, right, table, left, op === "IN");
|
|
559
|
+
return op === "IN" ? sql`${value} = ANY (ARRAY(SELECT to_jsonb(v) FROM unnest(${lit}) AS v))` : sql`${value} = to_jsonb(${lit})`;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (!isNegatedOperator(op) || right.type !== "literal") return;
|
|
563
|
+
const t = leafType(right);
|
|
564
|
+
const { raw, jsonType } = jsonPathParts(spec, left, table);
|
|
565
|
+
if (t === void 0) return op === "NOT IN" ? sql`${raw} IS NOT NULL` : void 0;
|
|
566
|
+
const leaf = sql`${raw}::${sql.__dangerous__rawValue(pgTypeForLiteralType(t))}`;
|
|
567
|
+
const plural = op === "NOT IN";
|
|
568
|
+
const lit = valueComparison(spec, right, table, left, plural);
|
|
569
|
+
const cmp = plural ? sql`NOT (${leaf} = ANY (${lit}))` : sql`${leaf} ${sql.__dangerous__rawValue(op)} ${lit}`;
|
|
570
|
+
return sql`(CASE COALESCE(${jsonType}, 'null') WHEN 'null' THEN false WHEN ${sqlConvertSingularLiteralArg(t)} THEN ${cmp} ELSE true END)`;
|
|
571
|
+
}
|
|
235
572
|
function makeJunctionJoin(spec, relationship) {
|
|
236
573
|
const participatingTables = pullTablesForJunction(spec, relationship);
|
|
237
574
|
const joins = [];
|
|
@@ -270,7 +607,7 @@ function toJSON(table, singular = false) {
|
|
|
270
607
|
function selectIdent(server, column) {
|
|
271
608
|
const serverColumnSchema = server.schema[server.mapper.tableName(column.table.zql)][server.mapper.columnName(column.table.zql, column.zql)];
|
|
272
609
|
const serverType = serverColumnSchema.type;
|
|
273
|
-
if (!serverColumnSchema.isEnum) {
|
|
610
|
+
if (!serverColumnSchema.isEnum && isBuiltinTypeSchema(serverColumnSchema.typeSchema)) {
|
|
274
611
|
let needsNormalization = false;
|
|
275
612
|
switch (serverType) {
|
|
276
613
|
case "timetz":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.js","names":["parseBigIntJson"],"sources":["../../../../z2s/src/compiler.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport {last, zip} from '../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n parse as parseBigIntJson,\n type JSONValue as BigIntJSONValue,\n} from '../../shared/src/bigint-json.ts';\nimport {hasOwn} from '../../shared/src/has-own.ts';\nimport {type JSONValue} from '../../shared/src/json.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {\n AST,\n Bound,\n Condition,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Correlation,\n LiteralReference,\n Ordering,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {\n clientToServer,\n type NameMapper,\n} from '../../zero-schema/src/name-mapper.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {ServerSchema} from '../../zero-types/src/server-schema.ts';\nimport type {Format} from '../../zql/src/ivm/view.ts';\nimport {completeOrdering} from '../../zql/src/query/complete-ordering.ts';\nimport {\n sql,\n sqlConvertColumnArg,\n sqlConvertPluralLiteralArg,\n sqlConvertSingularLiteralArg,\n type PluralLiteralType,\n} from './sql.ts';\n\ntype Table = {\n zql: string;\n alias: string;\n};\n\ntype QualifiedColumn = {\n table: Table;\n zql: string;\n};\n\ntype ServerSpec = {\n schema: ServerSchema;\n // maps zql names to server names\n mapper: NameMapper;\n};\n\nexport type Spec = {\n server: ServerSpec;\n zql: Schema['tables'];\n aliasCount: number;\n};\n\nconst ZQL_RESULT_KEY = 'zql_result';\nconst ZQL_RESULT_KEY_IDENT = sql.ident(ZQL_RESULT_KEY);\n\nconst ZQL_RESULT_TABLE_KEY = 'zql_root';\nconst ZQL_RESULT_TABLE_IDENT = sql.ident(ZQL_RESULT_TABLE_KEY);\n\nexport function compile(\n serverSchema: ServerSchema,\n zqlSchema: Schema,\n ast: AST,\n format?: Format,\n): SQLQuery {\n ast = completeOrdering(\n ast,\n tableName => zqlSchema.tables[tableName].primaryKey,\n );\n const spec: Spec = {\n aliasCount: 0,\n server: {\n schema: serverSchema,\n mapper: clientToServer(zqlSchema.tables),\n },\n zql: zqlSchema.tables,\n };\n return sql`SELECT \n ${toJSON(ZQL_RESULT_TABLE_KEY, format?.singular)}::text AS ${ZQL_RESULT_KEY_IDENT}\n FROM (${select(spec, ast, format)}) ${ZQL_RESULT_TABLE_IDENT}`;\n}\n\nfunction select(\n spec: Spec,\n ast: AST,\n format: Format | undefined,\n correlate?: (childTable: Table) => SQLQuery,\n): SQLQuery {\n const table = makeTable(spec, ast.table);\n const selectionSet = related(spec, ast.related ?? [], format, table);\n const tableSchema = spec.zql[ast.table];\n const usedAliases = new Set<string>(\n ast.related?.map(r => r.subquery.alias ?? ''),\n );\n for (const column of Object.keys(tableSchema.columns)) {\n if (!usedAliases.has(column)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table,\n zql: column,\n }),\n );\n }\n }\n\n let appliedWhere = false;\n function maybeWhere(test: unknown) {\n if (!test) {\n return sql``;\n }\n\n const ret = appliedWhere ? sql`AND` : sql`WHERE`;\n appliedWhere = true;\n return ret;\n }\n\n return sql`SELECT ${sql.join(selectionSet, ',')}\n FROM ${fromIdent(spec.server, table)}\n ${maybeWhere(ast.where)} ${where(spec, ast.where, table)}${\n ast.start\n ? sql`\n ${maybeWhere(ast.start)} ${start(spec, ast.start, ast.orderBy, table)}`\n : sql``\n }\n ${maybeWhere(correlate)} ${correlate ? correlate(table) : sql``}\n ${orderBy(spec, ast.orderBy, table)}\n ${limit(ast.limit, format?.singular)}`;\n}\n\nexport function limit(\n limit: number | undefined,\n singular: boolean | undefined,\n): SQLQuery {\n if (limit === 0) {\n return sql`LIMIT 0`;\n }\n if (singular) {\n return sql`LIMIT 1`;\n }\n if (limit === undefined) {\n return sql``;\n }\n return sql`LIMIT ${sqlConvertSingularLiteralArg(limit)}`;\n}\n\nfunction makeTable(spec: Spec, zql: string, alias?: string): Table {\n alias = alias ?? zql + '_' + spec.aliasCount++;\n return {\n zql,\n alias,\n };\n}\n\nexport function orderBy(\n spec: Spec,\n orderBy: Ordering | undefined,\n table: Table,\n): SQLQuery {\n if (!orderBy) {\n return sql``;\n }\n return sql`ORDER BY ${sql.join(\n orderBy.map(([col, dir]) =>\n dir === 'asc'\n ? // Oh postgres. The table must be referred to by client name but the column by server name.\n // E.g., `SELECT server_col as client_col FROM server_table as client_table ORDER BY client_Table.server_col`\n sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} ASC NULLS FIRST`\n : sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} DESC NULLS LAST`,\n ),\n ', ',\n )}`;\n}\n\nexport function start(\n spec: Spec,\n bound: Bound | undefined,\n orderBy: Ordering | undefined,\n table: Table,\n): SQLQuery {\n if (!bound) {\n return sql``;\n }\n assert(\n orderBy !== undefined && orderBy.length > 0,\n 'start requires ordering',\n );\n\n const constraints: SQLQuery[] = [];\n for (let i = 0; i < orderBy.length; i++) {\n const group: SQLQuery[] = [];\n const [iField, iDirection] = orderBy[i];\n for (let j = 0; j <= i; j++) {\n const [field] = orderBy[j];\n if (j === i) {\n group.push(\n startRangeComparison(\n spec,\n table,\n iField,\n bound.row[iField] ?? null,\n iDirection === 'asc' ? '>' : '<',\n ),\n );\n } else {\n group.push(startEquality(spec, table, field, bound.row[field] ?? null));\n }\n }\n constraints.push(sql`(${sql.join(group, ' AND ')})`);\n }\n\n if (!bound.exclusive) {\n constraints.push(\n sql`(${sql.join(\n orderBy.map(([field]) =>\n startEquality(spec, table, field, bound.row[field] ?? null),\n ),\n ' AND ',\n )})`,\n );\n }\n\n return sql`(${sql.join(constraints, ' OR ')})`;\n}\n\nfunction related(\n spec: Spec,\n relationships: readonly CorrelatedSubquery[],\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery[] {\n return relationships.map(relationship =>\n relationshipSubquery(\n spec,\n relationship,\n format?.relationships[must(relationship.subquery.alias)],\n parentTable,\n ),\n );\n}\n\nfunction relationshipSubquery(\n spec: Spec,\n relationship: CorrelatedSubquery,\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery {\n const innerAlias = `inner_${relationship.subquery.alias}`;\n if (relationship.hidden) {\n const {join, participatingTables} = makeJunctionJoin(spec, relationship);\n const lastTable = must(last(participatingTables)).table;\n\n assert(\n relationship.subquery.related,\n 'hidden relationship must be a junction',\n );\n const nestedAst = relationship.subquery.related[0].subquery;\n const selectionSet = related(\n spec,\n nestedAst.related ?? [],\n format,\n lastTable,\n );\n const tableSchema = spec.zql[nestedAst.table];\n for (const column of Object.keys(tableSchema.columns)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table: lastTable,\n zql: column,\n }),\n );\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (SELECT ${sql.join(\n selectionSet,\n ',',\n )} FROM ${join} WHERE (${makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n )(participatingTables[0].table)}) ${\n nestedAst.where\n ? sql`AND ${where(spec, nestedAst.where, lastTable)}`\n : sql``\n }${\n nestedAst.start\n ? sql` AND ${start(\n spec,\n nestedAst.start,\n nestedAst.orderBy,\n lastTable,\n )}`\n : sql``\n } ${orderBy(spec, nestedAst.orderBy, lastTable)} ${limit(\n last(participatingTables)?.limit,\n format?.singular,\n )} ) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (${select(\n spec,\n relationship.subquery,\n format,\n makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n ),\n )}) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n}\n\nfunction where(\n spec: Spec,\n condition: Condition | undefined,\n table: Table,\n): SQLQuery {\n if (!condition) {\n return sql``;\n }\n\n switch (condition.type) {\n case 'and':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' AND ',\n )})`;\n case 'or':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' OR ',\n )})`;\n case 'correlatedSubquery':\n // `scalar` is deliberately ignored here. It is a planner hint for the\n // IVM engines, which have no cost-based planner and benefit from\n // pre-resolving an at-most-one-row subquery to a literal comparison\n // (see zqlite's `resolveSimpleScalarSubqueries`). Postgres decorrelates\n // EXISTS into a semi-join on its own, so the hint buys nothing here —\n // and honoring it as `parentField = (SELECT childField … LIMIT 1)` is\n // only sound when the subquery matches at most one row *globally*.\n // Applying it unconditionally silently dropped rows whenever the\n // subquery was not pinned to a unique key.\n return exists(spec, condition, table);\n case 'simple':\n return simple(spec, condition, table);\n }\n}\n\nfunction exists(\n spec: Spec,\n condition: CorrelatedSubqueryCondition,\n parentTable: Table,\n): SQLQuery {\n switch (condition.op) {\n case 'EXISTS':\n return sql`EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n case 'NOT EXISTS':\n return sql`NOT EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n }\n}\n\nexport function makeCorrelator(\n spec: Spec,\n parentFields: readonly QualifiedColumn[],\n childZqlFields: readonly string[],\n): (childTable: Table) => SQLQuery {\n return (childTable: Table) => {\n const childFields = childZqlFields.map(zqlField => ({\n table: childTable,\n zql: zqlField,\n }));\n return sql.join(\n zip(parentFields, childFields).map(\n ([parentColumn, childColumn]) =>\n sql`${colIdent(spec.server, parentColumn)} = ${colIdent(\n spec.server,\n childColumn,\n )}`,\n ),\n ' AND ',\n );\n };\n}\n\nexport function simple(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n switch (condition.op) {\n case 'ILIKE':\n case 'LIKE':\n case 'NOT ILIKE':\n case 'NOT LIKE': {\n // The pattern is a string, not a value of the column's type. Converted\n // to the `bpchar` of a `char(n)` column it would lose its trailing\n // spaces. Like ZQL's own LIKE, non-string patterns match as strings.\n const {right} = condition;\n assert(\n right.type === 'literal',\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n return sql`${valueComparison(\n spec,\n condition.left,\n table,\n right,\n false,\n )} ${sql.__dangerous__rawValue(condition.op)} ${sqlConvertSingularLiteralArg(\n right.value === null ? null : String(right.value),\n )}`;\n }\n case '!=':\n case '<':\n case '<=':\n case '=':\n case '>':\n case '>=':\n return sql`${valueComparison(\n spec,\n condition.left,\n table,\n condition.right,\n false,\n )} ${sql.__dangerous__rawValue(condition.op)} ${valueComparison(\n spec,\n condition.right,\n table,\n condition.left,\n false,\n )}`;\n case 'NOT IN':\n case 'IN':\n return any(spec, condition, table);\n case 'IS':\n case 'IS NOT':\n return distinctFrom(spec, condition, table);\n }\n}\n\nexport function any(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${condition.op === 'NOT IN' ? sql`NOT` : sql``}\n (\n ${valueComparison(spec, condition.left, table, condition.right, false)} = ANY \n (${valueComparison(spec, condition.right, table, condition.left, true)})\n )`;\n}\n\nexport function distinctFrom(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${valueComparison(spec, condition.left, table, condition.right, false)} ${\n condition.op === 'IS' ? sql`IS NOT DISTINCT FROM` : sql`IS DISTINCT FROM`\n } ${valueComparison(spec, condition.right, table, condition.left, false)}`;\n}\n\nfunction startEquality(\n spec: Spec,\n table: Table,\n field: string,\n value: unknown,\n): SQLQuery {\n return sql`${colIdent(spec.server, {\n table,\n zql: field,\n })} IS NOT DISTINCT FROM ${startValue(spec, table, field, value)}`;\n}\n\nfunction startRangeComparison(\n spec: Spec,\n table: Table,\n field: string,\n value: unknown,\n operator: '>' | '<',\n): SQLQuery {\n const column = colIdent(spec.server, {table, zql: field});\n if (value === null) {\n return operator === '>' ? sql`${column} IS NOT NULL` : sql`FALSE`;\n }\n const typedValue = startValue(spec, table, field, value);\n return operator === '>'\n ? sql`${column} > ${typedValue}`\n : sql`(${column} IS NULL OR ${column} < ${typedValue})`;\n}\n\nfunction startValue(\n spec: Spec,\n table: Table,\n field: string,\n value: unknown,\n): SQLQuery {\n return sqlConvertColumnArg(\n getServerColumn(spec.server, table, field),\n value,\n false,\n true,\n );\n}\n\nfunction valueComparison(\n spec: Spec,\n valuePos: ValuePosition,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const valuePosType = valuePos.type;\n switch (valuePosType) {\n case 'column': {\n const qualified: QualifiedColumn = {\n table,\n zql: valuePos.name,\n };\n return colIdent(spec.server, qualified);\n }\n case 'literal':\n return literalValueComparison(\n spec,\n valuePos,\n table,\n otherValuePos,\n plural,\n );\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(valuePosType);\n break;\n }\n}\n\nfunction literalValueComparison(\n spec: Spec,\n valuePos: LiteralReference,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const otherType = otherValuePos.type;\n switch (otherType) {\n case 'column':\n return sqlConvertColumnArg(\n getServerColumn(spec.server, table, otherValuePos.name),\n valuePos.value,\n plural,\n true,\n );\n case 'literal': {\n assert(\n plural === Array.isArray(valuePos.value),\n 'Expected plural flag to match whether value is an array',\n );\n if (Array.isArray(valuePos.value)) {\n if (valuePos.value.length > 0) {\n // If the array is non-empty base its type on its first\n // element\n return sqlConvertPluralLiteralArg(\n typeof valuePos.value[0] as PluralLiteralType,\n valuePos.value as PluralLiteralType[],\n );\n }\n // If the array is empty, base its type on the other value\n // position's type (as long as the other value position is non-null,\n // cannot have a null[]).\n if (otherValuePos.value !== null) {\n return sqlConvertPluralLiteralArg(\n typeof otherValuePos.value as PluralLiteralType,\n [],\n );\n }\n // If the other value position is null, it can be compared to any\n // type of empty array, chose 'string' arbitrarily.\n return sqlConvertPluralLiteralArg('string', []);\n }\n if (\n typeof valuePos.value === 'string' ||\n typeof valuePos.value === 'number' ||\n typeof valuePos.value === 'boolean'\n ) {\n return sqlConvertSingularLiteralArg(valuePos.value);\n }\n throw new Error(`Literal of unexpected type: ${typeof valuePos.value}`);\n }\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(otherType);\n }\n}\n\nexport function makeJunctionJoin(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): {\n join: SQLQuery;\n participatingTables: ReturnType<typeof pullTablesForJunction>;\n} {\n const participatingTables = pullTablesForJunction(spec, relationship);\n const joins: SQLQuery[] = [];\n\n for (const {table} of participatingTables) {\n if (joins.length === 0) {\n joins.push(fromIdent(spec.server, table));\n continue;\n }\n joins.push(\n sql` JOIN ${fromIdent(spec.server, table)} ON ${makeCorrelator(\n spec,\n participatingTables[joins.length].correlation.parentField.map(f => ({\n table: participatingTables[joins.length - 1].table,\n zql: f,\n })),\n participatingTables[joins.length].correlation.childField,\n )(participatingTables[joins.length].table)}`,\n );\n }\n\n return {\n join: sql`${sql.join(joins, '')}`,\n participatingTables,\n // lastTable: participatingTables[participatingTables.length - 1].table,\n // lastLimit: participatingTables[participatingTables.length - 1].limit,\n };\n}\n\nexport function pullTablesForJunction(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): [\n {\n table: Table;\n correlation: Correlation;\n limit: number | undefined;\n },\n {table: Table; correlation: Correlation; limit: number | undefined},\n] {\n assert(\n relationship.subquery.related?.length === 1,\n 'Too many related tables for a junction edge',\n );\n const otherRelationship = relationship.subquery.related[0];\n assert(\n !otherRelationship.hidden,\n 'Expected junction edge relationship to not be hidden',\n );\n return [\n {\n table: makeTable(spec, relationship.subquery.table),\n correlation: relationship.correlation,\n limit: relationship.subquery.limit,\n },\n {\n table: makeTable(spec, otherRelationship.subquery.table),\n correlation: otherRelationship.correlation,\n limit: otherRelationship.subquery.limit,\n },\n ];\n}\n\nfunction toJSON(table: string, singular = false): SQLQuery {\n return sql`${\n singular ? sql`` : sql`COALESCE(json_agg`\n }(row_to_json(${sql.ident(table)}))${singular ? sql`` : sql`, '[]'::json)`}`;\n}\n\nfunction selectIdent(server: ServerSpec, column: QualifiedColumn): SQLQuery {\n const serverColumnSchema =\n server.schema[server.mapper.tableName(column.table.zql)][\n server.mapper.columnName(column.table.zql, column.zql)\n ];\n const serverType = serverColumnSchema.type;\n if (!serverColumnSchema.isEnum) {\n let needsNormalization = false;\n switch (serverType) {\n case 'timetz':\n // @ts-expect-error Fallthrough intended\n case 'time with time zone':\n needsNormalization = true;\n // fallthrough\n\n case 'date':\n case 'time':\n case 'time without time zone':\n case 'timestamp':\n case 'timestamp without time zone':\n case 'timestamptz':\n case 'timestamp with time zone': {\n // EXTRACT(EPOCH FROM timetz) can be negative when the UTC offset is\n // positive (e.g. 01:00+02 = 23:00 UTC prev day = -3600s). Wrap with\n // modular arithmetic to normalize to 0..86400000.\n const toMs = (epochExpr: SQLQuery): SQLQuery =>\n needsNormalization\n ? sql`((${epochExpr})::bigint + 86400000) % 86400000`\n : epochExpr;\n\n if (serverColumnSchema.isArray) {\n const col = colIdent(server, column);\n return sql`CASE WHEN ${col} IS NULL THEN NULL ELSE ARRAY(SELECT ${toMs(\n sql`EXTRACT(EPOCH FROM unnest(${col})) * 1000`,\n )}) END as ${sql.ident(column.zql)}`;\n }\n\n return sql`${toMs(\n sql`EXTRACT(EPOCH FROM ${colIdent(server, column)}) * 1000`,\n )} as ${sql.ident(column.zql)}`;\n }\n }\n }\n\n return sql`${colIdent(server, column)} as ${sql.ident(column.zql)}`;\n}\n\nfunction colIdent(server: ServerSpec, column: QualifiedColumn) {\n return sql.ident(\n column.table.alias,\n server.mapper.columnName(column.table.zql, column.zql),\n );\n}\n\nfunction fromIdent(server: ServerSpec, table: Table) {\n return sql`${sql.ident(server.mapper.tableName(table.zql))} AS ${sql.ident(table.alias)}`;\n}\n\nfunction getServerColumn(spec: ServerSpec, table: Table, zqlColumn: string) {\n return spec.schema[spec.mapper.tableName(table.zql)][\n spec.mapper.columnName(table.zql, zqlColumn)\n ];\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nexport function extractZqlResult(pgResult: Array<any>): JSONValue {\n const bigIntJson: BigIntJSONValue = parseBigIntJson(\n pgResult[0][ZQL_RESULT_KEY],\n );\n assertJSONValue(bigIntJson);\n return bigIntJson;\n}\n\nfunction assertJSONValue(v: BigIntJSONValue): asserts v is JSONValue {\n const path = findPathToBigInt(v);\n if (path) {\n throw new Error(`Value exceeds safe Number range. ${path}`);\n }\n}\n\nfunction findPathToBigInt(v: BigIntJSONValue): string | undefined {\n const typeOfV = typeof v;\n switch (typeOfV) {\n case 'bigint':\n return ` = ${v}`;\n case 'object': {\n if (v === null) {\n return;\n }\n if (Array.isArray(v)) {\n for (let i = 0; i < v.length; i++) {\n const path = findPathToBigInt(v[i]);\n if (path) {\n return `[${i}]${path}`;\n }\n }\n return undefined;\n }\n\n const o = v as Record<string, BigIntJSONValue>;\n for (const k in o) {\n if (hasOwn(o, k)) {\n const path = findPathToBigInt(o[k]);\n if (path) {\n return `['${k}']${path}`;\n }\n }\n }\n return undefined;\n }\n case 'number':\n return undefined;\n case 'boolean':\n return undefined;\n default:\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compiler.js","names":["parseBigIntJson"],"sources":["../../../../z2s/src/compiler.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport {last, zip} from '../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n parse as parseBigIntJson,\n type JSONValue as BigIntJSONValue,\n} from '../../shared/src/bigint-json.ts';\nimport {hasOwn} from '../../shared/src/has-own.ts';\nimport {type JSONValue} from '../../shared/src/json.ts';\nimport {must} from '../../shared/src/must.ts';\nimport {isPgTextRepresentedType} from '../../zero-cache/src/types/pg-data-type.ts';\nimport {\n isLikeOperator,\n isNegatedOperator,\n jsonLiteralType,\n type Aggregate,\n type AST,\n type Bound,\n type Condition,\n type CorrelatedSubquery,\n type CorrelatedSubqueryCondition,\n type Correlation,\n type JsonPathReference,\n type LiteralReference,\n type Ordering,\n type SimpleCondition,\n type ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {\n clientToServer,\n type NameMapper,\n} from '../../zero-schema/src/name-mapper.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {ServerSchema} from '../../zero-types/src/server-schema.ts';\nimport {groupOrdering} from '../../zql/src/ivm/group-by.ts';\nimport type {Format} from '../../zql/src/ivm/view.ts';\nimport {completeOrdering} from '../../zql/src/query/complete-ordering.ts';\nimport {\n isBuiltinTypeSchema,\n pgTypeForLiteralType,\n sql,\n sqlConvertColumnArg,\n sqlConvertPluralLiteralArg,\n sqlConvertSingularLiteralArg,\n type PluralLiteralType,\n} from './sql.ts';\n\ntype Table = {\n zql: string;\n alias: string;\n};\n\ntype QualifiedColumn = {\n table: Table;\n zql: string;\n};\n\ntype ServerSpec = {\n schema: ServerSchema;\n // maps zql names to server names\n mapper: NameMapper;\n};\n\nexport type Spec = {\n server: ServerSpec;\n zql: Schema['tables'];\n aliasCount: number;\n};\n\nconst ZQL_RESULT_KEY = 'zql_result';\nconst ZQL_RESULT_KEY_IDENT = sql.ident(ZQL_RESULT_KEY);\n\nconst ZQL_RESULT_TABLE_KEY = 'zql_root';\nconst ZQL_RESULT_TABLE_IDENT = sql.ident(ZQL_RESULT_TABLE_KEY);\n\nexport function compile(\n serverSchema: ServerSchema,\n zqlSchema: Schema,\n ast: AST,\n format?: Format,\n): SQLQuery {\n assert(\n ast.groupBy === undefined || ast.aggregate?.distinct === undefined,\n 'a count of distinct values per group is not supported yet',\n );\n // The value would be selected under a group column's name. The query\n // builder rejects such a query; a hand-built AST can still name one.\n assert(\n ast.groupBy === undefined ||\n ast.aggregate === undefined ||\n !ast.groupBy.includes(ast.aggregate.fn),\n () =>\n `groupBy(): the column \"${ast.aggregate?.fn}\" has the same name as the ${ast.aggregate?.fn}() value`,\n );\n // As in the IVM builder: the rows are grouped in the group's order, not the\n // one a bound would be taken in.\n assert(\n (ast.groupBy === undefined && ast.aggregate?.distinct === undefined) ||\n (ast.start === undefined && ast.limit === undefined),\n 'groupBy and a count of distinct values do not support start or limit',\n );\n ast = completeOrdering(\n ast,\n tableName => zqlSchema.tables[tableName].primaryKey,\n );\n const spec: Spec = {\n aliasCount: 0,\n server: {\n schema: serverSchema,\n mapper: clientToServer(zqlSchema.tables),\n },\n zql: zqlSchema.tables,\n };\n if (ast.groupBy) {\n const groups = ast.aggregate\n ? selectGroups(spec, ast, ast.aggregate)\n : selectDistinct(spec, ast);\n return sql`SELECT ${toJSON(ZQL_RESULT_TABLE_KEY)}::text AS ${ZQL_RESULT_KEY_IDENT}\n FROM (${groups}) ${ZQL_RESULT_TABLE_IDENT}`;\n }\n\n if (ast.aggregate) {\n if (ast.aggregate.distinct) {\n // A count of the distinct combinations counts the rows a distinct()\n // of them gives.\n const groups = selectDistinct(spec, {\n ...ast,\n groupBy: ast.aggregate.distinct,\n aggregate: undefined,\n });\n return sql`SELECT to_json(COUNT(*))::text AS ${ZQL_RESULT_KEY_IDENT}\n FROM (${groups}) ${ZQL_RESULT_TABLE_IDENT}`;\n }\n // Top-level (ungrouped) aggregate: the result is a single scalar, not rows.\n // It reduces the same normalized projection a relationship aggregate does,\n // so values such as timestamps come back in the form ZQL uses. Like the\n // IVM operator, it reduces the rows left after `start`/`limit` and ignores\n // `related`. The order only matters for picking those rows.\n const bounded = ast.limit !== undefined || ast.start !== undefined;\n const inner = select(\n spec,\n {\n ...ast,\n aggregate: undefined,\n related: undefined,\n orderBy: bounded ? ast.orderBy : undefined,\n },\n undefined,\n );\n // An aggregate over no rows (other than COUNT) is SQL NULL, and to_json()\n // of NULL is NULL rather than the JSON text `null` the result parser reads.\n return sql`SELECT COALESCE(to_json(${aggregateExpr(spec, ast.table, ast.aggregate)}), 'null'::json)::text AS ${ZQL_RESULT_KEY_IDENT}\n FROM (${inner}) ${ZQL_RESULT_TABLE_IDENT}`;\n }\n\n return sql`SELECT \n ${toJSON(ZQL_RESULT_TABLE_KEY, format?.singular)}::text AS ${ZQL_RESULT_KEY_IDENT}\n FROM (${select(spec, ast, format)}) ${ZQL_RESULT_TABLE_IDENT}`;\n}\n\n/**\n * The groups of `ast.groupBy` among the rows that pass `ast.where`, each with\n * the aggregate under the function's name (`count`, `sum`, …), in the order a\n * grouped query's rows have (see `groupOrdering`). Like a top-level\n * aggregate, it reduces the normalized projection {@link select} gives, so a\n * timestamp comes back in epoch milliseconds, and groups by those values.\n */\nfunction selectGroups(spec: Spec, ast: AST, agg: Aggregate): SQLQuery {\n const inner = select(\n spec,\n {\n ...ast,\n groupBy: undefined,\n aggregate: undefined,\n related: undefined,\n orderBy: undefined,\n },\n undefined,\n );\n const cols = must(ast.groupBy).map(col => sql.ident(col));\n return sql`SELECT ${sql.join(cols, ',')}, ${aggregateExpr(spec, ast.table, agg)} AS ${sql.ident(agg.fn)}\n FROM (${inner}) ${sql.ident('zql_group')}\n GROUP BY ${sql.join(cols, ', ')}\n ORDER BY ${sql.join(\n groupOrdering(ast).map(([col, dir]) => {\n const value = orderedValue(spec, ast.table, col, sql.ident(col));\n return dir === 'asc'\n ? sql`${value} ASC NULLS FIRST`\n : sql`${value} DESC NULLS LAST`;\n }),\n ', ',\n )}`;\n}\n\n/**\n * The distinct values of `ast.groupBy` among the rows that pass `ast.where`,\n * one row of those columns each, in the order a distinct query's rows have\n * (see `groupOrdering`). It groups by the columns rather than selecting\n * DISTINCT, which would need the converted values {@link selectIdent} selects\n * to appear in the ORDER BY too. Like the IVM operator, it ignores `related`.\n */\nfunction selectDistinct(spec: Spec, ast: AST): SQLQuery {\n const table = makeTable(spec, ast.table);\n const columns = must(ast.groupBy).map(zql => ({table, zql}));\n return sql`SELECT ${sql.join(\n columns.map(c => selectIdent(spec.server, c)),\n ',',\n )}\n FROM ${fromIdent(spec.server, table)}\n ${ast.where ? sql`WHERE ${where(spec, ast.where, table)}` : sql``}\n GROUP BY ${sql.join(\n columns.map(c => colIdent(spec.server, c)),\n ', ',\n )}\n ORDER BY ${sql.join(\n groupOrdering(ast).map(([col, dir]) => {\n const value = orderedValue(\n spec,\n ast.table,\n col,\n colIdent(spec.server, {table, zql: col}),\n );\n return dir === 'asc'\n ? sql`${value} ASC NULLS FIRST`\n : sql`${value} DESC NULLS LAST`;\n }),\n ', ',\n )}`;\n}\n\n/**\n * The SQL aggregate for `aggregate`, over a subquery that exposes the\n * aggregated column by its client name (as {@link select} does).\n *\n * `COUNT(*)` is left as Postgres's 64-bit count: the result parser rejects a\n * value outside the safe integer range rather than rounding it.\n *\n * `SUM`/`AVG` add the values as float8, as the IVM operator adds JS numbers:\n * Postgres would otherwise sum a `real` in float4 and a `numeric` exactly.\n *\n * `MIN`/`MAX` of an enum, or of a type Zero represents as text (`uuid`,\n * `inet`, …), compare that text byte by byte, as the IVM operator compares\n * strings. Otherwise an enum would use its declaration order, an `inet` its\n * network order, and a `uuid` would fail (it has no `MIN`).\n */\nfunction aggregateExpr(spec: Spec, zqlTable: string, agg: Aggregate): SQLQuery {\n assert(\n agg.distinct === undefined,\n 'a count of distinct values is not supported in a relationship yet',\n );\n const {fn, field, path} = agg;\n if (path !== undefined) {\n return jsonAggregateExpr(spec, zqlTable, agg, path);\n }\n switch (fn) {\n case 'count':\n return sql`COUNT(*)`;\n case 'sum':\n return sql`SUM(${sql.ident(must(field))}::float8)`;\n case 'avg':\n return sql`AVG(${sql.ident(must(field))}::float8)`;\n case 'min':\n return sql`MIN(${orderedAggregateArg(spec, zqlTable, must(field))})`;\n case 'max':\n return sql`MAX(${orderedAggregateArg(spec, zqlTable, must(field))})`;\n default:\n unreachable(fn);\n }\n}\n\n/**\n * The SQL aggregate over the JSON leaf at `path` inside the (client-named)\n * json column `field` of the subquery. Only leaves the aggregate takes count\n * (see `aggregateValue`): numbers for `sum`/`avg`, numbers and strings for\n * `min`/`max`, each gated on `jsonb_typeof` so a mismatched leaf is SQL NULL\n * (skipped) rather than a cast error.\n *\n * `min`/`max` reduce numbers and strings separately and combine them with the\n * client's cross-type order, numbers before strings (`compareAggregateValues`),\n * instead of Postgres's jsonb order, which puts strings first. The result is\n * jsonb so either type comes back as itself.\n */\nfunction jsonAggregateExpr(\n spec: Spec,\n zqlTable: string,\n {fn, field}: Aggregate,\n path: readonly (string | number)[],\n): SQLQuery {\n const name = must(field);\n const {type, isArray} = getServerColumn(\n spec.server,\n {zql: zqlTable, alias: zqlTable},\n name,\n );\n assert(\n isArray || type === 'json' || type === 'jsonb',\n () => `JSON path on non-JSON column \"${name}\" of type ${type}`,\n );\n const {raw, jsonType} = jsonNavigate(\n jsonBase(sql.ident(name), type, isArray),\n path,\n );\n const num = sql`(CASE WHEN ${jsonType} = 'number' THEN ${raw}::float8 END)`;\n const str = sql`(CASE WHEN ${jsonType} = 'string' THEN ${raw} END)`;\n switch (fn) {\n case 'sum':\n return sql`SUM(${num})::float8`;\n case 'avg':\n return sql`AVG(${num})::float8`;\n case 'min':\n return sql`COALESCE(to_jsonb(MIN(${num})), to_jsonb(MIN(${str})))`;\n case 'max':\n return sql`COALESCE(to_jsonb(MAX(${str})), to_jsonb(MAX(${num})))`;\n case 'count':\n throw new Error('count() takes no JSON path');\n default:\n unreachable(fn);\n }\n}\n\nfunction orderedAggregateArg(\n spec: Spec,\n zqlTable: string,\n field: string,\n): SQLQuery {\n return orderedValue(spec, zqlTable, field, sql.ident(field));\n}\n\n/**\n * `value`, the value of `zqlTable`'s column `field`, in a form Postgres\n * orders as the IVM does: an enum, or a type Zero represents as text, by that\n * text byte by byte. Otherwise an enum would use its declaration order and an\n * `inet` its network order.\n */\nfunction orderedValue(\n spec: Spec,\n zqlTable: string,\n field: string,\n value: SQLQuery,\n): SQLQuery {\n const {server} = spec;\n const column =\n server.schema[server.mapper.tableName(zqlTable)][\n server.mapper.columnName(zqlTable, field)\n ];\n // `format` gives the type's own text: `::text` adds the netmask to an `inet`.\n return column.isEnum || isPgTextRepresentedType(column.type)\n ? sql`format('%s', ${value}) COLLATE \"C\"`\n : value;\n}\n\nfunction select(\n spec: Spec,\n ast: AST,\n format: Format | undefined,\n correlate?: (childTable: Table) => SQLQuery,\n): SQLQuery {\n const table = makeTable(spec, ast.table);\n const selectionSet = related(spec, ast.related ?? [], format, table);\n const tableSchema = spec.zql[ast.table];\n const usedAliases = new Set<string>(\n ast.related?.map(r => r.subquery.alias ?? ''),\n );\n for (const column of Object.keys(tableSchema.columns)) {\n if (!usedAliases.has(column)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table,\n zql: column,\n }),\n );\n }\n }\n\n let appliedWhere = false;\n function maybeWhere(test: unknown) {\n if (!test) {\n return sql``;\n }\n\n const ret = appliedWhere ? sql`AND` : sql`WHERE`;\n appliedWhere = true;\n return ret;\n }\n\n return sql`SELECT ${sql.join(selectionSet, ',')}\n FROM ${fromIdent(spec.server, table)}\n ${maybeWhere(ast.where)} ${where(spec, ast.where, table)}${\n ast.start\n ? sql`\n ${maybeWhere(ast.start)} ${start(spec, ast.start, ast.orderBy, table)}`\n : sql``\n }\n ${maybeWhere(correlate)} ${correlate ? correlate(table) : sql``}\n ${orderBy(spec, ast.orderBy, table)}\n ${limit(ast.limit, format?.singular)}`;\n}\n\nexport function limit(\n limit: number | undefined,\n singular: boolean | undefined,\n): SQLQuery {\n if (limit === 0) {\n return sql`LIMIT 0`;\n }\n if (singular) {\n return sql`LIMIT 1`;\n }\n if (limit === undefined) {\n return sql``;\n }\n return sql`LIMIT ${sqlConvertSingularLiteralArg(limit)}`;\n}\n\nfunction makeTable(spec: Spec, zql: string, alias?: string): Table {\n alias = alias ?? zql + '_' + spec.aliasCount++;\n return {\n zql,\n alias,\n };\n}\n\nexport function orderBy(\n spec: Spec,\n orderBy: Ordering | undefined,\n table: Table,\n): SQLQuery {\n if (!orderBy) {\n return sql``;\n }\n return sql`ORDER BY ${sql.join(\n orderBy.map(([col, dir]) =>\n dir === 'asc'\n ? // Oh postgres. The table must be referred to by client name but the column by server name.\n // E.g., `SELECT server_col as client_col FROM server_table as client_table ORDER BY client_Table.server_col`\n sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} ASC NULLS FIRST`\n : sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} DESC NULLS LAST`,\n ),\n ', ',\n )}`;\n}\n\nexport function start(\n spec: Spec,\n bound: Bound | undefined,\n orderBy: Ordering | undefined,\n table: Table,\n): SQLQuery {\n if (!bound) {\n return sql``;\n }\n assert(\n orderBy !== undefined && orderBy.length > 0,\n 'start requires ordering',\n );\n\n const constraints: SQLQuery[] = [];\n for (let i = 0; i < orderBy.length; i++) {\n const group: SQLQuery[] = [];\n const [iField, iDirection] = orderBy[i];\n for (let j = 0; j <= i; j++) {\n const [field] = orderBy[j];\n if (j === i) {\n group.push(\n startRangeComparison(\n spec,\n table,\n iField,\n bound.row[iField] ?? null,\n iDirection === 'asc' ? '>' : '<',\n ),\n );\n } else {\n group.push(startEquality(spec, table, field, bound.row[field] ?? null));\n }\n }\n constraints.push(sql`(${sql.join(group, ' AND ')})`);\n }\n\n if (!bound.exclusive) {\n constraints.push(\n sql`(${sql.join(\n orderBy.map(([field]) =>\n startEquality(spec, table, field, bound.row[field] ?? null),\n ),\n ' AND ',\n )})`,\n );\n }\n\n return sql`(${sql.join(constraints, ' OR ')})`;\n}\n\nfunction related(\n spec: Spec,\n relationships: readonly CorrelatedSubquery[],\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery[] {\n return relationships.map(relationship =>\n relationshipSubquery(\n spec,\n relationship,\n format?.relationships[must(relationship.subquery.alias)],\n parentTable,\n ),\n );\n}\n\nfunction relationshipSubquery(\n spec: Spec,\n relationship: CorrelatedSubquery,\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery {\n const innerAlias = `inner_${relationship.subquery.alias}`;\n if (relationship.aggregate) {\n // Aggregate relationship: emit a correlated scalar subquery returning the\n // aggregate over the matching child rows, instead of aggregating the rows\n // to JSON. No rows are materialized. The inner subquery exposes columns by\n // their client names, so the aggregated field is referenced as-is.\n const {field} = relationship.aggregate;\n const isJunction = !!relationship.subquery.related?.length;\n const aggExpr = aggregateExpr(\n spec,\n isJunction\n ? must(relationship.subquery.related)[0].subquery.table\n : relationship.subquery.table,\n relationship.aggregate,\n );\n\n let inner: SQLQuery;\n if (isJunction) {\n // Junction (many-to-many) aggregate: the value lives on the destination,\n // one hop past the junction. Aggregate over the junction join, exposing\n // the destination field by its client name so `aggExpr` references it. A\n // `where` on the destination filters the joined rows before aggregating.\n const {join, participatingTables} = makeJunctionJoin(spec, relationship);\n const lastTable = must(last(participatingTables)).table;\n const destWhere = relationship.subquery.related[0].subquery.where;\n inner = sql`SELECT ${\n field\n ? selectIdent(spec.server, {table: lastTable, zql: field})\n : sql`NULL`\n } FROM ${join} WHERE (${makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n )(participatingTables[0].table)})${\n destWhere ? sql` AND (${where(spec, destWhere, lastTable)})` : sql``\n }`;\n } else {\n // As for a top-level aggregate, the order only matters for picking the\n // rows a `limit`/`start` keeps; otherwise it is a needless sort per parent.\n const {subquery} = relationship;\n const bounded =\n subquery.limit !== undefined || subquery.start !== undefined;\n inner = select(\n spec,\n bounded ? subquery : {...subquery, orderBy: undefined},\n undefined,\n makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n ),\n );\n }\n return sql`(\n SELECT ${aggExpr} FROM (${inner}) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n }\n if (relationship.hidden) {\n const {join, participatingTables} = makeJunctionJoin(spec, relationship);\n const lastTable = must(last(participatingTables)).table;\n\n assert(\n relationship.subquery.related,\n 'hidden relationship must be a junction',\n );\n const nestedAst = relationship.subquery.related[0].subquery;\n const selectionSet = related(\n spec,\n nestedAst.related ?? [],\n format,\n lastTable,\n );\n const tableSchema = spec.zql[nestedAst.table];\n for (const column of Object.keys(tableSchema.columns)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table: lastTable,\n zql: column,\n }),\n );\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (SELECT ${sql.join(\n selectionSet,\n ',',\n )} FROM ${join} WHERE (${makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n )(participatingTables[0].table)}) ${\n nestedAst.where\n ? sql`AND ${where(spec, nestedAst.where, lastTable)}`\n : sql``\n }${\n nestedAst.start\n ? sql` AND ${start(\n spec,\n nestedAst.start,\n nestedAst.orderBy,\n lastTable,\n )}`\n : sql``\n } ${orderBy(spec, nestedAst.orderBy, lastTable)} ${limit(\n last(participatingTables)?.limit,\n format?.singular,\n )} ) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (${select(\n spec,\n relationship.subquery,\n format,\n makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n ),\n )}) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n}\n\nfunction where(\n spec: Spec,\n condition: Condition | undefined,\n table: Table,\n): SQLQuery {\n if (!condition) {\n return sql``;\n }\n\n switch (condition.type) {\n case 'and':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' AND ',\n )})`;\n case 'or':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' OR ',\n )})`;\n case 'correlatedSubquery':\n // `scalar` is deliberately ignored here. It is a planner hint for the\n // IVM engines, which have no cost-based planner and benefit from\n // pre-resolving an at-most-one-row subquery to a literal comparison\n // (see zqlite's `resolveSimpleScalarSubqueries`). Postgres decorrelates\n // EXISTS into a semi-join on its own, so the hint buys nothing here —\n // and honoring it as `parentField = (SELECT childField … LIMIT 1)` is\n // only sound when the subquery matches at most one row *globally*.\n // Applying it unconditionally silently dropped rows whenever the\n // subquery was not pinned to a unique key.\n return exists(spec, condition, table);\n case 'simple':\n return simple(spec, condition, table);\n }\n}\n\nfunction exists(\n spec: Spec,\n condition: CorrelatedSubqueryCondition,\n parentTable: Table,\n): SQLQuery {\n switch (condition.op) {\n case 'EXISTS':\n return sql`EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n case 'NOT EXISTS':\n return sql`NOT EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n }\n}\n\nexport function makeCorrelator(\n spec: Spec,\n parentFields: readonly QualifiedColumn[],\n childZqlFields: readonly string[],\n): (childTable: Table) => SQLQuery {\n return (childTable: Table) => {\n const childFields = childZqlFields.map(zqlField => ({\n table: childTable,\n zql: zqlField,\n }));\n return sql.join(\n zip(parentFields, childFields).map(\n ([parentColumn, childColumn]) =>\n sql`${colIdent(spec.server, parentColumn)} = ${colIdent(\n spec.server,\n childColumn,\n )}`,\n ),\n ' AND ',\n );\n };\n}\n\nexport function simple(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n if (condition.left.type === 'json') {\n const special = jsonPathCondition(spec, condition.left, condition, table);\n if (special) {\n return special;\n }\n }\n switch (condition.op) {\n case 'ILIKE':\n case 'LIKE':\n case 'NOT ILIKE':\n case 'NOT LIKE': {\n // The pattern is a string, not a value of the column's type. Converted\n // to the `bpchar` of a `char(n)` column it would lose its trailing\n // spaces. Like ZQL's own LIKE, non-string patterns match as strings.\n const {right} = condition;\n assert(\n right.type === 'literal',\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n return sql`${valueComparison(\n spec,\n condition.left,\n table,\n right,\n false,\n )} ${sql.__dangerous__rawValue(condition.op)} ${sqlConvertSingularLiteralArg(\n right.value === null ? null : String(right.value),\n )}`;\n }\n case '!=':\n case '<':\n case '<=':\n case '=':\n case '>':\n case '>=':\n return sql`${valueComparison(\n spec,\n condition.left,\n table,\n condition.right,\n false,\n )} ${sql.__dangerous__rawValue(condition.op)} ${valueComparison(\n spec,\n condition.right,\n table,\n condition.left,\n false,\n )}`;\n case 'NOT IN':\n case 'IN':\n return any(spec, condition, table);\n case 'IS':\n case 'IS NOT':\n return distinctFrom(spec, condition, table);\n }\n}\n\nexport function any(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${condition.op === 'NOT IN' ? sql`NOT` : sql``}\n (\n ${valueComparison(spec, condition.left, table, condition.right, false)} = ANY \n (${valueComparison(spec, condition.right, table, condition.left, true)})\n )`;\n}\n\nexport function distinctFrom(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${valueComparison(spec, condition.left, table, condition.right, false)} ${\n condition.op === 'IS' ? sql`IS NOT DISTINCT FROM` : sql`IS DISTINCT FROM`\n } ${valueComparison(spec, condition.right, table, condition.left, false)}`;\n}\n\nfunction startEquality(\n spec: Spec,\n table: Table,\n field: string,\n value: unknown,\n): SQLQuery {\n return sql`${colIdent(spec.server, {\n table,\n zql: field,\n })} IS NOT DISTINCT FROM ${startValue(spec, table, field, value)}`;\n}\n\nfunction startRangeComparison(\n spec: Spec,\n table: Table,\n field: string,\n value: unknown,\n operator: '>' | '<',\n): SQLQuery {\n const column = colIdent(spec.server, {table, zql: field});\n if (value === null) {\n return operator === '>' ? sql`${column} IS NOT NULL` : sql`FALSE`;\n }\n const typedValue = startValue(spec, table, field, value);\n return operator === '>'\n ? sql`${column} > ${typedValue}`\n : sql`(${column} IS NULL OR ${column} < ${typedValue})`;\n}\n\nfunction startValue(\n spec: Spec,\n table: Table,\n field: string,\n value: unknown,\n): SQLQuery {\n return sqlConvertColumnArg(\n getServerColumn(spec.server, table, field),\n value,\n false,\n true,\n );\n}\n\nfunction valueComparison(\n spec: Spec,\n valuePos: ValuePosition,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const valuePosType = valuePos.type;\n switch (valuePosType) {\n case 'column': {\n const qualified: QualifiedColumn = {\n table,\n zql: valuePos.name,\n };\n return colIdent(spec.server, qualified);\n }\n case 'json':\n return jsonPathLeaf(spec, valuePos, table, otherValuePos);\n case 'literal':\n return literalValueComparison(\n spec,\n valuePos,\n table,\n otherValuePos,\n plural,\n );\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(valuePosType);\n }\n}\n\nfunction literalValueComparison(\n spec: Spec,\n valuePos: LiteralReference,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const otherType = otherValuePos.type;\n switch (otherType) {\n case 'column':\n return sqlConvertColumnArg(\n getServerColumn(spec.server, table, otherValuePos.name),\n valuePos.value,\n plural,\n true,\n );\n case 'json': {\n // The other side is a JSON path leaf, which is dynamically typed. Render\n // this literal by its OWN JS type so its cast matches the leaf's cast in\n // `jsonPathLeaf` (`leafType`). LiteralValue is primitives or a\n // homogeneous primitive list (enforced at the wire and by the builder).\n assert(\n plural === Array.isArray(valuePos.value),\n 'Expected plural flag to match whether value is an array',\n );\n const {value} = valuePos;\n if (Array.isArray(value)) {\n return sqlConvertPluralLiteralArg(\n jsonLiteralType(value) ?? 'string',\n value as PluralLiteralType[],\n );\n }\n // `Array.isArray` does not narrow a `readonly` array out of the union.\n return sqlConvertSingularLiteralArg(\n value as string | number | boolean | null,\n );\n }\n case 'literal': {\n assert(\n plural === Array.isArray(valuePos.value),\n 'Expected plural flag to match whether value is an array',\n );\n if (Array.isArray(valuePos.value)) {\n if (valuePos.value.length > 0) {\n // If the array is non-empty base its type on its first\n // element\n return sqlConvertPluralLiteralArg(\n typeof valuePos.value[0] as PluralLiteralType,\n valuePos.value as PluralLiteralType[],\n );\n }\n // If the array is empty, base its type on the other value\n // position's type (as long as the other value position is non-null,\n // cannot have a null[]).\n if (otherValuePos.value !== null) {\n return sqlConvertPluralLiteralArg(\n typeof otherValuePos.value as PluralLiteralType,\n [],\n );\n }\n // If the other value position is null, it can be compared to any\n // type of empty array, chose 'string' arbitrarily.\n return sqlConvertPluralLiteralArg('string', []);\n }\n if (\n typeof valuePos.value === 'string' ||\n typeof valuePos.value === 'number' ||\n typeof valuePos.value === 'boolean'\n ) {\n return sqlConvertSingularLiteralArg(valuePos.value);\n }\n throw new Error(`Literal of unexpected type: ${typeof valuePos.value}`);\n }\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(otherType);\n }\n}\n\n/**\n * The two SQL pieces every JSON path comparison is built from: the leaf's text\n * (`raw`, SQL NULL for a missing key or a JSON null) and its JSON type\n * (`jsonType`, via `jsonb_typeof`).\n *\n * Navigation chains `->` with a *typed* operand per segment (a text operand\n * for an object key, an integer operand for an array index), so Postgres\n * applies the same strict rule as the in-memory reader and SQLite: a string\n * segment never indexes an array and a number never reads an object key. (A\n * `#>>` text[] path would instead resolve a digit string by the container's\n * runtime type, including `'-1'` from the end.) The last step uses `->>` for\n * the text form.\n *\n * The base is the column as jsonb: a `json` column is cast, and a Postgres\n * array column (which zero maps to a `json()` column and the replica stores\n * as JSON text) is converted with `to_jsonb`.\n */\nfunction jsonPathParts(\n spec: Spec,\n ref: JsonPathReference,\n table: Table,\n): {value: SQLQuery; raw: SQLQuery; jsonType: SQLQuery} {\n const {name} = ref.value;\n const col = colIdent(spec.server, {table, zql: name});\n const {type, isArray} = getServerColumn(spec.server, table, name);\n assert(\n isArray || type === 'json' || type === 'jsonb',\n () => `JSON path on non-JSON column \"${name}\" of type ${type}`,\n );\n return jsonNavigate(jsonBase(col, type, isArray), ref.path);\n}\n\n/** A json/jsonb/array column (or an expression of one) as jsonb. */\nfunction jsonBase(col: SQLQuery, type: string, isArray: boolean): SQLQuery {\n return isArray\n ? sql`to_jsonb(${col})`\n : type === 'json'\n ? sql`${col}::jsonb`\n : col;\n}\n\n/** Navigates `path` from the jsonb `base`; see {@link jsonPathParts}. */\nfunction jsonNavigate(\n base: SQLQuery,\n path: readonly (string | number)[],\n): {value: SQLQuery; raw: SQLQuery; jsonType: SQLQuery} {\n let obj = base;\n const operand = (seg: string | number): SQLQuery =>\n typeof seg === 'number'\n ? // A validated non-negative int32 (see isValidJsonPathIndex), so it is\n // safe to inline; `->` needs an integer operand to index an array.\n sql.__dangerous__rawValue(String(seg))\n : sqlConvertSingularLiteralArg(seg);\n const last = path.length - 1;\n for (let i = 0; i < last; i++) {\n obj = sql`(${obj} -> ${operand(path[i])})`;\n }\n const leaf = operand(path[last]);\n return {\n // The leaf as jsonb; `raw` is its text form.\n value: sql`(${obj} -> ${leaf})`,\n raw: sql`(${obj} ->> ${leaf})`,\n jsonType: sql`jsonb_typeof(${obj} -> ${leaf})`,\n };\n}\n\n/**\n * The JS type the leaf must have to be compared against the literal on the\n * other side (`jsonLiteralType`, shared across engines). It is also the\n * `jsonb_typeof` name and the key into `pgTypeForLiteralType` for the cast, so\n * the leaf's cast and the literal's own cast cannot drift. `undefined` for a\n * `null` literal (`IS NULL`: a missing key and a JSON null must both read as\n * SQL NULL), an empty list, or a non-literal.\n */\nfunction leafType(other: ValuePosition): PluralLiteralType | undefined {\n return other.type === 'literal' ? jsonLiteralType(other.value) : undefined;\n}\n\n/**\n * Compiles a JSON path reference to its text form, cast to the comparison type\n * derived from the literal on the other side (`leafType`) so it lines up with\n * that literal's own cast.\n *\n * `->>` maps **both** a missing key and a JSON `null` to SQL `NULL`, matching\n * the SQLite `json_extract` pushdown and the in-memory predicate, so `IS NULL`\n * agrees across all three.\n *\n * The cast is gated on the leaf's JSON type (`CASE WHEN jsonb_typeof(...)`), so a\n * leaf of a different type than the literal is SQL NULL, i.e. a non-match. This\n * is the type-strict comparison documented on {@link JsonPathReference}: `->>`\n * renders a numeric `42` as the text `'42'`, so an ungated text comparison\n * would wrongly match it against the string `'42'`. For `number`/`boolean` the\n * gate is also what keeps the cast from throwing: Postgres errors when casting\n * non-conforming text (a string `\"n/a\"`, an object's JSON text) to\n * `double precision`/`boolean`, which would fail the whole query on one\n * mismatched row. Negated operators need a different form; see\n * `jsonPathCondition`.\n */\nfunction jsonPathLeaf(\n spec: Spec,\n ref: JsonPathReference,\n table: Table,\n other: ValuePosition,\n): SQLQuery {\n const {raw, jsonType} = jsonPathParts(spec, ref, table);\n const t = leafType(other);\n if (t === undefined) {\n return raw;\n }\n return sql`(CASE WHEN ${jsonType} = ${sqlConvertSingularLiteralArg(\n t,\n )} THEN ${raw}::${sql.__dangerous__rawValue(pgTypeForLiteralType(t))} END)`;\n}\n\n/**\n * The comparisons on a JSON path left operand that cannot go through the\n * generic operator rendering with the gated leaf (`jsonPathLeaf`); returns\n * `undefined` for the ones that can.\n *\n * - `IN`/`NOT IN` with a `null` literal is constant-false, as in the\n * in-memory predicate (the generic forms would assert, or match every\n * non-null leaf).\n * - `=`/`IN` against a string or boolean literal compare the leaf *as jsonb*:\n * jsonb equality is type-strict by itself (`\"42\"` never equals `42`, a JSON\n * `null` never equals a string) and a missing key is SQL NULL, so the\n * `jsonb_typeof` gate is unnecessary. Without the `CASE` around the\n * extraction, an expression index on `(col -> 'key')` can serve the\n * predicate. Numbers keep the gated `double precision` form: jsonb compares\n * numbers exactly (`numeric`), which would diverge from the client's and\n * SQLite's IEEE-754 equality above 2^53 or beyond double precision.\n * - An empty `NOT IN` list matches every non-null leaf: SQL's\n * `NOT (x = ANY('{}'))` is TRUE even for a NULL leaf, whereas the\n * predicate's null guard excludes it.\n * - The LIKE family compares text, so the leaf must be a string whatever the\n * literal's type, and the pattern is the literal's text form, as in the\n * in-memory predicate (`String(pattern)`) and SQLite. Deriving the leaf type\n * from a numeric or boolean literal instead would cast the leaf to\n * `double precision`/`boolean` and hand Postgres a LIKE it cannot execute.\n * - The negated operators (`!=`, `NOT LIKE`, `NOT ILIKE`, `NOT IN`): the gate\n * makes a mismatched leaf SQL NULL, which a positive comparison correctly\n * excludes. But NULL also excludes under a negated operator, where a\n * mismatch must *match* (JS `42 !== '42'` is true). `jsonb_typeof` is NULL\n * for a missing key and `'null'` for a JSON null, so one `COALESCE` covers\n * the null guard without a second extraction: a null/missing leaf is\n * false, the same type is the real (negated) comparison, another type is\n * true.\n */\nfunction jsonPathCondition(\n spec: Spec,\n left: JsonPathReference,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery | undefined {\n const {op} = condition;\n let {right} = condition;\n if (\n (op === 'IN' || op === 'NOT IN') &&\n right.type === 'literal' &&\n right.value === null\n ) {\n return sql`false`;\n }\n if (\n isLikeOperator(op) &&\n right.type === 'literal' &&\n right.value !== null &&\n !Array.isArray(right.value)\n ) {\n right = {type: 'literal', value: String(right.value)};\n if (!isNegatedOperator(op)) {\n return sql`${valueComparison(\n spec,\n left,\n table,\n right,\n false,\n )} ${sql.__dangerous__rawValue(op)} ${valueComparison(\n spec,\n right,\n table,\n left,\n false,\n )}`;\n }\n }\n if ((op === '=' || op === 'IN') && right.type === 'literal') {\n const t = leafType(right);\n if (t === 'string' || t === 'boolean') {\n const {value} = jsonPathParts(spec, left, table);\n const lit = valueComparison(spec, right, table, left, op === 'IN');\n return op === 'IN'\n ? sql`${value} = ANY (ARRAY(SELECT to_jsonb(v) FROM unnest(${lit}) AS v))`\n : sql`${value} = to_jsonb(${lit})`;\n }\n }\n // A non-literal (an unbound static parameter) falls through to the generic\n // rendering, which rejects it; it must not be mistaken for an empty list.\n if (!isNegatedOperator(op) || right.type !== 'literal') {\n return undefined;\n }\n const t = leafType(right);\n const {raw, jsonType} = jsonPathParts(spec, left, table);\n if (t === undefined) {\n // Only an empty NOT IN list reaches here: `!=`/`NOT LIKE` against null\n // are constant-false through the generic NULL comparison.\n return op === 'NOT IN' ? sql`${raw} IS NOT NULL` : undefined;\n }\n const leaf = sql`${raw}::${sql.__dangerous__rawValue(pgTypeForLiteralType(t))}`;\n const plural = op === 'NOT IN';\n const lit = valueComparison(spec, right, table, left, plural);\n const cmp = plural\n ? sql`NOT (${leaf} = ANY (${lit}))`\n : sql`${leaf} ${sql.__dangerous__rawValue(op)} ${lit}`;\n return sql`(CASE COALESCE(${jsonType}, 'null') WHEN 'null' THEN false WHEN ${sqlConvertSingularLiteralArg(\n t,\n )} THEN ${cmp} ELSE true END)`;\n}\n\nexport function makeJunctionJoin(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): {\n join: SQLQuery;\n participatingTables: ReturnType<typeof pullTablesForJunction>;\n} {\n const participatingTables = pullTablesForJunction(spec, relationship);\n const joins: SQLQuery[] = [];\n\n for (const {table} of participatingTables) {\n if (joins.length === 0) {\n joins.push(fromIdent(spec.server, table));\n continue;\n }\n joins.push(\n sql` JOIN ${fromIdent(spec.server, table)} ON ${makeCorrelator(\n spec,\n participatingTables[joins.length].correlation.parentField.map(f => ({\n table: participatingTables[joins.length - 1].table,\n zql: f,\n })),\n participatingTables[joins.length].correlation.childField,\n )(participatingTables[joins.length].table)}`,\n );\n }\n\n return {\n join: sql`${sql.join(joins, '')}`,\n participatingTables,\n // lastTable: participatingTables[participatingTables.length - 1].table,\n // lastLimit: participatingTables[participatingTables.length - 1].limit,\n };\n}\n\nexport function pullTablesForJunction(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): [\n {\n table: Table;\n correlation: Correlation;\n limit: number | undefined;\n },\n {table: Table; correlation: Correlation; limit: number | undefined},\n] {\n assert(\n relationship.subquery.related?.length === 1,\n 'Too many related tables for a junction edge',\n );\n const otherRelationship = relationship.subquery.related[0];\n assert(\n !otherRelationship.hidden,\n 'Expected junction edge relationship to not be hidden',\n );\n return [\n {\n table: makeTable(spec, relationship.subquery.table),\n correlation: relationship.correlation,\n limit: relationship.subquery.limit,\n },\n {\n table: makeTable(spec, otherRelationship.subquery.table),\n correlation: otherRelationship.correlation,\n limit: otherRelationship.subquery.limit,\n },\n ];\n}\n\nfunction toJSON(table: string, singular = false): SQLQuery {\n return sql`${\n singular ? sql`` : sql`COALESCE(json_agg`\n }(row_to_json(${sql.ident(table)}))${singular ? sql`` : sql`, '[]'::json)`}`;\n}\n\nfunction selectIdent(server: ServerSpec, column: QualifiedColumn): SQLQuery {\n const serverColumnSchema =\n server.schema[server.mapper.tableName(column.table.zql)][\n server.mapper.columnName(column.table.zql, column.zql)\n ];\n const serverType = serverColumnSchema.type;\n // A user-defined type can have a built-in name such as `timestamp`; only\n // convert the values of the built-in types.\n if (\n !serverColumnSchema.isEnum &&\n isBuiltinTypeSchema(serverColumnSchema.typeSchema)\n ) {\n let needsNormalization = false;\n switch (serverType) {\n case 'timetz':\n // @ts-expect-error Fallthrough intended\n case 'time with time zone':\n needsNormalization = true;\n // fallthrough\n\n case 'date':\n case 'time':\n case 'time without time zone':\n case 'timestamp':\n case 'timestamp without time zone':\n case 'timestamptz':\n case 'timestamp with time zone': {\n // EXTRACT(EPOCH FROM timetz) can be negative when the UTC offset is\n // positive (e.g. 01:00+02 = 23:00 UTC prev day = -3600s). Wrap with\n // modular arithmetic to normalize to 0..86400000.\n const toMs = (epochExpr: SQLQuery): SQLQuery =>\n needsNormalization\n ? sql`((${epochExpr})::bigint + 86400000) % 86400000`\n : epochExpr;\n\n if (serverColumnSchema.isArray) {\n const col = colIdent(server, column);\n return sql`CASE WHEN ${col} IS NULL THEN NULL ELSE ARRAY(SELECT ${toMs(\n sql`EXTRACT(EPOCH FROM unnest(${col})) * 1000`,\n )}) END as ${sql.ident(column.zql)}`;\n }\n\n return sql`${toMs(\n sql`EXTRACT(EPOCH FROM ${colIdent(server, column)}) * 1000`,\n )} as ${sql.ident(column.zql)}`;\n }\n }\n }\n\n return sql`${colIdent(server, column)} as ${sql.ident(column.zql)}`;\n}\n\nfunction colIdent(server: ServerSpec, column: QualifiedColumn) {\n return sql.ident(\n column.table.alias,\n server.mapper.columnName(column.table.zql, column.zql),\n );\n}\n\nfunction fromIdent(server: ServerSpec, table: Table) {\n return sql`${sql.ident(server.mapper.tableName(table.zql))} AS ${sql.ident(table.alias)}`;\n}\n\nfunction getServerColumn(spec: ServerSpec, table: Table, zqlColumn: string) {\n return spec.schema[spec.mapper.tableName(table.zql)][\n spec.mapper.columnName(table.zql, zqlColumn)\n ];\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nexport function extractZqlResult(pgResult: Array<any>): JSONValue {\n const bigIntJson: BigIntJSONValue = parseBigIntJson(\n pgResult[0][ZQL_RESULT_KEY],\n );\n assertJSONValue(bigIntJson);\n return bigIntJson;\n}\n\nfunction assertJSONValue(v: BigIntJSONValue): asserts v is JSONValue {\n const path = findPathToBigInt(v);\n if (path) {\n throw new Error(`Value exceeds safe Number range. ${path}`);\n }\n}\n\nfunction findPathToBigInt(v: BigIntJSONValue): string | undefined {\n const typeOfV = typeof v;\n switch (typeOfV) {\n case 'bigint':\n return ` = ${v}`;\n case 'object': {\n if (v === null) {\n return;\n }\n if (Array.isArray(v)) {\n for (let i = 0; i < v.length; i++) {\n const path = findPathToBigInt(v[i]);\n if (path) {\n return `[${i}]${path}`;\n }\n }\n return undefined;\n }\n\n const o = v as Record<string, BigIntJSONValue>;\n for (const k in o) {\n if (hasOwn(o, k)) {\n const path = findPathToBigInt(o[k]);\n if (path) {\n return `['${k}']${path}`;\n }\n }\n }\n return undefined;\n }\n case 'number':\n return undefined;\n case 'boolean':\n return undefined;\n default:\n return undefined;\n }\n}\n"],"mappings":"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"}
|