orez 0.0.37 → 0.0.39
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 -11
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -4
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/dist/mutex.d.ts.map +1 -1
- package/dist/mutex.js +13 -2
- package/dist/mutex.js.map +1 -1
- package/dist/pg-proxy.d.ts +3 -2
- package/dist/pg-proxy.d.ts.map +1 -1
- package/dist/pg-proxy.js +336 -167
- package/dist/pg-proxy.js.map +1 -1
- package/dist/replication/change-tracker.d.ts +5 -0
- package/dist/replication/change-tracker.d.ts.map +1 -1
- package/dist/replication/change-tracker.js +70 -0
- package/dist/replication/change-tracker.js.map +1 -1
- package/dist/replication/handler.d.ts.map +1 -1
- package/dist/replication/handler.js +3 -1
- package/dist/replication/handler.js.map +1 -1
- package/package.json +2 -3
- package/src/cli.ts +22 -5
- package/src/config.ts +2 -0
- package/src/index.ts +18 -3
- package/src/integration/integration.test.ts +133 -264
- package/src/integration/restore.test.ts +274 -0
- package/src/mutex.ts +12 -2
- package/src/pg-proxy.ts +404 -187
- package/src/replication/change-tracker.ts +81 -0
- package/src/replication/handler.ts +4 -0
|
@@ -67,6 +67,35 @@ export async function installChangeTracking(db: PGlite): Promise<void> {
|
|
|
67
67
|
$$ LANGUAGE plpgsql;
|
|
68
68
|
`)
|
|
69
69
|
|
|
70
|
+
// auto-install change tracking on tables created after startup (e.g. via restore
|
|
71
|
+
// or wire protocol). uses a DDL event trigger that fires on CREATE TABLE.
|
|
72
|
+
await db.exec(`
|
|
73
|
+
CREATE OR REPLACE FUNCTION public._zero_auto_track() RETURNS event_trigger AS $$
|
|
74
|
+
DECLARE
|
|
75
|
+
obj record;
|
|
76
|
+
BEGIN
|
|
77
|
+
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands()
|
|
78
|
+
WHERE command_tag = 'CREATE TABLE'
|
|
79
|
+
LOOP
|
|
80
|
+
IF obj.schema_name = 'public'
|
|
81
|
+
AND obj.object_identity NOT LIKE '%._zero_%'
|
|
82
|
+
AND obj.object_identity NOT LIKE '%.migrations'
|
|
83
|
+
THEN
|
|
84
|
+
EXECUTE format(
|
|
85
|
+
'CREATE TRIGGER _zero_change_trigger AFTER INSERT OR UPDATE OR DELETE ON %s FOR EACH ROW EXECUTE FUNCTION public._zero_track_change()',
|
|
86
|
+
obj.object_identity
|
|
87
|
+
);
|
|
88
|
+
END IF;
|
|
89
|
+
END LOOP;
|
|
90
|
+
END;
|
|
91
|
+
$$ LANGUAGE plpgsql;
|
|
92
|
+
|
|
93
|
+
DROP EVENT TRIGGER IF EXISTS _zero_auto_track_trigger;
|
|
94
|
+
CREATE EVENT TRIGGER _zero_auto_track_trigger ON ddl_command_end
|
|
95
|
+
WHEN TAG IN ('CREATE TABLE')
|
|
96
|
+
EXECUTE FUNCTION public._zero_auto_track();
|
|
97
|
+
`)
|
|
98
|
+
|
|
70
99
|
// install triggers on all public tables
|
|
71
100
|
await installTriggersOnAllTables(db)
|
|
72
101
|
}
|
|
@@ -140,6 +169,58 @@ async function installTriggersOnAllTables(db: PGlite): Promise<void> {
|
|
|
140
169
|
log.debug.pglite(`installed change tracking triggers on ${count} tables`)
|
|
141
170
|
}
|
|
142
171
|
|
|
172
|
+
/**
|
|
173
|
+
* re-install change tracking triggers on any public tables that don't have them.
|
|
174
|
+
* catches tables created between startup and replication start.
|
|
175
|
+
*/
|
|
176
|
+
export async function ensureChangeTrackingOnAllTables(db: PGlite): Promise<void> {
|
|
177
|
+
const pubName = process.env.ZERO_APP_PUBLICATIONS
|
|
178
|
+
let tables: { tablename: string }[]
|
|
179
|
+
|
|
180
|
+
if (pubName) {
|
|
181
|
+
const result = await db.query<{ tablename: string }>(
|
|
182
|
+
`SELECT tablename FROM pg_publication_tables
|
|
183
|
+
WHERE pubname = $1
|
|
184
|
+
AND schemaname = 'public'
|
|
185
|
+
AND tablename NOT LIKE '_zero_%'`,
|
|
186
|
+
[pubName]
|
|
187
|
+
)
|
|
188
|
+
tables = result.rows
|
|
189
|
+
} else {
|
|
190
|
+
const result = await db.query<{ tablename: string }>(
|
|
191
|
+
`SELECT tablename FROM pg_tables
|
|
192
|
+
WHERE schemaname = 'public'
|
|
193
|
+
AND tablename NOT IN ('migrations', '_zero_changes')
|
|
194
|
+
AND tablename NOT LIKE '_zero_%'`
|
|
195
|
+
)
|
|
196
|
+
tables = result.rows
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// find tables missing the change trigger
|
|
200
|
+
const triggered = await db.query<{ event_object_table: string }>(
|
|
201
|
+
`SELECT DISTINCT event_object_table FROM information_schema.triggers
|
|
202
|
+
WHERE trigger_name = '_zero_change_trigger'
|
|
203
|
+
AND event_object_schema = 'public'`
|
|
204
|
+
)
|
|
205
|
+
const hasTracker = new Set(triggered.rows.map((r) => r.event_object_table))
|
|
206
|
+
|
|
207
|
+
let count = 0
|
|
208
|
+
for (const { tablename } of tables) {
|
|
209
|
+
if (hasTracker.has(tablename)) continue
|
|
210
|
+
const quoted = quoteIdent(tablename)
|
|
211
|
+
await db.exec(`
|
|
212
|
+
CREATE TRIGGER _zero_change_trigger
|
|
213
|
+
AFTER INSERT OR UPDATE OR DELETE ON public.${quoted}
|
|
214
|
+
FOR EACH ROW EXECUTE FUNCTION public._zero_track_change();
|
|
215
|
+
`)
|
|
216
|
+
count++
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (count > 0) {
|
|
220
|
+
log.debug.pglite(`installed change tracking on ${count} new tables`)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
143
224
|
/**
|
|
144
225
|
* install change tracking triggers on tables in shard schemas.
|
|
145
226
|
* zero-cache creates shard schemas (e.g. chat_0) with clients/mutations
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getChangesSince,
|
|
12
12
|
getCurrentWatermark,
|
|
13
13
|
installTriggersOnShardTables,
|
|
14
|
+
ensureChangeTrackingOnAllTables,
|
|
14
15
|
type ChangeRecord,
|
|
15
16
|
} from './change-tracker.js'
|
|
16
17
|
import {
|
|
@@ -284,6 +285,9 @@ export async function handleStartReplication(
|
|
|
284
285
|
// "already in transaction" errors when they interleave.
|
|
285
286
|
await mutex.acquire()
|
|
286
287
|
try {
|
|
288
|
+
// install change tracking triggers on any tables created after startup
|
|
289
|
+
await ensureChangeTrackingOnAllTables(db)
|
|
290
|
+
|
|
287
291
|
// install change tracking triggers on shard schema tables (e.g. chat_0.clients)
|
|
288
292
|
// these track zero-cache's lastMutationID for .server promise resolution
|
|
289
293
|
await installTriggersOnShardTables(db)
|