@taladb/react-native 0.5.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.
@@ -0,0 +1,151 @@
1
+ #pragma once
2
+ #ifndef TALADB_FFI_H
3
+ #define TALADB_FFI_H
4
+
5
+ /*
6
+ * TalaDB C FFI header.
7
+ *
8
+ * This file is the stable C interface between the Rust taladb-ffi crate and
9
+ * the C++ JSI HostObject. It is kept in sync with rust/src/lib.rs manually
10
+ * (or regenerated with cbindgen — see rust/cbindgen.toml).
11
+ *
12
+ * Ownership rules
13
+ * ---------------
14
+ * - Strings IN : caller-owned, UTF-8, null-terminated.
15
+ * - Strings OUT : heap-allocated by Rust; caller must free with
16
+ * taladb_free_string().
17
+ * - Handles : allocated by taladb_open(); freed by taladb_close().
18
+ * - Errors : string functions return NULL; integer functions return -1.
19
+ */
20
+
21
+ #include <stdint.h>
22
+ #include <stdlib.h>
23
+
24
+ #ifdef __cplusplus
25
+ extern "C" {
26
+ #endif
27
+
28
+ /* -------------------------------------------------------------------------
29
+ * Opaque database handle
30
+ * ---------------------------------------------------------------------- */
31
+ typedef struct TalaDbHandle TalaDbHandle;
32
+
33
+ /* -------------------------------------------------------------------------
34
+ * Lifecycle
35
+ * ---------------------------------------------------------------------- */
36
+
37
+ /** Open (or create) a database at the given file-system path. */
38
+ TalaDbHandle *taladb_open(const char *path);
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
+
48
+ /** Flush and close the database, freeing the handle. */
49
+ void taladb_close(TalaDbHandle *handle);
50
+
51
+ /** Free a C string returned by any taladb_* function. */
52
+ void taladb_free_string(char *s);
53
+
54
+ /* -------------------------------------------------------------------------
55
+ * Insert
56
+ * ---------------------------------------------------------------------- */
57
+
58
+ /**
59
+ * Insert a document (JSON object).
60
+ * Returns the new document's ULID as a C string, or NULL on error.
61
+ * Caller must free with taladb_free_string().
62
+ */
63
+ char *taladb_insert(TalaDbHandle *handle,
64
+ const char *collection,
65
+ const char *doc_json);
66
+
67
+ /**
68
+ * Insert multiple documents (JSON array of objects).
69
+ * Returns a JSON array of ULID strings, or NULL on error.
70
+ * Caller must free with taladb_free_string().
71
+ */
72
+ char *taladb_insert_many(TalaDbHandle *handle,
73
+ const char *collection,
74
+ const char *docs_json);
75
+
76
+ /* -------------------------------------------------------------------------
77
+ * Find
78
+ * ---------------------------------------------------------------------- */
79
+
80
+ /**
81
+ * Find all documents matching filter_json.
82
+ * Pass "{}" or "null" to match all.
83
+ * Returns a JSON array string, or NULL on error.
84
+ * Caller must free with taladb_free_string().
85
+ */
86
+ char *taladb_find(TalaDbHandle *handle,
87
+ const char *collection,
88
+ const char *filter_json);
89
+
90
+ /**
91
+ * Find the first document matching filter_json.
92
+ * Returns a JSON object string, or the string "null" if not found.
93
+ * Caller must free with taladb_free_string().
94
+ */
95
+ char *taladb_find_one(TalaDbHandle *handle,
96
+ const char *collection,
97
+ const char *filter_json);
98
+
99
+ /* -------------------------------------------------------------------------
100
+ * Update
101
+ * ---------------------------------------------------------------------- */
102
+
103
+ /** Update the first matching document. Returns 1 updated, 0 not found, -1 error. */
104
+ int32_t taladb_update_one(TalaDbHandle *handle,
105
+ const char *collection,
106
+ const char *filter_json,
107
+ const char *update_json);
108
+
109
+ /** Update all matching documents. Returns count updated, or -1 on error. */
110
+ int32_t taladb_update_many(TalaDbHandle *handle,
111
+ const char *collection,
112
+ const char *filter_json,
113
+ const char *update_json);
114
+
115
+ /* -------------------------------------------------------------------------
116
+ * Delete
117
+ * ---------------------------------------------------------------------- */
118
+
119
+ /** Delete the first matching document. Returns 1 deleted, 0 not found, -1 error. */
120
+ int32_t taladb_delete_one(TalaDbHandle *handle,
121
+ const char *collection,
122
+ const char *filter_json);
123
+
124
+ /** Delete all matching documents. Returns count deleted, or -1 on error. */
125
+ int32_t taladb_delete_many(TalaDbHandle *handle,
126
+ const char *collection,
127
+ const char *filter_json);
128
+
129
+ /* -------------------------------------------------------------------------
130
+ * Count
131
+ * ---------------------------------------------------------------------- */
132
+
133
+ /** Count documents matching filter_json. Returns count, or -1 on error. */
134
+ int32_t taladb_count(TalaDbHandle *handle,
135
+ const char *collection,
136
+ const char *filter_json);
137
+
138
+ /* -------------------------------------------------------------------------
139
+ * Index management
140
+ * ---------------------------------------------------------------------- */
141
+
142
+ void taladb_create_index (TalaDbHandle *handle, const char *collection, const char *field);
143
+ void taladb_drop_index (TalaDbHandle *handle, const char *collection, const char *field);
144
+ void taladb_create_fts_index(TalaDbHandle *handle, const char *collection, const char *field);
145
+ void taladb_drop_fts_index (TalaDbHandle *handle, const char *collection, const char *field);
146
+
147
+ #ifdef __cplusplus
148
+ } /* extern "C" */
149
+ #endif
150
+
151
+ #endif /* TALADB_FFI_H */
@@ -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
+ }