@foretag/tanstack-db-surrealdb 0.1.14 → 0.1.15
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 +1 -1
- package/dist/index.js +89 -42
- package/dist/index.mjs +89 -42
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Note: Please note this Software is Pre-release pending testing and not yet recommended for production use.
|
|
4
4
|
|
|
5
|
-
Add Offline / Local First Caching & Syncing to your SurrealDB app with TanstackDB and Loro (CRDTs). For SurrealDB v3 and SurrealDB JS SDK v2.
|
|
5
|
+
Add Offline / Local First Caching & Syncing to your SurrealDB app with TanstackDB and Loro (CRDTs). For SurrealDB v3.alpha-13 and SurrealDB JS SDK v2 (and above).
|
|
6
6
|
|
|
7
7
|
- Local / Offline first applications with TanstackDB and Loro
|
|
8
8
|
- High performance with Low resource consumption
|
package/dist/index.js
CHANGED
|
@@ -27,32 +27,43 @@ var import_surrealdb2 = require("surrealdb");
|
|
|
27
27
|
|
|
28
28
|
// src/table.ts
|
|
29
29
|
var import_surrealdb = require("surrealdb");
|
|
30
|
-
function manageTable(db, { name, ...args }) {
|
|
30
|
+
function manageTable(db, useLoro, { name, ...args }) {
|
|
31
31
|
const fields = args.fields ?? "*";
|
|
32
32
|
const listAll = async () => {
|
|
33
33
|
return await db.select(new import_surrealdb.Table(name)).where(args.where).fields(...fields);
|
|
34
34
|
};
|
|
35
35
|
const listActive = async () => {
|
|
36
|
+
if (!useLoro) return listAll();
|
|
36
37
|
return await db.select(new import_surrealdb.Table(name)).where((0, import_surrealdb.and)(args.where, (0, import_surrealdb.eq)("sync_deleted", false))).fields(...fields);
|
|
37
38
|
};
|
|
38
39
|
const create = async (data) => {
|
|
39
40
|
await db.create(new import_surrealdb.Table(name)).content(data);
|
|
40
41
|
};
|
|
41
42
|
const update = async (id, data) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
if (useLoro) {
|
|
44
|
+
await db.update(id).merge({
|
|
45
|
+
...data,
|
|
46
|
+
sync_deleted: false,
|
|
47
|
+
updated_at: Date.now()
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
await db.update(id).merge({
|
|
51
|
+
...data
|
|
52
|
+
});
|
|
53
|
+
}
|
|
47
54
|
};
|
|
48
55
|
const remove = async (id) => {
|
|
49
56
|
await db.delete(id);
|
|
50
57
|
};
|
|
51
58
|
const softDelete = async (id) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
if (useLoro) {
|
|
60
|
+
await db.update(id).merge({
|
|
61
|
+
sync_deleted: true,
|
|
62
|
+
updated_at: Date.now()
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
await db.delete(id);
|
|
66
|
+
}
|
|
56
67
|
};
|
|
57
68
|
const subscribe = (cb) => {
|
|
58
69
|
let killed = false;
|
|
@@ -120,11 +131,17 @@ function surrealCollectionOptions({
|
|
|
120
131
|
loro?.doc?.commit?.();
|
|
121
132
|
};
|
|
122
133
|
const pushQueue = [];
|
|
123
|
-
const enqueuePush = (op) =>
|
|
134
|
+
const enqueuePush = (op) => {
|
|
135
|
+
if (!useLoro) return;
|
|
136
|
+
pushQueue.push(op);
|
|
137
|
+
};
|
|
124
138
|
const flushPushQueue = async () => {
|
|
139
|
+
if (!useLoro) return;
|
|
125
140
|
const ops = pushQueue.splice(0, pushQueue.length);
|
|
126
141
|
for (const op of ops) {
|
|
127
|
-
if (op.kind === "create")
|
|
142
|
+
if (op.kind === "create") {
|
|
143
|
+
await table.create(op.row);
|
|
144
|
+
}
|
|
128
145
|
if (op.kind === "update") {
|
|
129
146
|
const rid = new import_surrealdb2.RecordId(
|
|
130
147
|
config.table.name,
|
|
@@ -140,13 +157,17 @@ function surrealCollectionOptions({
|
|
|
140
157
|
};
|
|
141
158
|
const newer = (a, b) => (a?.getTime() ?? -1) > (b?.getTime() ?? -1);
|
|
142
159
|
const reconcileBoot = (serverRows, write) => {
|
|
143
|
-
|
|
160
|
+
if (!useLoro) {
|
|
161
|
+
diffAndEmit(serverRows, write);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const localRows = loroToArray();
|
|
144
165
|
const serverById = new Map(serverRows.map((r) => [getKey(r), r]));
|
|
145
166
|
const localById = new Map(localRows.map((r) => [getKey(r), r]));
|
|
146
167
|
const ids = /* @__PURE__ */ new Set([...serverById.keys(), ...localById.keys()]);
|
|
147
168
|
const current = [];
|
|
148
169
|
const applyLocal = (row) => {
|
|
149
|
-
if (!
|
|
170
|
+
if (!row) return;
|
|
150
171
|
if (row.sync_deleted) loroRemove(getKey(row));
|
|
151
172
|
else loroPut(row);
|
|
152
173
|
};
|
|
@@ -154,18 +175,22 @@ function surrealCollectionOptions({
|
|
|
154
175
|
const s = serverById.get(id2);
|
|
155
176
|
const l = localById.get(id2);
|
|
156
177
|
if (s && l) {
|
|
157
|
-
|
|
178
|
+
const sDeleted = s.sync_deleted ?? false;
|
|
179
|
+
const lDeleted = l.sync_deleted ?? false;
|
|
180
|
+
const sUpdated = s.updated_at;
|
|
181
|
+
const lUpdated = l.updated_at;
|
|
182
|
+
if (sDeleted && lDeleted) {
|
|
158
183
|
applyLocal(s);
|
|
159
184
|
current.push(s);
|
|
160
|
-
} else if (
|
|
185
|
+
} else if (sDeleted && !lDeleted) {
|
|
161
186
|
applyLocal(s);
|
|
162
187
|
current.push(s);
|
|
163
|
-
} else if (!
|
|
164
|
-
if (newer(
|
|
188
|
+
} else if (!sDeleted && lDeleted) {
|
|
189
|
+
if (newer(lUpdated, sUpdated)) {
|
|
165
190
|
enqueuePush({
|
|
166
191
|
kind: "delete",
|
|
167
192
|
id: id2,
|
|
168
|
-
updated_at:
|
|
193
|
+
updated_at: lUpdated ?? /* @__PURE__ */ new Date()
|
|
169
194
|
});
|
|
170
195
|
applyLocal(l);
|
|
171
196
|
current.push(l);
|
|
@@ -174,7 +199,7 @@ function surrealCollectionOptions({
|
|
|
174
199
|
current.push(s);
|
|
175
200
|
}
|
|
176
201
|
} else {
|
|
177
|
-
if (newer(
|
|
202
|
+
if (newer(lUpdated, sUpdated)) {
|
|
178
203
|
enqueuePush({ kind: "update", row: l });
|
|
179
204
|
applyLocal(l);
|
|
180
205
|
current.push(l);
|
|
@@ -187,11 +212,13 @@ function surrealCollectionOptions({
|
|
|
187
212
|
applyLocal(s);
|
|
188
213
|
current.push(s);
|
|
189
214
|
} else if (!s && l) {
|
|
190
|
-
|
|
215
|
+
const lDeleted = l.sync_deleted ?? false;
|
|
216
|
+
const lUpdated = l.updated_at;
|
|
217
|
+
if (lDeleted) {
|
|
191
218
|
enqueuePush({
|
|
192
219
|
kind: "delete",
|
|
193
220
|
id: id2,
|
|
194
|
-
updated_at:
|
|
221
|
+
updated_at: lUpdated ?? /* @__PURE__ */ new Date()
|
|
195
222
|
});
|
|
196
223
|
applyLocal(l);
|
|
197
224
|
current.push(l);
|
|
@@ -206,15 +233,24 @@ function surrealCollectionOptions({
|
|
|
206
233
|
};
|
|
207
234
|
let prevById = /* @__PURE__ */ new Map();
|
|
208
235
|
const buildMap = (rows) => new Map(rows.map((r) => [getKey(r), r]));
|
|
209
|
-
const same = (a, b) =>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
236
|
+
const same = (a, b) => {
|
|
237
|
+
if (useLoro) {
|
|
238
|
+
const aUpdated = a.updated_at;
|
|
239
|
+
const bUpdated = b.updated_at;
|
|
240
|
+
const aDeleted = a.sync_deleted ?? false;
|
|
241
|
+
const bDeleted = b.sync_deleted ?? false;
|
|
242
|
+
return aDeleted === bDeleted && (aUpdated?.getTime() ?? 0) === (bUpdated?.getTime() ?? 0) && JSON.stringify({
|
|
243
|
+
...a,
|
|
244
|
+
updated_at: void 0,
|
|
245
|
+
sync_deleted: void 0
|
|
246
|
+
}) === JSON.stringify({
|
|
247
|
+
...b,
|
|
248
|
+
updated_at: void 0,
|
|
249
|
+
sync_deleted: void 0
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
253
|
+
};
|
|
218
254
|
const diffAndEmit = (currentRows, write) => {
|
|
219
255
|
const currById = buildMap(currentRows);
|
|
220
256
|
for (const [id2, row] of currById) {
|
|
@@ -232,7 +268,8 @@ function surrealCollectionOptions({
|
|
|
232
268
|
}
|
|
233
269
|
prevById = currById;
|
|
234
270
|
};
|
|
235
|
-
const table = manageTable(db, config.table);
|
|
271
|
+
const table = manageTable(db, useLoro, config.table);
|
|
272
|
+
const now = () => /* @__PURE__ */ new Date();
|
|
236
273
|
const sync = ({
|
|
237
274
|
begin,
|
|
238
275
|
write,
|
|
@@ -242,15 +279,18 @@ function surrealCollectionOptions({
|
|
|
242
279
|
let offLive = null;
|
|
243
280
|
const makeTombstone = (id2) => ({
|
|
244
281
|
id: new import_surrealdb2.RecordId(config.table.name, id2).toString(),
|
|
245
|
-
updated_at:
|
|
282
|
+
updated_at: now(),
|
|
246
283
|
sync_deleted: true
|
|
247
284
|
});
|
|
248
285
|
const start = async () => {
|
|
249
286
|
try {
|
|
250
287
|
const serverRows = await table.listAll();
|
|
251
288
|
begin();
|
|
252
|
-
if (useLoro)
|
|
253
|
-
|
|
289
|
+
if (useLoro) {
|
|
290
|
+
reconcileBoot(serverRows, write);
|
|
291
|
+
} else {
|
|
292
|
+
diffAndEmit(serverRows, write);
|
|
293
|
+
}
|
|
254
294
|
commit();
|
|
255
295
|
markReady();
|
|
256
296
|
await flushPushQueue();
|
|
@@ -259,7 +299,8 @@ function surrealCollectionOptions({
|
|
|
259
299
|
try {
|
|
260
300
|
if (evt.type === "insert" || evt.type === "update") {
|
|
261
301
|
const row = evt.row;
|
|
262
|
-
|
|
302
|
+
const deleted = useLoro ? row.sync_deleted ?? false : false;
|
|
303
|
+
if (deleted) {
|
|
263
304
|
if (useLoro) loroRemove(getKey(row));
|
|
264
305
|
const prev = prevById.get(getKey(row)) ?? makeTombstone(getKey(row));
|
|
265
306
|
write({ type: "delete", value: prev });
|
|
@@ -294,16 +335,16 @@ function surrealCollectionOptions({
|
|
|
294
335
|
if (offLive) offLive();
|
|
295
336
|
};
|
|
296
337
|
};
|
|
297
|
-
const now = () => /* @__PURE__ */ new Date();
|
|
298
338
|
const onInsert = async (p) => {
|
|
299
339
|
const resultRows = [];
|
|
300
340
|
for (const m of p.transaction.mutations) {
|
|
301
341
|
if (m.type !== "insert") continue;
|
|
302
|
-
const
|
|
303
|
-
|
|
342
|
+
const base = { ...m.modified };
|
|
343
|
+
const row = useLoro ? {
|
|
344
|
+
...base,
|
|
304
345
|
updated_at: now(),
|
|
305
346
|
sync_deleted: false
|
|
306
|
-
};
|
|
347
|
+
} : base;
|
|
307
348
|
if (useLoro) loroPut(row);
|
|
308
349
|
await table.create(row);
|
|
309
350
|
resultRows.push(row);
|
|
@@ -315,7 +356,11 @@ function surrealCollectionOptions({
|
|
|
315
356
|
for (const m of p.transaction.mutations) {
|
|
316
357
|
if (m.type !== "update") continue;
|
|
317
358
|
const id2 = m.key;
|
|
318
|
-
const
|
|
359
|
+
const base = { ...m.modified, id: id2 };
|
|
360
|
+
const merged = useLoro ? {
|
|
361
|
+
...base,
|
|
362
|
+
updated_at: now()
|
|
363
|
+
} : base;
|
|
319
364
|
if (useLoro) loroPut(merged);
|
|
320
365
|
const rid = new import_surrealdb2.RecordId(config.table.name, keyOf(id2));
|
|
321
366
|
await table.update(rid, merged);
|
|
@@ -328,7 +373,9 @@ function surrealCollectionOptions({
|
|
|
328
373
|
for (const m of p.transaction.mutations) {
|
|
329
374
|
if (m.type !== "delete") continue;
|
|
330
375
|
const id2 = m.key;
|
|
331
|
-
if (useLoro)
|
|
376
|
+
if (useLoro) {
|
|
377
|
+
loroRemove(keyOf(id2));
|
|
378
|
+
}
|
|
332
379
|
await table.softDelete(new import_surrealdb2.RecordId(config.table.name, keyOf(id2)));
|
|
333
380
|
}
|
|
334
381
|
return resultRows;
|
package/dist/index.mjs
CHANGED
|
@@ -9,32 +9,43 @@ import {
|
|
|
9
9
|
Features,
|
|
10
10
|
Table
|
|
11
11
|
} from "surrealdb";
|
|
12
|
-
function manageTable(db, { name, ...args }) {
|
|
12
|
+
function manageTable(db, useLoro, { name, ...args }) {
|
|
13
13
|
const fields = args.fields ?? "*";
|
|
14
14
|
const listAll = async () => {
|
|
15
15
|
return await db.select(new Table(name)).where(args.where).fields(...fields);
|
|
16
16
|
};
|
|
17
17
|
const listActive = async () => {
|
|
18
|
+
if (!useLoro) return listAll();
|
|
18
19
|
return await db.select(new Table(name)).where(and(args.where, eq("sync_deleted", false))).fields(...fields);
|
|
19
20
|
};
|
|
20
21
|
const create = async (data) => {
|
|
21
22
|
await db.create(new Table(name)).content(data);
|
|
22
23
|
};
|
|
23
24
|
const update = async (id, data) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
if (useLoro) {
|
|
26
|
+
await db.update(id).merge({
|
|
27
|
+
...data,
|
|
28
|
+
sync_deleted: false,
|
|
29
|
+
updated_at: Date.now()
|
|
30
|
+
});
|
|
31
|
+
} else {
|
|
32
|
+
await db.update(id).merge({
|
|
33
|
+
...data
|
|
34
|
+
});
|
|
35
|
+
}
|
|
29
36
|
};
|
|
30
37
|
const remove = async (id) => {
|
|
31
38
|
await db.delete(id);
|
|
32
39
|
};
|
|
33
40
|
const softDelete = async (id) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
if (useLoro) {
|
|
42
|
+
await db.update(id).merge({
|
|
43
|
+
sync_deleted: true,
|
|
44
|
+
updated_at: Date.now()
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
await db.delete(id);
|
|
48
|
+
}
|
|
38
49
|
};
|
|
39
50
|
const subscribe = (cb) => {
|
|
40
51
|
let killed = false;
|
|
@@ -102,11 +113,17 @@ function surrealCollectionOptions({
|
|
|
102
113
|
loro?.doc?.commit?.();
|
|
103
114
|
};
|
|
104
115
|
const pushQueue = [];
|
|
105
|
-
const enqueuePush = (op) =>
|
|
116
|
+
const enqueuePush = (op) => {
|
|
117
|
+
if (!useLoro) return;
|
|
118
|
+
pushQueue.push(op);
|
|
119
|
+
};
|
|
106
120
|
const flushPushQueue = async () => {
|
|
121
|
+
if (!useLoro) return;
|
|
107
122
|
const ops = pushQueue.splice(0, pushQueue.length);
|
|
108
123
|
for (const op of ops) {
|
|
109
|
-
if (op.kind === "create")
|
|
124
|
+
if (op.kind === "create") {
|
|
125
|
+
await table.create(op.row);
|
|
126
|
+
}
|
|
110
127
|
if (op.kind === "update") {
|
|
111
128
|
const rid = new RecordId(
|
|
112
129
|
config.table.name,
|
|
@@ -122,13 +139,17 @@ function surrealCollectionOptions({
|
|
|
122
139
|
};
|
|
123
140
|
const newer = (a, b) => (a?.getTime() ?? -1) > (b?.getTime() ?? -1);
|
|
124
141
|
const reconcileBoot = (serverRows, write) => {
|
|
125
|
-
|
|
142
|
+
if (!useLoro) {
|
|
143
|
+
diffAndEmit(serverRows, write);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const localRows = loroToArray();
|
|
126
147
|
const serverById = new Map(serverRows.map((r) => [getKey(r), r]));
|
|
127
148
|
const localById = new Map(localRows.map((r) => [getKey(r), r]));
|
|
128
149
|
const ids = /* @__PURE__ */ new Set([...serverById.keys(), ...localById.keys()]);
|
|
129
150
|
const current = [];
|
|
130
151
|
const applyLocal = (row) => {
|
|
131
|
-
if (!
|
|
152
|
+
if (!row) return;
|
|
132
153
|
if (row.sync_deleted) loroRemove(getKey(row));
|
|
133
154
|
else loroPut(row);
|
|
134
155
|
};
|
|
@@ -136,18 +157,22 @@ function surrealCollectionOptions({
|
|
|
136
157
|
const s = serverById.get(id2);
|
|
137
158
|
const l = localById.get(id2);
|
|
138
159
|
if (s && l) {
|
|
139
|
-
|
|
160
|
+
const sDeleted = s.sync_deleted ?? false;
|
|
161
|
+
const lDeleted = l.sync_deleted ?? false;
|
|
162
|
+
const sUpdated = s.updated_at;
|
|
163
|
+
const lUpdated = l.updated_at;
|
|
164
|
+
if (sDeleted && lDeleted) {
|
|
140
165
|
applyLocal(s);
|
|
141
166
|
current.push(s);
|
|
142
|
-
} else if (
|
|
167
|
+
} else if (sDeleted && !lDeleted) {
|
|
143
168
|
applyLocal(s);
|
|
144
169
|
current.push(s);
|
|
145
|
-
} else if (!
|
|
146
|
-
if (newer(
|
|
170
|
+
} else if (!sDeleted && lDeleted) {
|
|
171
|
+
if (newer(lUpdated, sUpdated)) {
|
|
147
172
|
enqueuePush({
|
|
148
173
|
kind: "delete",
|
|
149
174
|
id: id2,
|
|
150
|
-
updated_at:
|
|
175
|
+
updated_at: lUpdated ?? /* @__PURE__ */ new Date()
|
|
151
176
|
});
|
|
152
177
|
applyLocal(l);
|
|
153
178
|
current.push(l);
|
|
@@ -156,7 +181,7 @@ function surrealCollectionOptions({
|
|
|
156
181
|
current.push(s);
|
|
157
182
|
}
|
|
158
183
|
} else {
|
|
159
|
-
if (newer(
|
|
184
|
+
if (newer(lUpdated, sUpdated)) {
|
|
160
185
|
enqueuePush({ kind: "update", row: l });
|
|
161
186
|
applyLocal(l);
|
|
162
187
|
current.push(l);
|
|
@@ -169,11 +194,13 @@ function surrealCollectionOptions({
|
|
|
169
194
|
applyLocal(s);
|
|
170
195
|
current.push(s);
|
|
171
196
|
} else if (!s && l) {
|
|
172
|
-
|
|
197
|
+
const lDeleted = l.sync_deleted ?? false;
|
|
198
|
+
const lUpdated = l.updated_at;
|
|
199
|
+
if (lDeleted) {
|
|
173
200
|
enqueuePush({
|
|
174
201
|
kind: "delete",
|
|
175
202
|
id: id2,
|
|
176
|
-
updated_at:
|
|
203
|
+
updated_at: lUpdated ?? /* @__PURE__ */ new Date()
|
|
177
204
|
});
|
|
178
205
|
applyLocal(l);
|
|
179
206
|
current.push(l);
|
|
@@ -188,15 +215,24 @@ function surrealCollectionOptions({
|
|
|
188
215
|
};
|
|
189
216
|
let prevById = /* @__PURE__ */ new Map();
|
|
190
217
|
const buildMap = (rows) => new Map(rows.map((r) => [getKey(r), r]));
|
|
191
|
-
const same = (a, b) =>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
218
|
+
const same = (a, b) => {
|
|
219
|
+
if (useLoro) {
|
|
220
|
+
const aUpdated = a.updated_at;
|
|
221
|
+
const bUpdated = b.updated_at;
|
|
222
|
+
const aDeleted = a.sync_deleted ?? false;
|
|
223
|
+
const bDeleted = b.sync_deleted ?? false;
|
|
224
|
+
return aDeleted === bDeleted && (aUpdated?.getTime() ?? 0) === (bUpdated?.getTime() ?? 0) && JSON.stringify({
|
|
225
|
+
...a,
|
|
226
|
+
updated_at: void 0,
|
|
227
|
+
sync_deleted: void 0
|
|
228
|
+
}) === JSON.stringify({
|
|
229
|
+
...b,
|
|
230
|
+
updated_at: void 0,
|
|
231
|
+
sync_deleted: void 0
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
235
|
+
};
|
|
200
236
|
const diffAndEmit = (currentRows, write) => {
|
|
201
237
|
const currById = buildMap(currentRows);
|
|
202
238
|
for (const [id2, row] of currById) {
|
|
@@ -214,7 +250,8 @@ function surrealCollectionOptions({
|
|
|
214
250
|
}
|
|
215
251
|
prevById = currById;
|
|
216
252
|
};
|
|
217
|
-
const table = manageTable(db, config.table);
|
|
253
|
+
const table = manageTable(db, useLoro, config.table);
|
|
254
|
+
const now = () => /* @__PURE__ */ new Date();
|
|
218
255
|
const sync = ({
|
|
219
256
|
begin,
|
|
220
257
|
write,
|
|
@@ -224,15 +261,18 @@ function surrealCollectionOptions({
|
|
|
224
261
|
let offLive = null;
|
|
225
262
|
const makeTombstone = (id2) => ({
|
|
226
263
|
id: new RecordId(config.table.name, id2).toString(),
|
|
227
|
-
updated_at:
|
|
264
|
+
updated_at: now(),
|
|
228
265
|
sync_deleted: true
|
|
229
266
|
});
|
|
230
267
|
const start = async () => {
|
|
231
268
|
try {
|
|
232
269
|
const serverRows = await table.listAll();
|
|
233
270
|
begin();
|
|
234
|
-
if (useLoro)
|
|
235
|
-
|
|
271
|
+
if (useLoro) {
|
|
272
|
+
reconcileBoot(serverRows, write);
|
|
273
|
+
} else {
|
|
274
|
+
diffAndEmit(serverRows, write);
|
|
275
|
+
}
|
|
236
276
|
commit();
|
|
237
277
|
markReady();
|
|
238
278
|
await flushPushQueue();
|
|
@@ -241,7 +281,8 @@ function surrealCollectionOptions({
|
|
|
241
281
|
try {
|
|
242
282
|
if (evt.type === "insert" || evt.type === "update") {
|
|
243
283
|
const row = evt.row;
|
|
244
|
-
|
|
284
|
+
const deleted = useLoro ? row.sync_deleted ?? false : false;
|
|
285
|
+
if (deleted) {
|
|
245
286
|
if (useLoro) loroRemove(getKey(row));
|
|
246
287
|
const prev = prevById.get(getKey(row)) ?? makeTombstone(getKey(row));
|
|
247
288
|
write({ type: "delete", value: prev });
|
|
@@ -276,16 +317,16 @@ function surrealCollectionOptions({
|
|
|
276
317
|
if (offLive) offLive();
|
|
277
318
|
};
|
|
278
319
|
};
|
|
279
|
-
const now = () => /* @__PURE__ */ new Date();
|
|
280
320
|
const onInsert = async (p) => {
|
|
281
321
|
const resultRows = [];
|
|
282
322
|
for (const m of p.transaction.mutations) {
|
|
283
323
|
if (m.type !== "insert") continue;
|
|
284
|
-
const
|
|
285
|
-
|
|
324
|
+
const base = { ...m.modified };
|
|
325
|
+
const row = useLoro ? {
|
|
326
|
+
...base,
|
|
286
327
|
updated_at: now(),
|
|
287
328
|
sync_deleted: false
|
|
288
|
-
};
|
|
329
|
+
} : base;
|
|
289
330
|
if (useLoro) loroPut(row);
|
|
290
331
|
await table.create(row);
|
|
291
332
|
resultRows.push(row);
|
|
@@ -297,7 +338,11 @@ function surrealCollectionOptions({
|
|
|
297
338
|
for (const m of p.transaction.mutations) {
|
|
298
339
|
if (m.type !== "update") continue;
|
|
299
340
|
const id2 = m.key;
|
|
300
|
-
const
|
|
341
|
+
const base = { ...m.modified, id: id2 };
|
|
342
|
+
const merged = useLoro ? {
|
|
343
|
+
...base,
|
|
344
|
+
updated_at: now()
|
|
345
|
+
} : base;
|
|
301
346
|
if (useLoro) loroPut(merged);
|
|
302
347
|
const rid = new RecordId(config.table.name, keyOf(id2));
|
|
303
348
|
await table.update(rid, merged);
|
|
@@ -310,7 +355,9 @@ function surrealCollectionOptions({
|
|
|
310
355
|
for (const m of p.transaction.mutations) {
|
|
311
356
|
if (m.type !== "delete") continue;
|
|
312
357
|
const id2 = m.key;
|
|
313
|
-
if (useLoro)
|
|
358
|
+
if (useLoro) {
|
|
359
|
+
loroRemove(keyOf(id2));
|
|
360
|
+
}
|
|
314
361
|
await table.softDelete(new RecordId(config.table.name, keyOf(id2)));
|
|
315
362
|
}
|
|
316
363
|
return resultRows;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foretag/tanstack-db-surrealdb",
|
|
3
3
|
"description": "Add Offline / Local First Caching & Syncing to your SurrealDB app with TanstackDB and Loro (CRDTs)",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.15",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
7
7
|
],
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"loro-crdt": "^1.9.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"@tanstack/db": "
|
|
47
|
-
"@tanstack/query-db-collection": "
|
|
46
|
+
"@tanstack/db": "^0.5.0",
|
|
47
|
+
"@tanstack/query-db-collection": "^1.0.0",
|
|
48
48
|
"surrealdb": "2.0.0-alpha.13"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|