@taladb/react-native 0.10.1 → 0.11.0
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/LICENSE-MIT +21 -0
- package/android/src/main/jniLibs/arm64-v8a/{libredb-cabe8e041f57653a.so → libredb-c8c61b1f6c018b08.so} +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libtaladb_ffi.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libredb-9ad37c880f82971f.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libtaladb_ffi.so +0 -0
- package/android/src/main/jniLibs/x86_64/{libredb-c48d0cacc11f2aba.so → libredb-5f8ad3451c0f8dea.so} +0 -0
- package/android/src/main/jniLibs/x86_64/libtaladb_ffi.so +0 -0
- package/cpp/TalaDBHostObject.cpp +2 -129
- package/cpp/taladb.h +2 -75
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/TalaDBHostObject.cpp +2 -129
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/taladb.h +2 -75
- package/ios/TalaDBFfi.xcframework/ios-arm64/libtaladb_ffi.a +0 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/TalaDBHostObject.cpp +2 -129
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/taladb.h +2 -75
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/libtaladb_ffi_sim.a +0 -0
- package/package.json +7 -2
- package/src/NativeTalaDB.ts +3 -27
- package/src/index.tsx +122 -92
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libredb-700774fab536b136.so +0 -0
- /package/{LICENSE → LICENSE-APACHE} +0 -0
|
@@ -38,7 +38,6 @@ TalaDBHostObject::TalaDBHostObject(TalaDbHandle *db) : db_(db) {}
|
|
|
38
38
|
|
|
39
39
|
TalaDBHostObject::~TalaDBHostObject() {
|
|
40
40
|
if (db_) {
|
|
41
|
-
taladb_sync_flush(db_, 5000);
|
|
42
41
|
taladb_close(db_);
|
|
43
42
|
db_ = nullptr;
|
|
44
43
|
}
|
|
@@ -241,14 +240,12 @@ Value TalaDBHostObject::awaitJobAsPromise(Runtime &rt, TalaDbJob *job, bool pars
|
|
|
241
240
|
std::vector<PropNameID> TalaDBHostObject::getPropertyNames(Runtime &rt) {
|
|
242
241
|
std::vector<std::string> names = {
|
|
243
242
|
"insert", "insertMany",
|
|
244
|
-
"replaceManyWithIds", "deleteManyWithIds",
|
|
245
243
|
"find", "findOne",
|
|
246
244
|
"updateOne", "updateMany",
|
|
247
245
|
"deleteOne", "deleteMany",
|
|
248
246
|
"count",
|
|
249
247
|
"aggregate",
|
|
250
|
-
"
|
|
251
|
-
"importChangesValidated", "quarantined",
|
|
248
|
+
"listCollectionNames",
|
|
252
249
|
"userVersion", "setUserVersion",
|
|
253
250
|
"flush",
|
|
254
251
|
"createIndex", "dropIndex",
|
|
@@ -259,7 +256,6 @@ std::vector<PropNameID> TalaDBHostObject::getPropertyNames(Runtime &rt) {
|
|
|
259
256
|
"searchText", "hybridSearch",
|
|
260
257
|
"findAsync",
|
|
261
258
|
"compact",
|
|
262
|
-
"syncStatus", "flushSync",
|
|
263
259
|
"close",
|
|
264
260
|
};
|
|
265
261
|
std::vector<PropNameID> result;
|
|
@@ -315,46 +311,6 @@ Value TalaDBHostObject::get(Runtime &rt, const PropNameID &propName) {
|
|
|
315
311
|
});
|
|
316
312
|
}
|
|
317
313
|
|
|
318
|
-
// ------------------------------------------------------------------
|
|
319
|
-
// replaceManyWithIds(collection: string, docs: object[], origin: string): string[]
|
|
320
|
-
// ------------------------------------------------------------------
|
|
321
|
-
if (name == "replaceManyWithIds") {
|
|
322
|
-
return Function::createFromHostFunction(
|
|
323
|
-
rt, PropNameID::forAscii(rt, "replaceManyWithIds"), 3,
|
|
324
|
-
[this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
325
|
-
if (count < 3) throw JSError(rt, "replaceManyWithIds requires 3 arguments");
|
|
326
|
-
auto col = args[0].getString(rt).utf8(rt);
|
|
327
|
-
auto docsJson = stringify(rt, args[1]);
|
|
328
|
-
auto origin = args[2].getString(rt).utf8(rt);
|
|
329
|
-
char *result = taladb_replace_many_with_ids(
|
|
330
|
-
db_, col.c_str(), docsJson.c_str(), origin.c_str());
|
|
331
|
-
if (!result) throw ffiError(rt, "taladb_replace_many_with_ids failed");
|
|
332
|
-
std::string json(result);
|
|
333
|
-
taladb_free_string(result);
|
|
334
|
-
return parse(rt, json);
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// ------------------------------------------------------------------
|
|
339
|
-
// deleteManyWithIds(collection: string, ids: string[], origin: string): number
|
|
340
|
-
// ------------------------------------------------------------------
|
|
341
|
-
if (name == "deleteManyWithIds") {
|
|
342
|
-
return Function::createFromHostFunction(
|
|
343
|
-
rt, PropNameID::forAscii(rt, "deleteManyWithIds"), 3,
|
|
344
|
-
[this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
345
|
-
if (count < 3) throw JSError(rt, "deleteManyWithIds requires 3 arguments");
|
|
346
|
-
auto col = args[0].getString(rt).utf8(rt);
|
|
347
|
-
auto idsJson = stringify(rt, args[1]);
|
|
348
|
-
auto origin = args[2].getString(rt).utf8(rt);
|
|
349
|
-
char *result = taladb_delete_many_with_ids(
|
|
350
|
-
db_, col.c_str(), idsJson.c_str(), origin.c_str());
|
|
351
|
-
if (!result) throw ffiError(rt, "taladb_delete_many_with_ids failed");
|
|
352
|
-
std::string json(result);
|
|
353
|
-
taladb_free_string(result);
|
|
354
|
-
return parse(rt, json);
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
|
|
358
314
|
// ------------------------------------------------------------------
|
|
359
315
|
// find(collection: string, filter: object | null): object[]
|
|
360
316
|
// ------------------------------------------------------------------
|
|
@@ -494,38 +450,8 @@ Value TalaDBHostObject::get(Runtime &rt, const PropNameID &propName) {
|
|
|
494
450
|
}
|
|
495
451
|
|
|
496
452
|
// ------------------------------------------------------------------
|
|
497
|
-
//
|
|
498
|
-
// (back JS db.sync(); the runtime-agnostic loop lives in taladb/src/sync.ts)
|
|
453
|
+
// Collection metadata
|
|
499
454
|
// ------------------------------------------------------------------
|
|
500
|
-
if (name == "exportChanges") {
|
|
501
|
-
return Function::createFromHostFunction(
|
|
502
|
-
rt, PropNameID::forAscii(rt, "exportChanges"), 2,
|
|
503
|
-
[this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
504
|
-
if (count < 2) throw JSError(rt, "exportChanges requires 2 arguments");
|
|
505
|
-
auto collectionsJson = stringify(rt, args[0]); // string[] → JSON array
|
|
506
|
-
double sinceMs = args[1].getNumber();
|
|
507
|
-
char *result = taladb_export_changes(db_, collectionsJson.c_str(), sinceMs);
|
|
508
|
-
if (!result) throw JSError(rt, "taladb_export_changes failed");
|
|
509
|
-
std::string json(result);
|
|
510
|
-
taladb_free_string(result);
|
|
511
|
-
// Return the changeset as an opaque string (not parsed) — the
|
|
512
|
-
// JS sync adapter passes it straight to the transport.
|
|
513
|
-
return String::createFromUtf8(rt, json);
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
if (name == "importChanges") {
|
|
518
|
-
return Function::createFromHostFunction(
|
|
519
|
-
rt, PropNameID::forAscii(rt, "importChanges"), 1,
|
|
520
|
-
[this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
521
|
-
if (count < 1) throw JSError(rt, "importChanges requires 1 argument");
|
|
522
|
-
auto changeset = args[0].getString(rt).utf8(rt);
|
|
523
|
-
int32_t n = taladb_import_changes(db_, changeset.c_str());
|
|
524
|
-
if (n < 0) throw JSError(rt, "taladb_import_changes failed");
|
|
525
|
-
return Value(static_cast<double>(n));
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
|
|
529
455
|
if (name == "listCollectionNames") {
|
|
530
456
|
return Function::createFromHostFunction(
|
|
531
457
|
rt, PropNameID::forAscii(rt, "listCollectionNames"), 0,
|
|
@@ -538,38 +464,6 @@ Value TalaDBHostObject::get(Runtime &rt, const PropNameID &propName) {
|
|
|
538
464
|
});
|
|
539
465
|
}
|
|
540
466
|
|
|
541
|
-
// ------------------------------------------------------------------
|
|
542
|
-
// Validate-on-import — importChangesValidated / quarantined
|
|
543
|
-
// ------------------------------------------------------------------
|
|
544
|
-
if (name == "importChangesValidated") {
|
|
545
|
-
return Function::createFromHostFunction(
|
|
546
|
-
rt, PropNameID::forAscii(rt, "importChangesValidated"), 2,
|
|
547
|
-
[this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
548
|
-
if (count < 2) throw JSError(rt, "importChangesValidated requires 2 arguments");
|
|
549
|
-
auto changeset = args[0].getString(rt).utf8(rt);
|
|
550
|
-
auto schemas = args[1].getString(rt).utf8(rt);
|
|
551
|
-
char *result = taladb_import_changes_validated(db_, changeset.c_str(), schemas.c_str());
|
|
552
|
-
if (!result) throw JSError(rt, "taladb_import_changes_validated failed");
|
|
553
|
-
std::string json(result);
|
|
554
|
-
taladb_free_string(result);
|
|
555
|
-
return parse(rt, json); // { applied, skipped, quarantined }
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
if (name == "quarantined") {
|
|
560
|
-
return Function::createFromHostFunction(
|
|
561
|
-
rt, PropNameID::forAscii(rt, "quarantined"), 1,
|
|
562
|
-
[this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
563
|
-
if (count < 1) throw JSError(rt, "quarantined requires 1 argument");
|
|
564
|
-
auto col = args[0].getString(rt).utf8(rt);
|
|
565
|
-
char *result = taladb_quarantined(db_, col.c_str());
|
|
566
|
-
if (!result) throw JSError(rt, "taladb_quarantined failed");
|
|
567
|
-
std::string json(result);
|
|
568
|
-
taladb_free_string(result);
|
|
569
|
-
return parse(rt, json); // [{ document, reason, changedAt }]
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
|
|
573
467
|
// ------------------------------------------------------------------
|
|
574
468
|
// Application migrations — userVersion / setUserVersion
|
|
575
469
|
// ------------------------------------------------------------------
|
|
@@ -866,26 +760,6 @@ Value TalaDBHostObject::get(Runtime &rt, const PropNameID &propName) {
|
|
|
866
760
|
});
|
|
867
761
|
}
|
|
868
762
|
|
|
869
|
-
if (name == "syncStatus") {
|
|
870
|
-
return Function::createFromHostFunction(
|
|
871
|
-
rt, PropNameID::forAscii(rt, "syncStatus"), 0,
|
|
872
|
-
[this](Runtime &rt, const Value &, const Value *, size_t) -> Value {
|
|
873
|
-
char *raw = taladb_sync_status(db_);
|
|
874
|
-
if (!raw) throw ffiError(rt, "taladb_sync_status failed");
|
|
875
|
-
std::string json(raw); taladb_free_string(raw);
|
|
876
|
-
return parse(rt, json);
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
if (name == "flushSync") {
|
|
881
|
-
return Function::createFromHostFunction(
|
|
882
|
-
rt, PropNameID::forAscii(rt, "flushSync"), 1,
|
|
883
|
-
[this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
|
|
884
|
-
uint64_t timeout = count && args[0].isNumber() ? (uint64_t)args[0].getNumber() : 5000;
|
|
885
|
-
return Value(taladb_sync_flush(db_, timeout) == 1);
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
|
|
889
763
|
// ------------------------------------------------------------------
|
|
890
764
|
// close(): void (synchronous — the destructor does the real work)
|
|
891
765
|
// ------------------------------------------------------------------
|
|
@@ -894,7 +768,6 @@ Value TalaDBHostObject::get(Runtime &rt, const PropNameID &propName) {
|
|
|
894
768
|
rt, PropNameID::forAscii(rt, "close"), 0,
|
|
895
769
|
[this](Runtime &rt, const Value &, const Value *, size_t) -> Value {
|
|
896
770
|
if (db_) {
|
|
897
|
-
taladb_sync_flush(db_, 5000);
|
|
898
771
|
taladb_close(db_);
|
|
899
772
|
db_ = nullptr;
|
|
900
773
|
}
|
|
@@ -38,9 +38,9 @@ typedef struct TalaDbHandle TalaDbHandle;
|
|
|
38
38
|
TalaDbHandle *taladb_open(const char *path);
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Open (or create) a database with
|
|
41
|
+
* Open (or create) a database with durability/encryption configuration.
|
|
42
42
|
*
|
|
43
|
-
* config_json — JSON-serialised TalaDbConfig, or NULL
|
|
43
|
+
* config_json — JSON-serialised TalaDbConfig, or NULL for defaults.
|
|
44
44
|
* Returns an opaque handle (same semantics as taladb_open), or NULL on failure.
|
|
45
45
|
*/
|
|
46
46
|
TalaDbHandle *taladb_open_with_config(const char *path, const char *config_json);
|
|
@@ -79,39 +79,6 @@ char *taladb_insert_many(TalaDbHandle *handle,
|
|
|
79
79
|
const char *collection,
|
|
80
80
|
const char *docs_json);
|
|
81
81
|
|
|
82
|
-
/* -------------------------------------------------------------------------
|
|
83
|
-
* Replication writes — id-addressed upsert / delete
|
|
84
|
-
* ---------------------------------------------------------------------- */
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Upsert many documents by caller-supplied `_id`, in one commit.
|
|
88
|
-
*
|
|
89
|
-
* Unlike taladb_insert_many(), which discards `_id` and mints a fresh ULID, this
|
|
90
|
-
* honours the id on each document — which is what makes a replication upsert
|
|
91
|
-
* idempotent across repeated fetches of the same remote row.
|
|
92
|
-
*
|
|
93
|
-
* `origin` is "remote" (authoritative rows replicated in from an origin) or
|
|
94
|
-
* "local" (ordinary user writes). Remote rows are marked so they never replicate
|
|
95
|
-
* back out.
|
|
96
|
-
*
|
|
97
|
-
* Returns a JSON array of ULID strings, or NULL on error.
|
|
98
|
-
* Caller must free with taladb_free_string().
|
|
99
|
-
*/
|
|
100
|
-
char *taladb_replace_many_with_ids(TalaDbHandle *handle,
|
|
101
|
-
const char *collection,
|
|
102
|
-
const char *docs_json,
|
|
103
|
-
const char *origin);
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Delete many documents by id, in one commit.
|
|
107
|
-
* Returns a JSON number (the count removed), or NULL on error.
|
|
108
|
-
* Caller must free with taladb_free_string().
|
|
109
|
-
*/
|
|
110
|
-
char *taladb_delete_many_with_ids(TalaDbHandle *handle,
|
|
111
|
-
const char *collection,
|
|
112
|
-
const char *ids_json,
|
|
113
|
-
const char *origin);
|
|
114
|
-
|
|
115
82
|
/* -------------------------------------------------------------------------
|
|
116
83
|
* Find
|
|
117
84
|
* ---------------------------------------------------------------------- */
|
|
@@ -187,49 +154,12 @@ char *taladb_aggregate(TalaDbHandle *handle,
|
|
|
187
154
|
const char *collection,
|
|
188
155
|
const char *pipeline_json);
|
|
189
156
|
|
|
190
|
-
/* -------------------------------------------------------------------------
|
|
191
|
-
* Bidirectional sync — changeset export / import (backs JS db.sync())
|
|
192
|
-
* ---------------------------------------------------------------------- */
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Export a changeset for the collections in collections_json (a JSON array of
|
|
196
|
-
* names) with changed_at > since_ms. Returns a JSON string, or NULL on error.
|
|
197
|
-
* Caller must free with taladb_free_string().
|
|
198
|
-
*/
|
|
199
|
-
char *taladb_export_changes(TalaDbHandle *handle,
|
|
200
|
-
const char *collections_json,
|
|
201
|
-
double since_ms);
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Merge a JSON changeset (from a remote peer) via Last-Write-Wins.
|
|
205
|
-
* Returns the number of documents changed, or -1 on error.
|
|
206
|
-
*/
|
|
207
|
-
int32_t taladb_import_changes(TalaDbHandle *handle,
|
|
208
|
-
const char *changeset_json);
|
|
209
|
-
|
|
210
157
|
/**
|
|
211
158
|
* User collection names (reserved names excluded) as a JSON array string.
|
|
212
159
|
* Returns NULL on error. Caller must free with taladb_free_string().
|
|
213
160
|
*/
|
|
214
161
|
char *taladb_list_collection_names(TalaDbHandle *handle);
|
|
215
162
|
|
|
216
|
-
/**
|
|
217
|
-
* Merge a JSON changeset through a tolerant structural validator built from
|
|
218
|
-
* schemas_json ({ "<collection>": { version, required, types, defaults,
|
|
219
|
-
* renames } }). Returns a JSON "{ applied, skipped, quarantined }" string, or
|
|
220
|
-
* NULL on error. Caller must free with taladb_free_string().
|
|
221
|
-
*/
|
|
222
|
-
char *taladb_import_changes_validated(TalaDbHandle *handle,
|
|
223
|
-
const char *changeset_json,
|
|
224
|
-
const char *schemas_json);
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Documents set aside in a collection's quarantine table by a validated import,
|
|
228
|
-
* as a JSON array of { document, reason, changedAt }. NULL on error. Caller
|
|
229
|
-
* must free with taladb_free_string().
|
|
230
|
-
*/
|
|
231
|
-
char *taladb_quarantined(TalaDbHandle *handle, const char *collection);
|
|
232
|
-
|
|
233
163
|
/**
|
|
234
164
|
* Read / write the application migration version (backs openDB({ migrations })).
|
|
235
165
|
* taladb_user_version returns the version (0 if unset) or -1 on error;
|
|
@@ -320,9 +250,6 @@ char *taladb_hybrid_search(TalaDbHandle *handle,
|
|
|
320
250
|
const char *filter_json,
|
|
321
251
|
const char *options_json);
|
|
322
252
|
|
|
323
|
-
char *taladb_sync_status(TalaDbHandle *handle);
|
|
324
|
-
int32_t taladb_sync_flush(TalaDbHandle *handle, uint64_t timeout_ms);
|
|
325
|
-
|
|
326
253
|
/* -------------------------------------------------------------------------
|
|
327
254
|
* Async job API — run heavy queries on a background thread.
|
|
328
255
|
*
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taladb/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "TalaDB React Native module — document and vector database via JSI HostObject",
|
|
5
5
|
"main": "src/index",
|
|
6
6
|
"types": "src/index.tsx",
|
|
7
7
|
"files": [
|
|
8
|
+
"LICENSE-APACHE",
|
|
9
|
+
"LICENSE-MIT",
|
|
8
10
|
"src/",
|
|
9
11
|
"cpp/",
|
|
10
12
|
"ios/",
|
|
@@ -33,7 +35,7 @@
|
|
|
33
35
|
"engines": {
|
|
34
36
|
"node": ">=18"
|
|
35
37
|
},
|
|
36
|
-
"license": "Apache-2.0",
|
|
38
|
+
"license": "MIT OR Apache-2.0",
|
|
37
39
|
"codegenConfig": {
|
|
38
40
|
"name": "TalaDB",
|
|
39
41
|
"type": "modules",
|
|
@@ -46,6 +48,9 @@
|
|
|
46
48
|
"typescript": "^5.9.3",
|
|
47
49
|
"react-native": "^0.83.0"
|
|
48
50
|
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"taladb": "0.11.0"
|
|
53
|
+
},
|
|
49
54
|
"scripts": {
|
|
50
55
|
"typecheck": "tsc --noEmit",
|
|
51
56
|
"build:ios": "sh scripts/build-ios.sh",
|
package/src/NativeTalaDB.ts
CHANGED
|
@@ -13,8 +13,7 @@ export interface Spec extends TurboModule {
|
|
|
13
13
|
* Open (or create) a TalaDB database file at the platform default path.
|
|
14
14
|
* Must be called once at app startup before using `collection()`.
|
|
15
15
|
*
|
|
16
|
-
* @param configJson
|
|
17
|
-
* HTTP push sync. When omitted, sync is disabled.
|
|
16
|
+
* @param configJson Optional JSON-serialised durability/encryption config.
|
|
18
17
|
*/
|
|
19
18
|
initialize(dbName: string, configJson?: string): Promise<void>;
|
|
20
19
|
|
|
@@ -25,35 +24,12 @@ export interface Spec extends TurboModule {
|
|
|
25
24
|
// Collection CRUD — all methods are synchronous via JSI
|
|
26
25
|
// ------------------------------------------------------------------
|
|
27
26
|
|
|
28
|
-
/** Insert a document.
|
|
27
|
+
/** Insert a document. Honours a supplied `_id`, otherwise creates a ULID. */
|
|
29
28
|
insert(collection: string, doc: Object): string;
|
|
30
29
|
|
|
31
|
-
/** Insert multiple documents
|
|
30
|
+
/** Insert multiple documents, honouring any supplied `_id` values. */
|
|
32
31
|
insertMany(collection: string, docs: Object[]): string[];
|
|
33
32
|
|
|
34
|
-
/**
|
|
35
|
-
* Upsert many documents **by caller-supplied `_id`**, in one commit.
|
|
36
|
-
*
|
|
37
|
-
* Unlike `insertMany`, which discards `_id` and mints a fresh ULID, this honours
|
|
38
|
-
* the id on each document — which is what makes a replication upsert idempotent
|
|
39
|
-
* across repeated fetches of the same remote row.
|
|
40
|
-
*
|
|
41
|
-
* `origin` is `'remote'` for authoritative rows replicated in from an origin, or
|
|
42
|
-
* `'local'` for ordinary user writes.
|
|
43
|
-
*/
|
|
44
|
-
replaceManyWithIds(
|
|
45
|
-
collection: string,
|
|
46
|
-
docs: Object[],
|
|
47
|
-
origin: 'local' | 'remote',
|
|
48
|
-
): string[];
|
|
49
|
-
|
|
50
|
-
/** Delete many documents by id, in one commit. Returns the number removed. */
|
|
51
|
-
deleteManyWithIds(
|
|
52
|
-
collection: string,
|
|
53
|
-
ids: string[],
|
|
54
|
-
origin: 'local' | 'remote',
|
|
55
|
-
): number;
|
|
56
|
-
|
|
57
33
|
/** Find documents matching the filter. */
|
|
58
34
|
find(collection: string, filter: Object | null): Object[];
|
|
59
35
|
|
package/src/index.tsx
CHANGED
|
@@ -1,71 +1,32 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* await TalaDBModule.initialize('myapp.db');
|
|
10
|
-
*
|
|
11
|
-
* // Anywhere in the app — same API as browser
|
|
12
|
-
* const db = openDB('myapp.db');
|
|
13
|
-
* const users = db.collection<User>('users');
|
|
14
|
-
* const id = users.insert({ name: 'Alice', age: 30 });
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* All operations are **synchronous** via JSI — no async/await needed
|
|
18
|
-
* after initialization.
|
|
19
|
-
*/
|
|
1
|
+
/** TalaDB React Native public API. CRUD is synchronous through the JSI host. */
|
|
2
|
+
import {
|
|
3
|
+
createWebhookDispatcher,
|
|
4
|
+
type WebhookConfig,
|
|
5
|
+
type WebhookDispatcher,
|
|
6
|
+
type WebhookEvent,
|
|
7
|
+
type WebhookStats,
|
|
8
|
+
} from 'taladb';
|
|
20
9
|
import NativeTalaDB from './NativeTalaDB';
|
|
21
10
|
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
// Module-level helpers
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
|
|
26
11
|
export const TalaDBModule = {
|
|
27
|
-
/**
|
|
28
|
-
* Open (or create) the database. Call once at app startup.
|
|
29
|
-
*
|
|
30
|
-
* @param configJson Optional JSON-serialised `TalaDbConfig` for HTTP push
|
|
31
|
-
* sync. Example: `JSON.stringify({ sync: { enabled: true,
|
|
32
|
-
* endpoint: 'https://api.example.com/events' } })`.
|
|
33
|
-
*/
|
|
12
|
+
/** Open the native database. The config controls durability/encryption only. */
|
|
34
13
|
initialize: (dbName: string, configJson?: string) =>
|
|
35
14
|
NativeTalaDB.initialize(dbName, configJson),
|
|
36
|
-
/** Close the database gracefully. */
|
|
37
15
|
close: () => NativeTalaDB.close(),
|
|
38
|
-
/** HTTP push events dropped by backpressure or failed after retries. */
|
|
39
|
-
syncStatus: () => native().syncStatus(),
|
|
40
|
-
/** Wait for HTTP push work accepted before this call. */
|
|
41
|
-
flushSync: (timeoutMs = 5000) => native().flushSync(timeoutMs),
|
|
42
16
|
};
|
|
43
17
|
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// Collection handle
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
|
|
48
18
|
export interface Document {
|
|
49
19
|
_id?: string;
|
|
50
20
|
[key: string]: unknown;
|
|
51
21
|
}
|
|
52
22
|
|
|
23
|
+
export type InsertDocument<T extends Document> = Omit<T, '_id'> & { _id?: string };
|
|
53
24
|
export type Filter = Record<string, unknown>;
|
|
54
25
|
export type Update = Record<string, unknown>;
|
|
55
26
|
|
|
56
27
|
export interface Collection<T extends Document = Document> {
|
|
57
|
-
insert(doc:
|
|
58
|
-
insertMany(docs:
|
|
59
|
-
/**
|
|
60
|
-
* Upsert many documents **by `_id`**, in one commit. Requires an `_id` on every
|
|
61
|
-
* document — for replicated rows that comes from `deriveDocId(collection, key)`.
|
|
62
|
-
*
|
|
63
|
-
* `origin: 'remote'` marks rows as replicated in from an authoritative origin so
|
|
64
|
-
* they are never replicated back out; it defaults to `'local'`.
|
|
65
|
-
*/
|
|
66
|
-
replaceManyWithIds(docs: T[], origin?: 'local' | 'remote'): string[];
|
|
67
|
-
/** Delete many documents by id, in one commit. Returns the number removed. */
|
|
68
|
-
deleteManyWithIds(ids: string[], origin?: 'local' | 'remote'): number;
|
|
28
|
+
insert(doc: InsertDocument<T>): string;
|
|
29
|
+
insertMany(docs: InsertDocument<T>[]): string[];
|
|
69
30
|
find(filter?: Filter): T[];
|
|
70
31
|
findOne(filter: Filter): T | null;
|
|
71
32
|
updateOne(filter: Filter, update: Update): boolean;
|
|
@@ -79,26 +40,21 @@ export interface Collection<T extends Document = Document> {
|
|
|
79
40
|
dropFtsIndex(field: string): void;
|
|
80
41
|
}
|
|
81
42
|
|
|
43
|
+
export interface OpenDBOptions {
|
|
44
|
+
/** Runtime-agnostic outbound change webhook, delivered with global `fetch`. */
|
|
45
|
+
webhook?: WebhookConfig;
|
|
46
|
+
}
|
|
47
|
+
|
|
82
48
|
export interface DB {
|
|
83
49
|
collection<T extends Document = Document>(name: string): Collection<T>;
|
|
84
|
-
|
|
85
|
-
|
|
50
|
+
webhookStats(): WebhookStats;
|
|
51
|
+
flushWebhook(timeoutMs?: number): Promise<boolean>;
|
|
86
52
|
close(): Promise<void>;
|
|
87
53
|
}
|
|
88
54
|
|
|
89
55
|
interface JsiTalaDB {
|
|
90
56
|
insert(collection: string, doc: Object): string;
|
|
91
57
|
insertMany(collection: string, docs: Object[]): string[];
|
|
92
|
-
replaceManyWithIds(
|
|
93
|
-
collection: string,
|
|
94
|
-
docs: Object[],
|
|
95
|
-
origin: 'local' | 'remote',
|
|
96
|
-
): string[];
|
|
97
|
-
deleteManyWithIds(
|
|
98
|
-
collection: string,
|
|
99
|
-
ids: string[],
|
|
100
|
-
origin: 'local' | 'remote',
|
|
101
|
-
): number;
|
|
102
58
|
find(collection: string, filter: Object | null): Object[];
|
|
103
59
|
findOne(collection: string, filter: Object | null): Object | null;
|
|
104
60
|
updateOne(collection: string, filter: Object, update: Object): boolean;
|
|
@@ -110,8 +66,6 @@ interface JsiTalaDB {
|
|
|
110
66
|
dropIndex(collection: string, field: string): void;
|
|
111
67
|
createFtsIndex(collection: string, field: string): void;
|
|
112
68
|
dropFtsIndex(collection: string, field: string): void;
|
|
113
|
-
syncStatus(): { dropped: number; failed: number };
|
|
114
|
-
flushSync(timeoutMs?: number): boolean;
|
|
115
69
|
}
|
|
116
70
|
|
|
117
71
|
function native(): JsiTalaDB {
|
|
@@ -120,31 +74,102 @@ function native(): JsiTalaDB {
|
|
|
120
74
|
return host;
|
|
121
75
|
}
|
|
122
76
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
77
|
+
const EMPTY_STATS: WebhookStats = { pending: 0, delivered: 0, failed: 0, dropped: 0 };
|
|
78
|
+
|
|
79
|
+
function emitPostImages<T extends Document>(
|
|
80
|
+
webhook: WebhookDispatcher | null,
|
|
81
|
+
collection: string,
|
|
82
|
+
ids: string[],
|
|
83
|
+
op: 'insert' | 'update',
|
|
84
|
+
committedAt: number,
|
|
85
|
+
): void {
|
|
86
|
+
if (!webhook?.reports(collection) || ids.length === 0) return;
|
|
87
|
+
const docs = native().find(collection, { _id: { $in: ids } }) as T[];
|
|
88
|
+
const byId = new Map(docs.map((doc) => [doc._id, doc]));
|
|
89
|
+
for (const id of ids) {
|
|
90
|
+
const document = byId.get(id);
|
|
91
|
+
if (document) webhook.emit({ op, collection, id, document, committedAt } as WebhookEvent);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function emitDeletes<T extends Document>(
|
|
96
|
+
webhook: WebhookDispatcher | null,
|
|
97
|
+
collection: string,
|
|
98
|
+
docs: T[],
|
|
99
|
+
committedAt: number,
|
|
100
|
+
): void {
|
|
101
|
+
if (!webhook?.reports(collection)) return;
|
|
102
|
+
for (const document of docs) {
|
|
103
|
+
if (typeof document._id !== 'string') continue;
|
|
104
|
+
// DELETE carries the pre-image: after commit there is no post-image to read.
|
|
105
|
+
webhook.emit({
|
|
106
|
+
op: 'delete',
|
|
107
|
+
collection,
|
|
108
|
+
id: document._id,
|
|
109
|
+
document,
|
|
110
|
+
committedAt,
|
|
111
|
+
} as WebhookEvent);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
126
114
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
* this function.
|
|
132
|
-
*/
|
|
133
|
-
function collection<T extends Document>(colName: string): Collection<T> {
|
|
115
|
+
function collection<T extends Document>(
|
|
116
|
+
colName: string,
|
|
117
|
+
webhook: WebhookDispatcher | null,
|
|
118
|
+
): Collection<T> {
|
|
134
119
|
return {
|
|
135
|
-
insert
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
120
|
+
insert(doc) {
|
|
121
|
+
const id = native().insert(colName, doc as Object);
|
|
122
|
+
const committedAt = Date.now();
|
|
123
|
+
emitPostImages<T>(webhook, colName, [id], 'insert', committedAt);
|
|
124
|
+
return id;
|
|
125
|
+
},
|
|
126
|
+
insertMany(docs) {
|
|
127
|
+
const ids = native().insertMany(colName, docs as Object[]);
|
|
128
|
+
const committedAt = Date.now();
|
|
129
|
+
emitPostImages<T>(webhook, colName, ids, 'insert', committedAt);
|
|
130
|
+
return ids;
|
|
131
|
+
},
|
|
132
|
+
find: (filter) => native().find(colName, filter ?? null) as T[],
|
|
142
133
|
findOne: (filter) => native().findOne(colName, filter) as T | null,
|
|
143
|
-
updateOne
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
134
|
+
updateOne(filter, update) {
|
|
135
|
+
const before = native().findOne(colName, filter) as T | null;
|
|
136
|
+
const changed = native().updateOne(colName, filter, update);
|
|
137
|
+
const committedAt = Date.now();
|
|
138
|
+
if (changed && typeof before?._id === 'string') {
|
|
139
|
+
emitPostImages<T>(webhook, colName, [before._id], 'update', committedAt);
|
|
140
|
+
}
|
|
141
|
+
return changed;
|
|
142
|
+
},
|
|
143
|
+
updateMany(filter, update) {
|
|
144
|
+
const before = native().find(colName, filter) as T[];
|
|
145
|
+
const changed = native().updateMany(colName, filter, update);
|
|
146
|
+
const committedAt = Date.now();
|
|
147
|
+
if (changed > 0) {
|
|
148
|
+
emitPostImages<T>(
|
|
149
|
+
webhook,
|
|
150
|
+
colName,
|
|
151
|
+
before.map((doc) => doc._id).filter((id): id is string => typeof id === 'string'),
|
|
152
|
+
'update',
|
|
153
|
+
committedAt,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return changed;
|
|
157
|
+
},
|
|
158
|
+
deleteOne(filter) {
|
|
159
|
+
const before = native().findOne(colName, filter) as T | null;
|
|
160
|
+
const deleted = native().deleteOne(colName, filter);
|
|
161
|
+
const committedAt = Date.now();
|
|
162
|
+
if (deleted && before) emitDeletes(webhook, colName, [before], committedAt);
|
|
163
|
+
return deleted;
|
|
164
|
+
},
|
|
165
|
+
deleteMany(filter) {
|
|
166
|
+
const before = native().find(colName, filter) as T[];
|
|
167
|
+
const deleted = native().deleteMany(colName, filter);
|
|
168
|
+
const committedAt = Date.now();
|
|
169
|
+
if (deleted > 0) emitDeletes(webhook, colName, before, committedAt);
|
|
170
|
+
return deleted;
|
|
171
|
+
},
|
|
172
|
+
count: (filter) => native().count(colName, filter ?? null),
|
|
148
173
|
createIndex: (field) => native().createIndex(colName, field),
|
|
149
174
|
dropIndex: (field) => native().dropIndex(colName, field),
|
|
150
175
|
createFtsIndex: (field) => native().createFtsIndex(colName, field),
|
|
@@ -152,11 +177,16 @@ function collection<T extends Document>(colName: string): Collection<T> {
|
|
|
152
177
|
};
|
|
153
178
|
}
|
|
154
179
|
|
|
155
|
-
|
|
180
|
+
/** Get a synchronous DB handle after `TalaDBModule.initialize(dbName)`. */
|
|
181
|
+
export function openDB(_dbName: string, options?: OpenDBOptions): DB {
|
|
182
|
+
const webhook = createWebhookDispatcher(options?.webhook);
|
|
156
183
|
return {
|
|
157
|
-
collection,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
close: () =>
|
|
184
|
+
collection: <T extends Document>(name: string) => collection<T>(name, webhook),
|
|
185
|
+
webhookStats: () => webhook?.stats() ?? { ...EMPTY_STATS },
|
|
186
|
+
flushWebhook: (timeoutMs) => webhook?.flush(timeoutMs) ?? Promise.resolve(true),
|
|
187
|
+
close: async () => {
|
|
188
|
+
await webhook?.flush();
|
|
189
|
+
await NativeTalaDB.close();
|
|
190
|
+
},
|
|
161
191
|
};
|
|
162
192
|
}
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|