okmodel 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -1116
- package/dist/adapters/capabilities.d.ts +3 -0
- package/dist/adapters/failure.d.ts +13 -2
- package/dist/adapters/lazy-errors.d.ts +22 -0
- package/dist/adapters/pg/bunsql-extra.d.ts +54 -3
- package/dist/adapters/pg/bunsql.d.ts +14 -1
- package/dist/adapters/pg/cursor.d.ts +17 -0
- package/dist/adapters/pg/no-inflight-timeout.d.ts +20 -0
- package/dist/adapters/pg/nodepostgres-extra.d.ts +22 -1
- package/dist/adapters/pg/nodepostgres.d.ts +12 -0
- package/dist/adapters/pg/pglite-wire.d.ts +24 -0
- package/dist/adapters/pg/pglite.d.ts +10 -0
- package/dist/adapters/pg/postgres-extra.d.ts +41 -3
- package/dist/adapters/pg/reserved.d.ts +42 -0
- package/dist/adapters/pg/session.d.ts +0 -18
- package/dist/contracts/catalog/document.d.ts +19 -5
- package/dist/contracts/catalog/object.d.ts +2 -1
- package/dist/contracts/catalog/policy.d.ts +48 -0
- package/dist/contracts/catalog/types.d.ts +25 -1
- package/dist/contracts/catalog/view.d.ts +2 -0
- package/dist/contracts/connection.d.ts +7 -6
- package/dist/contracts/internal.js +1 -1
- package/dist/contracts/location.d.ts +10 -0
- package/dist/dialects/pg/column.d.ts +13 -2
- package/dist/dialects/pg/ddl.d.ts +37 -1
- package/dist/dialects/pg/emit.d.ts +19 -1
- package/dist/dialects/pg/errors.d.ts +32 -1
- package/dist/dialects/pg/ext/citext.js +1 -1
- package/dist/dialects/pg/ext/index.js +1 -1
- package/dist/dialects/pg/ext/pg-trgm.js +1 -1
- package/dist/dialects/pg/filter-parse.d.ts +5 -4
- package/dist/dialects/pg/floor.d.ts +68 -0
- package/dist/dialects/pg/fn/index.js +2 -2
- package/dist/dialects/pg/index.d.ts +8 -2
- package/dist/dialects/pg/index.js +67 -171
- package/dist/dialects/pg/introspect.d.ts +7 -0
- package/dist/dialects/pg/keys.d.ts +11 -8
- package/dist/dialects/pg/model.d.ts +47 -2
- package/dist/dialects/pg/morph.d.ts +43 -0
- package/dist/dialects/pg/operator-fit.d.ts +2 -2
- package/dist/dialects/pg/operators.d.ts +14 -7
- package/dist/dialects/pg/ops/bucket.d.ts +65 -0
- package/dist/dialects/pg/ops/inc.d.ts +2 -2
- package/dist/dialects/pg/ops/matches.d.ts +9 -12
- package/dist/dialects/pg/ops/relevance.d.ts +13 -0
- package/dist/dialects/pg/ops/search-query.d.ts +22 -0
- package/dist/dialects/pg/ops/window.d.ts +103 -0
- package/dist/dialects/pg/owner.d.ts +42 -0
- package/dist/dialects/pg/path-endpoint.d.ts +20 -0
- package/dist/dialects/pg/preset.d.ts +1 -1
- package/dist/dialects/pg/relations.d.ts +100 -3
- package/dist/dialects/pg/role/check.d.ts +3 -0
- package/dist/dialects/pg/role/index.d.ts +71 -6
- package/dist/dialects/pg/role/sql.d.ts +11 -0
- package/dist/dialects/pg/schema.d.ts +33 -3
- package/dist/dialects/pg/table.d.ts +25 -3
- package/dist/dialects/pg/tenancy.d.ts +45 -3
- package/dist/dialects/pg/view/client.d.ts +19 -1
- package/dist/dialects/pg/view/index.d.ts +4 -0
- package/dist/dialects/pg/view/index.js +21 -178
- package/dist/dialects/pg/view/refresh.d.ts +24 -0
- package/dist/runtime/aggregate.d.ts +8 -2
- package/dist/runtime/batch.d.ts +1 -1
- package/dist/runtime/bucket-group.d.ts +70 -0
- package/dist/runtime/conflict.d.ts +24 -6
- package/dist/runtime/drift.d.ts +9 -0
- package/dist/runtime/include.d.ts +0 -8
- package/dist/runtime/inflight.d.ts +14 -0
- package/dist/runtime/page.d.ts +4 -1
- package/dist/runtime/pg/bun.js +12 -5
- package/dist/runtime/pg/pg.js +5 -5
- package/dist/runtime/pg/pglite.d.ts +1 -0
- package/dist/runtime/pg/pglite.js +9 -8
- package/dist/runtime/pg/postgresjs.js +5 -5
- package/dist/runtime/plan.d.ts +113 -15
- package/dist/runtime/predicate.d.ts +19 -0
- package/dist/runtime/read-stream.d.ts +13 -16
- package/dist/runtime/result-name.d.ts +17 -0
- package/dist/runtime/safety/index.js +1 -1
- package/dist/runtime/server-check.d.ts +3 -3
- package/dist/runtime/sort-bind.d.ts +21 -0
- package/dist/runtime/sort.d.ts +56 -0
- package/dist/runtime/sync.d.ts +70 -0
- package/dist/runtime/tenancy/composite.d.ts +26 -0
- package/dist/runtime/tenancy/context.d.ts +16 -0
- package/dist/runtime/tenancy/index.d.ts +9 -5
- package/dist/runtime/tenancy/index.js +1511 -38
- package/dist/runtime/tenancy/path.d.ts +87 -0
- package/dist/runtime/tenancy/rls.d.ts +67 -0
- package/dist/runtime/tenancy/via.d.ts +22 -0
- package/dist/runtime/text-search.d.ts +20 -0
- package/dist/runtime/traits/index.d.ts +80 -0
- package/dist/runtime/traits/index.js +187 -17
- package/dist/runtime/tree.d.ts +38 -0
- package/dist/runtime/types.d.ts +231 -23
- package/dist/runtime/validate/index.js +4 -4
- package/dist/runtime/version.d.ts +39 -0
- package/dist/runtime/window.d.ts +21 -0
- package/dist/runtime/write.d.ts +55 -3
- package/dist/shared/{krxx77g0.js → 14vx95q4.js} +12 -18
- package/dist/shared/1est4ezg.js +313 -0
- package/dist/shared/{4az561fn.js → 1qa0qajz.js} +8 -23
- package/dist/shared/1w508jbr.js +1611 -0
- package/dist/shared/2c13q96h.js +18 -0
- package/dist/shared/2d3xq4ps.js +9 -0
- package/dist/shared/2shdbn8q.js +23 -0
- package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
- package/dist/shared/3v7t1yrv.js +208 -0
- package/dist/shared/5e3tf63j.js +220 -0
- package/dist/shared/5fe3kbsh.js +10 -0
- package/dist/shared/5v3xf80k.js +37 -0
- package/dist/shared/{51mvgj8w.js → 63qtkrca.js} +130 -3
- package/dist/shared/{gbtcc2d7.js → 67txcrcw.js} +62 -66
- package/dist/shared/79dt02vc.js +12 -0
- package/dist/shared/{v36c5g6p.js → 7k9grvf6.js} +407 -14
- package/dist/shared/7kms6fvj.js +20 -0
- package/dist/shared/7mnme5tn.js +8 -0
- package/dist/shared/7n7ddwt4.js +6 -0
- package/dist/shared/{87jvvhnt.js → 81ebdx9p.js} +48 -68
- package/dist/shared/{szm0cksa.js → 8skf0cam.js} +34 -6
- package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
- package/dist/shared/9a4ae4p8.js +31 -0
- package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
- package/dist/shared/9y3mmmh1.js +436 -0
- package/dist/shared/ab9gmbwy.js +213 -0
- package/dist/shared/{sycnx8gt.js → ax7qv55k.js} +18 -8
- package/dist/shared/{f5cw5q5r.js → aytqh5y2.js} +6 -4
- package/dist/shared/{fancm5pt.js → b5pftnn2.js} +138 -15
- package/dist/shared/{efmy2gcg.js → b76b8d95.js} +2 -2
- package/dist/shared/bdk4sty6.js +58 -0
- package/dist/shared/{32zqc1dw.js → bg3rym3g.js} +63 -32
- package/dist/shared/{0t22wwh1.js → bm22fvzr.js} +16 -14
- package/dist/shared/bz84tkzm.js +342 -0
- package/dist/shared/{31vm914h.js → cm3w0ywp.js} +15 -16
- package/dist/shared/cn957f8d.js +179 -0
- package/dist/shared/{pf0d8f77.js → cnkky55j.js} +25 -14
- package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
- package/dist/shared/{nkaxvt9q.js → dkxgzaqd.js} +224 -19
- package/dist/shared/dzj09cye.js +10 -0
- package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
- package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
- package/dist/shared/exn3sd90.js +359 -0
- package/dist/shared/g6evj1j3.js +66 -0
- package/dist/shared/ga9j92qj.js +25 -0
- package/dist/shared/{qv2ydck9.js → gs74dbj5.js} +651 -76
- package/dist/shared/gzaveazc.js +285 -0
- package/dist/shared/{8rsy3hxz.js → h15jx9bc.js} +1 -1
- package/dist/shared/{dyj86cmj.js → hyh73qk6.js} +3 -3
- package/dist/shared/je4axnm8.js +22 -0
- package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
- package/dist/shared/{6qd27mx0.js → jvd0mqag.js} +5 -5
- package/dist/shared/jznfax0y.js +155 -0
- package/dist/shared/{cgbamx3e.js → kb2sdhfb.js} +7 -4
- package/dist/shared/{ps7a6h14.js → kr0jzbw2.js} +12 -8
- package/dist/shared/{janx09m5.js → ktz42yez.js} +20 -8
- package/dist/shared/{gde73es6.js → m6p12kbr.js} +56 -55
- package/dist/shared/{r6nwkxnt.js → m7n9h2a5.js} +4 -4
- package/dist/shared/{672t5vym.js → mss6ctgv.js} +2 -2
- package/dist/shared/{nxdp2ze3.js → mtaszv5a.js} +144 -12
- package/dist/shared/n816peh1.js +45 -0
- package/dist/shared/nbw1z4yd.js +18 -0
- package/dist/shared/{cctw17hj.js → p6qc5gcp.js} +38 -34
- package/dist/shared/{6rk2gen5.js → pbp1ss85.js} +20 -17
- package/dist/shared/pt94kz7f.js +6 -0
- package/dist/shared/{wq9n6pwr.js → pz6rj8ay.js} +82 -9
- package/dist/shared/q5c6ngn3.js +13 -0
- package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
- package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
- package/dist/shared/rhs3xe4k.js +7 -0
- package/dist/shared/{ntneex2a.js → rpycarcr.js} +6 -6
- package/dist/shared/{sdc7r2ww.js → rs73fca9.js} +8 -8
- package/dist/shared/{tm5ab8we.js → sfz1ksn6.js} +7 -4
- package/dist/shared/{6mnp99hx.js → svncdeh5.js} +16 -12
- package/dist/shared/{hf22e0wt.js → tbrvgw6z.js} +62 -42
- package/dist/shared/te5as7z7.js +622 -0
- package/dist/shared/{ga3sfy93.js → tsvww22q.js} +535 -200
- package/dist/shared/{47x8x9ze.js → ttsqgp4p.js} +20 -13
- package/dist/shared/{x72jb7ad.js → v8g1vgv8.js} +1 -1
- package/dist/shared/vb6qfyve.js +152 -0
- package/dist/shared/{r2sp8hrc.js → vczs8gd4.js} +22 -13
- package/dist/shared/{1g0drakv.js → vqrjpcqn.js} +145 -3
- package/dist/shared/{2pqx26h8.js → w72kgg4q.js} +31 -22
- package/dist/shared/{96qcj21c.js → w79hsckn.js} +16 -51
- package/dist/shared/wa07eas9.js +730 -0
- package/dist/shared/{k8v5v5wj.js → x933k9a3.js} +75 -34
- package/dist/shared/{cr74e96e.js → xhfsfkgk.js} +62 -28
- package/dist/shared/xjk7hnn5.js +272 -0
- package/dist/shared/{5enne4ma.js → xnxsed62.js} +66 -113
- package/dist/shared/xqve9598.js +53 -0
- package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
- package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
- package/dist/shared/y6njgyda.js +249 -0
- package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
- package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
- package/dist/shared/z7s6fpxv.js +62 -0
- package/dist/shared/{n7mcc1gk.js → zchaghkf.js} +4 -3
- package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
- package/dist/shared/zm0ptry0.js +40 -0
- package/dist/shared/{nsva2a6b.js → znm0bpp5.js} +3 -0
- package/dist/shared/zp9fmend.js +145 -0
- package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
- package/dist/tooling/cli.js +41 -15
- package/dist/tooling/migrate/apply.d.ts +14 -0
- package/dist/tooling/migrate/check.d.ts +3 -4
- package/dist/tooling/migrate/classify.d.ts +4 -0
- package/dist/tooling/migrate/config.d.ts +3 -2
- package/dist/tooling/migrate/engine.d.ts +3 -2
- package/dist/tooling/migrate/files.d.ts +11 -1
- package/dist/tooling/migrate/index.js +14 -14
- package/dist/tooling/migrate/lint.d.ts +1 -1
- package/dist/tooling/migrate/lost.d.ts +28 -0
- package/dist/tooling/migrate/paths.d.ts +14 -0
- package/dist/tooling/migrate/plan.d.ts +6 -3
- package/dist/tooling/migrate/runner.d.ts +25 -0
- package/dist/tooling/migrate/sandbox.d.ts +57 -0
- package/dist/tooling/migrate/sql-lex.d.ts +20 -3
- package/dist/tooling/migrate/text.d.ts +42 -0
- package/dist/tooling/node-version.d.ts +21 -0
- package/dist/tooling/testing/facts.d.ts +33 -5
- package/dist/tooling/testing/index.d.ts +1 -1
- package/dist/tooling/testing/index.js +3 -3
- package/dist/tooling/testing/isolation.d.ts +11 -5
- package/package.json +8 -3
- package/dist/shared/7m88x3e9.js +0 -45
- package/dist/shared/7zwwyh0v.js +0 -448
- package/dist/shared/aj2qxyhj.js +0 -90
- package/dist/shared/caw8b9d8.js +0 -204
- package/dist/shared/jwtxdj06.js +0 -76
- package/dist/shared/kfjp0gck.js +0 -212
- package/dist/shared/q58y17hy.js +0 -21
- package/dist/shared/qm7cdtvr.js +0 -912
- package/dist/shared/r8x5qhd7.js +0 -86
- package/dist/shared/zqrnhwsq.js +0 -31
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {
|
|
2
|
+
queryHandle,
|
|
3
|
+
readHandle,
|
|
4
|
+
readCall,
|
|
5
|
+
attachHttp
|
|
6
|
+
} from "./tbrvgw6z.js";
|
|
7
|
+
import {
|
|
8
|
+
emitWhere,
|
|
9
|
+
emitOrder,
|
|
10
|
+
refuseHidden,
|
|
11
|
+
rejectKeys,
|
|
12
|
+
readLimit,
|
|
13
|
+
projectExpr,
|
|
14
|
+
cell,
|
|
15
|
+
indexes,
|
|
16
|
+
quote,
|
|
17
|
+
list,
|
|
18
|
+
isRecord,
|
|
19
|
+
fail2
|
|
20
|
+
} from "./67txcrcw.js";
|
|
21
|
+
import {
|
|
22
|
+
OkmError2,
|
|
23
|
+
throwNamed2
|
|
24
|
+
} from "./52szzakm.js";
|
|
25
|
+
|
|
26
|
+
// src/runtime/aggregate.ts
|
|
27
|
+
var BUCKET = Symbol.for("okmodel.bucket");
|
|
28
|
+
var bucketChunk;
|
|
29
|
+
function loadBucketGroup() {
|
|
30
|
+
return bucketChunk ??= import("./3v7t1yrv.js");
|
|
31
|
+
}
|
|
32
|
+
var OPTIONS = [
|
|
33
|
+
"where",
|
|
34
|
+
"groupBy",
|
|
35
|
+
"count",
|
|
36
|
+
"sum",
|
|
37
|
+
"avg",
|
|
38
|
+
"min",
|
|
39
|
+
"max",
|
|
40
|
+
"orderBy",
|
|
41
|
+
"limit",
|
|
42
|
+
"route",
|
|
43
|
+
"signal",
|
|
44
|
+
"timeout"
|
|
45
|
+
];
|
|
46
|
+
var NUMERIC = /^(smallint|integer|bigint|real|double precision|numeric|decimal)\b/;
|
|
47
|
+
var AS_NUMBER = (wire) => Number(wire);
|
|
48
|
+
var AS_TEXT = (wire) => wire;
|
|
49
|
+
var UNORDERED = /^(json|jsonb|bytea|point|line|tsvector)\b|\[\]$/;
|
|
50
|
+
var FUNCTIONS = [
|
|
51
|
+
{ option: "sum", tag: "s", numeric: true },
|
|
52
|
+
{ option: "avg", tag: "a", numeric: true },
|
|
53
|
+
{ option: "min", tag: "n", numeric: false },
|
|
54
|
+
{ option: "max", tag: "x", numeric: false }
|
|
55
|
+
];
|
|
56
|
+
function build(session, table, options, mods, view) {
|
|
57
|
+
try {
|
|
58
|
+
if (seesBucket(options))
|
|
59
|
+
return bucketHandle(session, table, options, mods, view);
|
|
60
|
+
return plan(session, table, options, mods, view);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw error instanceof OkmError2 ? attachHttp(session.http, error) : error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function bucketHandle(session, table, options, mods, view) {
|
|
66
|
+
const open = () => loadBucketGroup().then((mod) => {
|
|
67
|
+
try {
|
|
68
|
+
return { it: plan(session, table, options, mods, view, mod) };
|
|
69
|
+
} catch (error) {
|
|
70
|
+
throw error instanceof OkmError2 ? attachHttp(session.http, error) : error;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return queryHandle(() => open().then((box) => box.it), {
|
|
74
|
+
inspect: () => open().then((box) => box.it.inspect()),
|
|
75
|
+
sql: () => open().then((box) => box.it.sql()),
|
|
76
|
+
all: (reason) => build(session, table, options, { ...mods, all: reason }, view)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function seesBucket(options) {
|
|
80
|
+
if (!isRecord(options))
|
|
81
|
+
return false;
|
|
82
|
+
const groupBy = options.groupBy;
|
|
83
|
+
if (!Array.isArray(groupBy))
|
|
84
|
+
return false;
|
|
85
|
+
for (const item of groupBy) {
|
|
86
|
+
if (typeof item === "object" && item !== null && BUCKET in item)
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
function plan(session, table, options, mods, view, buckets) {
|
|
92
|
+
const record = isRecord(options) ? options : {};
|
|
93
|
+
rejectKeys(record, OPTIONS, "aggregate");
|
|
94
|
+
const indexed = indexes(session.schema).get(table);
|
|
95
|
+
if (indexed === undefined)
|
|
96
|
+
fail2("OKM1120", `Table ${table} is not in the schema.`);
|
|
97
|
+
const spec = parse(indexed, record, buckets);
|
|
98
|
+
if (spec.groups.length > 0 && record.limit === undefined && mods.all === undefined) {
|
|
99
|
+
fail2("OKM1101", "aggregate() with groupBy needs a limit, or .all(reason) for every group.");
|
|
100
|
+
}
|
|
101
|
+
const names = groupNames(spec.groups);
|
|
102
|
+
const orderBy = record.orderBy;
|
|
103
|
+
if (orderBy !== undefined) {
|
|
104
|
+
if (!isRecord(orderBy))
|
|
105
|
+
fail2("OKM1120", "orderBy must be an object of fields.");
|
|
106
|
+
for (const field of Object.keys(orderBy)) {
|
|
107
|
+
if (!names.includes(field)) {
|
|
108
|
+
const column = indexed.columns.get(field);
|
|
109
|
+
if (column !== undefined)
|
|
110
|
+
refuseHidden(column);
|
|
111
|
+
throwNamed2("OKM1120", field, names, `aggregate() orders by a groupBy field. Accepted names: ${list(names)}.`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (record.limit !== undefined)
|
|
116
|
+
readLimit(record.limit);
|
|
117
|
+
const base = readCall("find", table, {
|
|
118
|
+
where: record.where,
|
|
119
|
+
orderBy,
|
|
120
|
+
limit: record.limit,
|
|
121
|
+
signal: record.signal,
|
|
122
|
+
timeout: record.timeout,
|
|
123
|
+
route: record.route
|
|
124
|
+
}, mods.all, session.scope, session.schema.model[table], session.schema, view);
|
|
125
|
+
const call = { ...base, op: "aggregate", build: statement(spec, buckets) };
|
|
126
|
+
return readHandle(session, table, call, mods, (compiled, rows) => decode(compiled, rows));
|
|
127
|
+
}
|
|
128
|
+
function parse(table, record, buckets) {
|
|
129
|
+
const grouped = readGroups(table, record.groupBy, buckets);
|
|
130
|
+
const count = record.count === true;
|
|
131
|
+
if (record.count !== undefined && typeof record.count !== "boolean") {
|
|
132
|
+
fail2("OKM1120", "count is true when you want a row count.");
|
|
133
|
+
}
|
|
134
|
+
const calls = [];
|
|
135
|
+
for (const { option, tag, numeric } of FUNCTIONS) {
|
|
136
|
+
for (const column of columns(table, record[option], option)) {
|
|
137
|
+
const fits = numeric ? NUMERIC.test(column.dataType) : !UNORDERED.test(column.dataType);
|
|
138
|
+
if (!fits) {
|
|
139
|
+
fail2("OKM1124", `${option} does not apply to ${column.dataType} column ${column.field}. ${numeric ? "sum and avg take integer, real, and numeric columns." : "min and max need an ordered type."}`);
|
|
140
|
+
}
|
|
141
|
+
calls.push({ option, tag, column, decode: numeric ? sumDecode(column) : column.decode });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (!count && calls.length === 0 && grouped.groups.length === 0) {
|
|
145
|
+
fail2("OKM1120", "aggregate() needs count, sum, avg, min, max, or groupBy.");
|
|
146
|
+
}
|
|
147
|
+
return { groups: grouped.groups, bucketed: grouped.bucketed, count, calls };
|
|
148
|
+
}
|
|
149
|
+
function sumDecode(column) {
|
|
150
|
+
const kind = typeof (column.decode?.("0") ?? "");
|
|
151
|
+
if (kind === "string")
|
|
152
|
+
return AS_TEXT;
|
|
153
|
+
if (kind === "number")
|
|
154
|
+
return AS_NUMBER;
|
|
155
|
+
return fail2("OKM1124", `sum and avg need a column whose value is a number or a string. ${column.field} reads as ${kind}.`);
|
|
156
|
+
}
|
|
157
|
+
function columns(table, value, option) {
|
|
158
|
+
if (value === undefined)
|
|
159
|
+
return [];
|
|
160
|
+
if (!Array.isArray(value))
|
|
161
|
+
fail2("OKM1120", `${option} must be a list of field names.`);
|
|
162
|
+
const out = [];
|
|
163
|
+
for (const name of value) {
|
|
164
|
+
const column = typeof name === "string" ? table.columns.get(name) : undefined;
|
|
165
|
+
if (typeof name !== "string" || column === undefined) {
|
|
166
|
+
throwNamed2("OKM1120", String(name), table.names, `Field ${String(name)} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
167
|
+
}
|
|
168
|
+
if (column.hidden) {
|
|
169
|
+
fail2("OKM1120", `Field ${column.field} is hidden, so ${option} cannot read it.`);
|
|
170
|
+
}
|
|
171
|
+
out.push(column);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
function groupNames(groups) {
|
|
176
|
+
const names = [];
|
|
177
|
+
for (const group of groups)
|
|
178
|
+
names.push(group.kind === "field" ? group.column.field : group.as);
|
|
179
|
+
return names;
|
|
180
|
+
}
|
|
181
|
+
function readGroups(table, value, buckets) {
|
|
182
|
+
if (value === undefined)
|
|
183
|
+
return { groups: [], bucketed: false };
|
|
184
|
+
if (!Array.isArray(value))
|
|
185
|
+
fail2("OKM1120", "groupBy must be a list of field names.");
|
|
186
|
+
const fields = new Set;
|
|
187
|
+
const aliases = new Set;
|
|
188
|
+
const groups = [];
|
|
189
|
+
let bucketed = false;
|
|
190
|
+
for (const item of value) {
|
|
191
|
+
if (typeof item === "object" && item !== null && BUCKET in item) {
|
|
192
|
+
if (buckets === undefined)
|
|
193
|
+
fail2("OKM1120", "bucket group");
|
|
194
|
+
groups.push(buckets.readBucket(table, item, fields, aliases));
|
|
195
|
+
bucketed = true;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const column = typeof item === "string" ? table.columns.get(item) : undefined;
|
|
199
|
+
if (typeof item !== "string" || column === undefined) {
|
|
200
|
+
throwNamed2("OKM1120", String(item), table.names, `Field ${String(item)} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
201
|
+
}
|
|
202
|
+
if (column.hidden) {
|
|
203
|
+
fail2("OKM1120", `Field ${column.field} is hidden, so groupBy cannot read it.`);
|
|
204
|
+
}
|
|
205
|
+
if (aliases.has(column.field)) {
|
|
206
|
+
fail2("OKM1120", `group field ${column.field} clashes with a bucket as.`);
|
|
207
|
+
}
|
|
208
|
+
fields.add(column.field);
|
|
209
|
+
groups.push({ kind: "field", column });
|
|
210
|
+
}
|
|
211
|
+
return { groups, bucketed };
|
|
212
|
+
}
|
|
213
|
+
function statement(spec, buckets) {
|
|
214
|
+
return (schema, table, sink, outputs, call) => {
|
|
215
|
+
sink.mark(`aggregate|${table.model.name}|g:${groupMark(spec.groups)}|c:${String(spec.count)}|${spec.calls.map((item) => `${item.tag}:${item.column.field}`).join(",")}|`);
|
|
216
|
+
sink.text("select ");
|
|
217
|
+
const wrote = { at: 0 };
|
|
218
|
+
for (const group of spec.groups) {
|
|
219
|
+
if (group.kind === "field") {
|
|
220
|
+
put(sink, outputs, wrote, projectExpr(`t.${quote(group.column.sql)}`, group.column.dataType), {
|
|
221
|
+
key: `g:${group.column.field}`,
|
|
222
|
+
decode: group.column.decode
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
if (buckets === undefined)
|
|
226
|
+
fail2("OKM1120", "bucket group");
|
|
227
|
+
buckets.writeBucket(sink, outputs, wrote, group);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (spec.count)
|
|
231
|
+
put(sink, outputs, wrote, "count(*)::text", { key: "c:", decode: undefined });
|
|
232
|
+
for (const item of spec.calls) {
|
|
233
|
+
const ref = `t.${quote(item.column.sql)}`;
|
|
234
|
+
const expr = item.option === "sum" || item.option === "avg" ? `${item.option}(${ref})::text` : projectExpr(`${item.option}(${ref})`, item.column.dataType);
|
|
235
|
+
put(sink, outputs, wrote, expr, {
|
|
236
|
+
key: `${item.tag}:${item.column.field}`,
|
|
237
|
+
decode: item.decode
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
sink.text(" from ");
|
|
241
|
+
sink.text(quote(table.model.sql));
|
|
242
|
+
sink.text(" t");
|
|
243
|
+
emitWhere(schema, table, call.where, sink, "t", 0);
|
|
244
|
+
if (spec.groups.length > 0) {
|
|
245
|
+
sink.text(" group by ");
|
|
246
|
+
if (spec.bucketed) {
|
|
247
|
+
if (buckets === undefined)
|
|
248
|
+
fail2("OKM1120", "bucket group");
|
|
249
|
+
buckets.writeGrouped(sink, groupNames(spec.groups), call.orderBy);
|
|
250
|
+
} else {
|
|
251
|
+
sink.text(spec.groups.map((group) => fieldRef(group)).join(", "));
|
|
252
|
+
if (isRecord(call.orderBy) && Object.keys(call.orderBy).length > 0) {
|
|
253
|
+
emitOrder(table, call.orderBy, sink, "t");
|
|
254
|
+
} else {
|
|
255
|
+
sink.text(" order by ");
|
|
256
|
+
sink.text(spec.groups.map((group) => `${fieldRef(group)} asc nulls last`).join(", "));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (call.limit !== undefined) {
|
|
261
|
+
const limit = String(call.limit);
|
|
262
|
+
sink.text(" limit ");
|
|
263
|
+
sink.param(limit);
|
|
264
|
+
sink.mark(`l:${limit}`);
|
|
265
|
+
}
|
|
266
|
+
if (typeof call.all === "string")
|
|
267
|
+
sink.mark(`all:${call.all}`);
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function groupMark(groups) {
|
|
271
|
+
const parts = [];
|
|
272
|
+
for (const group of groups) {
|
|
273
|
+
parts.push(group.kind === "field" ? group.column.field : `b:${group.column.field}:${group.as}:${group.unit}:${String(group.shift)}`);
|
|
274
|
+
}
|
|
275
|
+
return parts.join(",");
|
|
276
|
+
}
|
|
277
|
+
function fieldRef(group) {
|
|
278
|
+
if (group.kind !== "field")
|
|
279
|
+
return fail2("OKM1120", "bucket group");
|
|
280
|
+
return `t.${quote(group.column.sql)}`;
|
|
281
|
+
}
|
|
282
|
+
function put(sink, outputs, wrote, expr, out) {
|
|
283
|
+
if (wrote.at > 0)
|
|
284
|
+
sink.text(", ");
|
|
285
|
+
sink.text(expr);
|
|
286
|
+
outputs?.fields.push({ key: out.key, at: wrote.at, decode: out.decode });
|
|
287
|
+
wrote.at += 1;
|
|
288
|
+
}
|
|
289
|
+
function decode(compiled, rows) {
|
|
290
|
+
const items = [];
|
|
291
|
+
for (const row of rows) {
|
|
292
|
+
const item = {};
|
|
293
|
+
for (const field of compiled.outputs.fields) {
|
|
294
|
+
const value = row[field.at];
|
|
295
|
+
const tag = field.key.slice(0, 2);
|
|
296
|
+
const name = field.key.slice(2);
|
|
297
|
+
if (tag === "g:") {
|
|
298
|
+
item[name] = cell(value, field.decode);
|
|
299
|
+
} else if (tag === "c:") {
|
|
300
|
+
item.count = Number(value ?? 0);
|
|
301
|
+
} else {
|
|
302
|
+
const group = tag === "s:" ? "sum" : tag === "a:" ? "avg" : tag === "n:" ? "min" : "max";
|
|
303
|
+
const into = item[group] ??= {};
|
|
304
|
+
into[name] = cell(value, field.decode);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
items.push(item);
|
|
308
|
+
}
|
|
309
|
+
return items;
|
|
310
|
+
}
|
|
311
|
+
export {
|
|
312
|
+
build
|
|
313
|
+
};
|
|
@@ -4,12 +4,9 @@ import {
|
|
|
4
4
|
nextTransactionDepth,
|
|
5
5
|
EMPTY_NOTICES,
|
|
6
6
|
resultFrom
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./kb2sdhfb.js";
|
|
8
8
|
|
|
9
9
|
// src/adapters/pg/session.ts
|
|
10
|
-
function quoteIdent2(name) {
|
|
11
|
-
return `"${name.replaceAll('"', '""')}"`;
|
|
12
|
-
}
|
|
13
10
|
function noticeBuffer() {
|
|
14
11
|
let notices;
|
|
15
12
|
return {
|
|
@@ -63,7 +60,7 @@ class WireSession {
|
|
|
63
60
|
return resultFrom(result, this.notices.since(start));
|
|
64
61
|
}, (error) => {
|
|
65
62
|
this.onLeave();
|
|
66
|
-
return driverErrors().then((errors) => Promise.reject(errors.mapDriverError(error)));
|
|
63
|
+
return driverErrors().then((errors) => Promise.reject(errors.mapDriverError(stampQuery(error, text))));
|
|
67
64
|
});
|
|
68
65
|
}
|
|
69
66
|
return this.watched(pending, watch, start, text);
|
|
@@ -110,7 +107,7 @@ class WireSession {
|
|
|
110
107
|
return resultFrom(result, this.notices.since(start));
|
|
111
108
|
}, (error) => {
|
|
112
109
|
this.finishWatched(pending, watch, onAbort);
|
|
113
|
-
return classify(error, watch);
|
|
110
|
+
return classify(stampQuery(error, text), watch);
|
|
114
111
|
});
|
|
115
112
|
}
|
|
116
113
|
finishWatched(pending, watch, onAbort) {
|
|
@@ -119,22 +116,10 @@ class WireSession {
|
|
|
119
116
|
watch.signal.removeEventListener("abort", onAbort);
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
await run(`DECLARE ${name} NO SCROLL CURSOR FOR ${text}`, params);
|
|
127
|
-
for (;; ) {
|
|
128
|
-
const chunk = await run(`FETCH 64 FROM ${name}`);
|
|
129
|
-
if (chunk.rows.length === 0)
|
|
130
|
-
break;
|
|
131
|
-
yield chunk.rows;
|
|
132
|
-
}
|
|
133
|
-
} finally {
|
|
134
|
-
await run("ROLLBACK").catch(() => {
|
|
135
|
-
return;
|
|
136
|
-
});
|
|
137
|
-
}
|
|
119
|
+
function stampQuery(error, text) {
|
|
120
|
+
if (typeof error === "object" && error !== null && !("query" in error))
|
|
121
|
+
Reflect.set(error, "query", text);
|
|
122
|
+
return error;
|
|
138
123
|
}
|
|
139
124
|
async function classify(error, watch) {
|
|
140
125
|
const errors = await driverErrors();
|
|
@@ -151,4 +136,4 @@ async function classify(error, watch) {
|
|
|
151
136
|
return Promise.reject(errors.mapDriverError(error));
|
|
152
137
|
}
|
|
153
138
|
|
|
154
|
-
export {
|
|
139
|
+
export { noticeBuffer, WireSession };
|