dzql 0.7.0 → 0.9.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 +16 -0
- package/docs/README.md +6 -0
- package/docs/for_ai.md +6 -0
- package/docs/project-setup.md +6 -0
- package/package.json +18 -7
- package/src/cli/index.ts +7 -0
- package/src/compile/opens.ts +323 -0
- package/src/postgres/auth-jwt-sql.ts +32 -0
- package/src/postgres/auth-jwt.ts +209 -0
- package/src/postgres/auth.ts +50 -0
- package/src/postgres/bootstrap.ts +55 -0
- package/src/postgres/carry.ts +40 -0
- package/src/postgres/cli.ts +339 -0
- package/src/postgres/codegen.ts +175 -0
- package/src/postgres/index.ts +58 -0
- package/src/postgres/listener.ts +706 -0
- package/src/postgres/migrate.ts +143 -0
- package/src/postgres/pglite.ts +142 -0
- package/src/postgres/registry.ts +262 -0
- package/src/postgres/schema.ts +171 -0
- package/src/postgres/sql.ts +42 -0
- package/src/sql/001a-delta-meta.sql +204 -0
- package/src/sql/001b-delta-scope.sql +619 -0
- package/src/sql/001c-delta-read.sql +506 -0
- package/src/sql/001d-delta-write.sql +1088 -0
- package/src/sql/001e-delta-ops.sql +142 -0
- package/src/sql/001f-delta-as.sql +41 -0
- package/src/sql/001g-delta-ledger.sql +564 -0
- package/src/sql/auth-jwt.sql +62 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
-- =========================================================================
|
|
2
|
+
-- Delta-doc: catch-up, time-travel, pruning, snapshots
|
|
3
|
+
-- =========================================================================
|
|
4
|
+
|
|
5
|
+
-- ---------------------------------------------------------------------------
|
|
6
|
+
-- delta_fetch_ops: catch-up — get ops since a given version
|
|
7
|
+
-- ---------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
CREATE OR REPLACE FUNCTION delta_fetch_ops(p_doc_name TEXT, p_since BIGINT)
|
|
10
|
+
RETURNS TABLE(version BIGINT, ops JSONB) AS $$
|
|
11
|
+
SELECT l.version, l.ops
|
|
12
|
+
FROM _delta_ops_log l
|
|
13
|
+
WHERE l.doc_name = p_doc_name AND l.version > p_since
|
|
14
|
+
ORDER BY l.version
|
|
15
|
+
LIMIT 1000;
|
|
16
|
+
$$ LANGUAGE sql STABLE;
|
|
17
|
+
|
|
18
|
+
-- _delta_fetch_log: the listener's catch-up -- delta_fetch_ops' rows, each with
|
|
19
|
+
-- the write it carries for the custom documents (`applied`, 001a).
|
|
20
|
+
CREATE OR REPLACE FUNCTION _delta_fetch_log(p_doc_name TEXT, p_since BIGINT)
|
|
21
|
+
RETURNS TABLE(version BIGINT, ops JSONB, applied JSONB) AS $$
|
|
22
|
+
SELECT l.version, l.ops, l.applied
|
|
23
|
+
FROM _delta_ops_log l
|
|
24
|
+
WHERE l.doc_name = p_doc_name AND l.version > p_since
|
|
25
|
+
ORDER BY l.version
|
|
26
|
+
LIMIT 1000;
|
|
27
|
+
$$ LANGUAGE sql STABLE;
|
|
28
|
+
|
|
29
|
+
-- ---------------------------------------------------------------------------
|
|
30
|
+
-- delta_open_at: time-travel — load a doc as it existed at a point in time
|
|
31
|
+
-- ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
CREATE OR REPLACE FUNCTION delta_open_at(p_doc_name TEXT, p_at TIMESTAMPTZ)
|
|
34
|
+
RETURNS JSONB AS $$
|
|
35
|
+
DECLARE
|
|
36
|
+
v_def _delta_docs;
|
|
37
|
+
v_resolved JSONB;
|
|
38
|
+
v_mode TEXT;
|
|
39
|
+
v_doc_id BIGINT;
|
|
40
|
+
v_root_coll RECORD;
|
|
41
|
+
v_root_row JSONB;
|
|
42
|
+
v_result JSONB;
|
|
43
|
+
v_coll_key TEXT;
|
|
44
|
+
BEGIN
|
|
45
|
+
v_def := _delta_find_doc(p_doc_name);
|
|
46
|
+
IF v_def.prefix IS NULL THEN
|
|
47
|
+
RAISE EXCEPTION 'no doc def for: %', p_doc_name
|
|
48
|
+
USING ERRCODE = 'P0001';
|
|
49
|
+
END IF;
|
|
50
|
+
|
|
51
|
+
v_resolved := _delta_resolve_scope(v_def, p_doc_name);
|
|
52
|
+
v_mode := v_resolved->>'mode';
|
|
53
|
+
|
|
54
|
+
SELECT * INTO v_root_coll FROM _delta_collections
|
|
55
|
+
WHERE collection_key = v_def.root_collection;
|
|
56
|
+
IF NOT FOUND THEN
|
|
57
|
+
RAISE EXCEPTION 'doc "%" references unknown root collection: %',
|
|
58
|
+
p_doc_name, v_def.root_collection
|
|
59
|
+
USING ERRCODE = 'P0001';
|
|
60
|
+
END IF;
|
|
61
|
+
|
|
62
|
+
-- List mode (todo #74): as delta_open reads a list, at p_at -- each row as it shows (todo #70).
|
|
63
|
+
IF v_mode = 'list' THEN RETURN _delta_show_doc(v_def, _delta_read_list(v_def, v_resolved->>'where', p_at), FALSE); END IF;
|
|
64
|
+
|
|
65
|
+
v_doc_id := (v_resolved->'values'->>'id')::BIGINT;
|
|
66
|
+
|
|
67
|
+
-- the root as it stood, where it met the whole of its name's scope then
|
|
68
|
+
-- (a column beside its id), as delta_open reads it now
|
|
69
|
+
IF v_root_coll.temporal THEN
|
|
70
|
+
EXECUTE format(
|
|
71
|
+
'SELECT to_jsonb(t.*) FROM %I t WHERE t.id = $1 AND %s AND %s',
|
|
72
|
+
v_root_coll.table_name, _delta_temporal_where(p_at), v_resolved->>'where'
|
|
73
|
+
) INTO v_root_row USING v_doc_id;
|
|
74
|
+
v_root_row := _delta_strip_temporal(v_root_row);
|
|
75
|
+
ELSE
|
|
76
|
+
EXECUTE format('SELECT to_jsonb(t.*) FROM %I t WHERE t.id = $1 AND %s', v_root_coll.table_name, v_resolved->>'where')
|
|
77
|
+
INTO v_root_row USING v_doc_id;
|
|
78
|
+
END IF;
|
|
79
|
+
|
|
80
|
+
IF v_root_row IS NULL THEN RETURN NULL; END IF;
|
|
81
|
+
|
|
82
|
+
v_result := jsonb_build_object(v_def.root_collection, v_root_row);
|
|
83
|
+
|
|
84
|
+
FOREACH v_coll_key IN ARRAY v_def.include
|
|
85
|
+
LOOP
|
|
86
|
+
v_result := v_result || jsonb_build_object(
|
|
87
|
+
v_coll_key,
|
|
88
|
+
_delta_load_collection(v_coll_key, v_def.root_collection, v_doc_id, p_at)
|
|
89
|
+
);
|
|
90
|
+
END LOOP;
|
|
91
|
+
|
|
92
|
+
RETURN _delta_show_doc(v_def, v_result, TRUE);
|
|
93
|
+
END;
|
|
94
|
+
$$ LANGUAGE plpgsql STABLE;
|
|
95
|
+
|
|
96
|
+
-- ---------------------------------------------------------------------------
|
|
97
|
+
-- delta_prune_ops: clean up old log entries -- and the names nobody holds
|
|
98
|
+
-- open (todo #73): the rows of listeners that are gone, and the version of a
|
|
99
|
+
-- name no listener holds, with nothing left of it in the log or the ledger.
|
|
100
|
+
-- Opened again, it starts a fresh copy at 0. The table lock keeps an open from
|
|
101
|
+
-- holding a name between the question and the delete. Answers the log
|
|
102
|
+
-- entries cleared.
|
|
103
|
+
-- ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
CREATE OR REPLACE FUNCTION delta_prune_ops(p_keep INTERVAL DEFAULT '1 hour')
|
|
106
|
+
RETURNS BIGINT AS $$
|
|
107
|
+
DECLARE v_count BIGINT;
|
|
108
|
+
BEGIN
|
|
109
|
+
DELETE FROM _delta_ops_log WHERE created_at < NOW() - p_keep;
|
|
110
|
+
GET DIAGNOSTICS v_count = ROW_COUNT;
|
|
111
|
+
LOCK TABLE _delta_held IN SHARE ROW EXCLUSIVE MODE;
|
|
112
|
+
PERFORM _delta_clear_dead_holders();
|
|
113
|
+
DELETE FROM _delta_versions v
|
|
114
|
+
WHERE NOT EXISTS (SELECT 1 FROM _delta_held h WHERE h.doc_name = v.doc_name)
|
|
115
|
+
AND NOT EXISTS (SELECT 1 FROM _delta_ops_log l WHERE l.doc_name = v.doc_name)
|
|
116
|
+
AND NOT EXISTS (SELECT 1 FROM _delta_ledger g WHERE g.doc_name = v.doc_name);
|
|
117
|
+
RETURN v_count;
|
|
118
|
+
END;
|
|
119
|
+
$$ LANGUAGE plpgsql;
|
|
120
|
+
|
|
121
|
+
-- ---------------------------------------------------------------------------
|
|
122
|
+
-- Snapshots
|
|
123
|
+
-- ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
CREATE TABLE IF NOT EXISTS _delta_snapshots (
|
|
126
|
+
name TEXT PRIMARY KEY,
|
|
127
|
+
created_at TIMESTAMPTZ NOT NULL
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
CREATE OR REPLACE FUNCTION delta_snapshot(p_name TEXT, p_at TIMESTAMPTZ DEFAULT NOW())
|
|
131
|
+
RETURNS TIMESTAMPTZ AS $$
|
|
132
|
+
BEGIN
|
|
133
|
+
INSERT INTO _delta_snapshots (name, created_at) VALUES (p_name, p_at)
|
|
134
|
+
ON CONFLICT (name) DO UPDATE SET created_at = p_at;
|
|
135
|
+
RETURN p_at;
|
|
136
|
+
END;
|
|
137
|
+
$$ LANGUAGE plpgsql;
|
|
138
|
+
|
|
139
|
+
CREATE OR REPLACE FUNCTION delta_resolve_snapshot(p_name TEXT)
|
|
140
|
+
RETURNS TIMESTAMPTZ AS $$
|
|
141
|
+
SELECT created_at FROM _delta_snapshots WHERE name = p_name;
|
|
142
|
+
$$ LANGUAGE sql STABLE;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- =========================================================================
|
|
2
|
+
-- Delta-doc: identity-wrapped call variants (1-RTT hot path)
|
|
3
|
+
-- =========================================================================
|
|
4
|
+
--
|
|
5
|
+
-- Every authenticated doc operation is logically two things:
|
|
6
|
+
-- 1. Scope the session: `SELECT set_config('app.user_id', <id>, true)`
|
|
7
|
+
-- 2. Call the op: `SELECT delta_apply(...)` / `delta_open(...)`
|
|
8
|
+
--
|
|
9
|
+
-- The naive client does this as two separate round-trips inside an explicit
|
|
10
|
+
-- BEGIN / COMMIT — four RTTs per op. These wrappers collapse it to one:
|
|
11
|
+
-- the SELECT's implicit transaction scopes `set_config(..., true)`, which
|
|
12
|
+
-- RLS policies read via `current_setting('app.user_id', true)`.
|
|
13
|
+
--
|
|
14
|
+
-- SELECT delta_apply_as('42', 'todos:42', '[{...}]'::jsonb);
|
|
15
|
+
--
|
|
16
|
+
-- No explicit transaction, no client-side set_config, no client checkout.
|
|
17
|
+
-- =========================================================================
|
|
18
|
+
|
|
19
|
+
CREATE OR REPLACE FUNCTION delta_open_as(p_user_id TEXT, p_doc_name TEXT)
|
|
20
|
+
RETURNS jsonb LANGUAGE plpgsql AS $$
|
|
21
|
+
BEGIN
|
|
22
|
+
PERFORM set_config('app.user_id', p_user_id, true);
|
|
23
|
+
RETURN delta_open(p_doc_name);
|
|
24
|
+
END
|
|
25
|
+
$$;
|
|
26
|
+
|
|
27
|
+
CREATE OR REPLACE FUNCTION delta_apply_as(p_user_id TEXT, p_doc_name TEXT, p_ops jsonb)
|
|
28
|
+
RETURNS jsonb LANGUAGE plpgsql AS $$
|
|
29
|
+
BEGIN
|
|
30
|
+
PERFORM set_config('app.user_id', p_user_id, true);
|
|
31
|
+
RETURN delta_apply(p_doc_name, p_ops);
|
|
32
|
+
END
|
|
33
|
+
$$;
|
|
34
|
+
|
|
35
|
+
CREATE OR REPLACE FUNCTION delta_open_at_as(p_user_id TEXT, p_doc_name TEXT, p_at TIMESTAMPTZ)
|
|
36
|
+
RETURNS jsonb LANGUAGE plpgsql AS $$
|
|
37
|
+
BEGIN
|
|
38
|
+
PERFORM set_config('app.user_id', p_user_id, true);
|
|
39
|
+
RETURN delta_open_at(p_doc_name, p_at);
|
|
40
|
+
END
|
|
41
|
+
$$;
|