@foretag/tanstack-db-surrealdb 0.3.0 → 0.3.2
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/index.d.mts +20 -19
- package/dist/index.d.ts +20 -19
- package/dist/index.js +180 -487
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +175 -465
- package/dist/index.mjs.map +1 -0
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -1,109 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
import { LoroDoc } from
|
|
3
|
-
import { Features
|
|
1
|
+
import { queryCollectionOptions } from '@tanstack/query-db-collection';
|
|
2
|
+
import { LoroDoc } from 'loro-crdt';
|
|
3
|
+
import { RecordId, Features, Table, and, eq } from 'surrealdb';
|
|
4
4
|
|
|
5
|
-
// src/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const pageSize = args.pageSize ?? 100;
|
|
18
|
-
const initialPageSize = args.initialPageSize ?? Math.min(50, pageSize);
|
|
19
|
-
let cursor = 0;
|
|
20
|
-
let progressiveTask = null;
|
|
21
|
-
const idKey = (id) => typeof id === "string" ? id : id.toString();
|
|
22
|
-
const upsertCache = (rows) => {
|
|
23
|
-
for (const row of rows) cache.set(idKey(row.id), row);
|
|
24
|
-
};
|
|
25
|
-
const removeFromCache = (id) => {
|
|
26
|
-
cache.delete(idKey(id));
|
|
27
|
-
};
|
|
28
|
-
const listCached = () => Array.from(cache.values());
|
|
29
|
-
const buildWhere = () => {
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var normalizeFields = (raw) => {
|
|
7
|
+
if (!raw || raw === "*") return ["*"];
|
|
8
|
+
return raw;
|
|
9
|
+
};
|
|
10
|
+
var joinOrderBy = (o) => {
|
|
11
|
+
if (!o) return void 0;
|
|
12
|
+
return typeof o === "string" ? o : o.join(", ");
|
|
13
|
+
};
|
|
14
|
+
function manageTable(db, useLoro, { name, ...args }) {
|
|
15
|
+
const fields = normalizeFields(args.fields);
|
|
16
|
+
const baseWhere = () => {
|
|
30
17
|
if (!useLoro) return args.where;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const applyPaging = (q, start, limit) => {
|
|
40
|
-
if (typeof start === "number" && q.start) q = q.start(start);
|
|
41
|
-
if (typeof limit === "number" && q.limit) q = q.limit(limit);
|
|
42
|
-
return q;
|
|
43
|
-
};
|
|
44
|
-
const fetchAll = async () => {
|
|
45
|
-
const rows = await buildQuery().fields(...fields);
|
|
46
|
-
upsertCache(rows);
|
|
47
|
-
fullyLoaded = true;
|
|
48
|
-
return rows;
|
|
49
|
-
};
|
|
50
|
-
const fetchPage = async (opts) => {
|
|
51
|
-
const q = applyPaging(
|
|
52
|
-
buildQuery(),
|
|
53
|
-
opts?.start ?? 0,
|
|
54
|
-
opts?.limit ?? pageSize
|
|
55
|
-
);
|
|
56
|
-
const rows = await q.fields(...fields);
|
|
57
|
-
upsertCache(rows);
|
|
58
|
-
if (rows.length < (opts?.limit ?? pageSize)) fullyLoaded = true;
|
|
59
|
-
return rows;
|
|
60
|
-
};
|
|
61
|
-
const fetchById = async (id) => {
|
|
62
|
-
const key = idKey(id);
|
|
63
|
-
const cached = cache.get(key);
|
|
64
|
-
if (cached) return cached;
|
|
65
|
-
const res = await db.select(id);
|
|
66
|
-
const row = Array.isArray(res) ? res[0] : res;
|
|
67
|
-
if (!row) return null;
|
|
68
|
-
if (useLoro && row.sync_deleted)
|
|
69
|
-
return null;
|
|
70
|
-
cache.set(key, row);
|
|
71
|
-
return row;
|
|
72
|
-
};
|
|
73
|
-
const loadMore = async (limit = pageSize) => {
|
|
74
|
-
if (fullyLoaded) return { rows: [], done: true };
|
|
75
|
-
const rows = await fetchPage({ start: cursor, limit });
|
|
76
|
-
cursor += rows.length;
|
|
77
|
-
const done = fullyLoaded || rows.length < limit;
|
|
78
|
-
args.onProgress?.({
|
|
18
|
+
const alive = eq("sync_deleted", false);
|
|
19
|
+
return args.where ? and(args.where, alive) : alive;
|
|
20
|
+
};
|
|
21
|
+
const listAll = async () => {
|
|
22
|
+
const where = baseWhere();
|
|
23
|
+
const whereSql = where ? " WHERE $where" : "";
|
|
24
|
+
const sql = `SELECT ${fields.join(", ")} FROM type::table($table)${whereSql};`;
|
|
25
|
+
const [res] = await db.query(sql, {
|
|
79
26
|
table: name,
|
|
80
|
-
|
|
81
|
-
lastBatch: rows.length,
|
|
82
|
-
done
|
|
27
|
+
where
|
|
83
28
|
});
|
|
84
|
-
return
|
|
85
|
-
};
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
29
|
+
return res ?? [];
|
|
30
|
+
};
|
|
31
|
+
const loadSubset = async (subset) => {
|
|
32
|
+
const b = baseWhere();
|
|
33
|
+
const w = subset?.where;
|
|
34
|
+
const where = b && w ? and(b, w) : b ?? w;
|
|
35
|
+
const whereSql = where ? " WHERE $where" : "";
|
|
36
|
+
const order = joinOrderBy(subset?.orderBy);
|
|
37
|
+
const orderSql = order ? ` ORDER BY ${order}` : "";
|
|
38
|
+
const limitSql = typeof subset?.limit === "number" ? " LIMIT $limit" : "";
|
|
39
|
+
const startSql = typeof subset?.offset === "number" ? " START $offset" : "";
|
|
40
|
+
const sql = `SELECT ${fields.join(", ")} FROM type::table($table)${whereSql}${orderSql}${limitSql}${startSql};`;
|
|
41
|
+
const [res] = await db.query(sql, {
|
|
42
|
+
table: name,
|
|
43
|
+
where,
|
|
44
|
+
limit: subset?.limit,
|
|
45
|
+
offset: subset?.offset
|
|
96
46
|
});
|
|
97
|
-
|
|
98
|
-
const listAll = () => fetchAll();
|
|
99
|
-
const listActive = async () => {
|
|
100
|
-
if (syncMode === "eager") return fetchAll();
|
|
101
|
-
if (syncMode === "progressive") {
|
|
102
|
-
if (cache.size === 0) await loadMore(initialPageSize);
|
|
103
|
-
startProgressive();
|
|
104
|
-
return listCached();
|
|
105
|
-
}
|
|
106
|
-
return listCached();
|
|
47
|
+
return res ?? [];
|
|
107
48
|
};
|
|
108
49
|
const create = async (data) => {
|
|
109
50
|
await db.create(new Table(name)).content(data);
|
|
@@ -116,24 +57,21 @@ function manageTable(db, useLoro, { name, ...args }, syncMode = "eager") {
|
|
|
116
57
|
await db.update(id).merge({
|
|
117
58
|
...data,
|
|
118
59
|
sync_deleted: false,
|
|
119
|
-
updated_at:
|
|
60
|
+
updated_at: Date.now()
|
|
120
61
|
});
|
|
121
62
|
};
|
|
122
63
|
const remove = async (id) => {
|
|
123
64
|
await db.delete(id);
|
|
124
|
-
removeFromCache(id);
|
|
125
65
|
};
|
|
126
66
|
const softDelete = async (id) => {
|
|
127
67
|
if (!useLoro) {
|
|
128
68
|
await db.delete(id);
|
|
129
|
-
removeFromCache(id);
|
|
130
69
|
return;
|
|
131
70
|
}
|
|
132
71
|
await db.upsert(id).merge({
|
|
133
72
|
sync_deleted: true,
|
|
134
|
-
updated_at:
|
|
73
|
+
updated_at: Date.now()
|
|
135
74
|
});
|
|
136
|
-
removeFromCache(id);
|
|
137
75
|
};
|
|
138
76
|
const subscribe = (cb) => {
|
|
139
77
|
let killed = false;
|
|
@@ -141,25 +79,10 @@ function manageTable(db, useLoro, { name, ...args }, syncMode = "eager") {
|
|
|
141
79
|
const on = (msg) => {
|
|
142
80
|
const { action, value } = msg;
|
|
143
81
|
if (action === "KILLED") return;
|
|
144
|
-
if (action === "CREATE") {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
if (action === "UPDATE") {
|
|
150
|
-
if (useLoro && value.sync_deleted) {
|
|
151
|
-
removeFromCache(value.id);
|
|
152
|
-
cb({ type: "delete", row: { id: value.id } });
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
upsertCache([value]);
|
|
156
|
-
cb({ type: "update", row: value });
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (action === "DELETE") {
|
|
160
|
-
removeFromCache(value.id);
|
|
82
|
+
if (action === "CREATE") cb({ type: "insert", row: value });
|
|
83
|
+
else if (action === "UPDATE") cb({ type: "update", row: value });
|
|
84
|
+
else if (action === "DELETE")
|
|
161
85
|
cb({ type: "delete", row: { id: value.id } });
|
|
162
|
-
}
|
|
163
86
|
};
|
|
164
87
|
const start = async () => {
|
|
165
88
|
if (!db.isFeatureSupported(Features.LiveQueries)) return;
|
|
@@ -175,382 +98,169 @@ function manageTable(db, useLoro, { name, ...args }, syncMode = "eager") {
|
|
|
175
98
|
};
|
|
176
99
|
return {
|
|
177
100
|
listAll,
|
|
178
|
-
|
|
179
|
-
listCached,
|
|
180
|
-
fetchPage,
|
|
181
|
-
fetchById,
|
|
182
|
-
loadMore,
|
|
101
|
+
loadSubset,
|
|
183
102
|
create,
|
|
184
103
|
update,
|
|
185
104
|
remove,
|
|
186
105
|
softDelete,
|
|
187
|
-
subscribe
|
|
188
|
-
get isFullyLoaded() {
|
|
189
|
-
return fullyLoaded;
|
|
190
|
-
},
|
|
191
|
-
get cachedCount() {
|
|
192
|
-
return cache.size;
|
|
193
|
-
}
|
|
106
|
+
subscribe
|
|
194
107
|
};
|
|
195
108
|
}
|
|
196
109
|
|
|
197
110
|
// src/index.ts
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (typeof
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return String(v);
|
|
111
|
+
function toCleanup(res) {
|
|
112
|
+
if (!res) return () => {
|
|
113
|
+
};
|
|
114
|
+
if (typeof res === "function") {
|
|
115
|
+
return res;
|
|
116
|
+
}
|
|
117
|
+
if (typeof res === "object" && res !== null) {
|
|
118
|
+
const r = res;
|
|
119
|
+
const cleanup = r["cleanup"];
|
|
120
|
+
if (typeof cleanup === "function") return cleanup;
|
|
121
|
+
const unsubscribe = r["unsubscribe"];
|
|
122
|
+
if (typeof unsubscribe === "function") return unsubscribe;
|
|
123
|
+
const dispose = r["dispose"];
|
|
124
|
+
if (typeof dispose === "function") return dispose;
|
|
125
|
+
}
|
|
126
|
+
return () => {
|
|
215
127
|
};
|
|
216
|
-
|
|
217
|
-
};
|
|
218
|
-
var chunk = (arr, size) => {
|
|
219
|
-
const out = [];
|
|
220
|
-
for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
|
|
221
|
-
return out;
|
|
222
|
-
};
|
|
128
|
+
}
|
|
223
129
|
function surrealCollectionOptions({
|
|
224
130
|
id,
|
|
225
131
|
useLoro = false,
|
|
226
132
|
onError,
|
|
227
133
|
db,
|
|
228
|
-
|
|
134
|
+
queryClient,
|
|
135
|
+
queryKey,
|
|
136
|
+
syncMode = "eager",
|
|
229
137
|
...config
|
|
230
138
|
}) {
|
|
231
139
|
let loro;
|
|
232
140
|
if (useLoro) loro = { doc: new LoroDoc(), key: id };
|
|
141
|
+
const table = manageTable(db, useLoro, config.table);
|
|
233
142
|
const keyOf = (rid) => typeof rid === "string" ? rid : rid.toString();
|
|
234
143
|
const getKey = (row) => keyOf(row.id);
|
|
235
144
|
const loroKey = loro?.key ?? id ?? "surreal";
|
|
236
145
|
const loroMap = useLoro ? loro?.doc?.getMap?.(loroKey) ?? null : null;
|
|
237
|
-
const
|
|
238
|
-
if (!loroMap) return
|
|
239
|
-
|
|
240
|
-
return Object.values(json);
|
|
241
|
-
};
|
|
242
|
-
const loroPutMany = (rows) => {
|
|
243
|
-
if (!loroMap || rows.length === 0) return;
|
|
244
|
-
for (const row of rows) loroMap.set(getKey(row), row);
|
|
146
|
+
const loroPut = (row) => {
|
|
147
|
+
if (!loroMap) return;
|
|
148
|
+
loroMap.set(getKey(row), row);
|
|
245
149
|
loro?.doc?.commit?.();
|
|
246
150
|
};
|
|
247
|
-
const
|
|
248
|
-
if (!loroMap
|
|
249
|
-
|
|
151
|
+
const loroRemove = (idStr) => {
|
|
152
|
+
if (!loroMap) return;
|
|
153
|
+
loroMap.delete(idStr);
|
|
250
154
|
loro?.doc?.commit?.();
|
|
251
155
|
};
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const flushPushQueue = async () => {
|
|
259
|
-
if (!useLoro) return;
|
|
260
|
-
const ops = pushQueue.splice(0, pushQueue.length);
|
|
261
|
-
for (const op of ops) {
|
|
262
|
-
if (op.kind === "create") {
|
|
263
|
-
await table.create(op.row);
|
|
264
|
-
} else if (op.kind === "update") {
|
|
265
|
-
const rid = new RecordId(
|
|
266
|
-
config.table.name,
|
|
267
|
-
op.row.id.toString()
|
|
268
|
-
);
|
|
269
|
-
await table.update(rid, op.row);
|
|
270
|
-
} else {
|
|
271
|
-
const rid = new RecordId(config.table.name, op.id);
|
|
272
|
-
await table.softDelete(rid);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
const newer = (a, b) => (a?.getTime() ?? -1) > (b?.getTime() ?? -1);
|
|
277
|
-
const fetchServerByLocalIds = async (ids) => {
|
|
278
|
-
if (ids.length === 0) return [];
|
|
279
|
-
const tableName = config.table.name;
|
|
280
|
-
const parts = chunk(ids, LOCAL_ID_VERIFY_CHUNK);
|
|
156
|
+
const mergeLocalOverServer = (serverRows) => {
|
|
157
|
+
if (!useLoro || !loroMap) return serverRows;
|
|
158
|
+
const localJson = loroMap.toJSON?.() ?? {};
|
|
159
|
+
const localById = new Map(
|
|
160
|
+
Object.values(localJson).map((r) => [getKey(r), r])
|
|
161
|
+
);
|
|
281
162
|
const out = [];
|
|
282
|
-
for (const
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
);
|
|
290
|
-
if (res) out.push(...res);
|
|
291
|
-
}
|
|
292
|
-
return out;
|
|
293
|
-
};
|
|
294
|
-
const dedupeById = (rows) => {
|
|
295
|
-
const m = /* @__PURE__ */ new Map();
|
|
296
|
-
for (const r of rows) m.set(getKey(r), r);
|
|
297
|
-
return Array.from(m.values());
|
|
298
|
-
};
|
|
299
|
-
let prevById = /* @__PURE__ */ new Map();
|
|
300
|
-
const buildMap = (rows) => new Map(rows.map((r) => [getKey(r), r]));
|
|
301
|
-
const same = (a, b) => {
|
|
302
|
-
if (useLoro) {
|
|
303
|
-
return (a.sync_deleted ?? false) === (b.sync_deleted ?? false) && (a.updated_at?.getTime() ?? 0) === (b.updated_at?.getTime() ?? 0);
|
|
304
|
-
}
|
|
305
|
-
return stableStringify(a) === stableStringify(b);
|
|
306
|
-
};
|
|
307
|
-
const diffAndEmit = (currentRows, write) => {
|
|
308
|
-
const currById = buildMap(currentRows);
|
|
309
|
-
for (const [id2, row] of currById) {
|
|
310
|
-
const prev = prevById.get(id2);
|
|
311
|
-
if (!prev) write({ type: "insert", value: row });
|
|
312
|
-
else if (!same(prev, row)) write({ type: "update", value: row });
|
|
313
|
-
}
|
|
314
|
-
for (const [id2, prev] of prevById) {
|
|
315
|
-
if (!currById.has(id2)) write({ type: "delete", value: prev });
|
|
316
|
-
}
|
|
317
|
-
prevById = currById;
|
|
318
|
-
};
|
|
319
|
-
const reconcileBoot = (serverRows, write) => {
|
|
320
|
-
const localRows = loroToArray();
|
|
321
|
-
const serverById = new Map(serverRows.map((r) => [getKey(r), r]));
|
|
322
|
-
const localById = new Map(localRows.map((r) => [getKey(r), r]));
|
|
323
|
-
const ids = /* @__PURE__ */ new Set([...serverById.keys(), ...localById.keys()]);
|
|
324
|
-
const current = [];
|
|
325
|
-
const toRemove = [];
|
|
326
|
-
const toPut = [];
|
|
327
|
-
const applyLocal = (row) => {
|
|
328
|
-
if (!row) return;
|
|
329
|
-
if (row.sync_deleted) toRemove.push(getKey(row));
|
|
330
|
-
else toPut.push(row);
|
|
331
|
-
};
|
|
332
|
-
for (const id2 of ids) {
|
|
333
|
-
const s = serverById.get(id2);
|
|
334
|
-
const l = localById.get(id2);
|
|
335
|
-
if (s && l) {
|
|
336
|
-
const sDeleted = s.sync_deleted ?? false;
|
|
337
|
-
const lDeleted = l.sync_deleted ?? false;
|
|
338
|
-
const sUpdated = s.updated_at;
|
|
339
|
-
const lUpdated = l.updated_at;
|
|
340
|
-
if (sDeleted && lDeleted) {
|
|
341
|
-
applyLocal(s);
|
|
342
|
-
current.push(s);
|
|
343
|
-
} else if (sDeleted && !lDeleted) {
|
|
344
|
-
applyLocal(s);
|
|
345
|
-
current.push(s);
|
|
346
|
-
} else if (!sDeleted && lDeleted) {
|
|
347
|
-
if (newer(lUpdated, sUpdated)) {
|
|
348
|
-
enqueuePush({
|
|
349
|
-
kind: "delete",
|
|
350
|
-
id: id2,
|
|
351
|
-
updated_at: lUpdated ?? /* @__PURE__ */ new Date()
|
|
352
|
-
});
|
|
353
|
-
applyLocal(l);
|
|
354
|
-
current.push(l);
|
|
355
|
-
} else {
|
|
356
|
-
applyLocal(s);
|
|
357
|
-
current.push(s);
|
|
358
|
-
}
|
|
359
|
-
} else {
|
|
360
|
-
if (newer(lUpdated, sUpdated)) {
|
|
361
|
-
enqueuePush({ kind: "update", row: l });
|
|
362
|
-
applyLocal(l);
|
|
363
|
-
current.push(l);
|
|
364
|
-
} else {
|
|
365
|
-
applyLocal(s);
|
|
366
|
-
current.push(s);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
} else if (s && !l) {
|
|
370
|
-
applyLocal(s);
|
|
371
|
-
current.push(s);
|
|
372
|
-
} else if (!s && l) {
|
|
373
|
-
const lDeleted = l.sync_deleted ?? false;
|
|
374
|
-
const lUpdated = l.updated_at;
|
|
375
|
-
if (lDeleted) {
|
|
376
|
-
enqueuePush({
|
|
377
|
-
kind: "delete",
|
|
378
|
-
id: id2,
|
|
379
|
-
updated_at: lUpdated ?? /* @__PURE__ */ new Date()
|
|
380
|
-
});
|
|
381
|
-
applyLocal(l);
|
|
382
|
-
current.push(l);
|
|
383
|
-
} else {
|
|
384
|
-
enqueuePush({ kind: "create", row: l });
|
|
385
|
-
applyLocal(l);
|
|
386
|
-
current.push(l);
|
|
387
|
-
}
|
|
163
|
+
for (const s of serverRows) {
|
|
164
|
+
const idStr = getKey(s);
|
|
165
|
+
const l = localById.get(idStr);
|
|
166
|
+
if (!l) {
|
|
167
|
+
out.push(s);
|
|
168
|
+
continue;
|
|
388
169
|
}
|
|
170
|
+
const lDeleted = (l.sync_deleted ?? false) === true;
|
|
171
|
+
if (lDeleted) continue;
|
|
172
|
+
out.push(l);
|
|
389
173
|
}
|
|
390
|
-
|
|
391
|
-
loroPutMany(toPut);
|
|
392
|
-
diffAndEmit(current, write);
|
|
174
|
+
return out;
|
|
393
175
|
};
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
markReady
|
|
401
|
-
}) => {
|
|
402
|
-
if (!db.isFeatureSupported(Features2.LiveQueries)) {
|
|
403
|
-
markReady();
|
|
404
|
-
return () => {
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
let offLive = null;
|
|
408
|
-
let work = Promise.resolve();
|
|
409
|
-
const enqueueWork = (fn) => {
|
|
410
|
-
work = work.then(fn).catch((e) => onError?.(e));
|
|
411
|
-
return work;
|
|
412
|
-
};
|
|
413
|
-
const makeTombstone = (id2) => ({
|
|
414
|
-
id: new RecordId(config.table.name, id2).toString(),
|
|
415
|
-
updated_at: now(),
|
|
416
|
-
sync_deleted: true
|
|
417
|
-
});
|
|
418
|
-
const start = async () => {
|
|
176
|
+
const base = queryCollectionOptions({
|
|
177
|
+
getKey: (row) => getKey(row),
|
|
178
|
+
queryKey,
|
|
179
|
+
queryClient,
|
|
180
|
+
syncMode,
|
|
181
|
+
queryFn: async ({ meta }) => {
|
|
419
182
|
try {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
} else if (syncMode === "progressive") {
|
|
424
|
-
const first = await table.loadMore(
|
|
425
|
-
config.table.initialPageSize ?? DEFAULT_INITIAL_PAGE_SIZE
|
|
426
|
-
);
|
|
427
|
-
serverRows = first.rows;
|
|
428
|
-
} else {
|
|
429
|
-
serverRows = await table.listActive();
|
|
430
|
-
}
|
|
431
|
-
await enqueueWork(async () => {
|
|
432
|
-
begin();
|
|
433
|
-
if (useLoro) {
|
|
434
|
-
const localIds = loroToArray().map(getKey);
|
|
435
|
-
const verifiedServerRows = syncMode === "eager" ? serverRows : dedupeById([
|
|
436
|
-
...serverRows,
|
|
437
|
-
...await fetchServerByLocalIds(
|
|
438
|
-
localIds
|
|
439
|
-
)
|
|
440
|
-
]);
|
|
441
|
-
reconcileBoot(verifiedServerRows, write);
|
|
442
|
-
} else {
|
|
443
|
-
diffAndEmit(serverRows, write);
|
|
444
|
-
}
|
|
445
|
-
commit();
|
|
446
|
-
markReady();
|
|
447
|
-
});
|
|
448
|
-
if (syncMode === "progressive") {
|
|
449
|
-
void (async () => {
|
|
450
|
-
while (!table.isFullyLoaded) {
|
|
451
|
-
const { rows } = await table.loadMore();
|
|
452
|
-
if (rows.length === 0) break;
|
|
453
|
-
await enqueueWork(async () => {
|
|
454
|
-
begin();
|
|
455
|
-
try {
|
|
456
|
-
if (useLoro) loroPutMany(rows);
|
|
457
|
-
diffAndEmit(rows, write);
|
|
458
|
-
} finally {
|
|
459
|
-
commit();
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
})().catch((e) => onError?.(e));
|
|
464
|
-
}
|
|
465
|
-
await flushPushQueue();
|
|
466
|
-
offLive = table.subscribe((evt) => {
|
|
467
|
-
void enqueueWork(async () => {
|
|
468
|
-
begin();
|
|
469
|
-
try {
|
|
470
|
-
if (evt.type === "insert" || evt.type === "update") {
|
|
471
|
-
const row = evt.row;
|
|
472
|
-
const deleted = useLoro ? row.sync_deleted ?? false : false;
|
|
473
|
-
if (deleted) {
|
|
474
|
-
if (useLoro) loroRemove(getKey(row));
|
|
475
|
-
const prev = prevById.get(getKey(row)) ?? makeTombstone(getKey(row));
|
|
476
|
-
write({ type: "delete", value: prev });
|
|
477
|
-
prevById.delete(getKey(row));
|
|
478
|
-
} else {
|
|
479
|
-
if (useLoro) loroPutMany([row]);
|
|
480
|
-
const had = prevById.has(getKey(row));
|
|
481
|
-
write({
|
|
482
|
-
type: had ? "update" : "insert",
|
|
483
|
-
value: row
|
|
484
|
-
});
|
|
485
|
-
prevById.set(getKey(row), row);
|
|
486
|
-
}
|
|
487
|
-
} else {
|
|
488
|
-
const rid = getKey(evt.row);
|
|
489
|
-
if (useLoro) loroRemove(rid);
|
|
490
|
-
const prev = prevById.get(rid) ?? makeTombstone(rid);
|
|
491
|
-
write({ type: "delete", value: prev });
|
|
492
|
-
prevById.delete(rid);
|
|
493
|
-
}
|
|
494
|
-
} finally {
|
|
495
|
-
commit();
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
});
|
|
183
|
+
const subset = syncMode === "on-demand" ? meta["surrealSubset"] : void 0;
|
|
184
|
+
const rows = syncMode === "eager" ? await table.listAll() : await table.loadSubset(subset);
|
|
185
|
+
return mergeLocalOverServer(rows);
|
|
499
186
|
} catch (e) {
|
|
500
187
|
onError?.(e);
|
|
501
|
-
|
|
188
|
+
return [];
|
|
502
189
|
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
190
|
+
},
|
|
191
|
+
onInsert: (async (p) => {
|
|
192
|
+
const now = () => /* @__PURE__ */ new Date();
|
|
193
|
+
const resultRows = [];
|
|
194
|
+
for (const m of p.transaction.mutations) {
|
|
195
|
+
if (m.type !== "insert") continue;
|
|
196
|
+
const baseRow = { ...m.modified };
|
|
197
|
+
const row = useLoro ? {
|
|
198
|
+
...baseRow,
|
|
199
|
+
updated_at: now(),
|
|
200
|
+
sync_deleted: false
|
|
201
|
+
} : baseRow;
|
|
202
|
+
if (useLoro) loroPut(row);
|
|
203
|
+
await table.create(row);
|
|
204
|
+
resultRows.push(row);
|
|
205
|
+
}
|
|
206
|
+
return resultRows;
|
|
207
|
+
}),
|
|
208
|
+
onUpdate: (async (p) => {
|
|
209
|
+
const now = () => /* @__PURE__ */ new Date();
|
|
210
|
+
const resultRows = [];
|
|
211
|
+
for (const m of p.transaction.mutations) {
|
|
212
|
+
if (m.type !== "update") continue;
|
|
213
|
+
const idKey = m.key;
|
|
214
|
+
const baseRow = { ...m.modified, id: idKey };
|
|
215
|
+
const row = useLoro ? { ...baseRow, updated_at: now() } : baseRow;
|
|
216
|
+
if (useLoro) loroPut(row);
|
|
217
|
+
await table.update(
|
|
218
|
+
new RecordId(config.table.name, keyOf(idKey)),
|
|
219
|
+
row
|
|
220
|
+
);
|
|
221
|
+
resultRows.push(row);
|
|
222
|
+
}
|
|
223
|
+
return resultRows;
|
|
224
|
+
}),
|
|
225
|
+
onDelete: (async (p) => {
|
|
226
|
+
for (const m of p.transaction.mutations) {
|
|
227
|
+
if (m.type !== "delete") continue;
|
|
228
|
+
const idKey = m.key;
|
|
229
|
+
if (useLoro) loroRemove(keyOf(idKey));
|
|
230
|
+
await table.softDelete(
|
|
231
|
+
new RecordId(config.table.name, keyOf(idKey))
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return [];
|
|
235
|
+
})
|
|
236
|
+
});
|
|
237
|
+
const baseSync = base.sync?.sync;
|
|
238
|
+
const sync = baseSync ? {
|
|
239
|
+
sync: (ctx) => {
|
|
240
|
+
const offBase = baseSync(ctx);
|
|
241
|
+
if (!db.isFeatureSupported(Features.LiveQueries))
|
|
242
|
+
return offBase;
|
|
243
|
+
const offLive = table.subscribe((evt) => {
|
|
244
|
+
if (useLoro) {
|
|
245
|
+
if (evt.type === "delete")
|
|
246
|
+
loroRemove(getKey(evt.row));
|
|
247
|
+
else loroPut(evt.row);
|
|
248
|
+
}
|
|
249
|
+
void queryClient.invalidateQueries({ queryKey, exact: false }).catch((e) => onError?.(e));
|
|
250
|
+
});
|
|
251
|
+
const baseCleanup = toCleanup(baseSync(ctx));
|
|
252
|
+
return () => {
|
|
253
|
+
offLive();
|
|
254
|
+
baseCleanup();
|
|
255
|
+
};
|
|
542
256
|
}
|
|
543
|
-
|
|
544
|
-
};
|
|
257
|
+
} : void 0;
|
|
545
258
|
return {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
sync: { sync },
|
|
549
|
-
onInsert,
|
|
550
|
-
onDelete,
|
|
551
|
-
onUpdate
|
|
259
|
+
...base,
|
|
260
|
+
sync: sync ?? base.sync
|
|
552
261
|
};
|
|
553
262
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
263
|
+
|
|
264
|
+
export { surrealCollectionOptions };
|
|
265
|
+
//# sourceMappingURL=index.mjs.map
|
|
266
|
+
//# sourceMappingURL=index.mjs.map
|