@dxos/index-core 0.0.0 → 0.8.4-main.59c2e9b
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/browser/index.mjs +559 -0
- package/dist/lib/browser/index.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -0
- package/dist/lib/node-esm/index.mjs +561 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/types/src/index-engine.d.ts +63 -0
- package/dist/types/src/index-engine.d.ts.map +1 -0
- package/dist/types/src/index-engine.test.d.ts +2 -0
- package/dist/types/src/index-engine.test.d.ts.map +1 -0
- package/dist/types/src/index-tracker.d.ts +44 -0
- package/dist/types/src/index-tracker.d.ts.map +1 -0
- package/dist/types/src/index-tracker.test.d.ts +2 -0
- package/dist/types/src/index-tracker.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +7 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/indexes/fts-index.d.ts +63 -0
- package/dist/types/src/indexes/fts-index.d.ts.map +1 -0
- package/dist/types/src/indexes/fts-index.test.d.ts +2 -0
- package/dist/types/src/indexes/fts-index.test.d.ts.map +1 -0
- package/dist/types/src/indexes/fts5.test.d.ts +2 -0
- package/dist/types/src/indexes/fts5.test.d.ts.map +1 -0
- package/dist/types/src/indexes/index.d.ts +5 -0
- package/dist/types/src/indexes/index.d.ts.map +1 -0
- package/dist/types/src/indexes/interface.d.ts +47 -0
- package/dist/types/src/indexes/interface.d.ts.map +1 -0
- package/dist/types/src/indexes/object-meta-index.d.ts +37 -0
- package/dist/types/src/indexes/object-meta-index.d.ts.map +1 -0
- package/dist/types/src/indexes/object-meta-index.test.d.ts +2 -0
- package/dist/types/src/indexes/object-meta-index.test.d.ts.map +1 -0
- package/dist/types/src/indexes/reverse-ref-index.d.ts +37 -0
- package/dist/types/src/indexes/reverse-ref-index.d.ts.map +1 -0
- package/dist/types/src/indexes/reverse-ref-index.test.d.ts +2 -0
- package/dist/types/src/indexes/reverse-ref-index.test.d.ts.map +1 -0
- package/dist/types/src/utils.d.ts +17 -0
- package/dist/types/src/utils.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +7 -2
- package/src/index-engine.test.ts +8 -5
- package/src/index-engine.ts +18 -7
- package/src/index.ts +2 -2
- package/src/indexes/fts-index.ts +41 -2
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/index-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.4-main.59c2e9b",
|
|
4
4
|
"description": "Indexing core.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "info@dxos.org",
|
|
9
13
|
"sideEffects": false,
|
|
@@ -34,7 +38,8 @@
|
|
|
34
38
|
"@effect/experimental": "0.57.11",
|
|
35
39
|
"@effect/platform": "0.93.6",
|
|
36
40
|
"@effect/sql": "0.48.6",
|
|
37
|
-
"effect": "3.19.11"
|
|
41
|
+
"effect": "3.19.11",
|
|
42
|
+
"@dxos/sql-sqlite": "0.8.4-main.59c2e9b"
|
|
38
43
|
},
|
|
39
44
|
"devDependencies": {
|
|
40
45
|
"@effect/sql-sqlite-node": "0.49.1"
|
package/src/index-engine.test.ts
CHANGED
|
@@ -11,6 +11,7 @@ import * as Layer from 'effect/Layer';
|
|
|
11
11
|
import { ATTR_TYPE } from '@dxos/echo/internal';
|
|
12
12
|
import { invariant } from '@dxos/invariant';
|
|
13
13
|
import { DXN, ObjectId, SpaceId } from '@dxos/keys';
|
|
14
|
+
import * as SqlTransaction from '@dxos/sql-sqlite/SqlTransaction';
|
|
14
15
|
|
|
15
16
|
import { type DataSourceCursor, type IndexDataSource, IndexEngine } from './index-engine';
|
|
16
17
|
import { type IndexCursor, IndexTracker } from './index-tracker';
|
|
@@ -20,11 +21,13 @@ const TYPE_DEFAULT = DXN.parse('dxn:type:test.com/type/Type:0.1.0').toString();
|
|
|
20
21
|
const TYPE_A = DXN.parse('dxn:type:test.com/type/TypeA:0.1.0').toString();
|
|
21
22
|
const TYPE_B = DXN.parse('dxn:type:test.com/type/TypeB:0.1.0').toString();
|
|
22
23
|
|
|
23
|
-
const TestLayer =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const TestLayer = SqlTransaction.layer.pipe(
|
|
25
|
+
Layer.provideMerge(
|
|
26
|
+
SqliteClient.layer({
|
|
27
|
+
filename: ':memory:',
|
|
28
|
+
}),
|
|
29
|
+
),
|
|
30
|
+
Layer.provideMerge(Reactivity.layer),
|
|
28
31
|
);
|
|
29
32
|
|
|
30
33
|
class MockIndexDataSource implements IndexDataSource {
|
package/src/index-engine.ts
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
// Copyright 2026 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import * as SqlClient from '@effect/sql/SqlClient';
|
|
5
|
+
import type * as SqlClient from '@effect/sql/SqlClient';
|
|
6
6
|
import type * as SqlError from '@effect/sql/SqlError';
|
|
7
7
|
import * as Effect from 'effect/Effect';
|
|
8
8
|
|
|
9
9
|
import type { SpaceId } from '@dxos/keys';
|
|
10
|
+
import * as SqlTransaction from '@dxos/sql-sqlite/SqlTransaction';
|
|
10
11
|
|
|
11
12
|
import { type IndexCursor, IndexTracker } from './index-tracker';
|
|
12
13
|
import {
|
|
13
14
|
FtsIndex,
|
|
14
15
|
type FtsQuery,
|
|
16
|
+
type FtsQueryResult,
|
|
15
17
|
type Index,
|
|
16
18
|
type IndexerObject,
|
|
17
19
|
type ObjectMeta,
|
|
@@ -76,9 +78,9 @@ export class IndexEngine {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
/**
|
|
79
|
-
* Query text index and return full object metadata.
|
|
81
|
+
* Query text index and return full object metadata with rank.
|
|
80
82
|
*/
|
|
81
|
-
queryText(query: FtsQuery): Effect.Effect<readonly
|
|
83
|
+
queryText(query: FtsQuery): Effect.Effect<readonly FtsQueryResult[], SqlError.SqlError, SqlClient.SqlClient> {
|
|
82
84
|
return Effect.gen(this, function* () {
|
|
83
85
|
return yield* this.#ftsIndex.query(query);
|
|
84
86
|
});
|
|
@@ -106,7 +108,11 @@ export class IndexEngine {
|
|
|
106
108
|
update(
|
|
107
109
|
dataSource: IndexDataSource,
|
|
108
110
|
opts: { spaceId: SpaceId | null; limit?: number },
|
|
109
|
-
): Effect.Effect<
|
|
111
|
+
): Effect.Effect<
|
|
112
|
+
{ updated: number; done: boolean },
|
|
113
|
+
SqlError.SqlError,
|
|
114
|
+
SqlTransaction.SqlTransaction | SqlClient.SqlClient
|
|
115
|
+
> {
|
|
110
116
|
return Effect.gen(this, function* () {
|
|
111
117
|
let updated = 0;
|
|
112
118
|
|
|
@@ -145,10 +151,15 @@ export class IndexEngine {
|
|
|
145
151
|
index: Index,
|
|
146
152
|
source: IndexDataSource,
|
|
147
153
|
opts: { indexName: string; spaceId: SpaceId | null; limit?: number },
|
|
148
|
-
): Effect.Effect<
|
|
154
|
+
): Effect.Effect<
|
|
155
|
+
{ updated: number; done: boolean },
|
|
156
|
+
SqlError.SqlError,
|
|
157
|
+
SqlTransaction.SqlTransaction | SqlClient.SqlClient
|
|
158
|
+
> {
|
|
149
159
|
return Effect.gen(this, function* () {
|
|
150
|
-
const
|
|
151
|
-
|
|
160
|
+
const sqlTransaction = yield* SqlTransaction.SqlTransaction;
|
|
161
|
+
|
|
162
|
+
return yield* sqlTransaction.withTransaction(
|
|
152
163
|
Effect.gen(this, function* () {
|
|
153
164
|
const cursors = yield* this.#tracker.queryCursors({
|
|
154
165
|
indexName: opts.indexName,
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
export { IndexEngine, type IndexDataSource, type DataSourceCursor, type IndexEngineParams } from './index-engine';
|
|
6
6
|
export { IndexTracker, type IndexCursor } from './index-tracker';
|
|
7
7
|
export { type IndexerObject, type Index } from './indexes/interface';
|
|
8
|
-
export { FtsIndex } from './indexes/fts-index';
|
|
8
|
+
export { FtsIndex, type FtsQuery } from './indexes/fts-index';
|
|
9
9
|
export { ObjectMetaIndex, type ObjectMeta } from './indexes/object-meta-index';
|
|
10
|
-
export { ReverseRefIndex, type ReverseRef } from './indexes/reverse-ref-index';
|
|
10
|
+
export { ReverseRefIndex, type ReverseRef, type ReverseRefQuery } from './indexes/reverse-ref-index';
|
package/src/indexes/fts-index.ts
CHANGED
|
@@ -49,6 +49,18 @@ export interface FtsResult extends ObjectMeta {
|
|
|
49
49
|
snapshot: string;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Result of FTS query with rank.
|
|
54
|
+
*/
|
|
55
|
+
export interface FtsQueryResult extends ObjectMeta {
|
|
56
|
+
/**
|
|
57
|
+
* Relevance rank from FTS5.
|
|
58
|
+
* Higher values indicate better matches.
|
|
59
|
+
* Uses BM25 algorithm when available, falls back to 1 for non-BM25 queries.
|
|
60
|
+
*/
|
|
61
|
+
rank: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
/**
|
|
53
65
|
* Escapes user input for safe FTS5 queries.
|
|
54
66
|
*
|
|
@@ -92,7 +104,7 @@ export class FtsIndex implements Index {
|
|
|
92
104
|
spaceId,
|
|
93
105
|
includeAllQueues,
|
|
94
106
|
queueIds,
|
|
95
|
-
}: FtsQuery): Effect.Effect<readonly
|
|
107
|
+
}: FtsQuery): Effect.Effect<readonly FtsQueryResult[], SqlError.SqlError, SqlClient.SqlClient> {
|
|
96
108
|
return Effect.gen(function* () {
|
|
97
109
|
const trimmed = query.trim();
|
|
98
110
|
if (trimmed.length === 0) {
|
|
@@ -106,6 +118,11 @@ export class FtsIndex implements Index {
|
|
|
106
118
|
const terms = trimmed.split(/\s+/).filter(Boolean);
|
|
107
119
|
const minTermLength = Math.min(...terms.map((t) => t.length));
|
|
108
120
|
|
|
121
|
+
// Use BM25 ranking for FTS5 MATCH queries, fall back to rank 1 for LIKE queries.
|
|
122
|
+
// BM25 returns negative values where lower (more negative) means better match,
|
|
123
|
+
// so we negate it to get higher = better.
|
|
124
|
+
const useBm25 = minTermLength >= 3;
|
|
125
|
+
|
|
109
126
|
const conditions =
|
|
110
127
|
minTermLength < 3
|
|
111
128
|
? // LIKE fallback - scan the entire table, AND all terms.
|
|
@@ -135,7 +152,29 @@ export class FtsIndex implements Index {
|
|
|
135
152
|
conditions.push(sql`(${sql.or(sourceConditions)})`);
|
|
136
153
|
}
|
|
137
154
|
|
|
138
|
-
|
|
155
|
+
if (useBm25) {
|
|
156
|
+
// Use BM25 ranking for FTS5 MATCH queries.
|
|
157
|
+
// BM25 returns negative values, negate to get higher = better match.
|
|
158
|
+
// Order by rank descending so best matches come first.
|
|
159
|
+
// Note: bm25() requires the actual table name, not an alias.
|
|
160
|
+
const rows = yield* sql<ObjectMeta & { rank: number }>`
|
|
161
|
+
SELECT m.*, -bm25(ftsIndex) AS rank
|
|
162
|
+
FROM ftsIndex AS f
|
|
163
|
+
JOIN objectMeta AS m ON f.rowid = m.recordId
|
|
164
|
+
WHERE ${sql.and(conditions)}
|
|
165
|
+
ORDER BY rank DESC
|
|
166
|
+
`;
|
|
167
|
+
return rows;
|
|
168
|
+
} else {
|
|
169
|
+
// LIKE fallback - no ranking available, default to 1.
|
|
170
|
+
const rows = yield* sql<ObjectMeta>`
|
|
171
|
+
SELECT m.*
|
|
172
|
+
FROM ftsIndex AS f
|
|
173
|
+
JOIN objectMeta AS m ON f.rowid = m.recordId
|
|
174
|
+
WHERE ${sql.and(conditions)}
|
|
175
|
+
`;
|
|
176
|
+
return rows.map((row) => ({ ...row, rank: 1 }));
|
|
177
|
+
}
|
|
139
178
|
});
|
|
140
179
|
}
|
|
141
180
|
|