okmodel 0.7.0 → 0.8.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/dist/adapters/capabilities.d.ts +32 -0
- package/dist/adapters/failure.d.ts +1 -1
- package/dist/adapters/pg/bun-sql.d.ts +53 -0
- package/dist/adapters/pg/bunsql-extra.d.ts +1 -1
- package/dist/adapters/pg/bunsql.d.ts +1 -1
- package/dist/adapters/pg/neon-extra.d.ts +18 -0
- package/dist/adapters/pg/neon.d.ts +104 -0
- package/dist/adapters/pg/no-inflight-timeout.d.ts +1 -1
- package/dist/contracts/error.d.ts +1 -1
- package/dist/dialects/pg/fn/index.d.ts +39 -1
- package/dist/dialects/pg/fn/index.js +118 -26
- package/dist/dialects/pg/index.d.ts +2 -0
- package/dist/dialects/pg/index.js +393 -18
- package/dist/dialects/pg/introspect.d.ts +11 -0
- package/dist/dialects/pg/operators.d.ts +1 -1
- package/dist/dialects/pg/ops/fragment.d.ts +119 -0
- package/dist/dialects/pg/ops/lane.d.ts +49 -0
- package/dist/dialects/pg/view/client.d.ts +14 -6
- package/dist/dialects/pg/view/index.d.ts +73 -1
- package/dist/dialects/pg/view/index.js +156 -5
- package/dist/dialects/pg/view/scratch.d.ts +8 -5
- package/dist/runtime/otel.d.ts +105 -0
- package/dist/runtime/otel.js +97 -0
- package/dist/runtime/pg/bun.js +4 -4
- package/dist/runtime/pg/neon.d.ts +38 -0
- package/dist/runtime/pg/neon.js +64 -0
- package/dist/runtime/pg/pg.js +4 -4
- package/dist/runtime/pg/pglite.js +4 -4
- package/dist/runtime/pg/postgresjs.js +4 -4
- package/dist/runtime/plan.d.ts +1 -1
- package/dist/runtime/sql-fragment.d.ts +43 -0
- package/dist/runtime/tenancy/index.js +10 -10
- package/dist/runtime/topology.d.ts +1 -1
- package/dist/runtime/traits/index.js +15 -16
- package/dist/runtime/types.d.ts +15 -1
- package/dist/runtime/validate/index.js +4 -4
- package/dist/shared/{mtaszv5a.js → 0wrea3jq.js} +102 -4
- package/dist/shared/{qq3899ht.js → 12z7aznj.js} +243 -14
- package/dist/shared/{w79hsckn.js → 14x60fbf.js} +5 -5
- package/dist/shared/{ek2wt2dz.js → 16kvjebh.js} +4 -4
- package/dist/shared/{svncdeh5.js → 195pzzzz.js} +8 -8
- package/dist/shared/{gzaveazc.js → 1d9q9cv2.js} +29 -2
- package/dist/shared/{jvd0mqag.js → 3449rcae.js} +5 -5
- package/dist/shared/{14vx95q4.js → 35q0n9tz.js} +7 -7
- package/dist/shared/3bb7wsqt.js +99 -0
- package/dist/shared/{y6njgyda.js → 3t6kw83m.js} +2 -2
- package/dist/shared/{81ebdx9p.js → 4m6hskg8.js} +4 -4
- package/dist/shared/{xhfsfkgk.js → 4vbf83xx.js} +9 -2
- package/dist/shared/{bg3rym3g.js → 63f4ksbz.js} +2 -2
- package/dist/shared/{pt94kz7f.js → 6m78c8ss.js} +1 -1
- package/dist/shared/{5e3tf63j.js → 760ppr76.js} +14 -6
- package/dist/shared/{zm0ptry0.js → 7ghwamrf.js} +1 -1
- package/dist/shared/{xnxsed62.js → 9dr2qnx7.js} +14 -14
- package/dist/shared/{h15jx9bc.js → 9dvh1dr6.js} +1 -1
- package/dist/shared/{q5c6ngn3.js → a62rb2da.js} +1 -1
- package/dist/shared/{kb2sdhfb.js → ae4j5f42.js} +17 -1
- package/dist/shared/agsfb86s.js +233 -0
- package/dist/shared/{7k9grvf6.js → b6d6p0zc.js} +5 -5
- package/dist/shared/{tbrvgw6z.js → bah9nbg3.js} +17 -16
- package/dist/shared/{5fe3kbsh.js → bnby0esn.js} +1 -1
- package/dist/shared/bsek72fg.js +225 -0
- package/dist/shared/{1w508jbr.js → bxas03mq.js} +21 -17
- package/dist/shared/{dk8v79p3.js → d5nmj7vv.js} +1 -1
- package/dist/shared/{tsvww22q.js → dpc2r7rb.js} +7 -7
- package/dist/shared/{vb6qfyve.js → e8zyaqvj.js} +2 -2
- package/dist/shared/{hyh73qk6.js → ecn8mfdq.js} +5 -5
- package/dist/shared/{gs74dbj5.js → f4jy1j7x.js} +27 -14
- package/dist/shared/{ttsqgp4p.js → fjpnhqan.js} +2 -2
- package/dist/shared/{xjk7hnn5.js → g5yc06ka.js} +2 -2
- package/dist/shared/{w72kgg4q.js → hfqmpasr.js} +6 -6
- package/dist/shared/{kr0jzbw2.js → hm5f8jby.js} +7 -7
- package/dist/shared/{dkxgzaqd.js → hqpxf4a4.js} +1 -1
- package/dist/shared/{cn957f8d.js → jebgrkeq.js} +3 -3
- package/dist/shared/{wa07eas9.js → jp36k7dp.js} +11 -11
- package/dist/shared/jx2m62cs.js +96 -0
- package/dist/shared/{sfz1ksn6.js → k86n8vq3.js} +2 -2
- package/dist/shared/{67txcrcw.js → kgwp4jdd.js} +4 -4
- package/dist/shared/{8skf0cam.js → kj9d8maq.js} +1 -1
- package/dist/shared/{aytqh5y2.js → m4xff2a6.js} +2 -2
- package/dist/shared/{zp9fmend.js → mfedzr74.js} +4 -4
- package/dist/shared/{ax7qv55k.js → mkrn359n.js} +60 -11
- package/dist/shared/{m6p12kbr.js → mnvjvqyp.js} +10 -10
- package/dist/shared/{1qa0qajz.js → mtw6jz76.js} +1 -1
- package/dist/shared/{1est4ezg.js → n05z9nwz.js} +3 -3
- package/dist/shared/{pbp1ss85.js → n0jmpgj1.js} +2 -2
- package/dist/shared/{ktz42yez.js → n41w4fbz.js} +5 -5
- package/dist/shared/{n816peh1.js → n454kcnw.js} +1 -1
- package/dist/shared/n7kg8mmx.js +61 -0
- package/dist/shared/{g6evj1j3.js → needfe47.js} +1 -1
- package/dist/shared/{2shdbn8q.js → njga14v4.js} +9 -9
- package/dist/shared/{vqrjpcqn.js → nmnsgj7x.js} +1 -1
- package/dist/shared/{b5pftnn2.js → p3xbdcvt.js} +14 -18
- package/dist/shared/{te5as7z7.js → p5nh3r8q.js} +3 -3
- package/dist/shared/{p6qc5gcp.js → pan0370z.js} +6 -6
- package/dist/shared/{79dt02vc.js → q0cqt2sp.js} +1 -1
- package/dist/shared/{5v3xf80k.js → qd9hhd8f.js} +1 -1
- package/dist/shared/{bm22fvzr.js → qfw14tna.js} +2 -2
- package/dist/shared/{9s0ypp87.js → sjk86yrx.js} +1 -1
- package/dist/shared/{3v7t1yrv.js → th3be82n.js} +2 -2
- package/dist/shared/{ed0b8k4s.js → typ3vy7t.js} +1 -1
- package/dist/shared/{vczs8gd4.js → v1wad97q.js} +2 -2
- package/dist/shared/{9628a9xt.js → vk7rag46.js} +1 -1
- package/dist/shared/{ze4hxsmy.js → w9ejzaqf.js} +1 -1
- package/dist/shared/{bz84tkzm.js → wcrheftc.js} +2 -2
- package/dist/shared/{ab9gmbwy.js → wvdjznah.js} +5 -5
- package/dist/shared/{7mnme5tn.js → wz2a78mp.js} +1 -1
- package/dist/shared/{9y3mmmh1.js → xfhe73sb.js} +1 -1
- package/dist/shared/{je4axnm8.js → z581d7ny.js} +2 -2
- package/dist/shared/{x933k9a3.js → zbqbmmrp.js} +10 -10
- package/dist/shared/{rs73fca9.js → zgex00fd.js} +6 -6
- package/dist/shared/{jznfax0y.js → zq1he88x.js} +4 -4
- package/dist/tooling/cli.js +26 -13
- package/dist/tooling/driver-run.js +4971 -0
- package/dist/tooling/driver-test.d.ts +36 -0
- package/dist/tooling/migrate/commands.d.ts +2 -2
- package/dist/tooling/migrate/index.js +9 -9
- package/dist/tooling/migrate/project.d.ts +3 -0
- package/dist/tooling/shared/03k6res6.js +210 -0
- package/dist/tooling/shared/08kemxjd.js +10 -0
- package/dist/tooling/shared/2revefqt.js +209 -0
- package/dist/tooling/shared/2wtvc7rw.js +1425 -0
- package/dist/tooling/shared/345tbc2k.js +16 -0
- package/dist/tooling/shared/3m1hkg7z.js +344 -0
- package/dist/tooling/shared/3rrw5w8f.js +81 -0
- package/dist/tooling/shared/3tq8pnb8.js +131 -0
- package/dist/tooling/shared/417zdsk7.js +194 -0
- package/dist/tooling/shared/4d2w25vw.js +40 -0
- package/dist/tooling/shared/54tqkxja.js +51 -0
- package/dist/tooling/shared/5bvw2nev.js +12 -0
- package/dist/tooling/shared/6nyfyw70.js +231 -0
- package/dist/tooling/shared/72fyg4zv.js +160 -0
- package/dist/tooling/shared/733a1tq3.js +38 -0
- package/dist/tooling/shared/7ae7rjmn.js +20 -0
- package/dist/tooling/shared/7kms6fvj.js +20 -0
- package/dist/tooling/shared/8sqrsw3s.js +49 -0
- package/dist/tooling/shared/96ps4g1z.js +32 -0
- package/dist/tooling/shared/9kazs5p6.js +195 -0
- package/dist/tooling/shared/9xzm7hjg.js +38 -0
- package/dist/tooling/shared/a6pp9d12.js +49 -0
- package/dist/tooling/shared/a7q7t4n3.js +22 -0
- package/dist/tooling/shared/aftb2mwr.js +18 -0
- package/dist/tooling/shared/bz2dqhab.js +311 -0
- package/dist/tooling/shared/cmptmb4f.js +12 -0
- package/dist/tooling/shared/ddjtfgnx.js +177 -0
- package/dist/tooling/shared/djydjpqt.js +261 -0
- package/dist/tooling/shared/dw08f3m8.js +9 -0
- package/dist/tooling/shared/dy672fz6.js +16 -0
- package/dist/tooling/shared/dzx85q70.js +66 -0
- package/dist/tooling/shared/ec71zqgt.js +270 -0
- package/dist/tooling/shared/ep8zh3bk.js +6 -0
- package/dist/tooling/shared/f9mphxej.js +3789 -0
- package/dist/tooling/shared/fb9k2qwd.js +89 -0
- package/dist/tooling/shared/g9ad4n80.js +211 -0
- package/dist/tooling/shared/gfvtj6d0.js +94 -0
- package/dist/tooling/shared/gmcf9cxf.js +294 -0
- package/dist/tooling/shared/htnaj77v.js +17 -0
- package/dist/tooling/shared/j9t5s12a.js +7 -0
- package/dist/tooling/shared/jne7b93p.js +42 -0
- package/dist/tooling/shared/ma2340rx.js +118 -0
- package/dist/tooling/shared/mtrqn2hn.js +505 -0
- package/dist/tooling/shared/n4jqhpqz.js +27 -0
- package/dist/tooling/shared/nf7jmhfa.js +20 -0
- package/dist/tooling/shared/p7f08ktn.js +332 -0
- package/dist/tooling/shared/ppnnnvj8.js +13 -0
- package/dist/tooling/shared/pqy21k24.js +312 -0
- package/dist/tooling/shared/pw8fgahx.js +69 -0
- package/dist/tooling/shared/pwsytxm5.js +17 -0
- package/dist/tooling/shared/rf83gr2d.js +94 -0
- package/dist/tooling/shared/rq5kk8j6.js +401 -0
- package/dist/tooling/shared/rs1jb051.js +12 -0
- package/dist/tooling/shared/smn6kz1p.js +157 -0
- package/dist/tooling/shared/spk1jg3r.js +1696 -0
- package/dist/tooling/shared/tn8gay14.js +143 -0
- package/dist/tooling/shared/vraj6d74.js +42 -0
- package/dist/tooling/shared/vs0t6qt8.js +64 -0
- package/dist/tooling/shared/vx86qjv8.js +150 -0
- package/dist/tooling/shared/w7qe8sj1.js +140 -0
- package/dist/tooling/shared/wt7j7nf6.js +15 -0
- package/dist/tooling/shared/wwnekq5n.js +6 -0
- package/dist/tooling/shared/xhrnjch9.js +185 -0
- package/dist/tooling/shared/xjs6zqtc.js +190 -0
- package/dist/tooling/shared/y031jct9.js +16 -0
- package/dist/tooling/shared/y5656f0e.js +233 -0
- package/dist/tooling/shared/yfr8hzhm.js +604 -0
- package/dist/tooling/shared/yk9mp7vb.js +250 -0
- package/dist/tooling/shared/yw30vnq2.js +139 -0
- package/dist/tooling/shared/z8d7ptht.js +618 -0
- package/dist/tooling/shared/zhwnfyb2.js +9 -0
- package/dist/tooling/shared/zvnhh1n0.js +198 -0
- package/dist/tooling/testing/index.js +3 -3
- package/package.json +14 -2
- package/dist/shared/y34a8714.js +0 -150
- package/dist/shared/zy8r7qvz.js +0 -116
- package/dist/shared/{ywr8hmey.js → 606g0nbf.js} +3 -3
- package/dist/shared/{rpycarcr.js → gcefca6p.js} +4 -4
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import {
|
|
2
|
+
queryHandle,
|
|
3
|
+
readHandle,
|
|
4
|
+
readCall,
|
|
5
|
+
attachHttp
|
|
6
|
+
} from "./mtrqn2hn.js";
|
|
7
|
+
import {
|
|
8
|
+
OkmError,
|
|
9
|
+
throwNamed,
|
|
10
|
+
emitWhere,
|
|
11
|
+
emitOrder,
|
|
12
|
+
refuseHidden,
|
|
13
|
+
rejectKeys,
|
|
14
|
+
readLimit,
|
|
15
|
+
projectExpr,
|
|
16
|
+
cell,
|
|
17
|
+
indexes,
|
|
18
|
+
quote,
|
|
19
|
+
list,
|
|
20
|
+
isRecord,
|
|
21
|
+
fail2
|
|
22
|
+
} from "./f9mphxej.js";
|
|
23
|
+
|
|
24
|
+
// src/runtime/aggregate.ts
|
|
25
|
+
var BUCKET = Symbol.for("okmodel.bucket");
|
|
26
|
+
var bucketChunk;
|
|
27
|
+
function loadBucketGroup() {
|
|
28
|
+
return bucketChunk ??= import("./2revefqt.js");
|
|
29
|
+
}
|
|
30
|
+
var OPTIONS = [
|
|
31
|
+
"where",
|
|
32
|
+
"groupBy",
|
|
33
|
+
"count",
|
|
34
|
+
"sum",
|
|
35
|
+
"avg",
|
|
36
|
+
"min",
|
|
37
|
+
"max",
|
|
38
|
+
"orderBy",
|
|
39
|
+
"limit",
|
|
40
|
+
"route",
|
|
41
|
+
"signal",
|
|
42
|
+
"timeout"
|
|
43
|
+
];
|
|
44
|
+
var NUMERIC = /^(smallint|integer|bigint|real|double precision|numeric|decimal)\b/;
|
|
45
|
+
var AS_NUMBER = (wire) => Number(wire);
|
|
46
|
+
var AS_TEXT = (wire) => wire;
|
|
47
|
+
var UNORDERED = /^(json|jsonb|bytea|point|line|tsvector)\b|\[\]$/;
|
|
48
|
+
var FUNCTIONS = [
|
|
49
|
+
{ option: "sum", tag: "s", numeric: true },
|
|
50
|
+
{ option: "avg", tag: "a", numeric: true },
|
|
51
|
+
{ option: "min", tag: "n", numeric: false },
|
|
52
|
+
{ option: "max", tag: "x", numeric: false }
|
|
53
|
+
];
|
|
54
|
+
function build(session, table, options, mods, view) {
|
|
55
|
+
try {
|
|
56
|
+
if (seesBucket(options))
|
|
57
|
+
return bucketHandle(session, table, options, mods, view);
|
|
58
|
+
return plan(session, table, options, mods, view);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
throw error instanceof OkmError ? attachHttp(session.http, error) : error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function bucketHandle(session, table, options, mods, view) {
|
|
64
|
+
const open = () => loadBucketGroup().then((mod) => {
|
|
65
|
+
try {
|
|
66
|
+
return { it: plan(session, table, options, mods, view, mod) };
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw error instanceof OkmError ? attachHttp(session.http, error) : error;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return queryHandle(() => open().then((box) => box.it), {
|
|
72
|
+
inspect: () => open().then((box) => box.it.inspect()),
|
|
73
|
+
sql: () => open().then((box) => box.it.sql()),
|
|
74
|
+
all: (reason) => build(session, table, options, { ...mods, all: reason }, view)
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function seesBucket(options) {
|
|
78
|
+
if (!isRecord(options))
|
|
79
|
+
return false;
|
|
80
|
+
const groupBy = options.groupBy;
|
|
81
|
+
if (!Array.isArray(groupBy))
|
|
82
|
+
return false;
|
|
83
|
+
for (const item of groupBy) {
|
|
84
|
+
if (typeof item === "object" && item !== null && BUCKET in item)
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
function plan(session, table, options, mods, view, buckets) {
|
|
90
|
+
const record = isRecord(options) ? options : {};
|
|
91
|
+
rejectKeys(record, OPTIONS, "aggregate");
|
|
92
|
+
const indexed = indexes(session.schema).get(table);
|
|
93
|
+
if (indexed === undefined)
|
|
94
|
+
fail2("OKM1120", `Table ${table} is not in the schema.`);
|
|
95
|
+
const spec = parse(indexed, record, buckets);
|
|
96
|
+
if (spec.groups.length > 0 && record.limit === undefined && mods.all === undefined) {
|
|
97
|
+
fail2("OKM1101", "aggregate() with groupBy needs a limit, or .all(reason) for every group.");
|
|
98
|
+
}
|
|
99
|
+
const names = groupNames(spec.groups);
|
|
100
|
+
const orderBy = record.orderBy;
|
|
101
|
+
if (orderBy !== undefined) {
|
|
102
|
+
if (!isRecord(orderBy))
|
|
103
|
+
fail2("OKM1120", "orderBy must be an object of fields.");
|
|
104
|
+
for (const field of Object.keys(orderBy)) {
|
|
105
|
+
if (!names.includes(field)) {
|
|
106
|
+
const column = indexed.columns.get(field);
|
|
107
|
+
if (column !== undefined)
|
|
108
|
+
refuseHidden(column);
|
|
109
|
+
throwNamed("OKM1120", field, names, `aggregate() orders by a groupBy field. Accepted names: ${list(names)}.`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (record.limit !== undefined)
|
|
114
|
+
readLimit(record.limit);
|
|
115
|
+
const base = readCall("find", table, {
|
|
116
|
+
where: record.where,
|
|
117
|
+
orderBy,
|
|
118
|
+
limit: record.limit,
|
|
119
|
+
signal: record.signal,
|
|
120
|
+
timeout: record.timeout,
|
|
121
|
+
route: record.route
|
|
122
|
+
}, mods.all, session.scope, session.schema.model[table], session.schema, view);
|
|
123
|
+
const call = { ...base, op: "aggregate", build: statement(spec, buckets) };
|
|
124
|
+
return readHandle(session, table, call, mods, (compiled, rows) => decode(compiled, rows));
|
|
125
|
+
}
|
|
126
|
+
function parse(table, record, buckets) {
|
|
127
|
+
const grouped = readGroups(table, record.groupBy, buckets);
|
|
128
|
+
const count = record.count === true;
|
|
129
|
+
if (record.count !== undefined && typeof record.count !== "boolean") {
|
|
130
|
+
fail2("OKM1120", "count is true when you want a row count.");
|
|
131
|
+
}
|
|
132
|
+
const calls = [];
|
|
133
|
+
for (const { option, tag, numeric } of FUNCTIONS) {
|
|
134
|
+
for (const column of columns(table, record[option], option)) {
|
|
135
|
+
const fits = numeric ? NUMERIC.test(column.dataType) : !UNORDERED.test(column.dataType);
|
|
136
|
+
if (!fits) {
|
|
137
|
+
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."}`);
|
|
138
|
+
}
|
|
139
|
+
calls.push({ option, tag, column, decode: numeric ? sumDecode(column) : column.decode });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (!count && calls.length === 0 && grouped.groups.length === 0) {
|
|
143
|
+
fail2("OKM1120", "aggregate() needs count, sum, avg, min, max, or groupBy.");
|
|
144
|
+
}
|
|
145
|
+
return { groups: grouped.groups, bucketed: grouped.bucketed, count, calls };
|
|
146
|
+
}
|
|
147
|
+
function sumDecode(column) {
|
|
148
|
+
const kind = typeof (column.decode?.("0") ?? "");
|
|
149
|
+
if (kind === "string")
|
|
150
|
+
return AS_TEXT;
|
|
151
|
+
if (kind === "number")
|
|
152
|
+
return AS_NUMBER;
|
|
153
|
+
return fail2("OKM1124", `sum and avg need a column whose value is a number or a string. ${column.field} reads as ${kind}.`);
|
|
154
|
+
}
|
|
155
|
+
function columns(table, value, option) {
|
|
156
|
+
if (value === undefined)
|
|
157
|
+
return [];
|
|
158
|
+
if (!Array.isArray(value))
|
|
159
|
+
fail2("OKM1120", `${option} must be a list of field names.`);
|
|
160
|
+
const out = [];
|
|
161
|
+
for (const name of value) {
|
|
162
|
+
const column = typeof name === "string" ? table.columns.get(name) : undefined;
|
|
163
|
+
if (typeof name !== "string" || column === undefined) {
|
|
164
|
+
throwNamed("OKM1120", String(name), table.names, `Field ${String(name)} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
165
|
+
}
|
|
166
|
+
if (column.hidden) {
|
|
167
|
+
fail2("OKM1120", `Field ${column.field} is hidden, so ${option} cannot read it.`);
|
|
168
|
+
}
|
|
169
|
+
out.push(column);
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
function groupNames(groups) {
|
|
174
|
+
const names = [];
|
|
175
|
+
for (const group of groups)
|
|
176
|
+
names.push(group.kind === "field" ? group.column.field : group.as);
|
|
177
|
+
return names;
|
|
178
|
+
}
|
|
179
|
+
function readGroups(table, value, buckets) {
|
|
180
|
+
if (value === undefined)
|
|
181
|
+
return { groups: [], bucketed: false };
|
|
182
|
+
if (!Array.isArray(value))
|
|
183
|
+
fail2("OKM1120", "groupBy must be a list of field names.");
|
|
184
|
+
const fields = new Set;
|
|
185
|
+
const aliases = new Set;
|
|
186
|
+
const groups = [];
|
|
187
|
+
let bucketed = false;
|
|
188
|
+
for (const item of value) {
|
|
189
|
+
if (typeof item === "object" && item !== null && BUCKET in item) {
|
|
190
|
+
if (buckets === undefined)
|
|
191
|
+
fail2("OKM1120", "bucket group");
|
|
192
|
+
groups.push(buckets.readBucket(table, item, fields, aliases));
|
|
193
|
+
bucketed = true;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const column = typeof item === "string" ? table.columns.get(item) : undefined;
|
|
197
|
+
if (typeof item !== "string" || column === undefined) {
|
|
198
|
+
throwNamed("OKM1120", String(item), table.names, `Field ${String(item)} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
199
|
+
}
|
|
200
|
+
if (column.hidden) {
|
|
201
|
+
fail2("OKM1120", `Field ${column.field} is hidden, so groupBy cannot read it.`);
|
|
202
|
+
}
|
|
203
|
+
if (aliases.has(column.field)) {
|
|
204
|
+
fail2("OKM1120", `group field ${column.field} clashes with a bucket as.`);
|
|
205
|
+
}
|
|
206
|
+
fields.add(column.field);
|
|
207
|
+
groups.push({ kind: "field", column });
|
|
208
|
+
}
|
|
209
|
+
return { groups, bucketed };
|
|
210
|
+
}
|
|
211
|
+
function statement(spec, buckets) {
|
|
212
|
+
return (schema, table, sink, outputs, call) => {
|
|
213
|
+
sink.mark(`aggregate|${table.model.name}|g:${groupMark(spec.groups)}|c:${String(spec.count)}|${spec.calls.map((item) => `${item.tag}:${item.column.field}`).join(",")}|`);
|
|
214
|
+
sink.text("select ");
|
|
215
|
+
const wrote = { at: 0 };
|
|
216
|
+
for (const group of spec.groups) {
|
|
217
|
+
if (group.kind === "field") {
|
|
218
|
+
put(sink, outputs, wrote, projectExpr(`t.${quote(group.column.sql)}`, group.column.dataType), {
|
|
219
|
+
key: `g:${group.column.field}`,
|
|
220
|
+
decode: group.column.decode
|
|
221
|
+
});
|
|
222
|
+
} else {
|
|
223
|
+
if (buckets === undefined)
|
|
224
|
+
fail2("OKM1120", "bucket group");
|
|
225
|
+
buckets.writeBucket(sink, outputs, wrote, group);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (spec.count)
|
|
229
|
+
put(sink, outputs, wrote, "count(*)::text", { key: "c:", decode: undefined });
|
|
230
|
+
for (const item of spec.calls) {
|
|
231
|
+
const ref = `t.${quote(item.column.sql)}`;
|
|
232
|
+
const expr = item.option === "sum" || item.option === "avg" ? `${item.option}(${ref})::text` : projectExpr(`${item.option}(${ref})`, item.column.dataType);
|
|
233
|
+
put(sink, outputs, wrote, expr, {
|
|
234
|
+
key: `${item.tag}:${item.column.field}`,
|
|
235
|
+
decode: item.decode
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
sink.text(" from ");
|
|
239
|
+
sink.text(quote(table.model.sql));
|
|
240
|
+
sink.text(" t");
|
|
241
|
+
emitWhere(schema, table, call.where, sink, "t", 0);
|
|
242
|
+
if (spec.groups.length > 0) {
|
|
243
|
+
sink.text(" group by ");
|
|
244
|
+
if (spec.bucketed) {
|
|
245
|
+
if (buckets === undefined)
|
|
246
|
+
fail2("OKM1120", "bucket group");
|
|
247
|
+
buckets.writeGrouped(sink, groupNames(spec.groups), call.orderBy);
|
|
248
|
+
} else {
|
|
249
|
+
sink.text(spec.groups.map((group) => fieldRef(group)).join(", "));
|
|
250
|
+
if (isRecord(call.orderBy) && Object.keys(call.orderBy).length > 0) {
|
|
251
|
+
emitOrder(table, call.orderBy, sink, "t");
|
|
252
|
+
} else {
|
|
253
|
+
sink.text(" order by ");
|
|
254
|
+
sink.text(spec.groups.map((group) => `${fieldRef(group)} asc nulls last`).join(", "));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (call.limit !== undefined) {
|
|
259
|
+
const limit = String(call.limit);
|
|
260
|
+
sink.text(" limit ");
|
|
261
|
+
sink.param(limit);
|
|
262
|
+
sink.mark(`l:${limit}`);
|
|
263
|
+
}
|
|
264
|
+
if (typeof call.all === "string")
|
|
265
|
+
sink.mark(`all:${call.all}`);
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function groupMark(groups) {
|
|
269
|
+
const parts = [];
|
|
270
|
+
for (const group of groups) {
|
|
271
|
+
parts.push(group.kind === "field" ? group.column.field : `b:${group.column.field}:${group.as}:${group.unit}:${String(group.shift)}`);
|
|
272
|
+
}
|
|
273
|
+
return parts.join(",");
|
|
274
|
+
}
|
|
275
|
+
function fieldRef(group) {
|
|
276
|
+
if (group.kind !== "field")
|
|
277
|
+
return fail2("OKM1120", "bucket group");
|
|
278
|
+
return `t.${quote(group.column.sql)}`;
|
|
279
|
+
}
|
|
280
|
+
function put(sink, outputs, wrote, expr, out) {
|
|
281
|
+
if (wrote.at > 0)
|
|
282
|
+
sink.text(", ");
|
|
283
|
+
sink.text(expr);
|
|
284
|
+
outputs?.fields.push({ key: out.key, at: wrote.at, decode: out.decode });
|
|
285
|
+
wrote.at += 1;
|
|
286
|
+
}
|
|
287
|
+
function decode(compiled, rows) {
|
|
288
|
+
const items = [];
|
|
289
|
+
for (const row of rows) {
|
|
290
|
+
const item = {};
|
|
291
|
+
for (const field of compiled.outputs.fields) {
|
|
292
|
+
const value = row[field.at];
|
|
293
|
+
const tag = field.key.slice(0, 2);
|
|
294
|
+
const name = field.key.slice(2);
|
|
295
|
+
if (tag === "g:") {
|
|
296
|
+
item[name] = cell(value, field.decode);
|
|
297
|
+
} else if (tag === "c:") {
|
|
298
|
+
item.count = Number(value ?? 0);
|
|
299
|
+
} else {
|
|
300
|
+
const group = tag === "s:" ? "sum" : tag === "a:" ? "avg" : tag === "n:" ? "min" : "max";
|
|
301
|
+
const into = item[group] ??= {};
|
|
302
|
+
into[name] = cell(value, field.decode);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
items.push(item);
|
|
306
|
+
}
|
|
307
|
+
return items;
|
|
308
|
+
}
|
|
309
|
+
export {
|
|
310
|
+
build
|
|
311
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
tag
|
|
3
|
+
} from "./f9mphxej.js";
|
|
4
|
+
|
|
5
|
+
// src/runtime/preset-stack.ts
|
|
6
|
+
function stack2(where, presets) {
|
|
7
|
+
if (presets === undefined || presets.length === 0)
|
|
8
|
+
return where;
|
|
9
|
+
return tag("and", where === undefined ? presets : [where, ...presets]);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { stack2 };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
build3
|
|
3
|
+
} from "./zvnhh1n0.js";
|
|
4
|
+
import {
|
|
5
|
+
attachHttp
|
|
6
|
+
} from "./mtrqn2hn.js";
|
|
7
|
+
import {
|
|
8
|
+
OkmError,
|
|
9
|
+
rejectKeys,
|
|
10
|
+
readLimit,
|
|
11
|
+
indexes,
|
|
12
|
+
isRecord,
|
|
13
|
+
fail2
|
|
14
|
+
} from "./f9mphxej.js";
|
|
15
|
+
|
|
16
|
+
// src/runtime/read-stream.ts
|
|
17
|
+
var DEFAULT_BATCH = 1000;
|
|
18
|
+
var MAX_BATCH = 2147483647;
|
|
19
|
+
async function* streamRows(session, call, mods, view, batchOptions, log) {
|
|
20
|
+
const stop = (error) => {
|
|
21
|
+
throw log(attachHttp(session.http, error));
|
|
22
|
+
};
|
|
23
|
+
let batch;
|
|
24
|
+
let total;
|
|
25
|
+
let signal;
|
|
26
|
+
let deadline;
|
|
27
|
+
try {
|
|
28
|
+
if (call.op !== "find") {
|
|
29
|
+
fail2("OKM1120", `stream() reads rows from find(). ${call.op}() returns one value.`);
|
|
30
|
+
}
|
|
31
|
+
if (call.search !== undefined) {
|
|
32
|
+
fail2("OKM1120", "stream() does not take search in this version. Use find({ search, limit }) for a ranked list.", "Ranked pages are later. find({ search, limit }) returns one ranked list.");
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(call.select) && call.select.some((item) => typeof item !== "string")) {
|
|
35
|
+
fail2("OKM1120", "stream() does not take a window. The keyset cursor has no window value to encode.");
|
|
36
|
+
}
|
|
37
|
+
const indexed = indexes(session.schema).get(call.table);
|
|
38
|
+
if (indexed === undefined)
|
|
39
|
+
fail2("OKM1120", `Table ${call.table} is not in the schema.`);
|
|
40
|
+
if (indexed.model.primary.length === 0) {
|
|
41
|
+
fail2("OKM1120", `stream() needs a primary key on ${indexed.model.name}. A keyset batch orders by that key.`, "Give the table a primary key. stream() orders by it.");
|
|
42
|
+
}
|
|
43
|
+
batch = readBatch(batchOptions);
|
|
44
|
+
if (mods.all !== undefined && mods.all.length === 0) {
|
|
45
|
+
fail2("OKM1101", "find() .all needs a reason.");
|
|
46
|
+
}
|
|
47
|
+
if (call.limit !== undefined)
|
|
48
|
+
total = readLimit(call.limit);
|
|
49
|
+
else if (mods.all === undefined) {
|
|
50
|
+
fail2("OKM1101", "find() needs a limit, or .all(reason) when the full set is intentional.");
|
|
51
|
+
}
|
|
52
|
+
const timeout = call.timeout;
|
|
53
|
+
if (timeout !== undefined && (typeof timeout !== "number" || !(timeout > 0))) {
|
|
54
|
+
fail2("OKM1121", "timeout must be a number of milliseconds above 0.");
|
|
55
|
+
}
|
|
56
|
+
signal = signalOf(call.signal);
|
|
57
|
+
deadline = timeout === undefined ? undefined : Date.now() + timeout;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error instanceof OkmError)
|
|
60
|
+
stop(error);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
if (total === 0)
|
|
64
|
+
return;
|
|
65
|
+
const cancel = session.pool.capabilities.cancel === true;
|
|
66
|
+
const statement = session.timeouts?.statement;
|
|
67
|
+
const pin = {};
|
|
68
|
+
let after;
|
|
69
|
+
let left = total;
|
|
70
|
+
let pending;
|
|
71
|
+
try {
|
|
72
|
+
while (left === undefined || left > 0) {
|
|
73
|
+
if (signal?.aborted === true) {
|
|
74
|
+
stop(new OkmError("cancelled", "The stream was cancelled.", { kind: "cancelled" }));
|
|
75
|
+
}
|
|
76
|
+
const remaining = timeLeft(deadline);
|
|
77
|
+
const size = left === undefined ? batch : Math.min(batch, left);
|
|
78
|
+
const handle = build3(session, call.table, pageFields(call, size, after, signal, batchTimeout(remaining, cancel, statement)), mods, view, pin);
|
|
79
|
+
pending = handle;
|
|
80
|
+
const value = asPage(await handle);
|
|
81
|
+
pending = undefined;
|
|
82
|
+
for (const row of value.items) {
|
|
83
|
+
yield row;
|
|
84
|
+
if (left !== undefined) {
|
|
85
|
+
left -= 1;
|
|
86
|
+
if (left === 0)
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (value.next === null || value.items.length < size)
|
|
91
|
+
return;
|
|
92
|
+
after = value.next;
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error instanceof OkmError && error.kind === "timeout" && error.message === "The stream timed out.") {
|
|
96
|
+
stop(error);
|
|
97
|
+
}
|
|
98
|
+
throw error;
|
|
99
|
+
} finally {
|
|
100
|
+
if (pending !== undefined) {
|
|
101
|
+
pending.then(() => {
|
|
102
|
+
return;
|
|
103
|
+
}, () => {
|
|
104
|
+
return;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function readBatch(options) {
|
|
110
|
+
if (options === undefined)
|
|
111
|
+
return DEFAULT_BATCH;
|
|
112
|
+
if (!isRecord(options))
|
|
113
|
+
fail2("OKM1120", "stream() takes an object. Pass { batch }.");
|
|
114
|
+
rejectKeys(options, ["batch"], "stream");
|
|
115
|
+
const batch = options.batch;
|
|
116
|
+
if (batch === undefined)
|
|
117
|
+
return DEFAULT_BATCH;
|
|
118
|
+
if (typeof batch !== "number" || !Number.isInteger(batch) || batch < 1 || batch > MAX_BATCH) {
|
|
119
|
+
fail2("OKM1121", "stream() batch must be an integer from 1 to 2147483647.");
|
|
120
|
+
}
|
|
121
|
+
return batch;
|
|
122
|
+
}
|
|
123
|
+
function pageFields(call, size, after, signal, timeout) {
|
|
124
|
+
const out = { limit: size };
|
|
125
|
+
if (call.where !== undefined)
|
|
126
|
+
out.where = call.where;
|
|
127
|
+
if (call.select !== undefined)
|
|
128
|
+
out.select = call.select;
|
|
129
|
+
if (call.orderBy !== undefined)
|
|
130
|
+
out.orderBy = call.orderBy;
|
|
131
|
+
if (call.include !== undefined)
|
|
132
|
+
out.include = call.include;
|
|
133
|
+
if (call.route !== undefined)
|
|
134
|
+
out.route = call.route;
|
|
135
|
+
if (after !== undefined)
|
|
136
|
+
out.after = after;
|
|
137
|
+
if (signal !== undefined)
|
|
138
|
+
out.signal = signal;
|
|
139
|
+
if (timeout !== undefined)
|
|
140
|
+
out.timeout = timeout;
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
function timeLeft(deadline) {
|
|
144
|
+
if (deadline === undefined)
|
|
145
|
+
return;
|
|
146
|
+
const left = deadline - Date.now();
|
|
147
|
+
if (left <= 0)
|
|
148
|
+
throw new OkmError("timeout", "The stream timed out.", { kind: "timeout" });
|
|
149
|
+
return left;
|
|
150
|
+
}
|
|
151
|
+
function batchTimeout(remaining, cancel, statement) {
|
|
152
|
+
if (!cancel || remaining === undefined)
|
|
153
|
+
return;
|
|
154
|
+
if (statement !== undefined && statement > 0 && statement < remaining)
|
|
155
|
+
return statement;
|
|
156
|
+
return remaining;
|
|
157
|
+
}
|
|
158
|
+
function signalOf(value) {
|
|
159
|
+
if (typeof value === "object" && value !== null && "aborted" in value) {
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
function asPage(value) {
|
|
165
|
+
if (typeof value !== "object" || value === null || !("items" in value) || !("next" in value)) {
|
|
166
|
+
throw new OkmError("OKM1120", "stream() did not get a page of rows.");
|
|
167
|
+
}
|
|
168
|
+
const items = value.items;
|
|
169
|
+
const next = value.next;
|
|
170
|
+
if (!Array.isArray(items) || next !== null && typeof next !== "string") {
|
|
171
|
+
throw new OkmError("OKM1120", "stream() did not get a page of rows.");
|
|
172
|
+
}
|
|
173
|
+
return { items, next };
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
streamRows
|
|
177
|
+
};
|