@dxos/index-core 0.0.0 → 0.8.4-main.03d5cd7b56

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.
Files changed (47) hide show
  1. package/dist/lib/neutral/index.mjs +790 -0
  2. package/dist/lib/neutral/index.mjs.map +7 -0
  3. package/dist/lib/neutral/meta.json +1 -0
  4. package/dist/types/src/index-engine.d.ts +112 -0
  5. package/dist/types/src/index-engine.d.ts.map +1 -0
  6. package/dist/types/src/index-engine.test.d.ts +2 -0
  7. package/dist/types/src/index-engine.test.d.ts.map +1 -0
  8. package/dist/types/src/index-tracker.d.ts +44 -0
  9. package/dist/types/src/index-tracker.d.ts.map +1 -0
  10. package/dist/types/src/index-tracker.test.d.ts +2 -0
  11. package/dist/types/src/index-tracker.test.d.ts.map +1 -0
  12. package/dist/types/src/index.d.ts +8 -0
  13. package/dist/types/src/index.d.ts.map +1 -0
  14. package/dist/types/src/indexes/fts-index.d.ts +64 -0
  15. package/dist/types/src/indexes/fts-index.d.ts.map +1 -0
  16. package/dist/types/src/indexes/fts-index.test.d.ts +2 -0
  17. package/dist/types/src/indexes/fts-index.test.d.ts.map +1 -0
  18. package/dist/types/src/indexes/fts5.test.d.ts +2 -0
  19. package/dist/types/src/indexes/fts5.test.d.ts.map +1 -0
  20. package/dist/types/src/indexes/index.d.ts +5 -0
  21. package/dist/types/src/indexes/index.d.ts.map +1 -0
  22. package/dist/types/src/indexes/interface.d.ts +56 -0
  23. package/dist/types/src/indexes/interface.d.ts.map +1 -0
  24. package/dist/types/src/indexes/object-meta-index.d.ts +94 -0
  25. package/dist/types/src/indexes/object-meta-index.d.ts.map +1 -0
  26. package/dist/types/src/indexes/object-meta-index.test.d.ts +2 -0
  27. package/dist/types/src/indexes/object-meta-index.test.d.ts.map +1 -0
  28. package/dist/types/src/indexes/reverse-ref-index.d.ts +37 -0
  29. package/dist/types/src/indexes/reverse-ref-index.d.ts.map +1 -0
  30. package/dist/types/src/indexes/reverse-ref-index.test.d.ts +2 -0
  31. package/dist/types/src/indexes/reverse-ref-index.test.d.ts.map +1 -0
  32. package/dist/types/src/utils.d.ts +17 -0
  33. package/dist/types/src/utils.d.ts.map +1 -0
  34. package/dist/types/tsconfig.tsbuildinfo +1 -0
  35. package/package.json +22 -18
  36. package/src/index-engine.test.ts +172 -9
  37. package/src/index-engine.ts +161 -29
  38. package/src/index-tracker.ts +9 -0
  39. package/src/index.ts +10 -3
  40. package/src/indexes/fts-index.test.ts +153 -3
  41. package/src/indexes/fts-index.ts +66 -10
  42. package/src/indexes/interface.ts +10 -0
  43. package/src/indexes/object-meta-index.test.ts +361 -3
  44. package/src/indexes/object-meta-index.ts +304 -17
  45. package/src/indexes/reverse-ref-index.test.ts +16 -2
  46. package/src/indexes/reverse-ref-index.ts +0 -1
  47. package/src/utils.ts +1 -1
@@ -4,30 +4,80 @@
4
4
 
5
5
  import * as SqlClient from '@effect/sql/SqlClient';
6
6
  import type * as SqlError from '@effect/sql/SqlError';
7
+ import type * as Statement from '@effect/sql/Statement';
7
8
  import * as Effect from 'effect/Effect';
8
9
  import * as Schema from 'effect/Schema';
9
10
 
10
- import { ATTR_DELETED, ATTR_RELATION_SOURCE, ATTR_RELATION_TARGET, ATTR_TYPE } from '@dxos/echo/internal';
11
+ import { ATTR_DELETED, ATTR_PARENT, ATTR_RELATION_SOURCE, ATTR_RELATION_TARGET, ATTR_TYPE } from '@dxos/echo/internal';
12
+ import { DXN, type ObjectId, type SpaceId } from '@dxos/keys';
11
13
 
12
14
  import type { IndexerObject } from './interface';
13
15
  import type { Index } from './interface';
14
16
 
17
+ const _escapeLikePrefix = (prefix: string) => {
18
+ // Escape LIKE metacharacters in the *literal* prefix (we still append a wildcard for the version suffix).
19
+ // Backslash is used as the ESCAPE character.
20
+ // See: https://www.sqlite.org/lang_expr.html#like
21
+ const escaped = prefix.replaceAll('\\', '\\\\').replaceAll('%', '\\%').replaceAll('_', '\\_');
22
+ return `${escaped}:%`;
23
+ };
24
+
15
25
  export const ObjectMeta = Schema.Struct({
16
26
  recordId: Schema.Number,
17
27
  objectId: Schema.String,
18
28
  queueId: Schema.String,
29
+ /** Queue subspace namespace (e.g. 'data', 'trace'). Empty string for non-queue objects. */
30
+ queueNamespace: Schema.String,
19
31
  spaceId: Schema.String,
20
32
  documentId: Schema.String,
21
33
  entityKind: Schema.String,
34
+ /** The versioned DXN of the type of the object. */
22
35
  typeDxn: Schema.String,
23
36
  deleted: Schema.Boolean,
24
37
  source: Schema.NullOr(Schema.String),
25
38
  target: Schema.NullOr(Schema.String),
39
+ /** Parent object id (nullable). */
40
+ parent: Schema.NullOr(Schema.String),
26
41
  /** Monotonically increasing sequence number assigned on insert/update for tracking indexing order. */
27
42
  version: Schema.Number,
43
+ /** Unix ms timestamp when the object was first indexed. */
44
+ createdAt: Schema.NullOr(Schema.Number),
45
+ /** Unix ms timestamp when the object was last re-indexed. */
46
+ updatedAt: Schema.NullOr(Schema.Number),
28
47
  });
29
48
  export interface ObjectMeta extends Schema.Schema.Type<typeof ObjectMeta> {}
30
49
 
50
+ /**
51
+ * Builds a SQL condition for filtering by space and queue source.
52
+ * When `includeAllQueues` is false and no `queueIds`, only non-queue objects are returned.
53
+ */
54
+ const buildSourceCondition = (
55
+ sql: SqlClient.SqlClient,
56
+ spaceIds: readonly string[],
57
+ includeAllQueues: boolean,
58
+ queueIds: readonly string[] | null,
59
+ ): Statement.Fragment => {
60
+ const conditions: Statement.Fragment[] = [];
61
+
62
+ if (spaceIds.length > 0) {
63
+ if (includeAllQueues) {
64
+ conditions.push(sql`${sql.in('spaceId', spaceIds)}`);
65
+ } else {
66
+ conditions.push(sql`(${sql.in('spaceId', spaceIds)} AND queueId = '')`);
67
+ }
68
+ }
69
+
70
+ if (queueIds && queueIds.length > 0) {
71
+ conditions.push(sql`${sql.in('queueId', queueIds)}`);
72
+ }
73
+
74
+ if (conditions.length === 0) {
75
+ return sql`1 = 0`;
76
+ }
77
+
78
+ return sql.or(conditions);
79
+ };
80
+
31
81
  export class ObjectMetaIndex implements Index {
32
82
  migrate = Effect.fn('ObjectMetaIndex.runMigrations')(function* () {
33
83
  const sql = yield* SqlClient.SqlClient;
@@ -36,6 +86,7 @@ export class ObjectMetaIndex implements Index {
36
86
  recordId INTEGER PRIMARY KEY AUTOINCREMENT,
37
87
  objectId TEXT NOT NULL,
38
88
  queueId TEXT NOT NULL DEFAULT '',
89
+ queueNamespace TEXT NOT NULL DEFAULT '',
39
90
  spaceId TEXT NOT NULL,
40
91
  documentId TEXT NOT NULL DEFAULT '',
41
92
  entityKind TEXT NOT NULL,
@@ -43,23 +94,149 @@ export class ObjectMetaIndex implements Index {
43
94
  deleted INTEGER NOT NULL,
44
95
  source TEXT,
45
96
  target TEXT,
46
- version INTEGER NOT NULL
97
+ parent TEXT,
98
+ version INTEGER NOT NULL,
99
+ createdAt INTEGER,
100
+ updatedAt INTEGER
47
101
  )`;
48
102
 
103
+ // Add `parent` column for tables created before it was introduced.
104
+ yield* Effect.catchAll(sql`ALTER TABLE objectMeta ADD COLUMN parent TEXT`, () => Effect.void);
105
+ // Add timestamp columns for tables created before they were introduced.
106
+ yield* Effect.catchAll(sql`ALTER TABLE objectMeta ADD COLUMN createdAt INTEGER`, () => Effect.void);
107
+ yield* Effect.catchAll(sql`ALTER TABLE objectMeta ADD COLUMN updatedAt INTEGER`, () => Effect.void);
108
+ // Add queueNamespace column for tables created before it was introduced.
109
+ yield* Effect.catchAll(
110
+ sql`ALTER TABLE objectMeta ADD COLUMN queueNamespace TEXT NOT NULL DEFAULT ''`,
111
+ () => Effect.void,
112
+ );
113
+
49
114
  yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_objectId ON objectMeta(spaceId, objectId)`;
50
115
  yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_typeDxn ON objectMeta(spaceId, typeDxn)`;
51
116
  yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_version ON objectMeta(version)`;
117
+ yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_parent ON objectMeta(spaceId, parent)`;
118
+ yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_updatedAt ON objectMeta(updatedAt)`;
119
+ yield* sql`CREATE INDEX IF NOT EXISTS idx_object_index_createdAt ON objectMeta(createdAt)`;
52
120
  });
53
121
 
54
- query = Effect.fn('ObjectMetaIndex.queryType')(
122
+ query = Effect.fn('ObjectMetaIndex.query')(
55
123
  (
56
124
  query: Pick<ObjectMeta, 'spaceId' | 'typeDxn'>,
57
125
  ): Effect.Effect<readonly ObjectMeta[], SqlError.SqlError, SqlClient.SqlClient> =>
58
126
  Effect.gen(function* () {
59
127
  const sql = yield* SqlClient.SqlClient;
128
+ const parsedType = DXN.tryParse(query.typeDxn)?.asTypeDXN();
129
+
60
130
  // SQLite stores booleans as integers, so we need to specify the raw row type.
61
131
  const rows =
62
- yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE spaceId = ${query.spaceId} AND typeDxn = ${query.typeDxn}`;
132
+ parsedType && parsedType.version === undefined
133
+ ? yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE spaceId = ${query.spaceId} AND (typeDxn = ${
134
+ query.typeDxn
135
+ } OR typeDxn LIKE ${_escapeLikePrefix(query.typeDxn)} ESCAPE '\\')`
136
+ : yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE spaceId = ${query.spaceId} AND typeDxn = ${query.typeDxn}`;
137
+ return rows.map((row) => ({
138
+ ...row,
139
+ deleted: !!row.deleted,
140
+ }));
141
+ }),
142
+ );
143
+
144
+ queryAll = Effect.fn('ObjectMetaIndex.queryAll')(
145
+ (query: {
146
+ spaceIds: readonly ObjectMeta['spaceId'][];
147
+ includeAllQueues?: boolean;
148
+ queueIds?: readonly string[] | null;
149
+ }): Effect.Effect<readonly ObjectMeta[], SqlError.SqlError, SqlClient.SqlClient> =>
150
+ Effect.gen(function* () {
151
+ if (query.spaceIds.length === 0 && (!query.queueIds || query.queueIds.length === 0)) {
152
+ return [];
153
+ }
154
+
155
+ const sql = yield* SqlClient.SqlClient;
156
+ const sourceCondition = buildSourceCondition(
157
+ sql,
158
+ query.spaceIds,
159
+ query.includeAllQueues ?? false,
160
+ query.queueIds ?? null,
161
+ );
162
+ const rows = yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sourceCondition}`;
163
+ return rows.map((row) => ({
164
+ ...row,
165
+ deleted: !!row.deleted,
166
+ }));
167
+ }),
168
+ );
169
+
170
+ queryTypes = Effect.fn('ObjectMetaIndex.queryTypes')(
171
+ ({
172
+ spaceIds,
173
+ typeDxns,
174
+ inverted = false,
175
+ includeAllQueues = false,
176
+ queueIds = null,
177
+ }: {
178
+ spaceIds: readonly ObjectMeta['spaceId'][];
179
+ typeDxns: readonly ObjectMeta['typeDxn'][];
180
+ inverted?: boolean;
181
+ includeAllQueues?: boolean;
182
+ queueIds?: readonly string[] | null;
183
+ }): Effect.Effect<readonly ObjectMeta[], SqlError.SqlError, SqlClient.SqlClient> =>
184
+ Effect.gen(function* () {
185
+ if (spaceIds.length === 0 && (!queueIds || queueIds.length === 0)) {
186
+ return [];
187
+ }
188
+
189
+ if (typeDxns.length === 0) {
190
+ if (!inverted) {
191
+ return [];
192
+ }
193
+
194
+ const sql = yield* SqlClient.SqlClient;
195
+ const sourceCondition = buildSourceCondition(sql, spaceIds, includeAllQueues, queueIds);
196
+ const rows = yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sourceCondition}`;
197
+ return rows.map((row) => ({
198
+ ...row,
199
+ deleted: !!row.deleted,
200
+ }));
201
+ }
202
+ const sql = yield* SqlClient.SqlClient;
203
+ const sourceCondition = buildSourceCondition(sql, spaceIds, includeAllQueues, queueIds);
204
+ const typeWhere = sql.or(
205
+ typeDxns.map((typeDxn) => {
206
+ const parsedType = DXN.tryParse(typeDxn)?.asTypeDXN();
207
+ return parsedType && parsedType.version === undefined
208
+ ? sql.or([sql`typeDxn = ${typeDxn}`, sql`typeDxn LIKE ${_escapeLikePrefix(typeDxn)} ESCAPE '\\'`])
209
+ : sql`typeDxn = ${typeDxn}`;
210
+ }),
211
+ );
212
+ const rows = inverted
213
+ ? yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sourceCondition} AND NOT ${typeWhere}`
214
+ : yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sourceCondition} AND ${typeWhere}`;
215
+ return rows.map((row) => ({
216
+ ...row,
217
+ deleted: !!row.deleted,
218
+ }));
219
+ }),
220
+ );
221
+
222
+ queryRelations = Effect.fn('ObjectMetaIndex.queryRelations')(
223
+ ({
224
+ endpoint,
225
+ anchorDxns,
226
+ }: {
227
+ endpoint: 'source' | 'target';
228
+ anchorDxns: readonly string[];
229
+ }): Effect.Effect<readonly ObjectMeta[], SqlError.SqlError, SqlClient.SqlClient> =>
230
+ Effect.gen(function* () {
231
+ if (anchorDxns.length === 0) {
232
+ return [];
233
+ }
234
+ const sql = yield* SqlClient.SqlClient;
235
+ const column = endpoint === 'source' ? 'source' : 'target';
236
+ const rows = yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE entityKind = 'relation' AND ${sql.in(
237
+ column,
238
+ anchorDxns,
239
+ )}`;
63
240
  return rows.map((row) => ({
64
241
  ...row,
65
242
  deleted: !!row.deleted,
@@ -77,10 +254,9 @@ export class ObjectMetaIndex implements Index {
77
254
  objects,
78
255
  (object) =>
79
256
  Effect.gen(function* () {
80
- const { spaceId, queueId, documentId, data } = object;
257
+ const { spaceId, queueId, queueNamespace, documentId, data } = object;
81
258
 
82
259
  // Extract metadata (Logic emulating Echo APIs as strict imports are unavailable).
83
- // TODO(agent): Verify property access matches Obj.JSON structure.
84
260
  const castData = data;
85
261
  const objectId = castData.id;
86
262
 
@@ -111,27 +287,36 @@ export class ObjectMetaIndex implements Index {
111
287
  // Relations.
112
288
  const source = entityKind === 'relation' ? (castData[ATTR_RELATION_SOURCE] ?? null) : null;
113
289
  const target = entityKind === 'relation' ? (castData[ATTR_RELATION_TARGET] ?? null) : null;
290
+ // Parent (nullable).
291
+ const parent = castData[ATTR_PARENT] ?? null;
292
+
293
+ const sourceTimestamp = object.updatedAt;
114
294
 
115
295
  if (existing.length > 0) {
116
296
  yield* sql`
117
297
  UPDATE objectMeta SET
118
298
  version = ${version},
299
+ queueNamespace = ${queueNamespace ?? ''},
119
300
  entityKind = ${entityKind},
120
301
  typeDxn = ${typeDxn},
121
302
  deleted = ${deleted},
122
303
  source = ${source},
123
- target = ${target}
304
+ target = ${target},
305
+ parent = ${parent},
306
+ updatedAt = ${sourceTimestamp}
124
307
  WHERE recordId = ${existing[0].recordId}
125
308
  `;
126
309
  } else {
127
310
  yield* sql`
128
311
  INSERT INTO objectMeta (
129
- objectId, queueId, spaceId, documentId,
130
- entityKind, typeDxn, deleted, source, target, version
312
+ objectId, queueId, queueNamespace, spaceId, documentId,
313
+ entityKind, typeDxn, deleted, source, target, parent, version,
314
+ createdAt, updatedAt
131
315
  ) VALUES (
132
- ${objectId}, ${queueId ?? ''}, ${spaceId}, ${documentId ?? ''},
133
- ${entityKind}, ${typeDxn}, ${deleted},
134
- ${source}, ${target}, ${version}
316
+ ${objectId}, ${queueId ?? ''}, ${queueNamespace ?? ''}, ${spaceId}, ${documentId ?? ''},
317
+ ${entityKind}, ${typeDxn}, ${deleted},
318
+ ${source}, ${target}, ${parent}, ${version},
319
+ ${sourceTimestamp}, ${sourceTimestamp}
135
320
  )
136
321
  `;
137
322
  }
@@ -169,7 +354,7 @@ export class ObjectMetaIndex implements Index {
169
354
 
170
355
  if (result.length === 0) {
171
356
  // TODO(mykola): Handle this case gracefully.
172
- yield* Effect.die(
357
+ return yield* Effect.die(
173
358
  new Error(`Object not found in ObjectMetaIndex: ${spaceId}/${documentId ?? queueId}/${objectId}`),
174
359
  );
175
360
  }
@@ -189,12 +374,114 @@ export class ObjectMetaIndex implements Index {
189
374
  }
190
375
 
191
376
  const sql = yield* SqlClient.SqlClient;
192
- const placeholders = recordIds.map(() => '?').join(', ');
193
- const rows = yield* sql.unsafe<ObjectMeta>(
194
- `SELECT * FROM objectMeta WHERE recordId IN (${placeholders})`,
195
- recordIds,
377
+ const rows = yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sql.in('recordId', recordIds)}`;
378
+
379
+ return rows.map((row) => ({
380
+ ...row,
381
+ deleted: !!row.deleted,
382
+ }));
383
+ }),
384
+ );
385
+
386
+ /**
387
+ * Look up object metadata by objectId, spaceId, and queueId.
388
+ */
389
+ lookupByObjectId = Effect.fn('ObjectMetaIndex.lookupByObjectId')(
390
+ (query: {
391
+ objectId: string;
392
+ spaceId: string;
393
+ queueId: string;
394
+ }): Effect.Effect<ObjectMeta | null, SqlError.SqlError, SqlClient.SqlClient> =>
395
+ Effect.gen(function* () {
396
+ const sql = yield* SqlClient.SqlClient;
397
+ const rows =
398
+ yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE spaceId = ${query.spaceId} AND queueId = ${query.queueId} AND objectId = ${query.objectId} LIMIT 1`;
399
+
400
+ if (rows.length === 0) {
401
+ return null;
402
+ }
403
+
404
+ return {
405
+ ...rows[0],
406
+ deleted: !!rows[0].deleted,
407
+ };
408
+ }),
409
+ );
410
+
411
+ /**
412
+ * Query objects by timestamp range.
413
+ */
414
+ queryByTimeRange = Effect.fn('ObjectMetaIndex.queryByTimeRange')(
415
+ (query: {
416
+ spaceIds: readonly string[];
417
+ updatedAfter?: number;
418
+ updatedBefore?: number;
419
+ createdAfter?: number;
420
+ createdBefore?: number;
421
+ includeAllQueues?: boolean;
422
+ queueIds?: readonly string[] | null;
423
+ }): Effect.Effect<readonly ObjectMeta[], SqlError.SqlError, SqlClient.SqlClient> =>
424
+ Effect.gen(function* () {
425
+ if (query.spaceIds.length === 0 && (!query.queueIds || query.queueIds.length === 0)) {
426
+ return [];
427
+ }
428
+
429
+ const sql = yield* SqlClient.SqlClient;
430
+ const sourceCondition = buildSourceCondition(
431
+ sql,
432
+ query.spaceIds,
433
+ query.includeAllQueues ?? false,
434
+ query.queueIds ?? null,
196
435
  );
197
436
 
437
+ const timeConditions: Statement.Fragment[] = [];
438
+ if (query.updatedAfter != null) {
439
+ timeConditions.push(sql`updatedAt >= ${query.updatedAfter}`);
440
+ }
441
+ if (query.updatedBefore != null) {
442
+ timeConditions.push(sql`updatedAt <= ${query.updatedBefore}`);
443
+ }
444
+ if (query.createdAfter != null) {
445
+ timeConditions.push(sql`createdAt >= ${query.createdAfter}`);
446
+ }
447
+ if (query.createdBefore != null) {
448
+ timeConditions.push(sql`createdAt <= ${query.createdBefore}`);
449
+ }
450
+
451
+ const rows =
452
+ timeConditions.length > 0
453
+ ? yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sourceCondition} AND ${sql.and(timeConditions)}`
454
+ : yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sourceCondition}`;
455
+
456
+ return rows.map((row) => ({
457
+ ...row,
458
+ deleted: !!row.deleted,
459
+ }));
460
+ }),
461
+ );
462
+
463
+ /**
464
+ * Query children by parent object ids.
465
+ * Matches both:
466
+ * - Objects whose `parent` field references one of the given parent ids (standard parent/child hierarchy).
467
+ * - Queue items whose `queueId` equals one of the parent ids (e.g. items inside a Feed, since a feed's queue
468
+ * DXN uses the feed's object id as its queue id — see `Feed.getQueueDxn`).
469
+ */
470
+ queryChildren = Effect.fn('ObjectMetaIndex.queryChildren')(
471
+ (query: {
472
+ spaceId: SpaceId[];
473
+ parentIds: ObjectId[];
474
+ }): Effect.Effect<readonly ObjectMeta[], SqlError.SqlError, SqlClient.SqlClient> =>
475
+ Effect.gen(function* () {
476
+ if (query.parentIds.length === 0) {
477
+ return [];
478
+ }
479
+
480
+ const sql = yield* SqlClient.SqlClient;
481
+ const parentDxns = query.parentIds.map((id) => DXN.fromLocalObjectId(id).toString());
482
+ const rows =
483
+ yield* sql<ObjectMeta>`SELECT * FROM objectMeta WHERE ${sql.in('spaceId', query.spaceId)} AND (${sql.in('parent', parentDxns)} OR ${sql.in('queueId', query.parentIds)})`;
484
+
198
485
  return rows.map((row) => ({
199
486
  ...row,
200
487
  deleted: !!row.deleted,
@@ -14,8 +14,8 @@ import { DXN, ObjectId, SpaceId } from '@dxos/keys';
14
14
  import type { IndexerObject } from './interface';
15
15
  import { ReverseRefIndex } from './reverse-ref-index';
16
16
 
17
- const TYPE_PERSON = DXN.parse('dxn:type:example.com/type/Person:0.1.0').toString();
18
- const TYPE_EXAMPLE = DXN.parse('dxn:type:example.com/type/Example:0.1.0').toString();
17
+ const TYPE_PERSON = DXN.parse('dxn:type:com.example.type.person:0.1.0').toString();
18
+ const TYPE_EXAMPLE = DXN.parse('dxn:type:com.example.type.example:0.1.0').toString();
19
19
 
20
20
  const TestLayer = Layer.merge(
21
21
  SqliteClient.layer({
@@ -38,8 +38,10 @@ describe('ReverseRefIndex', () => {
38
38
  const sourceObject: IndexerObject = {
39
39
  spaceId,
40
40
  queueId: ObjectId.random(),
41
+ queueNamespace: 'data',
41
42
  documentId: null,
42
43
  recordId: 1,
44
+ updatedAt: Date.now(),
43
45
  data: {
44
46
  id: sourceObjectId,
45
47
  [ATTR_TYPE]: TYPE_PERSON,
@@ -71,8 +73,10 @@ describe('ReverseRefIndex', () => {
71
73
  const sourceObject: IndexerObject = {
72
74
  spaceId,
73
75
  queueId: ObjectId.random(),
76
+ queueNamespace: 'data',
74
77
  documentId: null,
75
78
  recordId: 1,
79
+ updatedAt: Date.now(),
76
80
  data: {
77
81
  id: sourceObjectId,
78
82
  [ATTR_TYPE]: TYPE_EXAMPLE,
@@ -112,8 +116,10 @@ describe('ReverseRefIndex', () => {
112
116
  const sourceObject: IndexerObject = {
113
117
  spaceId,
114
118
  queueId: ObjectId.random(),
119
+ queueNamespace: 'data',
115
120
  documentId: null,
116
121
  recordId: 1,
122
+ updatedAt: Date.now(),
117
123
  data: {
118
124
  id: sourceObjectId,
119
125
  [ATTR_TYPE]: TYPE_EXAMPLE,
@@ -151,8 +157,10 @@ describe('ReverseRefIndex', () => {
151
157
  const sourceObject: IndexerObject = {
152
158
  spaceId,
153
159
  queueId,
160
+ queueNamespace: 'data',
154
161
  documentId: null,
155
162
  recordId,
163
+ updatedAt: Date.now(),
156
164
  data: {
157
165
  id: sourceObjectId,
158
166
  [ATTR_TYPE]: TYPE_EXAMPLE,
@@ -169,8 +177,10 @@ describe('ReverseRefIndex', () => {
169
177
  const updatedObject: IndexerObject = {
170
178
  spaceId,
171
179
  queueId,
180
+ queueNamespace: 'data',
172
181
  documentId: null,
173
182
  recordId,
183
+ updatedAt: Date.now(),
174
184
  data: {
175
185
  id: sourceObjectId,
176
186
  [ATTR_TYPE]: TYPE_EXAMPLE,
@@ -201,8 +211,10 @@ describe('ReverseRefIndex', () => {
201
211
  const sourceObject: IndexerObject = {
202
212
  spaceId,
203
213
  queueId: ObjectId.random(),
214
+ queueNamespace: 'data',
204
215
  documentId: null,
205
216
  recordId: 1,
217
+ updatedAt: Date.now(),
206
218
  data: {
207
219
  id: sourceObjectId,
208
220
  [ATTR_TYPE]: TYPE_EXAMPLE,
@@ -232,8 +244,10 @@ describe('ReverseRefIndex', () => {
232
244
  const sourceObject: IndexerObject = {
233
245
  spaceId,
234
246
  queueId: null,
247
+ queueNamespace: null,
235
248
  documentId: 'doc-123',
236
249
  recordId: 1,
250
+ updatedAt: Date.now(),
237
251
  data: {
238
252
  id: sourceObjectId,
239
253
  [ATTR_TYPE]: TYPE_EXAMPLE,
@@ -10,7 +10,6 @@ import * as Schema from 'effect/Schema';
10
10
  import { EncodedReference, isEncodedReference } from '@dxos/echo-protocol';
11
11
 
12
12
  import { EscapedPropPath } from '../utils';
13
-
14
13
  import type { Index, IndexerObject } from './interface';
15
14
 
16
15
  /**
package/src/utils.ts CHANGED
@@ -6,7 +6,7 @@ import * as Schema from 'effect/Schema';
6
6
 
7
7
  import { invariant } from '@dxos/invariant';
8
8
 
9
- export type ObjectPropPath = (string | number)[];
9
+ export type ObjectPropPath = string[];
10
10
 
11
11
  /**
12
12
  * Escaped property path within an object.