@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.
- package/android/src/main/java/com/taladb/TalaDBModule.kt +10 -10
- 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/TalaDBJni.cpp +14 -6
- package/cpp/taladb.h +8 -0
- package/ios/TalaDB.mm +15 -9
- package/ios/TalaDBFfi.xcframework/Info.plist +48 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/TalaDBHostObject.cpp +285 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/TalaDBHostObject.h +55 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/TalaDBJni.cpp +53 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64/Headers/taladb.h +151 -0
- package/ios/{libtaladb.a → TalaDBFfi.xcframework/ios-arm64/libtaladb_ffi.a} +0 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/TalaDBHostObject.cpp +285 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/TalaDBHostObject.h +55 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/TalaDBJni.cpp +53 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/Headers/taladb.h +151 -0
- package/ios/TalaDBFfi.xcframework/ios-arm64_x86_64-simulator/libtaladb_ffi_sim.a +0 -0
- package/package.json +1 -1
- package/src/NativeTalaDB.ts +4 -1
- package/src/index.tsx +9 -2
- package/taladb-react-native.podspec +12 -15
|
@@ -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
|
|
37
|
-
//
|
|
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
|
-
|
|
64
|
-
|
|
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)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
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
|
|
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 =
|
|
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 `
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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
|
-
|
|
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
|
+
}
|