@taladb/react-native 0.11.3 → 0.11.4
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/android/src/main/jniLibs/arm64-v8a/libtaladb_ffi.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libtaladb_ffi.so +0 -0
- package/android/src/main/jniLibs/x86_64/libtaladb_ffi.so +0 -0
- package/cpp/TalaDBHostObject.cpp +19 -1
- package/cpp/taladb.h +307 -217
- package/ios/TalaDBFfi.xcframework/Info.plist +9 -9
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/TalaDBHostObject.cpp +19 -1
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/taladb.h +307 -217
- package/ios/TalaDBFfi.xcframework/ios-arm64/libtaladb_ffi.a +0 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/TalaDBHostObject.cpp +19 -1
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/taladb.h +307 -217
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/libtaladb_ffi_sim.a +0 -0
- package/package.json +3 -3
- package/src/NativeTalaDB.ts +12 -0
- package/src/index.tsx +309 -1
package/src/NativeTalaDB.ts
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
* This file is the Codegen source. It defines the native interface that
|
|
5
5
|
* both the iOS JSI HostObject (TalaDB.mm) and the Android JNI bridge
|
|
6
6
|
* (TalaDBModule.kt) must implement.
|
|
7
|
+
*
|
|
8
|
+
* # This is not the public API
|
|
9
|
+
*
|
|
10
|
+
* Only `initialize` and `close` are ever called through the TurboModule. Every
|
|
11
|
+
* other method below is a stub that exists so Codegen sees a complete surface;
|
|
12
|
+
* at runtime JS goes straight to the JSI HostObject at `global.__TalaDB__`.
|
|
13
|
+
*
|
|
14
|
+
* So do **not** add methods here to expose new functionality — each one
|
|
15
|
+
* generates an abstract member that `TalaDBModule.kt` and `TalaDB.mm` must
|
|
16
|
+
* override, and forgetting either breaks the native build for a stub nothing
|
|
17
|
+
* calls. The real surface is registered in `cpp/TalaDBHostObject.cpp` and typed
|
|
18
|
+
* by `JsiTalaDB` in `index.tsx`; extend those two together.
|
|
7
19
|
*/
|
|
8
20
|
import type { TurboModule } from 'react-native';
|
|
9
21
|
import { TurboModuleRegistry } from 'react-native';
|
package/src/index.tsx
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/** TalaDB React Native public API. CRUD is synchronous through the JSI host. */
|
|
2
2
|
import {
|
|
3
3
|
createWebhookDispatcher,
|
|
4
|
+
createVectorClient,
|
|
5
|
+
type VectorClient,
|
|
6
|
+
type HybridSearchOptions,
|
|
7
|
+
type TextSearchOptions,
|
|
8
|
+
type VectorMetric,
|
|
4
9
|
type WebhookConfig,
|
|
5
10
|
type WebhookDispatcher,
|
|
6
11
|
type WebhookEvent,
|
|
@@ -8,6 +13,13 @@ import {
|
|
|
8
13
|
} from 'taladb';
|
|
9
14
|
import NativeTalaDB from './NativeTalaDB';
|
|
10
15
|
|
|
16
|
+
export type {
|
|
17
|
+
HybridSearchOptions,
|
|
18
|
+
TextSearchOptions,
|
|
19
|
+
VectorMetric,
|
|
20
|
+
VectorClient, VectorQueryOptions, VectorRebuildOptions, VectorBuildProgress, VectorIndexStatus, VectorQueryResult, VectorRecall, VectorGraphOptions, VectorQuantization,
|
|
21
|
+
} from 'taladb';
|
|
22
|
+
|
|
11
23
|
export const TalaDBModule = {
|
|
12
24
|
/** Open the native database. The config controls durability/encryption only. */
|
|
13
25
|
initialize: (dbName: string, configJson?: string) =>
|
|
@@ -24,7 +36,75 @@ export type InsertDocument<T extends Document> = Omit<T, '_id'> & { _id?: string
|
|
|
24
36
|
export type Filter = Record<string, unknown>;
|
|
25
37
|
export type Update = Record<string, unknown>;
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
/** A query vector. `Float32Array` takes a zero-copy path across JSI. */
|
|
40
|
+
export type QueryVector = Float32Array | number[];
|
|
41
|
+
|
|
42
|
+
/** An ordered MongoDB-style aggregation pipeline. */
|
|
43
|
+
export type AggregatePipeline = Record<string, unknown>[];
|
|
44
|
+
|
|
45
|
+
/** A single result from `findNearest`. */
|
|
46
|
+
export interface VectorSearchResult<T extends Document = Document> {
|
|
47
|
+
document: T;
|
|
48
|
+
/**
|
|
49
|
+
* Similarity score — higher means more similar. Range depends on the
|
|
50
|
+
* metric: cosine ∈ [-1,1], dot ∈ ℝ, euclidean ∈ (0,1].
|
|
51
|
+
*/
|
|
52
|
+
score: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A single result from `searchText`. */
|
|
56
|
+
export interface TextSearchResult<T extends Document = Document> {
|
|
57
|
+
document: T;
|
|
58
|
+
/**
|
|
59
|
+
* BM25 relevance — higher is more relevant. Unbounded above and only
|
|
60
|
+
* meaningful for ordering within one query's result set.
|
|
61
|
+
*/
|
|
62
|
+
score: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** A single result from `hybridSearch`. */
|
|
66
|
+
export interface HybridSearchResult<T extends Document = Document> {
|
|
67
|
+
document: T;
|
|
68
|
+
/**
|
|
69
|
+
* Fused reciprocal-rank-fusion score. Small by construction and meaningful
|
|
70
|
+
* only as an ordering within one result set — never a similarity or a
|
|
71
|
+
* confidence.
|
|
72
|
+
*/
|
|
73
|
+
score: number;
|
|
74
|
+
/** Zero-based rank in the text ranking, or `null` if text did not return it. */
|
|
75
|
+
textRank: number | null;
|
|
76
|
+
/** Zero-based rank in the vector ranking, or `null` if vector did not return it. */
|
|
77
|
+
vectorRank: number | null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* HNSW build parameters.
|
|
82
|
+
*
|
|
83
|
+
* The native binding validates these values and reports malformed options.
|
|
84
|
+
* `ef_construction` is retained for compatibility with the direct native API;
|
|
85
|
+
* the shared asynchronous vector API uses `efConstruction`.
|
|
86
|
+
*/
|
|
87
|
+
export interface HnswBuildOptions {
|
|
88
|
+
/** Bi-directional links per node (2–128). */
|
|
89
|
+
m: number;
|
|
90
|
+
/** Build-time quality (ef during construction). Must be ≥ `m`. Typically 200. */
|
|
91
|
+
ef_construction: number;
|
|
92
|
+
quantization?: import("taladb").VectorQuantization;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface VectorIndexOptions {
|
|
96
|
+
/** Similarity metric. Defaults to `"cosine"`. */
|
|
97
|
+
metric?: VectorMetric;
|
|
98
|
+
/**
|
|
99
|
+
* Supply this to build an HNSW (approximate) index instead of a flat one.
|
|
100
|
+
*
|
|
101
|
+
* Nodes and links persist in the database and update with document writes.
|
|
102
|
+
* Reopening requires no warm-up.
|
|
103
|
+
*/
|
|
104
|
+
hnsw?: HnswBuildOptions;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface Collection<T extends Document = Document> extends VectorClient<T> {
|
|
28
108
|
insert(doc: InsertDocument<T>): string;
|
|
29
109
|
insertMany(docs: InsertDocument<T>[]): string[];
|
|
30
110
|
find(filter?: Filter): T[];
|
|
@@ -38,6 +118,95 @@ export interface Collection<T extends Document = Document> {
|
|
|
38
118
|
dropIndex(field: string): void;
|
|
39
119
|
createFtsIndex(field: string): void;
|
|
40
120
|
dropFtsIndex(field: string): void;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Find documents on a background thread. Prefer this over `find` for scans
|
|
124
|
+
* large enough to be felt as a dropped frame — every synchronous method here
|
|
125
|
+
* runs on the JS thread.
|
|
126
|
+
*/
|
|
127
|
+
findAsync(filter?: Filter): Promise<T[]>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Run a MongoDB-style aggregation pipeline: `$match`, `$group`, `$sort`,
|
|
131
|
+
* `$skip`, `$limit`, `$project`, with `$sum` / `$avg` / `$min` / `$max` /
|
|
132
|
+
* `$count` accumulators. `$match` uses an index where one exists.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* const [{ total }] = repairs.aggregate<{ total: number }>([
|
|
136
|
+
* { $match: { thingId } },
|
|
137
|
+
* { $group: { _id: null, total: { $sum: '$cost' } } },
|
|
138
|
+
* ]);
|
|
139
|
+
*/
|
|
140
|
+
aggregate<R extends Document = Document>(pipeline: AggregatePipeline): R[];
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Rank documents by BM25 keyword relevance. OR semantics — a document
|
|
144
|
+
* matching more of the query scores higher. Requires an FTS index on `field`.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* const hits = notes.searchText('body', 'chain replacement', 5);
|
|
148
|
+
*/
|
|
149
|
+
searchText(
|
|
150
|
+
field: string,
|
|
151
|
+
query: string,
|
|
152
|
+
topK: number,
|
|
153
|
+
filter?: Filter | null,
|
|
154
|
+
options?: TextSearchOptions,
|
|
155
|
+
): TextSearchResult<T>[];
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Rank by keyword relevance (BM25) **and** vector similarity, then fuse the
|
|
159
|
+
* two rankings with reciprocal rank fusion.
|
|
160
|
+
*
|
|
161
|
+
* The retrievers fail differently — keyword search misses paraphrases,
|
|
162
|
+
* vector search misses exact identifiers and rare proper nouns — so fusing
|
|
163
|
+
* them recovers both. Requires an FTS index on `textField` and a vector
|
|
164
|
+
* index on `vectorField`. `filter` applies to both retrievers before ranking.
|
|
165
|
+
*/
|
|
166
|
+
hybridSearch(
|
|
167
|
+
text: { textField: string; text: string },
|
|
168
|
+
vector: { vectorField: string; vector: QueryVector },
|
|
169
|
+
topK: number,
|
|
170
|
+
filter?: Filter | null,
|
|
171
|
+
options?: HybridSearchOptions,
|
|
172
|
+
): HybridSearchResult<T>[];
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Nearest neighbours by vector similarity.
|
|
176
|
+
*
|
|
177
|
+
* Passing a `filter` always takes the exact path: the graph cannot be
|
|
178
|
+
* traversed under an arbitrary predicate, so matching IDs are scored
|
|
179
|
+
* directly. That is usually what you want for a scoped search — it is exact,
|
|
180
|
+
* and it reads only the vectors that survive the filter.
|
|
181
|
+
*/
|
|
182
|
+
findNearest(
|
|
183
|
+
field: string,
|
|
184
|
+
query: QueryVector,
|
|
185
|
+
topK: number,
|
|
186
|
+
filter?: Filter | null,
|
|
187
|
+
): VectorSearchResult<T>[];
|
|
188
|
+
|
|
189
|
+
/** `findNearest` on a background thread. Prefer it for unfiltered searches. */
|
|
190
|
+
findNearestAsync(
|
|
191
|
+
field: string,
|
|
192
|
+
query: QueryVector,
|
|
193
|
+
topK: number,
|
|
194
|
+
filter?: Filter | null,
|
|
195
|
+
): Promise<VectorSearchResult<T>[]>;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Create a vector index on a numeric-array field. `dimensions` is enforced
|
|
199
|
+
* on every insert and every query.
|
|
200
|
+
*/
|
|
201
|
+
createVectorIndex(field: string, dimensions: number, options?: VectorIndexOptions): void;
|
|
202
|
+
dropVectorIndex(field: string): void;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Promote a flat/legacy index or compact a persistent graph. This synchronous
|
|
206
|
+
* call may be expensive; prefer rebuildVectorIndex for background batches,
|
|
207
|
+
* progress and AbortSignal cancellation on mobile.
|
|
208
|
+
*/
|
|
209
|
+
upgradeVectorIndex(field: string): void;
|
|
41
210
|
}
|
|
42
211
|
|
|
43
212
|
export interface OpenDBOptions {
|
|
@@ -50,9 +219,48 @@ export interface DB {
|
|
|
50
219
|
webhookStats(): WebhookStats;
|
|
51
220
|
flushWebhook(timeoutMs?: number): Promise<boolean>;
|
|
52
221
|
close(): Promise<void>;
|
|
222
|
+
|
|
223
|
+
/** Names of every collection that currently holds documents. */
|
|
224
|
+
listCollectionNames(): string[];
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Force a durable sync of everything written so far.
|
|
228
|
+
*
|
|
229
|
+
* Only meaningful when the database was opened with
|
|
230
|
+
* `durability.flush_every_write: false`, which trades an fsync per write for
|
|
231
|
+
* throughput. The default is `true` — every acknowledged write is already
|
|
232
|
+
* durable — so most apps never need this. Batch importers should turn the
|
|
233
|
+
* flag off, import, then call `flush()`.
|
|
234
|
+
*/
|
|
235
|
+
flush(): void;
|
|
236
|
+
|
|
237
|
+
/** Reclaim space from deleted documents. Expensive; run it off the hot path. */
|
|
238
|
+
compact(): void;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Warm every HNSW vector index in the database.
|
|
242
|
+
*
|
|
243
|
+
* Graphs persist across app launches. This is maintenance, not a startup
|
|
244
|
+
* requirement. Prefer per-field rebuildVectorIndex for progress/cancellation.
|
|
245
|
+
*/
|
|
246
|
+
rebuildVectorIndexes(): void;
|
|
247
|
+
|
|
248
|
+
/** The application-defined schema version stored in the database file. */
|
|
249
|
+
userVersion(): number;
|
|
250
|
+
setUserVersion(version: number): void;
|
|
53
251
|
}
|
|
54
252
|
|
|
253
|
+
/**
|
|
254
|
+
* The JSI host object installed as `global.__TalaDB__`.
|
|
255
|
+
*
|
|
256
|
+
* This mirrors the methods registered in `cpp/TalaDBHostObject.cpp`, which is
|
|
257
|
+
* the real runtime surface. The TurboModule spec in `NativeTalaDB.ts` is
|
|
258
|
+
* deliberately narrower: every method there generates an abstract member that
|
|
259
|
+
* `TalaDBModule.kt` and `TalaDB.mm` must stub out, and those stubs are never
|
|
260
|
+
* called. Add new methods here, not there.
|
|
261
|
+
*/
|
|
55
262
|
interface JsiTalaDB {
|
|
263
|
+
callAsync(op: string, args: unknown[]): Promise<any>;
|
|
56
264
|
insert(collection: string, doc: Object): string;
|
|
57
265
|
insertMany(collection: string, docs: Object[]): string[];
|
|
58
266
|
find(collection: string, filter: Object | null): Object[];
|
|
@@ -66,6 +274,54 @@ interface JsiTalaDB {
|
|
|
66
274
|
dropIndex(collection: string, field: string): void;
|
|
67
275
|
createFtsIndex(collection: string, field: string): void;
|
|
68
276
|
dropFtsIndex(collection: string, field: string): void;
|
|
277
|
+
findAsync(collection: string, filter: Object | null): Promise<Object[]>;
|
|
278
|
+
aggregate(collection: string, pipeline: Object[]): Object[];
|
|
279
|
+
searchText(
|
|
280
|
+
collection: string,
|
|
281
|
+
field: string,
|
|
282
|
+
query: string,
|
|
283
|
+
topK: number,
|
|
284
|
+
filter: Object | null,
|
|
285
|
+
options?: Object,
|
|
286
|
+
): Object[];
|
|
287
|
+
hybridSearch(
|
|
288
|
+
collection: string,
|
|
289
|
+
textField: string,
|
|
290
|
+
text: string,
|
|
291
|
+
vectorField: string,
|
|
292
|
+
vector: QueryVector,
|
|
293
|
+
topK: number,
|
|
294
|
+
filter: Object | null,
|
|
295
|
+
options?: Object,
|
|
296
|
+
): Object[];
|
|
297
|
+
findNearest(
|
|
298
|
+
collection: string,
|
|
299
|
+
field: string,
|
|
300
|
+
query: QueryVector,
|
|
301
|
+
topK: number,
|
|
302
|
+
filter: Object | null,
|
|
303
|
+
): Object[];
|
|
304
|
+
findNearestAsync(
|
|
305
|
+
collection: string,
|
|
306
|
+
field: string,
|
|
307
|
+
query: QueryVector,
|
|
308
|
+
topK: number,
|
|
309
|
+
filter: Object | null,
|
|
310
|
+
): Promise<Object[]>;
|
|
311
|
+
createVectorIndex(
|
|
312
|
+
collection: string,
|
|
313
|
+
field: string,
|
|
314
|
+
dimensions: number,
|
|
315
|
+
opts?: Object,
|
|
316
|
+
): void;
|
|
317
|
+
dropVectorIndex(collection: string, field: string): void;
|
|
318
|
+
upgradeVectorIndex(collection: string, field: string): void;
|
|
319
|
+
listCollectionNames(): string[];
|
|
320
|
+
rebuildVectorIndexes(): void;
|
|
321
|
+
flush(): void;
|
|
322
|
+
compact(): void;
|
|
323
|
+
userVersion(): number;
|
|
324
|
+
setUserVersion(version: number): void;
|
|
69
325
|
}
|
|
70
326
|
|
|
71
327
|
function native(): JsiTalaDB {
|
|
@@ -117,6 +373,7 @@ function collection<T extends Document>(
|
|
|
117
373
|
webhook: WebhookDispatcher | null,
|
|
118
374
|
): Collection<T> {
|
|
119
375
|
return {
|
|
376
|
+
...createVectorClient<T>(request => native().callAsync('vectorCommand', [colName, request])),
|
|
120
377
|
insert(doc) {
|
|
121
378
|
const id = native().insert(colName, doc as Object);
|
|
122
379
|
const committedAt = Date.now();
|
|
@@ -174,6 +431,51 @@ function collection<T extends Document>(
|
|
|
174
431
|
dropIndex: (field) => native().dropIndex(colName, field),
|
|
175
432
|
createFtsIndex: (field) => native().createFtsIndex(colName, field),
|
|
176
433
|
dropFtsIndex: (field) => native().dropFtsIndex(colName, field),
|
|
434
|
+
|
|
435
|
+
findAsync: async (filter) =>
|
|
436
|
+
(await native().findAsync(colName, filter ?? null)) as T[],
|
|
437
|
+
|
|
438
|
+
aggregate: <R extends Document = Document>(pipeline: AggregatePipeline) =>
|
|
439
|
+
native().aggregate(colName, pipeline as Object[]) as R[],
|
|
440
|
+
|
|
441
|
+
searchText: (field, query, topK, filter, options) =>
|
|
442
|
+
native().searchText(
|
|
443
|
+
colName,
|
|
444
|
+
field,
|
|
445
|
+
query,
|
|
446
|
+
topK,
|
|
447
|
+
filter ?? null,
|
|
448
|
+
options as Object | undefined,
|
|
449
|
+
) as TextSearchResult<T>[],
|
|
450
|
+
|
|
451
|
+
hybridSearch: (text, vector, topK, filter, options) =>
|
|
452
|
+
native().hybridSearch(
|
|
453
|
+
colName,
|
|
454
|
+
text.textField,
|
|
455
|
+
text.text,
|
|
456
|
+
vector.vectorField,
|
|
457
|
+
vector.vector,
|
|
458
|
+
topK,
|
|
459
|
+
filter ?? null,
|
|
460
|
+
options as Object | undefined,
|
|
461
|
+
) as HybridSearchResult<T>[],
|
|
462
|
+
|
|
463
|
+
findNearest: (field, query, topK, filter) =>
|
|
464
|
+
native().findNearest(colName, field, query, topK, filter ?? null) as VectorSearchResult<T>[],
|
|
465
|
+
|
|
466
|
+
findNearestAsync: async (field, query, topK, filter) =>
|
|
467
|
+
(await native().findNearestAsync(
|
|
468
|
+
colName,
|
|
469
|
+
field,
|
|
470
|
+
query,
|
|
471
|
+
topK,
|
|
472
|
+
filter ?? null,
|
|
473
|
+
)) as VectorSearchResult<T>[],
|
|
474
|
+
|
|
475
|
+
createVectorIndex: (field, dimensions, options) =>
|
|
476
|
+
native().createVectorIndex(colName, field, dimensions, options as Object | undefined),
|
|
477
|
+
dropVectorIndex: (field) => native().dropVectorIndex(colName, field),
|
|
478
|
+
upgradeVectorIndex: (field) => native().upgradeVectorIndex(colName, field),
|
|
177
479
|
};
|
|
178
480
|
}
|
|
179
481
|
|
|
@@ -184,6 +486,12 @@ export function openDB(_dbName: string, options?: OpenDBOptions): DB {
|
|
|
184
486
|
collection: <T extends Document>(name: string) => collection<T>(name, webhook),
|
|
185
487
|
webhookStats: () => webhook?.stats() ?? { ...EMPTY_STATS },
|
|
186
488
|
flushWebhook: (timeoutMs) => webhook?.flush(timeoutMs) ?? Promise.resolve(true),
|
|
489
|
+
listCollectionNames: () => native().listCollectionNames(),
|
|
490
|
+
flush: () => native().flush(),
|
|
491
|
+
compact: () => native().compact(),
|
|
492
|
+
rebuildVectorIndexes: () => native().rebuildVectorIndexes(),
|
|
493
|
+
userVersion: () => native().userVersion(),
|
|
494
|
+
setUserVersion: (version) => native().setUserVersion(version),
|
|
187
495
|
close: async () => {
|
|
188
496
|
await webhook?.flush();
|
|
189
497
|
await NativeTalaDB.close();
|