dzql 0.10.0 → 0.11.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 +6 -6
- package/package.json +1 -1
- package/src/compile/cascades.ts +6 -6
- package/src/compile/columns.ts +7 -8
- package/src/compile/holders.ts +5 -11
- package/src/compile/holds.ts +4 -5
- package/src/compile/ledger.ts +7 -8
- package/src/compile/lookups.ts +118 -0
- package/src/compile/opens.ts +6 -0
- package/src/compile/resolve.ts +4 -4
- package/src/compile/root.ts +4 -4
- package/src/compile/rows.ts +18 -17
- package/src/compile/scope.ts +5 -4
- package/src/compile/told.ts +5 -4
- package/src/postgres/codegen.ts +2 -1
- package/src/postgres/listener.ts +50 -35
- package/src/postgres/pglite.ts +4 -1
- package/src/sql/001a-delta-meta.sql +52 -19
- package/src/sql/001b-delta-scope.sql +18 -477
- package/src/sql/001c-delta-read.sql +14 -291
- package/src/sql/001d-delta-write.sql +64 -379
- package/src/sql/001e-delta-ops.sql +4 -62
- package/src/sql/001g-delta-ledger.sql +6 -29
|
@@ -37,140 +37,6 @@ $$ LANGUAGE plpgsql;
|
|
|
37
37
|
CREATE OR REPLACE FUNCTION _delta_bump_and_notify(p_doc TEXT, p_ops JSONB)
|
|
38
38
|
RETURNS BIGINT LANGUAGE sql AS $$ SELECT _delta_bump_and_notify(p_doc, p_ops, NULL); $$;
|
|
39
39
|
|
|
40
|
-
-- ---------------------------------------------------------------------------
|
|
41
|
-
-- _delta_load_collection: recursively load a collection's rows as a JSONB map.
|
|
42
|
-
-- When p_at is NULL, loads current state. When set, loads at that point in time.
|
|
43
|
-
-- ---------------------------------------------------------------------------
|
|
44
|
-
|
|
45
|
-
CREATE OR REPLACE FUNCTION _delta_load_collection(
|
|
46
|
-
p_collection_key TEXT,
|
|
47
|
-
p_root_collection TEXT,
|
|
48
|
-
p_root_id BIGINT,
|
|
49
|
-
p_at TIMESTAMPTZ DEFAULT NULL
|
|
50
|
-
) RETURNS JSONB AS $$
|
|
51
|
-
DECLARE
|
|
52
|
-
v_coll RECORD;
|
|
53
|
-
v_source TEXT;
|
|
54
|
-
v_strip BOOLEAN;
|
|
55
|
-
v_where TEXT;
|
|
56
|
-
v_result JSONB;
|
|
57
|
-
v_parent_map JSONB;
|
|
58
|
-
v_parent_ids BIGINT[];
|
|
59
|
-
BEGIN
|
|
60
|
-
SELECT * INTO v_coll FROM _delta_collections
|
|
61
|
-
WHERE collection_key = p_collection_key;
|
|
62
|
-
IF NOT FOUND THEN RETURN '{}'::jsonb; END IF;
|
|
63
|
-
|
|
64
|
-
v_source := _delta_source_view(v_coll.table_name, v_coll.temporal, p_at);
|
|
65
|
-
v_strip := v_coll.temporal;
|
|
66
|
-
v_where := CASE WHEN v_coll.temporal AND p_at IS NOT NULL
|
|
67
|
-
THEN _delta_temporal_where(p_at)
|
|
68
|
-
ELSE 'TRUE' END;
|
|
69
|
-
|
|
70
|
-
-- No parent
|
|
71
|
-
IF v_coll.parent_collection IS NULL THEN
|
|
72
|
-
IF v_strip THEN
|
|
73
|
-
EXECUTE format(
|
|
74
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, _delta_strip_temporal(to_jsonb(t.*))), ''{}''::jsonb) FROM %I t WHERE %s',
|
|
75
|
-
v_source, v_where
|
|
76
|
-
) INTO v_result;
|
|
77
|
-
ELSE
|
|
78
|
-
EXECUTE format(
|
|
79
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, to_jsonb(t.*)), ''{}''::jsonb) FROM %I t',
|
|
80
|
-
v_source
|
|
81
|
-
) INTO v_result;
|
|
82
|
-
END IF;
|
|
83
|
-
RETURN v_result;
|
|
84
|
-
END IF;
|
|
85
|
-
|
|
86
|
-
-- Direct child of root
|
|
87
|
-
IF v_coll.parent_collection = p_root_collection THEN
|
|
88
|
-
IF v_strip THEN
|
|
89
|
-
EXECUTE format(
|
|
90
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, _delta_strip_temporal(to_jsonb(t.*))), ''{}''::jsonb) FROM %I t WHERE t.%I = $1 AND %s',
|
|
91
|
-
v_source, v_coll.parent_fk, v_where
|
|
92
|
-
) INTO v_result USING p_root_id;
|
|
93
|
-
ELSE
|
|
94
|
-
EXECUTE format(
|
|
95
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, to_jsonb(t.*)), ''{}''::jsonb) FROM %I t WHERE t.%I = $1',
|
|
96
|
-
v_source, v_coll.parent_fk
|
|
97
|
-
) INTO v_result USING p_root_id;
|
|
98
|
-
END IF;
|
|
99
|
-
RETURN v_result;
|
|
100
|
-
END IF;
|
|
101
|
-
|
|
102
|
-
-- Grandchild+: load parent rows recursively, then filter by their IDs. The
|
|
103
|
-
-- parent is walked whether or not the document includes it; one with no
|
|
104
|
-
-- parent of its own ends the chain short of the root, so nothing under it is
|
|
105
|
-
-- in the document -- as _delta_chain_root and _delta_row_in_scope judge it,
|
|
106
|
-
-- and the SQLite backend reads it (todo #32).
|
|
107
|
-
IF NOT EXISTS (SELECT 1 FROM _delta_collections
|
|
108
|
-
WHERE collection_key = v_coll.parent_collection
|
|
109
|
-
AND parent_collection IS NOT NULL) THEN
|
|
110
|
-
RETURN '{}'::jsonb;
|
|
111
|
-
END IF;
|
|
112
|
-
v_parent_map := _delta_load_collection(
|
|
113
|
-
v_coll.parent_collection, p_root_collection, p_root_id, p_at
|
|
114
|
-
);
|
|
115
|
-
SELECT array_agg(k::BIGINT) INTO v_parent_ids
|
|
116
|
-
FROM jsonb_object_keys(v_parent_map) AS k;
|
|
117
|
-
|
|
118
|
-
IF v_parent_ids IS NULL THEN RETURN '{}'::jsonb; END IF;
|
|
119
|
-
|
|
120
|
-
IF v_strip THEN
|
|
121
|
-
EXECUTE format(
|
|
122
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, _delta_strip_temporal(to_jsonb(t.*))), ''{}''::jsonb) FROM %I t WHERE t.%I = ANY($1) AND %s',
|
|
123
|
-
v_source, v_coll.parent_fk, v_where
|
|
124
|
-
) INTO v_result USING v_parent_ids;
|
|
125
|
-
ELSE
|
|
126
|
-
EXECUTE format(
|
|
127
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, to_jsonb(t.*)), ''{}''::jsonb) FROM %I t WHERE t.%I = ANY($1)',
|
|
128
|
-
v_source, v_coll.parent_fk
|
|
129
|
-
) INTO v_result USING v_parent_ids;
|
|
130
|
-
END IF;
|
|
131
|
-
|
|
132
|
-
RETURN v_result;
|
|
133
|
-
END;
|
|
134
|
-
$$ LANGUAGE plpgsql STABLE;
|
|
135
|
-
|
|
136
|
-
-- ---------------------------------------------------------------------------
|
|
137
|
-
-- _delta_load_collection_all: load every row of a collection as a JSONB map.
|
|
138
|
-
-- Used by list-mode docs' `include` traversal (no FK filter — list mode has
|
|
139
|
-
-- no single root id to filter against, so "include" means "load it all").
|
|
140
|
-
-- ---------------------------------------------------------------------------
|
|
141
|
-
|
|
142
|
-
CREATE OR REPLACE FUNCTION _delta_load_collection_all(
|
|
143
|
-
p_collection_key TEXT,
|
|
144
|
-
p_at TIMESTAMPTZ DEFAULT NULL
|
|
145
|
-
) RETURNS JSONB AS $$
|
|
146
|
-
DECLARE
|
|
147
|
-
v_coll RECORD;
|
|
148
|
-
v_source TEXT;
|
|
149
|
-
v_result JSONB;
|
|
150
|
-
BEGIN
|
|
151
|
-
SELECT * INTO v_coll FROM _delta_collections
|
|
152
|
-
WHERE collection_key = p_collection_key;
|
|
153
|
-
IF NOT FOUND THEN RETURN '{}'::jsonb; END IF;
|
|
154
|
-
|
|
155
|
-
v_source := _delta_source_view(v_coll.table_name, v_coll.temporal, p_at);
|
|
156
|
-
|
|
157
|
-
IF v_coll.temporal THEN
|
|
158
|
-
EXECUTE format(
|
|
159
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, _delta_strip_temporal(to_jsonb(t.*))), ''{}''::jsonb) FROM %I t WHERE %s',
|
|
160
|
-
v_source,
|
|
161
|
-
CASE WHEN p_at IS NOT NULL THEN _delta_temporal_where(p_at) ELSE 'TRUE' END
|
|
162
|
-
) INTO v_result;
|
|
163
|
-
ELSE
|
|
164
|
-
EXECUTE format(
|
|
165
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, to_jsonb(t.*)), ''{}''::jsonb) FROM %I t',
|
|
166
|
-
v_source
|
|
167
|
-
) INTO v_result;
|
|
168
|
-
END IF;
|
|
169
|
-
|
|
170
|
-
RETURN v_result;
|
|
171
|
-
END;
|
|
172
|
-
$$ LANGUAGE plpgsql STABLE;
|
|
173
|
-
|
|
174
40
|
-- ---------------------------------------------------------------------------
|
|
175
41
|
-- Implied documents (todo #34): there before their root row is, as on SQLite.
|
|
176
42
|
--
|
|
@@ -193,14 +59,14 @@ RETURNS JSONB LANGUAGE sql STABLE AS $$
|
|
|
193
59
|
WHEN d->>'type' IN ('integer', 'real') THEN '0'::jsonb
|
|
194
60
|
WHEN d->>'type' = 'boolean' THEN 'false'::jsonb
|
|
195
61
|
ELSE 'null'::jsonb END)
|
|
196
|
-
FROM
|
|
197
|
-
|
|
62
|
+
FROM (SELECT _delta_collection(p_def.root_collection) AS c) AS r,
|
|
63
|
+
jsonb_each(_delta_cols((r.c).collection_key, (r.c).columns_def)) AS x(k, d)), '{}'::jsonb);
|
|
198
64
|
$$;
|
|
199
65
|
|
|
200
66
|
CREATE OR REPLACE FUNCTION _delta_make_implied(p_def _delta_docs, p_id BIGINT, p_ops JSONB, p_ts TIMESTAMPTZ)
|
|
201
67
|
RETURNS void AS $$
|
|
202
68
|
DECLARE
|
|
203
|
-
v_coll
|
|
69
|
+
v_coll _delta_collections;
|
|
204
70
|
v_exists BOOLEAN;
|
|
205
71
|
v_row JSONB;
|
|
206
72
|
BEGIN
|
|
@@ -210,8 +76,8 @@ BEGIN
|
|
|
210
76
|
AND (_delta_split_path(o->>'path'))[1] = p_def.root_collection) THEN
|
|
211
77
|
RETURN;
|
|
212
78
|
END IF;
|
|
213
|
-
|
|
214
|
-
IF
|
|
79
|
+
v_coll := _delta_collection(p_def.root_collection);
|
|
80
|
+
IF v_coll.collection_key IS NULL THEN RETURN; END IF;
|
|
215
81
|
v_exists := _delta_row_there(p_def.root_collection, p_id);
|
|
216
82
|
IF v_exists THEN RETURN; END IF;
|
|
217
83
|
-- Not there, as the writer reads it: made under the add rule (todo #71) -- an
|
|
@@ -244,43 +110,10 @@ BEGIN
|
|
|
244
110
|
END;
|
|
245
111
|
$$ LANGUAGE plpgsql;
|
|
246
112
|
|
|
247
|
-
-- ---------------------------------------------------------------------------
|
|
248
|
-
-- _delta_read_list: a list document -- the root rows `p_where` admits, and
|
|
249
|
-
-- each included collection in full (list mode has no single root id to filter
|
|
250
|
-
-- against, so "include" means "load it all") -- as they stand (p_at NULL), or
|
|
251
|
-
-- a temporal table's as they stood at p_at. delta_open's and delta_open_at's.
|
|
252
|
-
-- ---------------------------------------------------------------------------
|
|
253
|
-
|
|
254
|
-
CREATE OR REPLACE FUNCTION _delta_read_list(p_def _delta_docs, p_where TEXT, p_at TIMESTAMPTZ)
|
|
255
|
-
RETURNS JSONB AS $$
|
|
256
|
-
DECLARE
|
|
257
|
-
v_root RECORD;
|
|
258
|
-
v_rows JSONB;
|
|
259
|
-
v_result JSONB;
|
|
260
|
-
v_coll_key TEXT;
|
|
261
|
-
BEGIN
|
|
262
|
-
SELECT * INTO v_root FROM _delta_collections WHERE collection_key = p_def.root_collection;
|
|
263
|
-
EXECUTE format(
|
|
264
|
-
'SELECT COALESCE(jsonb_object_agg(t.id, %s), ''{}''::jsonb) FROM %I t WHERE %s AND %s',
|
|
265
|
-
CASE WHEN v_root.temporal THEN '_delta_strip_temporal(to_jsonb(t.*))' ELSE 'to_jsonb(t.*)' END,
|
|
266
|
-
_delta_source_view(v_root.table_name, v_root.temporal, p_at),
|
|
267
|
-
CASE WHEN v_root.temporal AND p_at IS NOT NULL THEN _delta_temporal_where(p_at) ELSE 'TRUE' END,
|
|
268
|
-
p_where
|
|
269
|
-
) INTO v_rows;
|
|
270
|
-
v_result := jsonb_build_object(p_def.root_collection, v_rows);
|
|
271
|
-
FOREACH v_coll_key IN ARRAY p_def.include
|
|
272
|
-
LOOP
|
|
273
|
-
v_result := v_result || jsonb_build_object(v_coll_key, _delta_load_collection_all(v_coll_key, p_at));
|
|
274
|
-
END LOOP;
|
|
275
|
-
RETURN v_result;
|
|
276
|
-
END;
|
|
277
|
-
$$ LANGUAGE plpgsql STABLE;
|
|
278
|
-
|
|
279
113
|
-- ---------------------------------------------------------------------------
|
|
280
114
|
-- _delta_show: a row of `p_coll` as a document shows it -- where it names that
|
|
281
115
|
-- collection's columns (`held`, todo #70), those, the row's id and its parent
|
|
282
|
-
-- key; else whole.
|
|
283
|
-
-- root is one row, not a map). showRow / showDoc in schema.ts.
|
|
116
|
+
-- key; else whole. showRow in schema.ts.
|
|
284
117
|
-- ---------------------------------------------------------------------------
|
|
285
118
|
|
|
286
119
|
CREATE OR REPLACE FUNCTION _delta_show(p_def _delta_docs, p_coll TEXT, p_row JSONB)
|
|
@@ -288,24 +121,9 @@ RETURNS JSONB AS $$
|
|
|
288
121
|
SELECT CASE WHEN NOT COALESCE(p_def.held, '{}'::jsonb) ? p_coll OR jsonb_typeof(p_row) IS DISTINCT FROM 'object' THEN p_row
|
|
289
122
|
ELSE (SELECT COALESCE(jsonb_object_agg(f, v), '{}'::jsonb) FROM jsonb_each(p_row) AS e(f, v)
|
|
290
123
|
WHERE f = 'id' OR (p_def.held->p_coll) ? f
|
|
291
|
-
OR f = (
|
|
124
|
+
OR f = (_delta_collection(p_coll)).parent_fk) END;
|
|
292
125
|
$$ LANGUAGE sql STABLE;
|
|
293
126
|
|
|
294
|
-
CREATE OR REPLACE FUNCTION _delta_show_doc(p_def _delta_docs, p_doc JSONB, p_single BOOLEAN)
|
|
295
|
-
RETURNS JSONB AS $$
|
|
296
|
-
DECLARE
|
|
297
|
-
v_out JSONB := p_doc;
|
|
298
|
-
v_coll TEXT;
|
|
299
|
-
BEGIN
|
|
300
|
-
FOR v_coll IN SELECT jsonb_object_keys(COALESCE(p_def.held, '{}'::jsonb)) LOOP
|
|
301
|
-
CONTINUE WHEN jsonb_typeof(p_doc->v_coll) IS DISTINCT FROM 'object';
|
|
302
|
-
v_out := v_out || jsonb_build_object(v_coll, CASE WHEN p_single AND v_coll = p_def.root_collection THEN _delta_show(p_def, v_coll, p_doc->v_coll)
|
|
303
|
-
ELSE (SELECT COALESCE(jsonb_object_agg(id, _delta_show(p_def, v_coll, r)), '{}'::jsonb) FROM jsonb_each(p_doc->v_coll) AS e(id, r)) END);
|
|
304
|
-
END LOOP;
|
|
305
|
-
RETURN v_out;
|
|
306
|
-
END;
|
|
307
|
-
$$ LANGUAGE plpgsql STABLE;
|
|
308
|
-
|
|
309
127
|
-- _delta_show_ops: ops as the document `p_doc_name` shows them -- what its
|
|
310
128
|
-- writer is answered (a write's ops and inverse, a walk's, its history): a
|
|
311
129
|
-- row's value, its columns (_delta_show); a field it does not hold
|
|
@@ -319,13 +137,13 @@ DECLARE
|
|
|
319
137
|
v_out JSONB := '[]'::jsonb;
|
|
320
138
|
v_op JSONB;
|
|
321
139
|
v_parts TEXT[];
|
|
322
|
-
v_coll
|
|
140
|
+
v_coll _delta_collections;
|
|
323
141
|
v_field TEXT;
|
|
324
142
|
BEGIN
|
|
325
143
|
IF v_def.prefix IS NULL OR COALESCE(v_def.held, '{}'::jsonb) = '{}'::jsonb OR jsonb_typeof(p_ops) <> 'array' THEN RETURN p_ops; END IF;
|
|
326
144
|
FOR v_op IN SELECT jsonb_array_elements(p_ops) LOOP
|
|
327
145
|
v_parts := _delta_split_path(v_op->>'path');
|
|
328
|
-
|
|
146
|
+
v_coll := _delta_collection(v_parts[1]);
|
|
329
147
|
v_field := CASE WHEN array_length(v_parts, 1) >= 3 THEN v_parts[3]
|
|
330
148
|
WHEN array_length(v_parts, 1) = 2 AND (_delta_cols(v_coll.collection_key, v_coll.columns_def) ? v_parts[2] OR v_parts[2] = v_coll.parent_fk) THEN v_parts[2] END;
|
|
331
149
|
IF v_field IS NOT NULL THEN
|
|
@@ -340,109 +158,14 @@ END;
|
|
|
340
158
|
$$ LANGUAGE plpgsql STABLE;
|
|
341
159
|
|
|
342
160
|
-- ---------------------------------------------------------------------------
|
|
343
|
-
-- delta_open:
|
|
344
|
-
--
|
|
345
|
-
--
|
|
161
|
+
-- delta_open: a document as it stands, with its version -- its rows as it
|
|
162
|
+
-- shows them. _delta_open(name, TRUE) reads them whole: what the ledger's
|
|
163
|
+
-- inverse and a walk's guard read. generateSql sends each document to its own
|
|
164
|
+
-- (compileLedger, compileOpens); before it is applied there is no document.
|
|
346
165
|
-- ---------------------------------------------------------------------------
|
|
347
166
|
|
|
348
|
-
CREATE OR REPLACE FUNCTION _delta_open_framework(p_doc_name TEXT, p_whole BOOLEAN)
|
|
349
|
-
RETURNS JSONB AS $$
|
|
350
|
-
DECLARE
|
|
351
|
-
v_def _delta_docs;
|
|
352
|
-
v_resolved JSONB;
|
|
353
|
-
v_where TEXT;
|
|
354
|
-
v_mode TEXT;
|
|
355
|
-
v_at TIMESTAMPTZ;
|
|
356
|
-
v_doc_id BIGINT;
|
|
357
|
-
v_root_coll RECORD;
|
|
358
|
-
v_view TEXT;
|
|
359
|
-
v_root_row JSONB;
|
|
360
|
-
v_result JSONB;
|
|
361
|
-
v_coll_key TEXT;
|
|
362
|
-
v_version BIGINT;
|
|
363
|
-
BEGIN
|
|
364
|
-
v_def := _delta_find_doc(p_doc_name);
|
|
365
|
-
IF v_def.prefix IS NULL THEN
|
|
366
|
-
-- Fail-fast: caller asked for a doc whose prefix isn't registered.
|
|
367
|
-
-- NULL-as-config-error used to mask typos and missing migrations.
|
|
368
|
-
RAISE EXCEPTION 'no doc def for: %', p_doc_name
|
|
369
|
-
USING ERRCODE = 'P0001';
|
|
370
|
-
END IF;
|
|
371
|
-
|
|
372
|
-
v_resolved := _delta_resolve_scope(v_def, p_doc_name);
|
|
373
|
-
v_where := v_resolved->>'where';
|
|
374
|
-
v_mode := v_resolved->>'mode';
|
|
375
|
-
IF v_resolved->>'at' IS NOT NULL THEN
|
|
376
|
-
v_at := (v_resolved->>'at')::TIMESTAMPTZ;
|
|
377
|
-
END IF;
|
|
378
|
-
|
|
379
|
-
SELECT * INTO v_root_coll FROM _delta_collections
|
|
380
|
-
WHERE collection_key = v_def.root_collection;
|
|
381
|
-
IF NOT FOUND THEN
|
|
382
|
-
RAISE EXCEPTION 'doc "%" references unknown root collection: %',
|
|
383
|
-
p_doc_name, v_def.root_collection
|
|
384
|
-
USING ERRCODE = 'P0001';
|
|
385
|
-
END IF;
|
|
386
|
-
|
|
387
|
-
-- A time in the name (`at:`): the whole document as it stood then, its root
|
|
388
|
-
-- as its included collections, as SQLite reads it.
|
|
389
|
-
v_view := _delta_source_view(v_root_coll.table_name, v_root_coll.temporal, v_at);
|
|
390
|
-
IF v_root_coll.temporal AND v_at IS NOT NULL THEN
|
|
391
|
-
v_where := v_where || ' AND ' || _delta_temporal_where(v_at);
|
|
392
|
-
END IF;
|
|
393
|
-
|
|
394
|
-
IF v_mode = 'list' THEN
|
|
395
|
-
v_result := _delta_read_list(v_def, v_resolved->>'where', v_at);
|
|
396
|
-
ELSE
|
|
397
|
-
-- Single mode: one root row + included collections
|
|
398
|
-
v_doc_id := (v_resolved->'values'->>'id')::BIGINT;
|
|
399
|
-
|
|
400
|
-
-- the row its name names, where it meets the rest of the name's scope too
|
|
401
|
-
-- (fo-guest:<id>:<email>: that id with that email), as SQLite reads it
|
|
402
|
-
EXECUTE format('SELECT to_jsonb(t.*) FROM %I t WHERE t.id = $1 AND %s', v_view, v_where)
|
|
403
|
-
INTO v_root_row USING v_doc_id;
|
|
404
|
-
|
|
405
|
-
IF v_root_row IS NULL AND NOT COALESCE(v_def.implied, FALSE) THEN RETURN NULL; END IF;
|
|
406
|
-
|
|
407
|
-
IF v_root_row IS NULL THEN
|
|
408
|
-
-- Implied: there before its root row is -- the root its first write will
|
|
409
|
-
-- make, each included collection empty, as on SQLite. No row is made.
|
|
410
|
-
v_result := jsonb_build_object(v_def.root_collection, _delta_implied_root(v_def, v_doc_id));
|
|
411
|
-
FOREACH v_coll_key IN ARRAY v_def.include
|
|
412
|
-
LOOP
|
|
413
|
-
v_result := v_result || jsonb_build_object(v_coll_key, '{}'::jsonb);
|
|
414
|
-
END LOOP;
|
|
415
|
-
ELSE
|
|
416
|
-
IF v_root_coll.temporal THEN
|
|
417
|
-
v_root_row := _delta_strip_temporal(v_root_row);
|
|
418
|
-
END IF;
|
|
419
|
-
|
|
420
|
-
v_result := jsonb_build_object(v_def.root_collection, v_root_row);
|
|
421
|
-
|
|
422
|
-
FOREACH v_coll_key IN ARRAY v_def.include
|
|
423
|
-
LOOP
|
|
424
|
-
v_result := v_result || jsonb_build_object(
|
|
425
|
-
v_coll_key,
|
|
426
|
-
_delta_load_collection(v_coll_key, v_def.root_collection, v_doc_id, v_at)
|
|
427
|
-
);
|
|
428
|
-
END LOOP;
|
|
429
|
-
END IF;
|
|
430
|
-
END IF;
|
|
431
|
-
|
|
432
|
-
-- Track version
|
|
433
|
-
INSERT INTO _delta_versions (doc_name, version) VALUES (p_doc_name, 0)
|
|
434
|
-
ON CONFLICT (doc_name) DO NOTHING;
|
|
435
|
-
SELECT version INTO v_version FROM _delta_versions WHERE doc_name = p_doc_name;
|
|
436
|
-
|
|
437
|
-
IF NOT p_whole THEN v_result := _delta_show_doc(v_def, v_result, v_mode <> 'list'); END IF;
|
|
438
|
-
RETURN v_result || jsonb_build_object('_version', v_version);
|
|
439
|
-
END;
|
|
440
|
-
$$ LANGUAGE plpgsql;
|
|
441
|
-
|
|
442
|
-
-- the framework's, until dzql's compiler (`compileLedger`) sends each document
|
|
443
|
-
-- it compiled to its own open, shown or whole
|
|
444
167
|
CREATE OR REPLACE FUNCTION _delta_open(p_doc_name TEXT, p_whole BOOLEAN)
|
|
445
|
-
RETURNS JSONB LANGUAGE
|
|
168
|
+
RETURNS JSONB LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'no doc def for: %', p_doc_name USING ERRCODE = 'P0001'; END $$;
|
|
446
169
|
|
|
447
170
|
CREATE OR REPLACE FUNCTION delta_open(p_doc_name TEXT)
|
|
448
171
|
RETURNS JSONB LANGUAGE sql AS $$ SELECT _delta_open(p_doc_name, FALSE); $$;
|