@syncular/server 0.0.1-60 → 0.0.1
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/clients.d.ts +0 -1
- package/dist/clients.d.ts.map +1 -1
- package/dist/clients.js.map +1 -1
- package/dist/dialect/types.d.ts +4 -17
- package/dist/dialect/types.d.ts.map +1 -1
- package/dist/proxy/handler.d.ts.map +1 -1
- package/dist/proxy/handler.js +0 -1
- package/dist/proxy/handler.js.map +1 -1
- package/dist/proxy/index.d.ts +2 -2
- package/dist/proxy/index.d.ts.map +1 -1
- package/dist/proxy/index.js.map +1 -1
- package/dist/proxy/oplog.d.ts +0 -1
- package/dist/proxy/oplog.d.ts.map +1 -1
- package/dist/proxy/oplog.js +3 -9
- package/dist/proxy/oplog.js.map +1 -1
- package/dist/proxy/registry.d.ts +11 -0
- package/dist/proxy/registry.d.ts.map +1 -1
- package/dist/proxy/registry.js +24 -0
- package/dist/proxy/registry.js.map +1 -1
- package/dist/proxy/types.d.ts +0 -2
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/pull.d.ts +0 -1
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +5 -23
- package/dist/pull.js.map +1 -1
- package/dist/push.d.ts +1 -13
- package/dist/push.d.ts.map +1 -1
- package/dist/push.js +7 -54
- package/dist/push.js.map +1 -1
- package/dist/realtime/types.d.ts +0 -2
- package/dist/realtime/types.d.ts.map +1 -1
- package/dist/schema.d.ts +0 -10
- package/dist/schema.d.ts.map +1 -1
- package/dist/shapes/create-handler.d.ts.map +1 -1
- package/dist/shapes/create-handler.js +26 -86
- package/dist/shapes/create-handler.js.map +1 -1
- package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -1
- package/dist/snapshot-chunks/db-metadata.js +0 -3
- package/dist/snapshot-chunks/db-metadata.js.map +1 -1
- package/dist/snapshot-chunks/types.d.ts +0 -2
- package/dist/snapshot-chunks/types.d.ts.map +1 -1
- package/dist/snapshot-chunks.d.ts +0 -3
- package/dist/snapshot-chunks.d.ts.map +1 -1
- package/dist/snapshot-chunks.js +1 -8
- package/dist/snapshot-chunks.js.map +1 -1
- package/package.json +7 -28
- package/src/clients.ts +0 -1
- package/src/dialect/types.ts +6 -27
- package/src/proxy/handler.ts +0 -1
- package/src/proxy/index.ts +1 -2
- package/src/proxy/oplog.ts +3 -10
- package/src/proxy/registry.ts +33 -0
- package/src/proxy/types.ts +0 -2
- package/src/pull.ts +5 -27
- package/src/push.ts +8 -77
- package/src/realtime/types.ts +0 -2
- package/src/schema.ts +0 -10
- package/src/shapes/create-handler.ts +43 -108
- package/src/snapshot-chunks/db-metadata.ts +0 -3
- package/src/snapshot-chunks/types.ts +0 -2
- package/src/snapshot-chunks.ts +1 -12
package/src/push.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
SyncChange,
|
|
3
|
-
SyncPushRequest,
|
|
4
|
-
SyncPushResponse,
|
|
5
|
-
} from '@syncular/core';
|
|
1
|
+
import type { SyncPushRequest, SyncPushResponse } from '@syncular/core';
|
|
6
2
|
import type {
|
|
7
3
|
Insertable,
|
|
8
4
|
Kysely,
|
|
@@ -25,17 +21,6 @@ export interface PushCommitResult {
|
|
|
25
21
|
* Empty for rejected commits and for commits that emit no changes.
|
|
26
22
|
*/
|
|
27
23
|
affectedTables: string[];
|
|
28
|
-
/**
|
|
29
|
-
* Scope keys derived from emitted changes (e.g. "org:abc", "team:xyz").
|
|
30
|
-
* Computed in-transaction so callers don't need an extra DB query.
|
|
31
|
-
* Empty for rejected/cached commits.
|
|
32
|
-
*/
|
|
33
|
-
scopeKeys: string[];
|
|
34
|
-
/**
|
|
35
|
-
* Changes emitted by this commit. Available for WS data delivery.
|
|
36
|
-
* Empty for rejected/cached commits.
|
|
37
|
-
*/
|
|
38
|
-
emittedChanges: SyncChange[];
|
|
39
24
|
}
|
|
40
25
|
|
|
41
26
|
class RejectCommitError extends Error {
|
|
@@ -48,8 +33,7 @@ class RejectCommitError extends Error {
|
|
|
48
33
|
async function readCommitAffectedTables<DB extends SyncCoreDb>(
|
|
49
34
|
db: Kysely<DB>,
|
|
50
35
|
dialect: ServerSyncDialect,
|
|
51
|
-
commitSeq: number
|
|
52
|
-
partitionId: string
|
|
36
|
+
commitSeq: number
|
|
53
37
|
): Promise<string[]> {
|
|
54
38
|
try {
|
|
55
39
|
const commitsQ = db.selectFrom('sync_commits') as SelectQueryBuilder<
|
|
@@ -61,7 +45,6 @@ async function readCommitAffectedTables<DB extends SyncCoreDb>(
|
|
|
61
45
|
const row = await commitsQ
|
|
62
46
|
.selectAll()
|
|
63
47
|
.where(sql<SqlBool>`commit_seq = ${commitSeq}`)
|
|
64
|
-
.where(sql<SqlBool>`partition_id = ${partitionId}`)
|
|
65
48
|
.executeTakeFirst();
|
|
66
49
|
|
|
67
50
|
const raw = row?.affected_tables;
|
|
@@ -71,21 +54,7 @@ async function readCommitAffectedTables<DB extends SyncCoreDb>(
|
|
|
71
54
|
}
|
|
72
55
|
|
|
73
56
|
// Fallback: read from changes using dialect-specific implementation
|
|
74
|
-
return dialect.readAffectedTablesFromChanges(db, commitSeq
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function scopeKeysFromEmitted(
|
|
78
|
-
emitted: Array<{ scopes: Record<string, string> }>
|
|
79
|
-
): string[] {
|
|
80
|
-
const keys = new Set<string>();
|
|
81
|
-
for (const c of emitted) {
|
|
82
|
-
for (const [key, value] of Object.entries(c.scopes)) {
|
|
83
|
-
if (!value) continue;
|
|
84
|
-
const prefix = key.replace(/_id$/, '');
|
|
85
|
-
keys.add(`${prefix}:${value}`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return Array.from(keys);
|
|
57
|
+
return dialect.readAffectedTablesFromChanges(db, commitSeq);
|
|
89
58
|
}
|
|
90
59
|
|
|
91
60
|
export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
@@ -93,12 +62,10 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
93
62
|
dialect: ServerSyncDialect;
|
|
94
63
|
shapes: TableRegistry<DB>;
|
|
95
64
|
actorId: string;
|
|
96
|
-
partitionId?: string;
|
|
97
65
|
request: SyncPushRequest;
|
|
98
66
|
}): Promise<PushCommitResult> {
|
|
99
67
|
const { request, dialect } = args;
|
|
100
68
|
const db = args.db;
|
|
101
|
-
const partitionId = args.partitionId ?? 'default';
|
|
102
69
|
|
|
103
70
|
if (!request.clientId || !request.clientCommitId) {
|
|
104
71
|
return {
|
|
@@ -116,8 +83,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
116
83
|
],
|
|
117
84
|
},
|
|
118
85
|
affectedTables: [],
|
|
119
|
-
scopeKeys: [],
|
|
120
|
-
emittedChanges: [],
|
|
121
86
|
};
|
|
122
87
|
}
|
|
123
88
|
|
|
@@ -138,8 +103,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
138
103
|
],
|
|
139
104
|
},
|
|
140
105
|
affectedTables: [],
|
|
141
|
-
scopeKeys: [],
|
|
142
|
-
emittedChanges: [],
|
|
143
106
|
};
|
|
144
107
|
}
|
|
145
108
|
|
|
@@ -156,7 +119,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
156
119
|
// before writing the result (e.g., on D1 without transaction support).
|
|
157
120
|
await syncTrx
|
|
158
121
|
.deleteFrom('sync_commits')
|
|
159
|
-
.where('partition_id', '=', partitionId)
|
|
160
122
|
.where('client_id', '=', request.clientId)
|
|
161
123
|
.where('client_commit_id', '=', request.clientCommitId)
|
|
162
124
|
.where('result_json', 'is', null)
|
|
@@ -164,7 +126,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
164
126
|
|
|
165
127
|
// Insert commit row (idempotency key)
|
|
166
128
|
const commitRow: Insertable<SyncCoreDb['sync_commits']> = {
|
|
167
|
-
partition_id: partitionId,
|
|
168
129
|
actor_id: args.actorId,
|
|
169
130
|
client_id: request.clientId,
|
|
170
131
|
client_commit_id: request.clientCommitId,
|
|
@@ -176,7 +137,7 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
176
137
|
.insertInto('sync_commits')
|
|
177
138
|
.values(commitRow)
|
|
178
139
|
.onConflict((oc) =>
|
|
179
|
-
oc.columns(['
|
|
140
|
+
oc.columns(['client_id', 'client_commit_id']).doNothing()
|
|
180
141
|
)
|
|
181
142
|
.executeTakeFirstOrThrow();
|
|
182
143
|
|
|
@@ -192,7 +153,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
192
153
|
>
|
|
193
154
|
)
|
|
194
155
|
.selectAll()
|
|
195
|
-
.where('partition_id', '=', partitionId)
|
|
196
156
|
.where('client_id', '=', request.clientId)
|
|
197
157
|
.where('client_commit_id', '=', request.clientCommitId);
|
|
198
158
|
|
|
@@ -219,8 +179,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
219
179
|
],
|
|
220
180
|
},
|
|
221
181
|
affectedTables: [],
|
|
222
|
-
scopeKeys: [],
|
|
223
|
-
emittedChanges: [],
|
|
224
182
|
};
|
|
225
183
|
}
|
|
226
184
|
|
|
@@ -239,20 +197,12 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
239
197
|
: await readCommitAffectedTables(
|
|
240
198
|
trx,
|
|
241
199
|
dialect,
|
|
242
|
-
Number(existing.commit_seq)
|
|
243
|
-
partitionId
|
|
200
|
+
Number(existing.commit_seq)
|
|
244
201
|
),
|
|
245
|
-
scopeKeys: [],
|
|
246
|
-
emittedChanges: [],
|
|
247
202
|
};
|
|
248
203
|
}
|
|
249
204
|
|
|
250
|
-
return {
|
|
251
|
-
response: base,
|
|
252
|
-
affectedTables: [],
|
|
253
|
-
scopeKeys: [],
|
|
254
|
-
emittedChanges: [],
|
|
255
|
-
};
|
|
205
|
+
return { response: base, affectedTables: [] };
|
|
256
206
|
}
|
|
257
207
|
|
|
258
208
|
const insertedCommit = await (
|
|
@@ -263,7 +213,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
263
213
|
>
|
|
264
214
|
)
|
|
265
215
|
.selectAll()
|
|
266
|
-
.where('partition_id', '=', partitionId)
|
|
267
216
|
.where('client_id', '=', request.clientId)
|
|
268
217
|
.where('client_commit_id', '=', request.clientCommitId)
|
|
269
218
|
.executeTakeFirstOrThrow();
|
|
@@ -343,7 +292,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
343
292
|
if (allEmitted.length > 0) {
|
|
344
293
|
const changeRows: Array<Insertable<SyncCoreDb['sync_changes']>> =
|
|
345
294
|
allEmitted.map((c) => ({
|
|
346
|
-
partition_id: partitionId,
|
|
347
295
|
commit_seq: commitSeq,
|
|
348
296
|
table: c.table,
|
|
349
297
|
row_id: c.row_id,
|
|
@@ -382,7 +330,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
382
330
|
const tableCommits: Array<
|
|
383
331
|
Insertable<SyncCoreDb['sync_table_commits']>
|
|
384
332
|
> = affectedTables.map((table) => ({
|
|
385
|
-
partition_id: partitionId,
|
|
386
333
|
table,
|
|
387
334
|
commit_seq: commitSeq,
|
|
388
335
|
}));
|
|
@@ -390,9 +337,7 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
390
337
|
await syncTrx
|
|
391
338
|
.insertInto('sync_table_commits')
|
|
392
339
|
.values(tableCommits)
|
|
393
|
-
.onConflict((oc) =>
|
|
394
|
-
oc.columns(['partition_id', 'table', 'commit_seq']).doNothing()
|
|
395
|
-
)
|
|
340
|
+
.onConflict((oc) => oc.columns(['table', 'commit_seq']).doNothing())
|
|
396
341
|
.execute();
|
|
397
342
|
}
|
|
398
343
|
|
|
@@ -403,15 +348,6 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
403
348
|
return {
|
|
404
349
|
response: appliedResponse,
|
|
405
350
|
affectedTables,
|
|
406
|
-
scopeKeys: scopeKeysFromEmitted(allEmitted),
|
|
407
|
-
emittedChanges: allEmitted.map((c) => ({
|
|
408
|
-
table: c.table,
|
|
409
|
-
row_id: c.row_id,
|
|
410
|
-
op: c.op,
|
|
411
|
-
row_json: c.row_json,
|
|
412
|
-
row_version: c.row_version,
|
|
413
|
-
scopes: c.scopes,
|
|
414
|
-
})),
|
|
415
351
|
};
|
|
416
352
|
} catch (err) {
|
|
417
353
|
// Roll back app writes but keep the commit row.
|
|
@@ -446,12 +382,7 @@ export async function pushCommit<DB extends SyncCoreDb>(args: {
|
|
|
446
382
|
.where('commit_seq', '=', commitSeq)
|
|
447
383
|
.execute();
|
|
448
384
|
|
|
449
|
-
return {
|
|
450
|
-
response: err.response,
|
|
451
|
-
affectedTables: [],
|
|
452
|
-
scopeKeys: [],
|
|
453
|
-
emittedChanges: [],
|
|
454
|
-
};
|
|
385
|
+
return { response: err.response, affectedTables: [] };
|
|
455
386
|
}
|
|
456
387
|
});
|
|
457
388
|
}
|
package/src/realtime/types.ts
CHANGED
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
export interface SyncRealtimeCommitEvent {
|
|
8
8
|
type: 'commit';
|
|
9
9
|
commitSeq: number;
|
|
10
|
-
/** Logical partition key (tenant / demo / workspace). */
|
|
11
|
-
partitionId?: string;
|
|
12
10
|
/**
|
|
13
11
|
* Optional scopes affected by the commit.
|
|
14
12
|
* Broadcasters may omit this to keep payloads small (listeners can look up in DB).
|
package/src/schema.ts
CHANGED
|
@@ -16,8 +16,6 @@ import type { Generated } from 'kysely';
|
|
|
16
16
|
export interface SyncCommitsTable {
|
|
17
17
|
/** Monotonic commit sequence (server-assigned) */
|
|
18
18
|
commit_seq: Generated<number>;
|
|
19
|
-
/** Logical partition key (tenant / demo / workspace) */
|
|
20
|
-
partition_id: string;
|
|
21
19
|
/** Actor who produced the commit */
|
|
22
20
|
actor_id: string;
|
|
23
21
|
/** Client/device identifier */
|
|
@@ -45,8 +43,6 @@ export interface SyncCommitsTable {
|
|
|
45
43
|
export interface SyncChangesTable {
|
|
46
44
|
/** Monotonic change id */
|
|
47
45
|
change_id: Generated<number>;
|
|
48
|
-
/** Logical partition key (tenant / demo / workspace) */
|
|
49
|
-
partition_id: string;
|
|
50
46
|
/** Commit sequence this change belongs to */
|
|
51
47
|
commit_seq: number;
|
|
52
48
|
/** Table name being changed */
|
|
@@ -70,8 +66,6 @@ export interface SyncChangesTable {
|
|
|
70
66
|
* Per-client cursor tracking (for pruning + observability).
|
|
71
67
|
*/
|
|
72
68
|
export interface SyncClientCursorsTable {
|
|
73
|
-
/** Logical partition key (tenant / demo / workspace) */
|
|
74
|
-
partition_id: string;
|
|
75
69
|
/** Client/device identifier */
|
|
76
70
|
client_id: string;
|
|
77
71
|
/** Actor currently associated with the client */
|
|
@@ -93,8 +87,6 @@ export interface SyncClientCursorsTable {
|
|
|
93
87
|
export interface SyncSnapshotChunksTable {
|
|
94
88
|
/** Opaque chunk id */
|
|
95
89
|
chunk_id: string;
|
|
96
|
-
/** Logical partition key (tenant / demo / workspace) */
|
|
97
|
-
partition_id: string;
|
|
98
90
|
/** Effective scope key this chunk belongs to */
|
|
99
91
|
scope_key: string;
|
|
100
92
|
/** Scope identifier */
|
|
@@ -130,8 +122,6 @@ export interface SyncSnapshotChunksTable {
|
|
|
130
122
|
* the (much larger) change log.
|
|
131
123
|
*/
|
|
132
124
|
export interface SyncTableCommitsTable {
|
|
133
|
-
/** Logical partition key (tenant / demo / workspace) */
|
|
134
|
-
partition_id: string;
|
|
135
125
|
table: string;
|
|
136
126
|
commit_seq: number;
|
|
137
127
|
}
|
|
@@ -39,24 +39,6 @@ type AuthorizeResult =
|
|
|
39
39
|
| true
|
|
40
40
|
| { error: string; code: string; retriable?: boolean };
|
|
41
41
|
|
|
42
|
-
function classifyConstraintViolationCode(message: string): string {
|
|
43
|
-
const normalized = message.toLowerCase();
|
|
44
|
-
if (normalized.includes('not null')) return 'NOT_NULL_CONSTRAINT';
|
|
45
|
-
if (normalized.includes('unique')) return 'UNIQUE_CONSTRAINT';
|
|
46
|
-
if (normalized.includes('foreign key')) return 'FOREIGN_KEY_CONSTRAINT';
|
|
47
|
-
return 'CONSTRAINT_VIOLATION';
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function isConstraintViolationError(message: string): boolean {
|
|
51
|
-
const normalized = message.toLowerCase();
|
|
52
|
-
return (
|
|
53
|
-
normalized.includes('constraint') ||
|
|
54
|
-
normalized.includes('not null') ||
|
|
55
|
-
normalized.includes('foreign key') ||
|
|
56
|
-
normalized.includes('unique')
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
42
|
/**
|
|
61
43
|
* Scope definition for a column - maps scope variable to column name.
|
|
62
44
|
*/
|
|
@@ -449,109 +431,62 @@ export function createServerHandler<
|
|
|
449
431
|
};
|
|
450
432
|
}
|
|
451
433
|
|
|
452
|
-
// If the client provided a base version, they expected this row to exist.
|
|
453
|
-
// A missing row usually indicates stale local state after a server reset.
|
|
454
|
-
if (!existing && op.base_version != null) {
|
|
455
|
-
return {
|
|
456
|
-
result: {
|
|
457
|
-
opIndex,
|
|
458
|
-
status: 'error',
|
|
459
|
-
error: 'ROW_NOT_FOUND_FOR_BASE_VERSION',
|
|
460
|
-
code: 'ROW_MISSING',
|
|
461
|
-
retriable: false,
|
|
462
|
-
},
|
|
463
|
-
emittedChanges: [],
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
|
|
467
434
|
const nextVersion = existingVersion + 1;
|
|
468
435
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
// Don't update primary key or scope columns
|
|
480
|
-
delete updateSet[primaryKey];
|
|
481
|
-
for (const col of Object.values(scopeColumns)) {
|
|
482
|
-
delete updateSet[col];
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
await (
|
|
486
|
-
trx.updateTable(table) as UpdateQueryBuilder<
|
|
487
|
-
ServerDB,
|
|
488
|
-
TableName,
|
|
489
|
-
TableName,
|
|
490
|
-
UpdateResult
|
|
491
|
-
>
|
|
492
|
-
)
|
|
493
|
-
.set(updateSet as UpdateSetObject)
|
|
494
|
-
.where(ref<string>(primaryKey), '=', op.row_id)
|
|
495
|
-
.execute();
|
|
496
|
-
} else {
|
|
497
|
-
// Insert
|
|
498
|
-
const insertValues: Record<string, unknown> = {
|
|
499
|
-
...payload,
|
|
500
|
-
[primaryKey]: op.row_id,
|
|
501
|
-
[versionColumn]: 1,
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
await (
|
|
505
|
-
trx.insertInto(table) as InsertQueryBuilder<
|
|
506
|
-
ServerDB,
|
|
507
|
-
TableName,
|
|
508
|
-
InsertResult
|
|
509
|
-
>
|
|
510
|
-
)
|
|
511
|
-
.values(insertValues as Insertable<ServerDB[TableName]>)
|
|
512
|
-
.execute();
|
|
436
|
+
if (existing) {
|
|
437
|
+
// Update - merge payload with existing
|
|
438
|
+
const updateSet: Record<string, unknown> = {
|
|
439
|
+
...payload,
|
|
440
|
+
[versionColumn]: nextVersion,
|
|
441
|
+
};
|
|
442
|
+
// Don't update primary key or scope columns
|
|
443
|
+
delete updateSet[primaryKey];
|
|
444
|
+
for (const col of Object.values(scopeColumns)) {
|
|
445
|
+
delete updateSet[col];
|
|
513
446
|
}
|
|
514
447
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
trx.selectFrom(table).selectAll() as SelectQueryBuilder<
|
|
448
|
+
await (
|
|
449
|
+
trx.updateTable(table) as UpdateQueryBuilder<
|
|
518
450
|
ServerDB,
|
|
519
|
-
|
|
520
|
-
|
|
451
|
+
TableName,
|
|
452
|
+
TableName,
|
|
453
|
+
UpdateResult
|
|
521
454
|
>
|
|
522
455
|
)
|
|
456
|
+
.set(updateSet as UpdateSetObject)
|
|
523
457
|
.where(ref<string>(primaryKey), '=', op.row_id)
|
|
524
|
-
.
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
constraintError = {
|
|
532
|
-
message,
|
|
533
|
-
code: classifyConstraintViolationCode(message),
|
|
458
|
+
.execute();
|
|
459
|
+
} else {
|
|
460
|
+
// Insert
|
|
461
|
+
const insertValues: Record<string, unknown> = {
|
|
462
|
+
...payload,
|
|
463
|
+
[primaryKey]: op.row_id,
|
|
464
|
+
[versionColumn]: 1,
|
|
534
465
|
};
|
|
535
|
-
}
|
|
536
466
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
emittedChanges: [],
|
|
547
|
-
};
|
|
467
|
+
await (
|
|
468
|
+
trx.insertInto(table) as InsertQueryBuilder<
|
|
469
|
+
ServerDB,
|
|
470
|
+
TableName,
|
|
471
|
+
InsertResult
|
|
472
|
+
>
|
|
473
|
+
)
|
|
474
|
+
.values(insertValues as Insertable<ServerDB[TableName]>)
|
|
475
|
+
.execute();
|
|
548
476
|
}
|
|
549
477
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
478
|
+
// Read back the updated row
|
|
479
|
+
const updated = await (
|
|
480
|
+
trx.selectFrom(table).selectAll() as SelectQueryBuilder<
|
|
481
|
+
ServerDB,
|
|
482
|
+
keyof ServerDB & string,
|
|
483
|
+
Record<string, unknown>
|
|
484
|
+
>
|
|
485
|
+
)
|
|
486
|
+
.where(ref<string>(primaryKey), '=', op.row_id)
|
|
487
|
+
.executeTakeFirstOrThrow();
|
|
553
488
|
|
|
554
|
-
const updatedRow = updated
|
|
489
|
+
const updatedRow = updated as Record<string, unknown>;
|
|
555
490
|
const rowVersion = (updatedRow[versionColumn] as number) ?? 1;
|
|
556
491
|
|
|
557
492
|
// Extract scopes from updated row
|
|
@@ -90,7 +90,6 @@ export function createDbMetadataChunkStorage(
|
|
|
90
90
|
.insertInto('sync_snapshot_chunks')
|
|
91
91
|
.values({
|
|
92
92
|
chunk_id: chunkId,
|
|
93
|
-
partition_id: metaWithoutBody.partitionId,
|
|
94
93
|
scope_key: metaWithoutBody.scopeKey,
|
|
95
94
|
scope: metaWithoutBody.scope,
|
|
96
95
|
as_of_commit_seq: metaWithoutBody.asOfCommitSeq,
|
|
@@ -107,7 +106,6 @@ export function createDbMetadataChunkStorage(
|
|
|
107
106
|
.onConflict((oc) =>
|
|
108
107
|
oc
|
|
109
108
|
.columns([
|
|
110
|
-
'partition_id',
|
|
111
109
|
'scope_key',
|
|
112
110
|
'scope',
|
|
113
111
|
'as_of_commit_seq',
|
|
@@ -170,7 +168,6 @@ export function createDbMetadataChunkStorage(
|
|
|
170
168
|
'encoding',
|
|
171
169
|
'compression',
|
|
172
170
|
])
|
|
173
|
-
.where('partition_id', '=', pageKey.partitionId)
|
|
174
171
|
.where('scope_key', '=', pageKey.scopeKey)
|
|
175
172
|
.where('scope', '=', pageKey.scope)
|
|
176
173
|
.where('as_of_commit_seq', '=', pageKey.asOfCommitSeq)
|
|
@@ -11,7 +11,6 @@ import type { SyncSnapshotChunkRef } from '@syncular/core';
|
|
|
11
11
|
* Page key for identifying a specific chunk
|
|
12
12
|
*/
|
|
13
13
|
export interface SnapshotChunkPageKey {
|
|
14
|
-
partitionId: string;
|
|
15
14
|
scopeKey: string;
|
|
16
15
|
scope: string;
|
|
17
16
|
asOfCommitSeq: number;
|
|
@@ -26,7 +25,6 @@ export interface SnapshotChunkPageKey {
|
|
|
26
25
|
*/
|
|
27
26
|
export interface SnapshotChunkMetadata {
|
|
28
27
|
chunkId: string;
|
|
29
|
-
partitionId: string;
|
|
30
28
|
scopeKey: string;
|
|
31
29
|
scope: string;
|
|
32
30
|
asOfCommitSeq: number;
|
package/src/snapshot-chunks.ts
CHANGED
|
@@ -10,7 +10,6 @@ import { type Kysely, sql } from 'kysely';
|
|
|
10
10
|
import type { SyncCoreDb } from './schema';
|
|
11
11
|
|
|
12
12
|
export interface SnapshotChunkPageKey {
|
|
13
|
-
partitionId: string;
|
|
14
13
|
scopeKey: string;
|
|
15
14
|
scope: string;
|
|
16
15
|
asOfCommitSeq: number;
|
|
@@ -22,7 +21,6 @@ export interface SnapshotChunkPageKey {
|
|
|
22
21
|
|
|
23
22
|
export interface SnapshotChunkRow {
|
|
24
23
|
chunkId: string;
|
|
25
|
-
partitionId: string;
|
|
26
24
|
scopeKey: string;
|
|
27
25
|
scope: string;
|
|
28
26
|
asOfCommitSeq: number;
|
|
@@ -72,8 +70,7 @@ export async function readSnapshotChunkRefByPageKey<DB extends SyncCoreDb>(
|
|
|
72
70
|
select chunk_id, sha256, byte_length, encoding, compression
|
|
73
71
|
from ${sql.table('sync_snapshot_chunks')}
|
|
74
72
|
where
|
|
75
|
-
|
|
76
|
-
and scope_key = ${args.scopeKey}
|
|
73
|
+
scope_key = ${args.scopeKey}
|
|
77
74
|
and scope = ${args.scope}
|
|
78
75
|
and as_of_commit_seq = ${args.asOfCommitSeq}
|
|
79
76
|
and row_cursor = ${rowCursorKey}
|
|
@@ -111,7 +108,6 @@ export async function insertSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
111
108
|
db: Kysely<DB>,
|
|
112
109
|
args: {
|
|
113
110
|
chunkId: string;
|
|
114
|
-
partitionId: string;
|
|
115
111
|
scopeKey: string;
|
|
116
112
|
scope: string;
|
|
117
113
|
asOfCommitSeq: number;
|
|
@@ -133,7 +129,6 @@ export async function insertSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
133
129
|
await sql`
|
|
134
130
|
insert into ${sql.table('sync_snapshot_chunks')} (
|
|
135
131
|
chunk_id,
|
|
136
|
-
partition_id,
|
|
137
132
|
scope_key,
|
|
138
133
|
scope,
|
|
139
134
|
as_of_commit_seq,
|
|
@@ -150,7 +145,6 @@ export async function insertSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
150
145
|
)
|
|
151
146
|
values (
|
|
152
147
|
${args.chunkId},
|
|
153
|
-
${args.partitionId},
|
|
154
148
|
${args.scopeKey},
|
|
155
149
|
${args.scope},
|
|
156
150
|
${args.asOfCommitSeq},
|
|
@@ -166,7 +160,6 @@ export async function insertSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
166
160
|
${args.expiresAt}
|
|
167
161
|
)
|
|
168
162
|
on conflict (
|
|
169
|
-
partition_id,
|
|
170
163
|
scope_key,
|
|
171
164
|
scope,
|
|
172
165
|
as_of_commit_seq,
|
|
@@ -181,7 +174,6 @@ export async function insertSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
181
174
|
`.execute(db);
|
|
182
175
|
|
|
183
176
|
const ref = await readSnapshotChunkRefByPageKey(db, {
|
|
184
|
-
partitionId: args.partitionId,
|
|
185
177
|
scopeKey: args.scopeKey,
|
|
186
178
|
scope: args.scope,
|
|
187
179
|
asOfCommitSeq: args.asOfCommitSeq,
|
|
@@ -208,7 +200,6 @@ export async function readSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
208
200
|
): Promise<SnapshotChunkRow | null> {
|
|
209
201
|
const rowResult = await sql<{
|
|
210
202
|
chunk_id: string;
|
|
211
|
-
partition_id: string;
|
|
212
203
|
scope_key: string;
|
|
213
204
|
scope: string;
|
|
214
205
|
as_of_commit_seq: number;
|
|
@@ -224,7 +215,6 @@ export async function readSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
224
215
|
}>`
|
|
225
216
|
select
|
|
226
217
|
chunk_id,
|
|
227
|
-
partition_id,
|
|
228
218
|
scope_key,
|
|
229
219
|
scope,
|
|
230
220
|
as_of_commit_seq,
|
|
@@ -273,7 +263,6 @@ export async function readSnapshotChunk<DB extends SyncCoreDb>(
|
|
|
273
263
|
|
|
274
264
|
return {
|
|
275
265
|
chunkId: row.chunk_id,
|
|
276
|
-
partitionId: row.partition_id,
|
|
277
266
|
scopeKey: row.scope_key,
|
|
278
267
|
scope: row.scope,
|
|
279
268
|
asOfCommitSeq: Number(row.as_of_commit_seq ?? 0),
|