@taladb/react-native 0.4.0 → 0.6.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.
@@ -23,7 +23,6 @@ package com.taladb
23
23
 
24
24
  import com.facebook.react.bridge.*
25
25
  import com.facebook.react.module.annotations.ReactModule
26
- import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
27
26
 
28
27
  @ReactModule(name = TalaDBModule.NAME)
29
28
  class TalaDBModule(private val reactContext: ReactApplicationContext) :
@@ -33,9 +32,11 @@ class TalaDBModule(private val reactContext: ReactApplicationContext) :
33
32
  const val NAME = "TalaDB"
34
33
 
35
34
  init {
36
- // libtaladb_ffi.so is built by CMakeLists.txt (see android/).
37
- // It bundles both the C++ JSI HostObject and the Rust FFI crate.
35
+ // libtaladb_ffi.so is the pre-built Rust crate (jniLibs/).
36
+ // libtaladb_jsi.so wraps the C++ JSI HostObject and links taladb_ffi.
37
+ // Load ffi first so the dynamic linker can resolve it when jsi loads.
38
38
  System.loadLibrary("taladb_ffi")
39
+ System.loadLibrary("taladb_jsi")
39
40
  }
40
41
  }
41
42
 
@@ -50,24 +51,23 @@ class TalaDBModule(private val reactContext: ReactApplicationContext) :
50
51
  * JSI runtime identified by [jsContextNativePtr].
51
52
  * Called once from [initialize].
52
53
  */
53
- private external fun nativeInstall(jsContextNativePtr: Long, dbPath: String)
54
+ private external fun nativeInstall(jsContextNativePtr: Long, dbPath: String, configJson: String?)
54
55
 
55
56
  // -----------------------------------------------------------------------
56
- // TurboModule: initialize(dbName) → Promise<void>
57
+ // TurboModule: initialize(dbName, configJson?) → Promise<void>
57
58
  // -----------------------------------------------------------------------
58
59
 
59
- override fun initialize(dbName: String, promise: Promise) {
60
+ override fun initialize(dbName: String, configJson: String?, promise: Promise) {
60
61
  try {
61
62
  val dbPath = reactContext.filesDir.absolutePath + "/$dbName"
62
63
 
63
- val jsCallInvokerHolder = reactContext.catalystInstance
64
- .jsCallInvokerHolder as CallInvokerHolderImpl
65
- val jsContextPtr = jsCallInvokerHolder.nativeCallInvoker
64
+ // javaScriptContextHolder.get() returns the raw jsi::Runtime* pointer.
65
+ val jsContextPtr = reactContext.javaScriptContextHolder!!.get()
66
66
 
67
67
  // Install on the JS thread
68
68
  reactContext.runOnJSQueueThread {
69
69
  try {
70
- nativeInstall(jsContextPtr, dbPath)
70
+ nativeInstall(jsContextPtr, dbPath, configJson)
71
71
  promise.resolve(null)
72
72
  } catch (e: Exception) {
73
73
  promise.reject("TALADB_INSTALL_ERROR", e.message, e)
package/cpp/TalaDBJni.cpp CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * TalaDB JNI glue — Android only.
3
3
  *
4
- * Exposes `nativeInstall(jsContextNativePtr, dbPath)` to Kotlin so that
5
- * `TalaDBModule.kt` can install the JSI HostObject from the JS thread.
4
+ * Exposes `nativeInstall(jsContextNativePtr, dbPath, configJson)` to Kotlin so
5
+ * that `TalaDBModule.kt` can install the JSI HostObject from the JS thread.
6
6
  *
7
7
  * The function signature must match the Kotlin `external fun` declaration:
8
8
  * package : com.taladb
9
9
  * class : TalaDBModule
10
- * method : nativeInstall(Long, String)
10
+ * method : nativeInstall(Long, String, String?)
11
11
  *
12
12
  * CMakeLists.txt compiles this file together with TalaDBHostObject.cpp.
13
13
  */
@@ -26,15 +26,23 @@ Java_com_taladb_TalaDBModule_nativeInstall(
26
26
  JNIEnv *env,
27
27
  jobject /* thiz */,
28
28
  jlong jsContextNativePtr,
29
- jstring dbPathJ)
29
+ jstring dbPathJ,
30
+ jstring configJsonJ)
30
31
  {
31
32
  // Resolve db path
32
33
  const char *dbPathC = env->GetStringUTFChars(dbPathJ, nullptr);
33
34
  std::string dbPath(dbPathC);
34
35
  env->ReleaseStringUTFChars(dbPathJ, dbPathC);
35
36
 
36
- // Open the Rust database
37
- TalaDbHandle *db = taladb_open(dbPath.c_str());
37
+ // Open the Rust database — use taladb_open_with_config when config provided
38
+ TalaDbHandle *db = nullptr;
39
+ if (configJsonJ != nullptr) {
40
+ const char *configC = env->GetStringUTFChars(configJsonJ, nullptr);
41
+ db = taladb_open_with_config(dbPath.c_str(), configC);
42
+ env->ReleaseStringUTFChars(configJsonJ, configC);
43
+ } else {
44
+ db = taladb_open(dbPath.c_str());
45
+ }
38
46
  if (!db) return; // failed to open — JS will see no __TalaDB__ global
39
47
 
40
48
  // Get the JSI runtime from the pointer passed by RN internals
package/cpp/taladb.h CHANGED
@@ -37,6 +37,14 @@ typedef struct TalaDbHandle TalaDbHandle;
37
37
  /** Open (or create) a database at the given file-system path. */
38
38
  TalaDbHandle *taladb_open(const char *path);
39
39
 
40
+ /**
41
+ * Open (or create) a database with HTTP push sync configuration.
42
+ *
43
+ * config_json — JSON-serialised TalaDbConfig, or NULL to open without sync.
44
+ * Returns an opaque handle (same semantics as taladb_open), or NULL on failure.
45
+ */
46
+ TalaDbHandle *taladb_open_with_config(const char *path, const char *config_json);
47
+
40
48
  /** Flush and close the database, freeing the handle. */
41
49
  void taladb_close(TalaDbHandle *handle);
42
50
 
package/ios/TalaDB.mm CHANGED
@@ -3,11 +3,10 @@
3
3
  *
4
4
  * Build setup (Xcode / CocoaPods)
5
5
  * --------------------------------
6
- * 1. Run `cargo build --target aarch64-apple-ios --release` (device) and
7
- * `cargo build --target x86_64-apple-ios --release` (simulator), then
8
- * `lipo` them into a universal `libtaladb_ffi.a`.
9
- * 2. The podspec links the fat archive and adds `cpp/` to the header search
10
- * paths — both are handled automatically when using the podspec.
6
+ * 1. Run `scripts/build-ios.sh` (or the release CI) to produce
7
+ * `ios/TalaDBFfi.xcframework` device (arm64) + simulator (arm64 + x86_64).
8
+ * 2. The podspec declares `vendored_frameworks` pointing to that xcframework.
9
+ * Headers and link flags are handled automatically by CocoaPods.
11
10
  *
12
11
  * Runtime flow
13
12
  * ------------
@@ -53,13 +52,19 @@ RCT_EXPORT_MODULE(TalaDB)
53
52
  // ---- Class method: open DB and install the JSI HostObject ----------------
54
53
 
55
54
  + (void)installInRuntime:(facebook::jsi::Runtime &)rt
56
- dbPath:(NSString *)path {
55
+ dbPath:(NSString *)path
56
+ configJson:(NSString * _Nullable)configJson {
57
57
  if (gHandle) {
58
58
  taladb_close(gHandle);
59
59
  gHandle = nullptr;
60
60
  }
61
61
 
62
- gHandle = taladb_open(path.UTF8String);
62
+ if (configJson != nil) {
63
+ gHandle = taladb_open_with_config(path.UTF8String, configJson.UTF8String);
64
+ } else {
65
+ gHandle = taladb_open(path.UTF8String);
66
+ }
67
+
63
68
  if (!gHandle) {
64
69
  NSLog(@"[TalaDB] Failed to open database at %@", path);
65
70
  return;
@@ -72,6 +77,7 @@ RCT_EXPORT_MODULE(TalaDB)
72
77
  // ---- initialize(dbName) → Promise<void> ---------------------------------
73
78
 
74
79
  RCT_EXPORT_METHOD(initialize:(NSString *)dbName
80
+ configJson:(NSString * _Nullable)configJson
75
81
  resolve:(RCTPromiseResolveBlock)resolve
76
82
  reject:(RCTPromiseRejectBlock)reject) {
77
83
  @try {
@@ -86,9 +92,9 @@ RCT_EXPORT_METHOD(initialize:(NSString *)dbName
86
92
  }
87
93
 
88
94
  // Install the HostObject on the JS thread
89
- bridge.jsCallInvoker->invokeAsync([bridge, dbPath]() {
95
+ bridge.jsCallInvoker->invokeAsync([bridge, dbPath, configJson]() {
90
96
  auto &rt = *(Runtime *)bridge.runtime;
91
- [TalaDB installInRuntime:rt dbPath:dbPath];
97
+ [TalaDB installInRuntime:rt dbPath:dbPath configJson:configJson];
92
98
  });
93
99
 
94
100
  resolve(nil);
@@ -0,0 +1,48 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>AvailableLibraries</key>
6
+ <array>
7
+ <dict>
8
+ <key>BinaryPath</key>
9
+ <string>libtaladb_ffi.a</string>
10
+ <key>HeadersPath</key>
11
+ <string>Headers</string>
12
+ <key>LibraryIdentifier</key>
13
+ <string>ios-arm64</string>
14
+ <key>LibraryPath</key>
15
+ <string>libtaladb_ffi.a</string>
16
+ <key>SupportedArchitectures</key>
17
+ <array>
18
+ <string>arm64</string>
19
+ </array>
20
+ <key>SupportedPlatform</key>
21
+ <string>ios</string>
22
+ </dict>
23
+ <dict>
24
+ <key>BinaryPath</key>
25
+ <string>libtaladb_ffi_sim.a</string>
26
+ <key>HeadersPath</key>
27
+ <string>Headers</string>
28
+ <key>LibraryIdentifier</key>
29
+ <string>ios-arm64_x86_64-simulator</string>
30
+ <key>LibraryPath</key>
31
+ <string>libtaladb_ffi_sim.a</string>
32
+ <key>SupportedArchitectures</key>
33
+ <array>
34
+ <string>arm64</string>
35
+ <string>x86_64</string>
36
+ </array>
37
+ <key>SupportedPlatform</key>
38
+ <string>ios</string>
39
+ <key>SupportedPlatformVariant</key>
40
+ <string>simulator</string>
41
+ </dict>
42
+ </array>
43
+ <key>CFBundlePackageType</key>
44
+ <string>XFWK</string>
45
+ <key>XCFrameworkFormatVersion</key>
46
+ <string>1.0</string>
47
+ </dict>
48
+ </plist>
@@ -0,0 +1,285 @@
1
+ #include "TalaDBHostObject.h"
2
+
3
+ #include <stdexcept>
4
+ #include <vector>
5
+
6
+ using namespace facebook::jsi;
7
+
8
+ namespace taladb {
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Constructor / Destructor
12
+ // ---------------------------------------------------------------------------
13
+
14
+ TalaDBHostObject::TalaDBHostObject(TalaDbHandle *db) : db_(db) {}
15
+
16
+ TalaDBHostObject::~TalaDBHostObject() {
17
+ if (db_) {
18
+ taladb_close(db_);
19
+ db_ = nullptr;
20
+ }
21
+ }
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Static installer
25
+ // ---------------------------------------------------------------------------
26
+
27
+ void TalaDBHostObject::install(Runtime &rt, TalaDbHandle *db) {
28
+ auto hostObject = std::make_shared<TalaDBHostObject>(db);
29
+ auto jsiObject = Object::createFromHostObject(rt, hostObject);
30
+ rt.global().setProperty(rt, "__TalaDB__", std::move(jsiObject));
31
+ }
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // JSON helpers
35
+ // ---------------------------------------------------------------------------
36
+
37
+ std::string TalaDBHostObject::stringify(Runtime &rt, const Value &val) {
38
+ auto json = rt.global().getPropertyAsObject(rt, "JSON");
39
+ auto strFn = json.getPropertyAsFunction(rt, "stringify");
40
+ auto result = strFn.call(rt, val);
41
+ if (result.isString()) {
42
+ return result.getString(rt).utf8(rt);
43
+ }
44
+ return "null";
45
+ }
46
+
47
+ Value TalaDBHostObject::parse(Runtime &rt, const std::string &json) {
48
+ auto jsonObj = rt.global().getPropertyAsObject(rt, "JSON");
49
+ auto parseFn = jsonObj.getPropertyAsFunction(rt, "parse");
50
+ return parseFn.call(rt, String::createFromUtf8(rt, json));
51
+ }
52
+
53
+ std::string TalaDBHostObject::valueToFilterJson(Runtime &rt, const Value &val) {
54
+ if (val.isNull() || val.isUndefined()) {
55
+ return "{}";
56
+ }
57
+ return stringify(rt, val);
58
+ }
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Property names advertised to JS
62
+ // ---------------------------------------------------------------------------
63
+
64
+ std::vector<PropNameID> TalaDBHostObject::getPropertyNames(Runtime &rt) {
65
+ std::vector<std::string> names = {
66
+ "insert", "insertMany",
67
+ "find", "findOne",
68
+ "updateOne", "updateMany",
69
+ "deleteOne", "deleteMany",
70
+ "count",
71
+ "createIndex", "dropIndex",
72
+ "createFtsIndex", "dropFtsIndex",
73
+ "close",
74
+ };
75
+ std::vector<PropNameID> result;
76
+ result.reserve(names.size());
77
+ for (auto &n : names) {
78
+ result.push_back(PropNameID::forUtf8(rt, n));
79
+ }
80
+ return result;
81
+ }
82
+
83
+ void TalaDBHostObject::set(Runtime &, const PropNameID &, const Value &) {}
84
+
85
+ // ---------------------------------------------------------------------------
86
+ // Property dispatch
87
+ // ---------------------------------------------------------------------------
88
+
89
+ Value TalaDBHostObject::get(Runtime &rt, const PropNameID &propName) {
90
+ auto name = propName.utf8(rt);
91
+
92
+ // ------------------------------------------------------------------
93
+ // insert(collection: string, doc: object): string
94
+ // ------------------------------------------------------------------
95
+ if (name == "insert") {
96
+ return Function::createFromHostFunction(
97
+ rt, PropNameID::forAscii(rt, "insert"), 2,
98
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
99
+ if (count < 2) throw JSError(rt, "insert requires 2 arguments");
100
+ auto col = args[0].getString(rt).utf8(rt);
101
+ auto docJson = stringify(rt, args[1]);
102
+ char *result = taladb_insert(db_, col.c_str(), docJson.c_str());
103
+ if (!result) throw JSError(rt, "taladb_insert failed");
104
+ std::string id(result);
105
+ taladb_free_string(result);
106
+ return String::createFromUtf8(rt, id);
107
+ });
108
+ }
109
+
110
+ // ------------------------------------------------------------------
111
+ // insertMany(collection: string, docs: object[]): string[]
112
+ // ------------------------------------------------------------------
113
+ if (name == "insertMany") {
114
+ return Function::createFromHostFunction(
115
+ rt, PropNameID::forAscii(rt, "insertMany"), 2,
116
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
117
+ if (count < 2) throw JSError(rt, "insertMany requires 2 arguments");
118
+ auto col = args[0].getString(rt).utf8(rt);
119
+ auto docsJson = stringify(rt, args[1]);
120
+ char *result = taladb_insert_many(db_, col.c_str(), docsJson.c_str());
121
+ if (!result) throw JSError(rt, "taladb_insert_many failed");
122
+ std::string json(result);
123
+ taladb_free_string(result);
124
+ return parse(rt, json);
125
+ });
126
+ }
127
+
128
+ // ------------------------------------------------------------------
129
+ // find(collection: string, filter: object | null): object[]
130
+ // ------------------------------------------------------------------
131
+ if (name == "find") {
132
+ return Function::createFromHostFunction(
133
+ rt, PropNameID::forAscii(rt, "find"), 2,
134
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
135
+ if (count < 1) throw JSError(rt, "find requires at least 1 argument");
136
+ auto col = args[0].getString(rt).utf8(rt);
137
+ auto filterJson = count > 1 ? valueToFilterJson(rt, args[1]) : "{}";
138
+ char *result = taladb_find(db_, col.c_str(), filterJson.c_str());
139
+ if (!result) throw JSError(rt, "taladb_find failed");
140
+ std::string json(result);
141
+ taladb_free_string(result);
142
+ return parse(rt, json);
143
+ });
144
+ }
145
+
146
+ // ------------------------------------------------------------------
147
+ // findOne(collection: string, filter: object | null): object | null
148
+ // ------------------------------------------------------------------
149
+ if (name == "findOne") {
150
+ return Function::createFromHostFunction(
151
+ rt, PropNameID::forAscii(rt, "findOne"), 2,
152
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
153
+ if (count < 1) throw JSError(rt, "findOne requires at least 1 argument");
154
+ auto col = args[0].getString(rt).utf8(rt);
155
+ auto filterJson = count > 1 ? valueToFilterJson(rt, args[1]) : "{}";
156
+ char *result = taladb_find_one(db_, col.c_str(), filterJson.c_str());
157
+ if (!result) throw JSError(rt, "taladb_find_one failed");
158
+ std::string json(result);
159
+ taladb_free_string(result);
160
+ return parse(rt, json);
161
+ });
162
+ }
163
+
164
+ // ------------------------------------------------------------------
165
+ // updateOne(collection, filter, update): boolean
166
+ // ------------------------------------------------------------------
167
+ if (name == "updateOne") {
168
+ return Function::createFromHostFunction(
169
+ rt, PropNameID::forAscii(rt, "updateOne"), 3,
170
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
171
+ if (count < 3) throw JSError(rt, "updateOne requires 3 arguments");
172
+ auto col = args[0].getString(rt).utf8(rt);
173
+ auto filterJson = stringify(rt, args[1]);
174
+ auto updateJson = stringify(rt, args[2]);
175
+ int32_t res = taladb_update_one(
176
+ db_, col.c_str(), filterJson.c_str(), updateJson.c_str());
177
+ if (res < 0) throw JSError(rt, "taladb_update_one failed");
178
+ return Value(res == 1);
179
+ });
180
+ }
181
+
182
+ // ------------------------------------------------------------------
183
+ // updateMany(collection, filter, update): number
184
+ // ------------------------------------------------------------------
185
+ if (name == "updateMany") {
186
+ return Function::createFromHostFunction(
187
+ rt, PropNameID::forAscii(rt, "updateMany"), 3,
188
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
189
+ if (count < 3) throw JSError(rt, "updateMany requires 3 arguments");
190
+ auto col = args[0].getString(rt).utf8(rt);
191
+ auto filterJson = stringify(rt, args[1]);
192
+ auto updateJson = stringify(rt, args[2]);
193
+ int32_t res = taladb_update_many(
194
+ db_, col.c_str(), filterJson.c_str(), updateJson.c_str());
195
+ if (res < 0) throw JSError(rt, "taladb_update_many failed");
196
+ return Value(static_cast<double>(res));
197
+ });
198
+ }
199
+
200
+ // ------------------------------------------------------------------
201
+ // deleteOne(collection, filter): boolean
202
+ // ------------------------------------------------------------------
203
+ if (name == "deleteOne") {
204
+ return Function::createFromHostFunction(
205
+ rt, PropNameID::forAscii(rt, "deleteOne"), 2,
206
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
207
+ if (count < 2) throw JSError(rt, "deleteOne requires 2 arguments");
208
+ auto col = args[0].getString(rt).utf8(rt);
209
+ auto filterJson = stringify(rt, args[1]);
210
+ int32_t res = taladb_delete_one(db_, col.c_str(), filterJson.c_str());
211
+ if (res < 0) throw JSError(rt, "taladb_delete_one failed");
212
+ return Value(res == 1);
213
+ });
214
+ }
215
+
216
+ // ------------------------------------------------------------------
217
+ // deleteMany(collection, filter): number
218
+ // ------------------------------------------------------------------
219
+ if (name == "deleteMany") {
220
+ return Function::createFromHostFunction(
221
+ rt, PropNameID::forAscii(rt, "deleteMany"), 2,
222
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
223
+ if (count < 2) throw JSError(rt, "deleteMany requires 2 arguments");
224
+ auto col = args[0].getString(rt).utf8(rt);
225
+ auto filterJson = stringify(rt, args[1]);
226
+ int32_t res = taladb_delete_many(db_, col.c_str(), filterJson.c_str());
227
+ if (res < 0) throw JSError(rt, "taladb_delete_many failed");
228
+ return Value(static_cast<double>(res));
229
+ });
230
+ }
231
+
232
+ // ------------------------------------------------------------------
233
+ // count(collection, filter): number
234
+ // ------------------------------------------------------------------
235
+ if (name == "count") {
236
+ return Function::createFromHostFunction(
237
+ rt, PropNameID::forAscii(rt, "count"), 2,
238
+ [this](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
239
+ if (count < 1) throw JSError(rt, "count requires at least 1 argument");
240
+ auto col = args[0].getString(rt).utf8(rt);
241
+ auto filterJson = count > 1 ? valueToFilterJson(rt, args[1]) : "{}";
242
+ int32_t res = taladb_count(db_, col.c_str(), filterJson.c_str());
243
+ if (res < 0) throw JSError(rt, "taladb_count failed");
244
+ return Value(static_cast<double>(res));
245
+ });
246
+ }
247
+
248
+ // ------------------------------------------------------------------
249
+ // createIndex / dropIndex / createFtsIndex / dropFtsIndex
250
+ // ------------------------------------------------------------------
251
+ if (name == "createIndex" || name == "dropIndex" ||
252
+ name == "createFtsIndex" || name == "dropFtsIndex") {
253
+ return Function::createFromHostFunction(
254
+ rt, PropNameID::forUtf8(rt, name), 2,
255
+ [this, name](Runtime &rt, const Value &, const Value *args, size_t count) -> Value {
256
+ if (count < 2) throw JSError(rt, (name + " requires 2 arguments").c_str());
257
+ auto col = args[0].getString(rt).utf8(rt);
258
+ auto field = args[1].getString(rt).utf8(rt);
259
+ if (name == "createIndex") taladb_create_index (db_, col.c_str(), field.c_str());
260
+ else if (name == "dropIndex") taladb_drop_index (db_, col.c_str(), field.c_str());
261
+ else if (name == "createFtsIndex") taladb_create_fts_index(db_, col.c_str(), field.c_str());
262
+ else taladb_drop_fts_index (db_, col.c_str(), field.c_str());
263
+ return Value::undefined();
264
+ });
265
+ }
266
+
267
+ // ------------------------------------------------------------------
268
+ // close(): void (synchronous — the destructor does the real work)
269
+ // ------------------------------------------------------------------
270
+ if (name == "close") {
271
+ return Function::createFromHostFunction(
272
+ rt, PropNameID::forAscii(rt, "close"), 0,
273
+ [this](Runtime &rt, const Value &, const Value *, size_t) -> Value {
274
+ if (db_) {
275
+ taladb_close(db_);
276
+ db_ = nullptr;
277
+ }
278
+ return Value::undefined();
279
+ });
280
+ }
281
+
282
+ return Value::undefined();
283
+ }
284
+
285
+ } // namespace taladb
@@ -0,0 +1,55 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+ #include <string>
5
+ #include "taladb.h"
6
+
7
+ namespace taladb {
8
+
9
+ /**
10
+ * TalaDBHostObject — JSI HostObject wrapping the Rust taladb-ffi C library.
11
+ *
12
+ * Installed into the JS runtime as a global:
13
+ * global.__TalaDB__ = <TalaDBHostObject instance>
14
+ *
15
+ * Every property access returns a JSI Function. All CRUD methods are
16
+ * synchronous (the Rust core does no async I/O); `initialize` and `close`
17
+ * are async only to conform to the TurboModule spec (they resolve immediately).
18
+ *
19
+ * JSON is used at the C boundary:
20
+ * JS object → JSON.stringify → C string → Rust → C string → JSON.parse → JS object
21
+ */
22
+ class TalaDBHostObject : public facebook::jsi::HostObject {
23
+ public:
24
+ explicit TalaDBHostObject(TalaDbHandle *db);
25
+ ~TalaDBHostObject() override;
26
+
27
+ facebook::jsi::Value get(facebook::jsi::Runtime &rt,
28
+ const facebook::jsi::PropNameID &name) override;
29
+
30
+ void set(facebook::jsi::Runtime &rt,
31
+ const facebook::jsi::PropNameID &name,
32
+ const facebook::jsi::Value &value) override;
33
+
34
+ std::vector<facebook::jsi::PropNameID>
35
+ getPropertyNames(facebook::jsi::Runtime &rt) override;
36
+
37
+ /** Install this object as global.__TalaDB__ in the given runtime. */
38
+ static void install(facebook::jsi::Runtime &rt, TalaDbHandle *db);
39
+
40
+ private:
41
+ TalaDbHandle *db_;
42
+
43
+ // JSON helpers
44
+ static std::string stringify(facebook::jsi::Runtime &rt,
45
+ const facebook::jsi::Value &val);
46
+ static facebook::jsi::Value parse(facebook::jsi::Runtime &rt,
47
+ const std::string &json);
48
+
49
+ // Convenience: convert a nullable JSI Value to a JSON C-string.
50
+ // Returns "{}" when the value is null/undefined.
51
+ static std::string valueToFilterJson(facebook::jsi::Runtime &rt,
52
+ const facebook::jsi::Value &val);
53
+ };
54
+
55
+ } // namespace taladb
@@ -0,0 +1,53 @@
1
+ /**
2
+ * TalaDB JNI glue — Android only.
3
+ *
4
+ * Exposes `nativeInstall(jsContextNativePtr, dbPath, configJson)` to Kotlin so
5
+ * that `TalaDBModule.kt` can install the JSI HostObject from the JS thread.
6
+ *
7
+ * The function signature must match the Kotlin `external fun` declaration:
8
+ * package : com.taladb
9
+ * class : TalaDBModule
10
+ * method : nativeInstall(Long, String, String?)
11
+ *
12
+ * CMakeLists.txt compiles this file together with TalaDBHostObject.cpp.
13
+ */
14
+
15
+ #include <jni.h>
16
+ #include <jsi/jsi.h>
17
+ #include <string>
18
+
19
+ #include "TalaDBHostObject.h"
20
+ #include "taladb.h"
21
+
22
+ using namespace facebook::jsi;
23
+
24
+ extern "C" JNIEXPORT void JNICALL
25
+ Java_com_taladb_TalaDBModule_nativeInstall(
26
+ JNIEnv *env,
27
+ jobject /* thiz */,
28
+ jlong jsContextNativePtr,
29
+ jstring dbPathJ,
30
+ jstring configJsonJ)
31
+ {
32
+ // Resolve db path
33
+ const char *dbPathC = env->GetStringUTFChars(dbPathJ, nullptr);
34
+ std::string dbPath(dbPathC);
35
+ env->ReleaseStringUTFChars(dbPathJ, dbPathC);
36
+
37
+ // Open the Rust database — use taladb_open_with_config when config provided
38
+ TalaDbHandle *db = nullptr;
39
+ if (configJsonJ != nullptr) {
40
+ const char *configC = env->GetStringUTFChars(configJsonJ, nullptr);
41
+ db = taladb_open_with_config(dbPath.c_str(), configC);
42
+ env->ReleaseStringUTFChars(configJsonJ, configC);
43
+ } else {
44
+ db = taladb_open(dbPath.c_str());
45
+ }
46
+ if (!db) return; // failed to open — JS will see no __TalaDB__ global
47
+
48
+ // Get the JSI runtime from the pointer passed by RN internals
49
+ auto &rt = *reinterpret_cast<Runtime *>(jsContextNativePtr);
50
+
51
+ // Install the JSI HostObject as global.__TalaDB__
52
+ taladb::TalaDBHostObject::install(rt, db);
53
+ }