@dxos/index-core 0.8.4-main.c85a9c8dae → 0.8.4-main.cb12b3f963
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/lib/neutral/index.mjs +126 -35
- package/dist/lib/neutral/index.mjs.map +3 -3
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/types/src/index-engine.d.ts +27 -7
- package/dist/types/src/index-engine.d.ts.map +1 -1
- package/dist/types/src/index-tracker.d.ts +3 -3
- package/dist/types/src/index-tracker.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/indexes/fts-index.d.ts +2 -1
- package/dist/types/src/indexes/fts-index.d.ts.map +1 -1
- package/dist/types/src/indexes/interface.d.ts +4 -0
- package/dist/types/src/indexes/interface.d.ts.map +1 -1
- package/dist/types/src/indexes/object-meta-index.d.ts +24 -4
- package/dist/types/src/indexes/object-meta-index.d.ts.map +1 -1
- package/dist/types/src/indexes/reverse-ref-index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -12
- package/src/index-engine.test.ts +155 -4
- package/src/index-engine.ts +102 -26
- package/src/index-tracker.ts +9 -0
- package/src/index.ts +7 -1
- package/src/indexes/fts-index.test.ts +131 -3
- package/src/indexes/fts-index.ts +25 -8
- package/src/indexes/interface.ts +5 -0
- package/src/indexes/object-meta-index.test.ts +114 -8
- package/src/indexes/object-meta-index.ts +78 -5
- package/src/indexes/reverse-ref-index.test.ts +9 -2
- package/src/indexes/reverse-ref-index.ts +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/index-engine.ts
|
|
2
2
|
import * as Effect5 from "effect/Effect";
|
|
3
|
+
import { ATTR_TYPE as ATTR_TYPE2 } from "@dxos/echo/internal";
|
|
3
4
|
import * as SqlTransaction from "@dxos/sql-sqlite/SqlTransaction";
|
|
4
5
|
|
|
5
6
|
// src/index-tracker.ts
|
|
@@ -31,6 +32,9 @@ var IndexCursor = Schema.Struct({
|
|
|
31
32
|
*/
|
|
32
33
|
cursor: Schema.Union(Schema.Number, Schema.String)
|
|
33
34
|
});
|
|
35
|
+
var DEPRECATED_INDEX_NAMES = [
|
|
36
|
+
"fts"
|
|
37
|
+
];
|
|
34
38
|
var IndexTracker = class {
|
|
35
39
|
migrate = Effect.fn("IndexTracker.migrate")(function* () {
|
|
36
40
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -42,6 +46,9 @@ var IndexTracker = class {
|
|
|
42
46
|
cursor,
|
|
43
47
|
PRIMARY KEY (indexName, spaceId, sourceName, resourceId)
|
|
44
48
|
)`;
|
|
49
|
+
yield* Effect.forEach(DEPRECATED_INDEX_NAMES, (indexName) => {
|
|
50
|
+
return sql`DELETE FROM indexCursor WHERE indexName = ${indexName}`;
|
|
51
|
+
});
|
|
45
52
|
});
|
|
46
53
|
queryCursors = Effect.fn("IndexTracker.queryCursors")((query) => Effect.gen(function* () {
|
|
47
54
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -82,6 +89,7 @@ var IndexTracker = class {
|
|
|
82
89
|
// src/indexes/fts-index.ts
|
|
83
90
|
import * as SqlClient3 from "@effect/sql/SqlClient";
|
|
84
91
|
import * as Effect2 from "effect/Effect";
|
|
92
|
+
var SQL_CHUNK_SIZE = 500;
|
|
85
93
|
var escapeFts5Query = (text) => {
|
|
86
94
|
return text.split(/\s+/).filter(Boolean).map((term) => `"${term.replace(/"/g, '""')}"`).join(" ");
|
|
87
95
|
};
|
|
@@ -143,6 +151,7 @@ var FtsIndex = class {
|
|
|
143
151
|
/**
|
|
144
152
|
* Query snapshots by recordIds.
|
|
145
153
|
* Returns the parsed JSON snapshots for queue objects.
|
|
154
|
+
* RecordIds not present in the FTS index are silently omitted from the result.
|
|
146
155
|
*/
|
|
147
156
|
querySnapshotsJSON(recordIds) {
|
|
148
157
|
return Effect2.gen(function* () {
|
|
@@ -150,11 +159,21 @@ var FtsIndex = class {
|
|
|
150
159
|
return [];
|
|
151
160
|
}
|
|
152
161
|
const sql = yield* SqlClient3.SqlClient;
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
const chunks = [];
|
|
163
|
+
for (let i = 0; i < recordIds.length; i += SQL_CHUNK_SIZE) {
|
|
164
|
+
chunks.push(recordIds.slice(i, i + SQL_CHUNK_SIZE));
|
|
165
|
+
}
|
|
166
|
+
const allResults = [];
|
|
167
|
+
for (const chunk of chunks) {
|
|
168
|
+
const rows = yield* sql`SELECT rowid, snapshot FROM ftsIndex WHERE rowid IN ${sql.in(chunk)}`;
|
|
169
|
+
for (const r of rows) {
|
|
170
|
+
allResults.push({
|
|
171
|
+
recordId: r.rowid,
|
|
172
|
+
snapshot: JSON.parse(r.snapshot)
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return allResults;
|
|
158
177
|
});
|
|
159
178
|
}
|
|
160
179
|
update = Effect2.fn("FtsIndex.update")((objects) => Effect2.gen(function* () {
|
|
@@ -201,7 +220,11 @@ var ObjectMeta = Schema2.Struct({
|
|
|
201
220
|
/** Parent object id (nullable). */
|
|
202
221
|
parent: Schema2.NullOr(Schema2.String),
|
|
203
222
|
/** Monotonically increasing sequence number assigned on insert/update for tracking indexing order. */
|
|
204
|
-
version: Schema2.Number
|
|
223
|
+
version: Schema2.Number,
|
|
224
|
+
/** Unix ms timestamp when the object was first indexed. */
|
|
225
|
+
createdAt: Schema2.NullOr(Schema2.Number),
|
|
226
|
+
/** Unix ms timestamp when the object was last re-indexed. */
|
|
227
|
+
updatedAt: Schema2.NullOr(Schema2.Number)
|
|
205
228
|
});
|
|
206
229
|
var buildSourceCondition = (sql, spaceIds, includeAllQueues, queueIds) => {
|
|
207
230
|
const conditions = [];
|
|
@@ -235,13 +258,19 @@ var ObjectMetaIndex = class {
|
|
|
235
258
|
source TEXT,
|
|
236
259
|
target TEXT,
|
|
237
260
|
parent TEXT,
|
|
238
|
-
version INTEGER NOT NULL
|
|
261
|
+
version INTEGER NOT NULL,
|
|
262
|
+
createdAt INTEGER,
|
|
263
|
+
updatedAt INTEGER
|
|
239
264
|
)`;
|
|
240
265
|
yield* Effect3.catchAll(sql`ALTER TABLE objectMeta ADD COLUMN parent TEXT`, () => Effect3.void);
|
|
266
|
+
yield* Effect3.catchAll(sql`ALTER TABLE objectMeta ADD COLUMN createdAt INTEGER`, () => Effect3.void);
|
|
267
|
+
yield* Effect3.catchAll(sql`ALTER TABLE objectMeta ADD COLUMN updatedAt INTEGER`, () => Effect3.void);
|
|
241
268
|
yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_objectId ON objectMeta(spaceId, objectId)`;
|
|
242
269
|
yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_typeDxn ON objectMeta(spaceId, typeDxn)`;
|
|
243
270
|
yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_version ON objectMeta(version)`;
|
|
244
271
|
yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_parent ON objectMeta(spaceId, parent)`;
|
|
272
|
+
yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_updatedAt ON objectMeta(updatedAt)`;
|
|
273
|
+
yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_createdAt ON objectMeta(createdAt)`;
|
|
245
274
|
});
|
|
246
275
|
query = Effect3.fn("ObjectMetaIndex.query")((query) => Effect3.gen(function* () {
|
|
247
276
|
const sql = yield* SqlClient5.SqlClient;
|
|
@@ -331,6 +360,7 @@ var ObjectMetaIndex = class {
|
|
|
331
360
|
const source = entityKind === "relation" ? castData[ATTR_RELATION_SOURCE] ?? null : null;
|
|
332
361
|
const target = entityKind === "relation" ? castData[ATTR_RELATION_TARGET] ?? null : null;
|
|
333
362
|
const parent = castData[ATTR_PARENT] ?? null;
|
|
363
|
+
const sourceTimestamp = object.updatedAt;
|
|
334
364
|
if (existing.length > 0) {
|
|
335
365
|
yield* sql`
|
|
336
366
|
UPDATE objectMeta SET
|
|
@@ -340,18 +370,21 @@ var ObjectMetaIndex = class {
|
|
|
340
370
|
deleted = ${deleted},
|
|
341
371
|
source = ${source},
|
|
342
372
|
target = ${target},
|
|
343
|
-
parent = ${parent}
|
|
373
|
+
parent = ${parent},
|
|
374
|
+
updatedAt = ${sourceTimestamp}
|
|
344
375
|
WHERE recordId = ${existing[0].recordId}
|
|
345
376
|
`;
|
|
346
377
|
} else {
|
|
347
378
|
yield* sql`
|
|
348
379
|
INSERT INTO objectMeta (
|
|
349
380
|
objectId, queueId, spaceId, documentId,
|
|
350
|
-
entityKind, typeDxn, deleted, source, target, parent, version
|
|
381
|
+
entityKind, typeDxn, deleted, source, target, parent, version,
|
|
382
|
+
createdAt, updatedAt
|
|
351
383
|
) VALUES (
|
|
352
384
|
${objectId}, ${queueId ?? ""}, ${spaceId}, ${documentId ?? ""},
|
|
353
385
|
${entityKind}, ${typeDxn}, ${deleted},
|
|
354
|
-
${source}, ${target}, ${parent}, ${version}
|
|
386
|
+
${source}, ${target}, ${parent}, ${version},
|
|
387
|
+
${sourceTimestamp}, ${sourceTimestamp}
|
|
355
388
|
)
|
|
356
389
|
`;
|
|
357
390
|
}
|
|
@@ -411,14 +444,47 @@ var ObjectMetaIndex = class {
|
|
|
411
444
|
};
|
|
412
445
|
}));
|
|
413
446
|
/**
|
|
447
|
+
* Query objects by timestamp range.
|
|
448
|
+
*/
|
|
449
|
+
queryByTimeRange = Effect3.fn("ObjectMetaIndex.queryByTimeRange")((query) => Effect3.gen(function* () {
|
|
450
|
+
if (query.spaceIds.length === 0 && (!query.queueIds || query.queueIds.length === 0)) {
|
|
451
|
+
return [];
|
|
452
|
+
}
|
|
453
|
+
const sql = yield* SqlClient5.SqlClient;
|
|
454
|
+
const sourceCondition = buildSourceCondition(sql, query.spaceIds, query.includeAllQueues ?? false, query.queueIds ?? null);
|
|
455
|
+
const timeConditions = [];
|
|
456
|
+
if (query.updatedAfter != null) {
|
|
457
|
+
timeConditions.push(sql`updatedAt >= ${query.updatedAfter}`);
|
|
458
|
+
}
|
|
459
|
+
if (query.updatedBefore != null) {
|
|
460
|
+
timeConditions.push(sql`updatedAt <= ${query.updatedBefore}`);
|
|
461
|
+
}
|
|
462
|
+
if (query.createdAfter != null) {
|
|
463
|
+
timeConditions.push(sql`createdAt >= ${query.createdAfter}`);
|
|
464
|
+
}
|
|
465
|
+
if (query.createdBefore != null) {
|
|
466
|
+
timeConditions.push(sql`createdAt <= ${query.createdBefore}`);
|
|
467
|
+
}
|
|
468
|
+
const rows = timeConditions.length > 0 ? yield* sql`SELECT * FROM objectMeta WHERE ${sourceCondition} AND ${sql.and(timeConditions)}` : yield* sql`SELECT * FROM objectMeta WHERE ${sourceCondition}`;
|
|
469
|
+
return rows.map((row) => ({
|
|
470
|
+
...row,
|
|
471
|
+
deleted: !!row.deleted
|
|
472
|
+
}));
|
|
473
|
+
}));
|
|
474
|
+
/**
|
|
414
475
|
* Query children by parent object ids.
|
|
476
|
+
* Matches both:
|
|
477
|
+
* - Objects whose `parent` field references one of the given parent ids (standard parent/child hierarchy).
|
|
478
|
+
* - Queue items whose `queueId` equals one of the parent ids (e.g. items inside a Feed, since a feed's queue
|
|
479
|
+
* DXN uses the feed's object id as its queue id — see `Feed.getQueueDxn`).
|
|
415
480
|
*/
|
|
416
481
|
queryChildren = Effect3.fn("ObjectMetaIndex.queryChildren")((query) => Effect3.gen(function* () {
|
|
417
482
|
if (query.parentIds.length === 0) {
|
|
418
483
|
return [];
|
|
419
484
|
}
|
|
420
485
|
const sql = yield* SqlClient5.SqlClient;
|
|
421
|
-
const
|
|
486
|
+
const parentDxns = query.parentIds.map((id) => DXN.fromLocalObjectId(id).toString());
|
|
487
|
+
const rows = yield* sql`SELECT * FROM objectMeta WHERE ${sql.in("spaceId", query.spaceId)} AND (${sql.in("parent", parentDxns)} OR ${sql.in("queueId", query.parentIds)})`;
|
|
422
488
|
return rows.map((row) => ({
|
|
423
489
|
...row,
|
|
424
490
|
deleted: !!row.deleted
|
|
@@ -447,15 +513,7 @@ var EscapedPropPath = class extends Schema3.String.annotations({
|
|
|
447
513
|
let current = "";
|
|
448
514
|
for (let i = 0; i < path.length; i++) {
|
|
449
515
|
if (path[i] === "\\") {
|
|
450
|
-
invariant(i + 1 < path.length && (path[i + 1] === "." || path[i + 1] === "\\"), "Malformed escaping.", {
|
|
451
|
-
F: __dxlog_file,
|
|
452
|
-
L: 34,
|
|
453
|
-
S: this,
|
|
454
|
-
A: [
|
|
455
|
-
"i + 1 < path.length && (path[i + 1] === '.' || path[i + 1] === '\\\\')",
|
|
456
|
-
"'Malformed escaping.'"
|
|
457
|
-
]
|
|
458
|
-
});
|
|
516
|
+
invariant(i + 1 < path.length && (path[i + 1] === "." || path[i + 1] === "\\"), "Malformed escaping.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 25, S: this, A: ["i + 1 < path.length && (path[i + 1] === '.' || path[i + 1] === '\\\\')", "'Malformed escaping.'"] });
|
|
459
517
|
current = current + path[i + 1];
|
|
460
518
|
i++;
|
|
461
519
|
} else if (path[i] === ".") {
|
|
@@ -555,6 +613,33 @@ var ReverseRefIndex = class {
|
|
|
555
613
|
};
|
|
556
614
|
|
|
557
615
|
// src/index-engine.ts
|
|
616
|
+
var makeEmptyIndexingResult = () => ({
|
|
617
|
+
updated: 0,
|
|
618
|
+
done: true,
|
|
619
|
+
spaces: /* @__PURE__ */ new Set(),
|
|
620
|
+
queues: /* @__PURE__ */ new Set(),
|
|
621
|
+
documents: /* @__PURE__ */ new Set(),
|
|
622
|
+
types: /* @__PURE__ */ new Set(),
|
|
623
|
+
objects: /* @__PURE__ */ new Set()
|
|
624
|
+
});
|
|
625
|
+
var accumulateIndexingResult = (acc, objects) => {
|
|
626
|
+
for (const obj of objects) {
|
|
627
|
+
acc.spaces.add(obj.spaceId);
|
|
628
|
+
if (obj.queueId) {
|
|
629
|
+
acc.queues.add(obj.queueId);
|
|
630
|
+
}
|
|
631
|
+
if (obj.documentId) {
|
|
632
|
+
acc.documents.add(obj.documentId);
|
|
633
|
+
}
|
|
634
|
+
const t = obj.data[ATTR_TYPE2];
|
|
635
|
+
if (t) {
|
|
636
|
+
acc.types.add(String(t));
|
|
637
|
+
}
|
|
638
|
+
if (obj.data.id) {
|
|
639
|
+
acc.objects.add(obj.data.id);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
};
|
|
558
643
|
var IndexEngine = class {
|
|
559
644
|
#tracker;
|
|
560
645
|
#objectMetaIndex;
|
|
@@ -607,6 +692,9 @@ var IndexEngine = class {
|
|
|
607
692
|
queryTypes(query) {
|
|
608
693
|
return this.#objectMetaIndex.queryTypes(query);
|
|
609
694
|
}
|
|
695
|
+
queryByTimeRange(query) {
|
|
696
|
+
return this.#objectMetaIndex.queryByTimeRange(query);
|
|
697
|
+
}
|
|
610
698
|
queryRelations(query) {
|
|
611
699
|
return this.#objectMetaIndex.queryRelations(query);
|
|
612
700
|
}
|
|
@@ -616,25 +704,26 @@ var IndexEngine = class {
|
|
|
616
704
|
lookupByObjectId(query) {
|
|
617
705
|
return this.#objectMetaIndex.lookupByObjectId(query);
|
|
618
706
|
}
|
|
619
|
-
update(dataSource, opts) {
|
|
707
|
+
update(ctx, dataSource, opts) {
|
|
620
708
|
return Effect5.gen(this, function* () {
|
|
621
|
-
|
|
622
|
-
const { updated: updatedFtsIndex, done: doneFtsIndex } = yield* this.#update(this.#ftsIndex, dataSource, {
|
|
623
|
-
indexName: "
|
|
709
|
+
const result = makeEmptyIndexingResult();
|
|
710
|
+
const { updated: updatedFtsIndex, done: doneFtsIndex, objects: ftsObjects } = yield* this.#update(ctx, this.#ftsIndex, dataSource, {
|
|
711
|
+
indexName: "fts5",
|
|
624
712
|
spaceId: opts.spaceId,
|
|
625
713
|
limit: opts.limit
|
|
626
714
|
});
|
|
627
|
-
updated += updatedFtsIndex;
|
|
628
|
-
|
|
715
|
+
result.updated += updatedFtsIndex;
|
|
716
|
+
result.done = result.done && doneFtsIndex;
|
|
717
|
+
accumulateIndexingResult(result, ftsObjects);
|
|
718
|
+
const { updated: updatedReverseRefIndex, done: doneReverseRefIndex, objects: reverseRefObjects } = yield* this.#update(ctx, this.#reverseRefIndex, dataSource, {
|
|
629
719
|
indexName: "reverseRef",
|
|
630
720
|
spaceId: opts.spaceId,
|
|
631
721
|
limit: opts.limit
|
|
632
722
|
});
|
|
633
|
-
updated += updatedReverseRefIndex;
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
};
|
|
723
|
+
result.updated += updatedReverseRefIndex;
|
|
724
|
+
result.done = result.done && doneReverseRefIndex;
|
|
725
|
+
accumulateIndexingResult(result, reverseRefObjects);
|
|
726
|
+
return result;
|
|
638
727
|
}).pipe(Effect5.withSpan("IndexEngine.update"));
|
|
639
728
|
}
|
|
640
729
|
/**
|
|
@@ -646,7 +735,7 @@ var IndexEngine = class {
|
|
|
646
735
|
* 4. Enriches objects with recordIds.
|
|
647
736
|
* 5. Updates the dependent index.
|
|
648
737
|
*/
|
|
649
|
-
#update(index, source, opts) {
|
|
738
|
+
#update(ctx, index, source, opts) {
|
|
650
739
|
return Effect5.gen(this, function* () {
|
|
651
740
|
const sqlTransaction = yield* SqlTransaction.SqlTransaction;
|
|
652
741
|
return yield* sqlTransaction.withTransaction(Effect5.gen(this, function* () {
|
|
@@ -656,13 +745,14 @@ var IndexEngine = class {
|
|
|
656
745
|
// Pass undefined to get all cursors when spaceId is null.
|
|
657
746
|
spaceId: opts.spaceId ?? void 0
|
|
658
747
|
});
|
|
659
|
-
const { objects, cursors: updatedCursors } = yield* source.getChangedObjects(cursors, {
|
|
748
|
+
const { objects, cursors: updatedCursors } = yield* source.getChangedObjects(ctx, cursors, {
|
|
660
749
|
limit: opts.limit
|
|
661
750
|
});
|
|
662
751
|
if (objects.length === 0) {
|
|
663
752
|
return {
|
|
664
753
|
updated: 0,
|
|
665
|
-
done: true
|
|
754
|
+
done: true,
|
|
755
|
+
objects: []
|
|
666
756
|
};
|
|
667
757
|
}
|
|
668
758
|
yield* this.#objectMetaIndex.update(objects);
|
|
@@ -677,7 +767,8 @@ var IndexEngine = class {
|
|
|
677
767
|
})));
|
|
678
768
|
return {
|
|
679
769
|
updated: objects.length,
|
|
680
|
-
done: false
|
|
770
|
+
done: false,
|
|
771
|
+
objects
|
|
681
772
|
};
|
|
682
773
|
}));
|
|
683
774
|
}).pipe(Effect5.withSpan("IndexEngine.#update"));
|