orez 0.2.26 → 0.2.29

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.
Files changed (172) hide show
  1. package/dist/cf-do/worker.d.ts.map +1 -1
  2. package/dist/cf-do/worker.js +9 -1
  3. package/dist/cf-do/worker.js.map +1 -1
  4. package/dist/pg-proxy-do-backend.d.ts +2 -0
  5. package/dist/pg-proxy-do-backend.d.ts.map +1 -1
  6. package/dist/pg-proxy-do-backend.js +49 -7
  7. package/dist/pg-proxy-do-backend.js.map +1 -1
  8. package/dist/pg-sqlite-compiler/catalog/seed.d.ts +67 -0
  9. package/dist/pg-sqlite-compiler/catalog/seed.d.ts.map +1 -0
  10. package/dist/pg-sqlite-compiler/catalog/seed.js +436 -0
  11. package/dist/pg-sqlite-compiler/catalog/seed.js.map +1 -0
  12. package/dist/pg-sqlite-compiler/index.d.ts +12 -0
  13. package/dist/pg-sqlite-compiler/index.d.ts.map +1 -0
  14. package/dist/pg-sqlite-compiler/index.js +59 -0
  15. package/dist/pg-sqlite-compiler/index.js.map +1 -0
  16. package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts +48 -0
  17. package/dist/pg-sqlite-compiler/passes/ast-utils.d.ts.map +1 -0
  18. package/dist/pg-sqlite-compiler/passes/ast-utils.js +93 -0
  19. package/dist/pg-sqlite-compiler/passes/ast-utils.js.map +1 -0
  20. package/dist/pg-sqlite-compiler/passes/catalog.d.ts +34 -0
  21. package/dist/pg-sqlite-compiler/passes/catalog.d.ts.map +1 -0
  22. package/dist/pg-sqlite-compiler/passes/catalog.js +30 -0
  23. package/dist/pg-sqlite-compiler/passes/catalog.js.map +1 -0
  24. package/dist/pg-sqlite-compiler/passes/datetime.d.ts +21 -0
  25. package/dist/pg-sqlite-compiler/passes/datetime.d.ts.map +1 -0
  26. package/dist/pg-sqlite-compiler/passes/datetime.js +53 -0
  27. package/dist/pg-sqlite-compiler/passes/datetime.js.map +1 -0
  28. package/dist/pg-sqlite-compiler/passes/index.d.ts +21 -0
  29. package/dist/pg-sqlite-compiler/passes/index.d.ts.map +1 -0
  30. package/dist/pg-sqlite-compiler/passes/index.js +39 -0
  31. package/dist/pg-sqlite-compiler/passes/index.js.map +1 -0
  32. package/dist/pg-sqlite-compiler/passes/types.d.ts +41 -0
  33. package/dist/pg-sqlite-compiler/passes/types.d.ts.map +1 -0
  34. package/dist/pg-sqlite-compiler/passes/types.js +103 -0
  35. package/dist/pg-sqlite-compiler/passes/types.js.map +1 -0
  36. package/dist/pg-sqlite-compiler/test/oracle.d.ts +34 -0
  37. package/dist/pg-sqlite-compiler/test/oracle.d.ts.map +1 -0
  38. package/dist/pg-sqlite-compiler/test/oracle.js +204 -0
  39. package/dist/pg-sqlite-compiler/test/oracle.js.map +1 -0
  40. package/dist/pg-sqlite-compiler/types.d.ts +55 -0
  41. package/dist/pg-sqlite-compiler/types.d.ts.map +1 -0
  42. package/dist/pg-sqlite-compiler/types.js +2 -0
  43. package/dist/pg-sqlite-compiler/types.js.map +1 -0
  44. package/package.json +8 -4
  45. package/src/admin/admin-data.test.ts +0 -348
  46. package/src/admin/http-proxy.ts +0 -252
  47. package/src/admin/log-store.ts +0 -192
  48. package/src/admin/server.ts +0 -471
  49. package/src/admin/ui.ts +0 -1322
  50. package/src/bench/proxy-throughput.bench.ts +0 -343
  51. package/src/bench/serial-mutations.bench.ts +0 -270
  52. package/src/browser.ts +0 -203
  53. package/src/cf-do/.wrangler/cache/cf.json +0 -1
  54. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
  55. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
  56. package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
  57. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0f0f3bdf0abda097eb6f1246db4657d9fc622081362d894d82c1a1ce067b05b6.sqlite +0 -0
  58. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/1ddd3a4a48a11b51658444f5458a1fb175194b1d5b6a5bda20ef3fe3205b900c.sqlite +0 -0
  59. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/204a39120310d37e972c5914cfd71ad55c151bdb9e8ed289a5f8c5b052dd60e4.sqlite +0 -0
  60. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/3835f242df9728adba3d127a238793fd054ed3e51df3f60749ee744c469bf2a2.sqlite +0 -0
  61. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/4aa9c80eb716cf55b8995ccf7afab0b36c683e6da07d7c37a3f9c570136036df.sqlite +0 -0
  62. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/533e2fd1d6ea46e7a9a0017916ef341802d438d72583462755f2c1f8225e9bf2.sqlite +0 -0
  63. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/5ffa1aced1225ecaeac6366f7586aa3de92761cdff8711d81fbd81f248076abd.sqlite +0 -0
  64. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/686c3a9f0d7e59ed2ab607efd4b76d779c97cafeb3818380033bf7c7eb86c819.sqlite +0 -0
  65. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/6e8214e8dcfadd0deb52d64e5e9ca85c6b329ace11193909845995396914c473.sqlite +0 -0
  66. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/78d9ec9ff873d3fe3507ff53c2a6f6dfc408b4268eb0db3f2a146c0678965366.sqlite +0 -0
  67. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/7eff9f0ed7e27ad0d3f9d923de0682fab1928591172c1ba336c5f79a134a5d85.sqlite +0 -0
  68. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/836cda5b995b25867d722ed4f4c2292167e80351a3c6038db626648eb247dd8b.sqlite +0 -0
  69. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/91ef63b112209ab30172763acd8a0935106c248f7f1bcae5545ce37a9f201551.sqlite +0 -0
  70. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/a66ea4293a5f5938bc6d116edfa2522bb85bc37aea3541fbc09c3b613b9b32c0.sqlite +0 -0
  71. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/ceb2ab26b80590840b65651deb6e948d3bf81565c6751f3a58752cf4bf4aecae.sqlite +0 -0
  72. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
  73. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
  74. package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
  75. package/src/cf-do/ARCHITECTURE.md +0 -83
  76. package/src/cf-do/watermark.test.ts +0 -103
  77. package/src/cf-do/watermark.ts +0 -118
  78. package/src/cf-do/worker.ts +0 -1033
  79. package/src/cf-do/wrangler.toml +0 -11
  80. package/src/cf-pglite/README.md +0 -19
  81. package/src/change-tracking.ts +0 -25
  82. package/src/child-process.test.ts +0 -147
  83. package/src/child-process.ts +0 -90
  84. package/src/cli-entry.ts +0 -72
  85. package/src/cli.test.ts +0 -38
  86. package/src/cli.ts +0 -1214
  87. package/src/config.ts +0 -150
  88. package/src/do-sql-tracking.test.ts +0 -19
  89. package/src/do-sql-tracking.ts +0 -19
  90. package/src/index.ts +0 -1215
  91. package/src/integration/integration.test.ts +0 -517
  92. package/src/integration/native-binary.guard.test.ts +0 -13
  93. package/src/integration/native-startup.test.ts +0 -44
  94. package/src/integration/replication-latency.test.ts +0 -428
  95. package/src/integration/restore-live-stress.test.ts +0 -433
  96. package/src/integration/restore-reset.test.ts +0 -400
  97. package/src/integration/restore.test.ts +0 -274
  98. package/src/integration/test-permissions.ts +0 -147
  99. package/src/load-config.ts +0 -46
  100. package/src/log.ts +0 -96
  101. package/src/mutex.ts +0 -47
  102. package/src/pg-proxy-browser.singledb.test.ts +0 -233
  103. package/src/pg-proxy-browser.ts +0 -2022
  104. package/src/pg-proxy-do-backend.test.ts +0 -3890
  105. package/src/pg-proxy-do-backend.ts +0 -7157
  106. package/src/pg-proxy.ts +0 -1087
  107. package/src/pglite-ipc.test.ts +0 -116
  108. package/src/pglite-ipc.ts +0 -266
  109. package/src/pglite-manager.ts +0 -557
  110. package/src/pglite-web-proxy.test.ts +0 -57
  111. package/src/pglite-web-proxy.ts +0 -221
  112. package/src/pglite-web-worker.ts +0 -152
  113. package/src/pglite-worker-thread.ts +0 -253
  114. package/src/port.ts +0 -25
  115. package/src/process-title.ts +0 -9
  116. package/src/recovery.ts +0 -155
  117. package/src/replication/change-tracker.test.ts +0 -357
  118. package/src/replication/change-tracker.ts +0 -279
  119. package/src/replication/handler.test.ts +0 -511
  120. package/src/replication/handler.ts +0 -1190
  121. package/src/replication/pgoutput-encoder.test.ts +0 -697
  122. package/src/replication/pgoutput-encoder.ts +0 -373
  123. package/src/replication/tcp-replication.test.ts +0 -876
  124. package/src/replication/zero-compat.test.ts +0 -1150
  125. package/src/restore-stress.test.ts +0 -188
  126. package/src/s3-local.ts +0 -203
  127. package/src/shim/hooks.mjs +0 -120
  128. package/src/shim/register.mjs +0 -4
  129. package/src/sqlite-mode/apply-mode.ts +0 -224
  130. package/src/sqlite-mode/index.ts +0 -15
  131. package/src/sqlite-mode/native-binary.ts +0 -89
  132. package/src/sqlite-mode/package-resolve.ts +0 -17
  133. package/src/sqlite-mode/resolve-mode.ts +0 -80
  134. package/src/sqlite-mode/shim-template.ts +0 -159
  135. package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
  136. package/src/sqlite-mode/types.ts +0 -30
  137. package/src/vite-plugin.ts +0 -67
  138. package/src/wasm-sqlite.test.ts +0 -537
  139. package/src/worker/browser-admin.ts +0 -52
  140. package/src/worker/browser-build-config.test.ts +0 -71
  141. package/src/worker/browser-build-config.ts +0 -109
  142. package/src/worker/browser-embed-admin.test.ts +0 -75
  143. package/src/worker/browser-embed.ts +0 -345
  144. package/src/worker/cf-patches.ts +0 -384
  145. package/src/worker/embed-integration.test.ts +0 -321
  146. package/src/worker/index.ts +0 -138
  147. package/src/worker/shims/fastify.test.ts +0 -255
  148. package/src/worker/shims/fastify.ts +0 -306
  149. package/src/worker/shims/http-service.test.ts +0 -355
  150. package/src/worker/shims/http-service.ts +0 -293
  151. package/src/worker/shims/node-stub.ts +0 -290
  152. package/src/worker/shims/oxfmt.ts +0 -3
  153. package/src/worker/shims/postgres-browser.ts +0 -59
  154. package/src/worker/shims/postgres-socket.test.ts +0 -576
  155. package/src/worker/shims/postgres-socket.ts +0 -310
  156. package/src/worker/shims/postgres.test.ts +0 -364
  157. package/src/worker/shims/postgres.ts +0 -1454
  158. package/src/worker/shims/sqlite-browser.test.ts +0 -233
  159. package/src/worker/shims/sqlite-browser.ts +0 -175
  160. package/src/worker/shims/sqlite.test.ts +0 -786
  161. package/src/worker/shims/sqlite.ts +0 -978
  162. package/src/worker/shims/stream-browser.ts +0 -15
  163. package/src/worker/shims/ws-browser.test.ts +0 -205
  164. package/src/worker/shims/ws-browser.ts +0 -248
  165. package/src/worker/shims/ws.test.ts +0 -288
  166. package/src/worker/shims/ws.ts +0 -467
  167. package/src/worker/shims/zero-process-env.ts +0 -11
  168. package/src/worker/types.ts +0 -75
  169. package/src/worker/worker-integration.test.ts +0 -223
  170. package/src/worker/worker.test.ts +0 -136
  171. package/src/worker/zero-cache-embed-cf.ts +0 -463
  172. package/src/worker/zero-cache-embed.ts +0 -277
@@ -1,279 +0,0 @@
1
- import { log } from '../log.js'
2
-
3
- export interface ChangeRecord {
4
- watermark: number
5
- table_name: string
6
- op: 'INSERT' | 'UPDATE' | 'DELETE'
7
- row_data: Record<string, unknown> | null
8
- old_data: Record<string, unknown> | null
9
- }
10
-
11
- /**
12
- * minimal db interface change tracking needs. any sql executor that provides
13
- * these two methods (e.g., a PGlite instance or a proxy wrapper) is accepted.
14
- * using a structural type here keeps this module free of heavy imports so it
15
- * can be loaded as the standalone `orez/change-tracking` entrypoint without
16
- * pulling in pglite-manager or other server-only modules.
17
- */
18
- export interface ChangeTrackingDb {
19
- exec(sql: string): Promise<Array<{ affectedRows?: number }>>
20
- query<T>(sql: string, params?: unknown[]): Promise<{ rows: T[] }>
21
- }
22
-
23
- // PGlite returns JSONB columns as parsed objects; the DO backend returns them
24
- // as JSON strings (it stores `row_data TEXT`). normalize once at the consumer
25
- // boundary so callers always get an object.
26
- function jsonRecord(value: unknown): Record<string, unknown> | null {
27
- if (value === null || value === undefined) return null
28
- if (typeof value === 'object') return value as Record<string, unknown>
29
- if (typeof value !== 'string' || value === '') return null
30
- return JSON.parse(value) as Record<string, unknown>
31
- }
32
-
33
- export async function installChangeTracking(db: ChangeTrackingDb): Promise<void> {
34
- // use _orez schema for internal tables - survives pg_restore of public schema
35
- await db.exec(`CREATE SCHEMA IF NOT EXISTS _orez`)
36
-
37
- // create changes table and watermark sequence
38
- // watermark is the primary key - monotonically increasing, no separate id needed
39
- await db.exec(`
40
- CREATE SEQUENCE IF NOT EXISTS _orez._zero_watermark;
41
-
42
- CREATE TABLE IF NOT EXISTS _orez._zero_changes (
43
- watermark BIGINT NOT NULL DEFAULT nextval('_orez._zero_watermark') PRIMARY KEY,
44
- table_name TEXT NOT NULL,
45
- op TEXT NOT NULL CHECK (op IN ('INSERT', 'UPDATE', 'DELETE')),
46
- row_data JSONB,
47
- old_data JSONB
48
- );
49
-
50
- CREATE TABLE IF NOT EXISTS _orez._zero_replication_slots (
51
- slot_name TEXT PRIMARY KEY,
52
- restart_lsn TEXT NOT NULL DEFAULT '0/1000000',
53
- confirmed_flush_lsn TEXT NOT NULL DEFAULT '0/1000000',
54
- wal_status TEXT NOT NULL DEFAULT 'reserved',
55
- plugin TEXT NOT NULL DEFAULT 'pgoutput',
56
- slot_type TEXT NOT NULL DEFAULT 'logical',
57
- active BOOLEAN NOT NULL DEFAULT false,
58
- active_pid INTEGER DEFAULT NULL,
59
- created_at TIMESTAMPTZ DEFAULT NOW()
60
- );
61
- `)
62
-
63
- // create trigger functions (writes to _orez schema)
64
- // uses to_jsonb() directly instead of row_to_json()::jsonb to avoid double conversion.
65
- // per-row trigger for single-row operations
66
- await db.exec(`
67
- CREATE OR REPLACE FUNCTION public._zero_track_change() RETURNS TRIGGER AS $$
68
- BEGIN
69
- IF TG_OP = 'DELETE' THEN
70
- INSERT INTO _orez._zero_changes (table_name, op, old_data)
71
- VALUES (TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME, 'DELETE', to_jsonb(OLD));
72
- RETURN OLD;
73
- ELSIF TG_OP = 'UPDATE' THEN
74
- -- skip no-op updates where no columns actually changed
75
- IF to_jsonb(NEW) = to_jsonb(OLD) THEN
76
- RETURN NEW;
77
- END IF;
78
- INSERT INTO _orez._zero_changes (table_name, op, row_data, old_data)
79
- VALUES (TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME, 'UPDATE', to_jsonb(NEW), to_jsonb(OLD));
80
- RETURN NEW;
81
- ELSE
82
- INSERT INTO _orez._zero_changes (table_name, op, row_data)
83
- VALUES (TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME, 'INSERT', to_jsonb(NEW));
84
- RETURN NEW;
85
- END IF;
86
- END;
87
- $$ LANGUAGE plpgsql;
88
- `)
89
-
90
- // install triggers on all public tables
91
- await installTriggersOnAllTables(db)
92
- }
93
-
94
- function quoteIdent(name: string): string {
95
- return '"' + name.replace(/"/g, '""') + '"'
96
- }
97
-
98
- async function installTriggersOnAllTables(db: ChangeTrackingDb): Promise<void> {
99
- // If a publication is configured, respect it strictly. This avoids accidentally
100
- // streaming private tables when publication membership is temporarily empty.
101
- const pubName = process.env.ZERO_APP_PUBLICATIONS?.trim()
102
- let tables: { tablename: string }[]
103
- if (pubName) {
104
- const result = await db.query<{ tablename: string }>(
105
- `SELECT tablename FROM pg_publication_tables
106
- WHERE pubname = $1
107
- AND schemaname = 'public'
108
- AND tablename NOT LIKE '_zero_%'`,
109
- [pubName]
110
- )
111
- tables = result.rows
112
- if (tables.length > 0) {
113
- log.debug.pglite(`using publication "${pubName}" (${tables.length} tables)`)
114
- } else {
115
- log.pglite(`publication "${pubName}" is empty; installing no public table triggers`)
116
- }
117
- } else {
118
- const all = await db.query<{ tablename: string }>(
119
- `SELECT tablename FROM pg_tables
120
- WHERE schemaname = 'public'
121
- AND tablename NOT IN ('migrations')
122
- AND tablename NOT LIKE '_zero_%'`
123
- )
124
- tables = all.rows
125
- log.debug.pglite(`using all public tables (${tables.length})`)
126
- }
127
-
128
- // drop stale triggers from tables NOT in the publication
129
- // (these may exist from a prior install before the publication was created)
130
- const publishedSet = new Set(tables.map((t) => t.tablename))
131
- const allTriggered = await db.query<{ event_object_table: string }>(
132
- `SELECT DISTINCT event_object_table FROM information_schema.triggers
133
- WHERE trigger_name = '_zero_change_trigger'
134
- AND event_object_schema = 'public'`
135
- )
136
- for (const { event_object_table } of allTriggered.rows) {
137
- if (!publishedSet.has(event_object_table)) {
138
- const quoted = quoteIdent(event_object_table)
139
- await db.exec(`DROP TRIGGER IF EXISTS _zero_change_trigger ON public.${quoted}`)
140
- log.debug.pglite(
141
- `removed stale trigger from non-published table: ${event_object_table}`
142
- )
143
- }
144
- }
145
-
146
- let count = 0
147
- for (const { tablename } of tables) {
148
- const quoted = quoteIdent(tablename)
149
- await db.exec(`
150
- DROP TRIGGER IF EXISTS _zero_change_trigger ON public.${quoted};
151
- CREATE TRIGGER _zero_change_trigger
152
- AFTER INSERT OR UPDATE OR DELETE ON public.${quoted}
153
- FOR EACH ROW EXECUTE FUNCTION public._zero_track_change();
154
- `)
155
- count++
156
- }
157
-
158
- if (count > 0) {
159
- log.debug.pglite(`installed change tracking triggers on ${count} tables`)
160
- } else {
161
- log.debug.pglite(`no tables to install change tracking triggers on`)
162
- }
163
- }
164
-
165
- /**
166
- * install change tracking triggers on tables in shard schemas.
167
- * zero-cache creates shard schemas (e.g. chat_0) with clients/mutations
168
- * tables that track mutation confirmations. these must be replicated
169
- * for .server promises to resolve.
170
- *
171
- * caches already-tracked shard tables to avoid redundant DDL while still
172
- * handling zero-cache creating a schema before the internal tables exist.
173
- */
174
- const trackedShardTables = new Set<string>()
175
- const TRACKED_SHARD_TABLES = new Set(['clients', 'mutations'])
176
-
177
- /** reset shard schema cache (for tests) */
178
- export function resetShardSchemaCache(): void {
179
- trackedShardTables.clear()
180
- }
181
-
182
- export async function installTriggersOnShardTables(db: ChangeTrackingDb): Promise<void> {
183
- const result = await db.query<{ nspname: string }>(
184
- `SELECT nspname FROM pg_namespace
185
- WHERE nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast', 'public')
186
- AND nspname NOT LIKE 'pg_%'
187
- AND nspname NOT LIKE 'zero_%'
188
- AND nspname NOT LIKE '_zero_%'
189
- AND nspname NOT LIKE '%/%'`
190
- )
191
-
192
- if (result.rows.length === 0) return
193
-
194
- // only track the shard tables zero-cache expects in the replication stream.
195
- // `clients` advances LMID for successful .server promises; `mutations`
196
- // carries per-mutation results for application errors. other shard tables
197
- // like `replicas` are zero-cache internal state and streaming them back
198
- // causes "Unknown table" crashes in zero-cache's change-processor.
199
- let count = 0
200
- for (const { nspname } of result.rows) {
201
- // remove stale triggers from non-replicated shard tables.
202
- const stale = await db.query<{ event_object_table: string }>(
203
- `SELECT DISTINCT event_object_table FROM information_schema.triggers
204
- WHERE trigger_name = '_zero_change_trigger'
205
- AND event_object_schema = $1
206
- AND event_object_table != ALL($2)`,
207
- [nspname, [...TRACKED_SHARD_TABLES]]
208
- )
209
- for (const { event_object_table } of stale.rows) {
210
- const qs = quoteIdent(nspname)
211
- const qt = quoteIdent(event_object_table)
212
- await db.exec(`DROP TRIGGER IF EXISTS _zero_change_trigger ON ${qs}.${qt}`)
213
- log.debug.pglite(
214
- `removed stale shard trigger from ${nspname}.${event_object_table}`
215
- )
216
- }
217
-
218
- const tables = await db.query<{ tablename: string }>(
219
- `SELECT tablename FROM pg_tables WHERE schemaname = $1 AND tablename = ANY($2)`,
220
- [nspname, [...TRACKED_SHARD_TABLES]]
221
- )
222
-
223
- for (const { tablename } of tables.rows) {
224
- const key = `${nspname}.${tablename}`
225
- if (trackedShardTables.has(key)) continue
226
-
227
- const quotedSchema = quoteIdent(nspname)
228
- const quotedTable = quoteIdent(tablename)
229
- await db.exec(`
230
- DROP TRIGGER IF EXISTS _zero_change_trigger ON ${quotedSchema}.${quotedTable};
231
- CREATE TRIGGER _zero_change_trigger
232
- AFTER INSERT OR UPDATE OR DELETE ON ${quotedSchema}.${quotedTable}
233
- FOR EACH ROW EXECUTE FUNCTION public._zero_track_change();
234
- `)
235
- trackedShardTables.add(key)
236
- count++
237
- }
238
- }
239
-
240
- if (count > 0) {
241
- log.debug.pglite(`installed change tracking on ${count} shard tables`)
242
- }
243
- }
244
-
245
- export async function getChangesSince(
246
- db: ChangeTrackingDb,
247
- watermark: number,
248
- limit = 50000
249
- ): Promise<ChangeRecord[]> {
250
- const result = await db.query<ChangeRecord>(
251
- 'SELECT watermark, table_name, op, row_data, old_data FROM _orez._zero_changes WHERE watermark > $1 ORDER BY watermark LIMIT $2',
252
- [watermark, limit]
253
- )
254
- return result.rows.map((row) => ({
255
- ...row,
256
- watermark: Number(row.watermark),
257
- row_data: jsonRecord(row.row_data),
258
- old_data: jsonRecord(row.old_data),
259
- }))
260
- }
261
-
262
- export async function purgeConsumedChanges(
263
- db: ChangeTrackingDb,
264
- watermark: number
265
- ): Promise<number> {
266
- const result = await db.exec(
267
- `DELETE FROM _orez._zero_changes WHERE watermark <= ${Number(watermark)}`
268
- )
269
- return result[0]?.affectedRows ?? 0
270
- }
271
-
272
- export async function getCurrentWatermark(db: ChangeTrackingDb): Promise<number> {
273
- const result = await db.query<{ last_value: string; is_called: boolean }>(
274
- 'SELECT last_value, is_called FROM _orez._zero_watermark'
275
- )
276
- const { last_value, is_called } = result.rows[0]
277
- if (!is_called) return 0
278
- return Number(last_value)
279
- }