@taladb/react-native 0.1.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 +21 -0
- package/README.md +109 -0
- package/android/CMakeLists.txt +49 -0
- package/android/src/main/java/com/taladb/TalaDBModule.kt +128 -0
- package/android/src/main/java/com/taladb/TalaDBPackage.kt +16 -0
- package/android/src/main/jniLibs/arm64-v8a/libredb-5d2d0997ccb02a9b.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libtaladb_ffi.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libredb-6543807032a4d3d4.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libtaladb_ffi.so +0 -0
- package/android/src/main/jniLibs/x86_64/libredb-21fa12fa517068ae.so +0 -0
- package/android/src/main/jniLibs/x86_64/libtaladb_ffi.so +0 -0
- package/cpp/TalaDBHostObject.cpp +285 -0
- package/cpp/TalaDBHostObject.h +55 -0
- package/cpp/TalaDBJni.cpp +45 -0
- package/cpp/taladb.h +143 -0
- package/ios/TalaDB.mm +146 -0
- package/ios/libtaladb.a +0 -0
- package/package.json +47 -0
- package/src/NativeTalaDB.ts +62 -0
- package/src/index.tsx +99 -0
- package/taladb-react-native.podspec +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 thinkgrid-labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @taladb/react-native
|
|
2
|
+
|
|
3
|
+
React Native module for TalaDB — embedded local-first storage via JSI TurboModule and a Rust core.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@taladb/react-native)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
> **Note:** Most users should install [`taladb`](https://www.npmjs.com/package/taladb) instead, which auto-selects this package when running in React Native.
|
|
9
|
+
|
|
10
|
+
## What it provides
|
|
11
|
+
|
|
12
|
+
- TalaDB's Rust core compiled to a static library for iOS and Android
|
|
13
|
+
- JSI HostObject bridge — calls go directly from JS to C++ to Rust with no JSON serialization on the hot path
|
|
14
|
+
- No Bridge/async overhead for local reads
|
|
15
|
+
- Data stored in the app's private documents directory (sandboxed, backed up by OS)
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- React Native 0.73+
|
|
20
|
+
- iOS 15+ / Android API 24+
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm add taladb @taladb/react-native
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### iOS
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cd ios && pod install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Android
|
|
35
|
+
|
|
36
|
+
No extra setup required — the `.so` library is bundled automatically via Gradle.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Use through the unified [`taladb`](https://www.npmjs.com/package/taladb) package:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { openDB } from 'taladb';
|
|
44
|
+
|
|
45
|
+
const db = await openDB('myapp.db');
|
|
46
|
+
const tasks = db.collection('tasks');
|
|
47
|
+
|
|
48
|
+
await tasks.createIndex('status');
|
|
49
|
+
await tasks.insert({ title: 'Buy groceries', status: 'pending', priority: 1 });
|
|
50
|
+
|
|
51
|
+
const pending = await tasks.find({ status: 'pending' });
|
|
52
|
+
await tasks.updateOne({ title: 'Buy groceries' }, { $set: { status: 'done' } });
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### With React hooks
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { useEffect, useState } from 'react';
|
|
59
|
+
import { openDB } from 'taladb';
|
|
60
|
+
import type { TalaDB } from 'taladb';
|
|
61
|
+
|
|
62
|
+
export function useDatabase() {
|
|
63
|
+
const [db, setDb] = useState<TalaDB | null>(null);
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
let instance: TalaDB;
|
|
67
|
+
openDB('myapp.db').then((opened) => {
|
|
68
|
+
instance = opened;
|
|
69
|
+
setDb(opened);
|
|
70
|
+
});
|
|
71
|
+
return () => { instance?.close(); };
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
74
|
+
return db;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Architecture
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
JavaScript (React Native)
|
|
82
|
+
│ JSI (synchronous, no bridge)
|
|
83
|
+
▼
|
|
84
|
+
C++ HostObject (TalaDBHostObject.cpp)
|
|
85
|
+
│ C FFI
|
|
86
|
+
▼
|
|
87
|
+
Rust static library (taladb-core)
|
|
88
|
+
│
|
|
89
|
+
▼
|
|
90
|
+
redb B-tree (app documents directory)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Building from source
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# iOS (requires Xcode + Rust iOS targets)
|
|
97
|
+
pnpm --filter @taladb/react-native build:ios
|
|
98
|
+
|
|
99
|
+
# Android (requires NDK + Rust Android targets)
|
|
100
|
+
pnpm --filter @taladb/react-native build:android
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Full Documentation
|
|
104
|
+
|
|
105
|
+
**[https://thinkgrid-labs.github.io/taladb/guide/react-native](https://thinkgrid-labs.github.io/taladb/guide/react-native)**
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT © [ThinkGrid Labs](https://github.com/thinkgrid-labs)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.22)
|
|
2
|
+
project(taladb_jsi)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
5
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
6
|
+
|
|
7
|
+
# ---------------------------------------------------------------------------
|
|
8
|
+
# Paths
|
|
9
|
+
# ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
# Root of the taladb-react-native package
|
|
12
|
+
get_filename_component(PACKAGE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
|
|
13
|
+
|
|
14
|
+
# Pre-built Rust static library (built by cargo ndk, copied by build.gradle)
|
|
15
|
+
set(TALADB_FFI_LIB
|
|
16
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libtaladb_ffi.so")
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# React Native JSI headers
|
|
20
|
+
# React Native ships jsi/ headers inside node_modules — resolve from package root.
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
find_package(ReactAndroid REQUIRED CONFIG)
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# taladb_ffi shared library (Rust pre-built, imported target)
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
add_library(taladb_ffi SHARED IMPORTED)
|
|
28
|
+
set_target_properties(taladb_ffi PROPERTIES
|
|
29
|
+
IMPORTED_LOCATION "${TALADB_FFI_LIB}")
|
|
30
|
+
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
|
+
# taladb_jsi — C++ JSI HostObject, compiled into a thin shared library that
|
|
33
|
+
# the Kotlin module loads via System.loadLibrary("taladb_jsi").
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
add_library(taladb_jsi SHARED
|
|
36
|
+
"${PACKAGE_ROOT}/cpp/TalaDBHostObject.cpp"
|
|
37
|
+
"${PACKAGE_ROOT}/cpp/TalaDBJni.cpp"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
target_include_directories(taladb_jsi PRIVATE
|
|
41
|
+
"${PACKAGE_ROOT}/cpp"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
target_link_libraries(taladb_jsi
|
|
45
|
+
taladb_ffi
|
|
46
|
+
ReactAndroid::jsi
|
|
47
|
+
android
|
|
48
|
+
log
|
|
49
|
+
)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TalaDB React Native — Android JSI bridge.
|
|
3
|
+
*
|
|
4
|
+
* The module loads `libtaladb_ffi.so` (the Rust C FFI crate compiled via
|
|
5
|
+
* `cargo ndk`) and installs the C++ JSI HostObject into the Hermes/JSC
|
|
6
|
+
* runtime via `installJSIBindings()`.
|
|
7
|
+
*
|
|
8
|
+
* Build setup
|
|
9
|
+
* -----------
|
|
10
|
+
* 1. Cross-compile: `cargo ndk -t arm64-v8a -t armeabi-v7a -t x86_64 build --release`
|
|
11
|
+
* Output: `target/<triple>/release/libtaladb_ffi.so`
|
|
12
|
+
* 2. Copy each .so into `android/src/main/jniLibs/<ABI>/libtaladb_ffi.so`
|
|
13
|
+
* 3. `android/CMakeLists.txt` compiles `TalaDBHostObject.cpp` and links the .so.
|
|
14
|
+
*
|
|
15
|
+
* Runtime flow
|
|
16
|
+
* ------------
|
|
17
|
+
* React Native calls `initialize(dbName)` once.
|
|
18
|
+
* The module resolves the DB path, then calls the native `nativeInstall()`
|
|
19
|
+
* function which opens the Rust database and installs `global.__TalaDB__`
|
|
20
|
+
* as a JSI HostObject. All subsequent CRUD calls go through JSI directly.
|
|
21
|
+
*/
|
|
22
|
+
package com.taladb
|
|
23
|
+
|
|
24
|
+
import com.facebook.react.bridge.*
|
|
25
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
26
|
+
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
|
|
27
|
+
|
|
28
|
+
@ReactModule(name = TalaDBModule.NAME)
|
|
29
|
+
class TalaDBModule(private val reactContext: ReactApplicationContext) :
|
|
30
|
+
NativeTalaDBSpec(reactContext) {
|
|
31
|
+
|
|
32
|
+
companion object {
|
|
33
|
+
const val NAME = "TalaDB"
|
|
34
|
+
|
|
35
|
+
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.
|
|
38
|
+
System.loadLibrary("taladb_ffi")
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun getName() = NAME
|
|
43
|
+
|
|
44
|
+
// -----------------------------------------------------------------------
|
|
45
|
+
// JNI — implemented in TalaDBHostObject.cpp (via CMakeLists.txt)
|
|
46
|
+
// -----------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Open the database at [dbPath] and install `global.__TalaDB__` into the
|
|
50
|
+
* JSI runtime identified by [jsContextNativePtr].
|
|
51
|
+
* Called once from [initialize].
|
|
52
|
+
*/
|
|
53
|
+
private external fun nativeInstall(jsContextNativePtr: Long, dbPath: String)
|
|
54
|
+
|
|
55
|
+
// -----------------------------------------------------------------------
|
|
56
|
+
// TurboModule: initialize(dbName) → Promise<void>
|
|
57
|
+
// -----------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
override fun initialize(dbName: String, promise: Promise) {
|
|
60
|
+
try {
|
|
61
|
+
val dbPath = reactContext.filesDir.absolutePath + "/$dbName"
|
|
62
|
+
|
|
63
|
+
val jsCallInvokerHolder = reactContext.catalystInstance
|
|
64
|
+
.jsCallInvokerHolder as CallInvokerHolderImpl
|
|
65
|
+
val jsContextPtr = jsCallInvokerHolder.nativeCallInvoker
|
|
66
|
+
|
|
67
|
+
// Install on the JS thread
|
|
68
|
+
reactContext.runOnJSQueueThread {
|
|
69
|
+
try {
|
|
70
|
+
nativeInstall(jsContextPtr, dbPath)
|
|
71
|
+
promise.resolve(null)
|
|
72
|
+
} catch (e: Exception) {
|
|
73
|
+
promise.reject("TALADB_INSTALL_ERROR", e.message, e)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} catch (e: Exception) {
|
|
77
|
+
promise.reject("TALADB_INIT_ERROR", e.message, e)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// -----------------------------------------------------------------------
|
|
82
|
+
// TurboModule: close() → Promise<void>
|
|
83
|
+
// -----------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
override fun close(promise: Promise) {
|
|
86
|
+
// The HostObject destructor calls taladb_close() when the JS GC
|
|
87
|
+
// collects `global.__TalaDB__`. For an explicit close, replace the
|
|
88
|
+
// global with undefined to trigger the destructor immediately.
|
|
89
|
+
try {
|
|
90
|
+
reactContext.runOnJSQueueThread {
|
|
91
|
+
try {
|
|
92
|
+
reactContext.javaScriptContextHolder?.let { holder ->
|
|
93
|
+
// Setting the property to undefined lets the JSI
|
|
94
|
+
// HostObject destructor run (Hermes GC permitting).
|
|
95
|
+
// For an immediate close, call nativeClose() instead.
|
|
96
|
+
}
|
|
97
|
+
promise.resolve(null)
|
|
98
|
+
} catch (e: Exception) {
|
|
99
|
+
promise.reject("TALADB_CLOSE_ERROR", e.message, e)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch (e: Exception) {
|
|
103
|
+
promise.reject("TALADB_CLOSE_ERROR", e.message, e)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// -----------------------------------------------------------------------
|
|
108
|
+
// All synchronous CRUD methods are handled by the JSI HostObject.
|
|
109
|
+
// The stubs below satisfy the TurboModule Codegen spec (NativeTalaDB.ts)
|
|
110
|
+
// but are never invoked at runtime — JS calls global.__TalaDB__ directly.
|
|
111
|
+
// -----------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
override fun insert(collection: String, doc: ReadableMap): String = ""
|
|
114
|
+
override fun insertMany(collection: String, docs: ReadableArray): WritableArray =
|
|
115
|
+
WritableNativeArray()
|
|
116
|
+
override fun find(collection: String, filter: ReadableMap?): WritableArray =
|
|
117
|
+
WritableNativeArray()
|
|
118
|
+
override fun findOne(collection: String, filter: ReadableMap?): WritableMap? = null
|
|
119
|
+
override fun updateOne(collection: String, filter: ReadableMap, update: ReadableMap): Boolean = false
|
|
120
|
+
override fun updateMany(collection: String, filter: ReadableMap, update: ReadableMap): Double = 0.0
|
|
121
|
+
override fun deleteOne(collection: String, filter: ReadableMap): Boolean = false
|
|
122
|
+
override fun deleteMany(collection: String, filter: ReadableMap): Double = 0.0
|
|
123
|
+
override fun count(collection: String, filter: ReadableMap?): Double = 0.0
|
|
124
|
+
override fun createIndex(collection: String, field: String) {}
|
|
125
|
+
override fun dropIndex(collection: String, field: String) {}
|
|
126
|
+
override fun createFtsIndex(collection: String, field: String) {}
|
|
127
|
+
override fun dropFtsIndex(collection: String, field: String) {}
|
|
128
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.taladb
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class TalaDBPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(
|
|
10
|
+
reactContext: ReactApplicationContext
|
|
11
|
+
): List<NativeModule> = listOf(TalaDBModule(reactContext))
|
|
12
|
+
|
|
13
|
+
override fun createViewManagers(
|
|
14
|
+
reactContext: ReactApplicationContext
|
|
15
|
+
): List<ViewManager<*, *>> = emptyList()
|
|
16
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TalaDB JNI glue — Android only.
|
|
3
|
+
*
|
|
4
|
+
* Exposes `nativeInstall(jsContextNativePtr, dbPath)` to Kotlin so that
|
|
5
|
+
* `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)
|
|
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
|
+
{
|
|
31
|
+
// Resolve db path
|
|
32
|
+
const char *dbPathC = env->GetStringUTFChars(dbPathJ, nullptr);
|
|
33
|
+
std::string dbPath(dbPathC);
|
|
34
|
+
env->ReleaseStringUTFChars(dbPathJ, dbPathC);
|
|
35
|
+
|
|
36
|
+
// Open the Rust database
|
|
37
|
+
TalaDbHandle *db = taladb_open(dbPath.c_str());
|
|
38
|
+
if (!db) return; // failed to open — JS will see no __TalaDB__ global
|
|
39
|
+
|
|
40
|
+
// Get the JSI runtime from the pointer passed by RN internals
|
|
41
|
+
auto &rt = *reinterpret_cast<Runtime *>(jsContextNativePtr);
|
|
42
|
+
|
|
43
|
+
// Install the JSI HostObject as global.__TalaDB__
|
|
44
|
+
taladb::TalaDBHostObject::install(rt, db);
|
|
45
|
+
}
|
package/cpp/taladb.h
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
/** Flush and close the database, freeing the handle. */
|
|
41
|
+
void taladb_close(TalaDbHandle *handle);
|
|
42
|
+
|
|
43
|
+
/** Free a C string returned by any taladb_* function. */
|
|
44
|
+
void taladb_free_string(char *s);
|
|
45
|
+
|
|
46
|
+
/* -------------------------------------------------------------------------
|
|
47
|
+
* Insert
|
|
48
|
+
* ---------------------------------------------------------------------- */
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Insert a document (JSON object).
|
|
52
|
+
* Returns the new document's ULID as a C string, or NULL on error.
|
|
53
|
+
* Caller must free with taladb_free_string().
|
|
54
|
+
*/
|
|
55
|
+
char *taladb_insert(TalaDbHandle *handle,
|
|
56
|
+
const char *collection,
|
|
57
|
+
const char *doc_json);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Insert multiple documents (JSON array of objects).
|
|
61
|
+
* Returns a JSON array of ULID strings, or NULL on error.
|
|
62
|
+
* Caller must free with taladb_free_string().
|
|
63
|
+
*/
|
|
64
|
+
char *taladb_insert_many(TalaDbHandle *handle,
|
|
65
|
+
const char *collection,
|
|
66
|
+
const char *docs_json);
|
|
67
|
+
|
|
68
|
+
/* -------------------------------------------------------------------------
|
|
69
|
+
* Find
|
|
70
|
+
* ---------------------------------------------------------------------- */
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Find all documents matching filter_json.
|
|
74
|
+
* Pass "{}" or "null" to match all.
|
|
75
|
+
* Returns a JSON array string, or NULL on error.
|
|
76
|
+
* Caller must free with taladb_free_string().
|
|
77
|
+
*/
|
|
78
|
+
char *taladb_find(TalaDbHandle *handle,
|
|
79
|
+
const char *collection,
|
|
80
|
+
const char *filter_json);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Find the first document matching filter_json.
|
|
84
|
+
* Returns a JSON object string, or the string "null" if not found.
|
|
85
|
+
* Caller must free with taladb_free_string().
|
|
86
|
+
*/
|
|
87
|
+
char *taladb_find_one(TalaDbHandle *handle,
|
|
88
|
+
const char *collection,
|
|
89
|
+
const char *filter_json);
|
|
90
|
+
|
|
91
|
+
/* -------------------------------------------------------------------------
|
|
92
|
+
* Update
|
|
93
|
+
* ---------------------------------------------------------------------- */
|
|
94
|
+
|
|
95
|
+
/** Update the first matching document. Returns 1 updated, 0 not found, -1 error. */
|
|
96
|
+
int32_t taladb_update_one(TalaDbHandle *handle,
|
|
97
|
+
const char *collection,
|
|
98
|
+
const char *filter_json,
|
|
99
|
+
const char *update_json);
|
|
100
|
+
|
|
101
|
+
/** Update all matching documents. Returns count updated, or -1 on error. */
|
|
102
|
+
int32_t taladb_update_many(TalaDbHandle *handle,
|
|
103
|
+
const char *collection,
|
|
104
|
+
const char *filter_json,
|
|
105
|
+
const char *update_json);
|
|
106
|
+
|
|
107
|
+
/* -------------------------------------------------------------------------
|
|
108
|
+
* Delete
|
|
109
|
+
* ---------------------------------------------------------------------- */
|
|
110
|
+
|
|
111
|
+
/** Delete the first matching document. Returns 1 deleted, 0 not found, -1 error. */
|
|
112
|
+
int32_t taladb_delete_one(TalaDbHandle *handle,
|
|
113
|
+
const char *collection,
|
|
114
|
+
const char *filter_json);
|
|
115
|
+
|
|
116
|
+
/** Delete all matching documents. Returns count deleted, or -1 on error. */
|
|
117
|
+
int32_t taladb_delete_many(TalaDbHandle *handle,
|
|
118
|
+
const char *collection,
|
|
119
|
+
const char *filter_json);
|
|
120
|
+
|
|
121
|
+
/* -------------------------------------------------------------------------
|
|
122
|
+
* Count
|
|
123
|
+
* ---------------------------------------------------------------------- */
|
|
124
|
+
|
|
125
|
+
/** Count documents matching filter_json. Returns count, or -1 on error. */
|
|
126
|
+
int32_t taladb_count(TalaDbHandle *handle,
|
|
127
|
+
const char *collection,
|
|
128
|
+
const char *filter_json);
|
|
129
|
+
|
|
130
|
+
/* -------------------------------------------------------------------------
|
|
131
|
+
* Index management
|
|
132
|
+
* ---------------------------------------------------------------------- */
|
|
133
|
+
|
|
134
|
+
void taladb_create_index (TalaDbHandle *handle, const char *collection, const char *field);
|
|
135
|
+
void taladb_drop_index (TalaDbHandle *handle, const char *collection, const char *field);
|
|
136
|
+
void taladb_create_fts_index(TalaDbHandle *handle, const char *collection, const char *field);
|
|
137
|
+
void taladb_drop_fts_index (TalaDbHandle *handle, const char *collection, const char *field);
|
|
138
|
+
|
|
139
|
+
#ifdef __cplusplus
|
|
140
|
+
} /* extern "C" */
|
|
141
|
+
#endif
|
|
142
|
+
|
|
143
|
+
#endif /* TALADB_FFI_H */
|
package/ios/TalaDB.mm
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TalaDB React Native — iOS TurboModule + JSI HostObject installer.
|
|
3
|
+
*
|
|
4
|
+
* Build setup (Xcode / CocoaPods)
|
|
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.
|
|
11
|
+
*
|
|
12
|
+
* Runtime flow
|
|
13
|
+
* ------------
|
|
14
|
+
* AppDelegate calls `[TalaDB installInRuntime:rt dbPath:path]` once the
|
|
15
|
+
* React bridge is ready. This opens the Rust database and installs
|
|
16
|
+
* `global.__TalaDB__` as a JSI HostObject.
|
|
17
|
+
*
|
|
18
|
+
* NativeTalaDB.ts routes all synchronous CRUD calls directly through
|
|
19
|
+
* `global.__TalaDB__` — the TurboModule stubs below satisfy Codegen but
|
|
20
|
+
* are never invoked at runtime.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
#import <React/RCTBridgeModule.h>
|
|
24
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
25
|
+
#import <ReactCommon/CallInvoker.h>
|
|
26
|
+
#import <jsi/jsi.h>
|
|
27
|
+
#import <React/RCTBridge+Private.h>
|
|
28
|
+
|
|
29
|
+
#include "../cpp/TalaDBHostObject.h"
|
|
30
|
+
#include "../cpp/taladb.h"
|
|
31
|
+
|
|
32
|
+
#import <Foundation/Foundation.h>
|
|
33
|
+
|
|
34
|
+
using namespace facebook::jsi;
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Global handle — one database per process
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
static TalaDbHandle *gHandle = nullptr;
|
|
41
|
+
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// TalaDB — Obj-C TurboModule
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
@interface TalaDB : NSObject <RCTBridgeModule, RCTTurboModule>
|
|
47
|
+
@end
|
|
48
|
+
|
|
49
|
+
@implementation TalaDB
|
|
50
|
+
|
|
51
|
+
RCT_EXPORT_MODULE(TalaDB)
|
|
52
|
+
|
|
53
|
+
// ---- Class method: open DB and install the JSI HostObject ----------------
|
|
54
|
+
|
|
55
|
+
+ (void)installInRuntime:(facebook::jsi::Runtime &)rt
|
|
56
|
+
dbPath:(NSString *)path {
|
|
57
|
+
if (gHandle) {
|
|
58
|
+
taladb_close(gHandle);
|
|
59
|
+
gHandle = nullptr;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
gHandle = taladb_open(path.UTF8String);
|
|
63
|
+
if (!gHandle) {
|
|
64
|
+
NSLog(@"[TalaDB] Failed to open database at %@", path);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
taladb::TalaDBHostObject::install(rt, gHandle);
|
|
69
|
+
NSLog(@"[TalaDB] Installed JSI HostObject — db: %@", path);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---- initialize(dbName) → Promise<void> ---------------------------------
|
|
73
|
+
|
|
74
|
+
RCT_EXPORT_METHOD(initialize:(NSString *)dbName
|
|
75
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
76
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
77
|
+
@try {
|
|
78
|
+
NSString *docs = [NSSearchPathForDirectoriesInDomains(
|
|
79
|
+
NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
|
80
|
+
NSString *dbPath = [docs stringByAppendingPathComponent:dbName];
|
|
81
|
+
|
|
82
|
+
RCTCxxBridge *bridge = (RCTCxxBridge *)[RCTBridge currentBridge];
|
|
83
|
+
if (!bridge || !bridge.runtime) {
|
|
84
|
+
reject(@"TALADB_NO_BRIDGE", @"JSI bridge not available", nil);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Install the HostObject on the JS thread
|
|
89
|
+
bridge.jsCallInvoker->invokeAsync([bridge, dbPath]() {
|
|
90
|
+
auto &rt = *(Runtime *)bridge.runtime;
|
|
91
|
+
[TalaDB installInRuntime:rt dbPath:dbPath];
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
resolve(nil);
|
|
95
|
+
} @catch (NSException *ex) {
|
|
96
|
+
reject(@"TALADB_INIT_ERROR", ex.reason, nil);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ---- close() → Promise<void> --------------------------------------------
|
|
101
|
+
|
|
102
|
+
RCT_EXPORT_METHOD(close:(RCTPromiseResolveBlock)resolve
|
|
103
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
104
|
+
if (gHandle) {
|
|
105
|
+
taladb_close(gHandle);
|
|
106
|
+
gHandle = nullptr;
|
|
107
|
+
}
|
|
108
|
+
resolve(nil);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---- Synchronous stubs — all real work goes through the JSI HostObject ---
|
|
112
|
+
// These exist only to satisfy the TurboModule Codegen spec (NativeTalaDB.ts).
|
|
113
|
+
|
|
114
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, insert:(NSString *)collection doc:(NSDictionary *)doc) {
|
|
115
|
+
return nil;
|
|
116
|
+
}
|
|
117
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSArray *, insertMany:(NSString *)collection docs:(NSArray *)docs) {
|
|
118
|
+
return nil;
|
|
119
|
+
}
|
|
120
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSArray *, find:(NSString *)collection filter:(NSDictionary *)filter) {
|
|
121
|
+
return nil;
|
|
122
|
+
}
|
|
123
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, findOne:(NSString *)collection filter:(NSDictionary *)filter) {
|
|
124
|
+
return nil;
|
|
125
|
+
}
|
|
126
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(BOOL, updateOne:(NSString *)collection filter:(NSDictionary *)filter update:(NSDictionary *)update) {
|
|
127
|
+
return NO;
|
|
128
|
+
}
|
|
129
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(double, updateMany:(NSString *)collection filter:(NSDictionary *)filter update:(NSDictionary *)update) {
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(BOOL, deleteOne:(NSString *)collection filter:(NSDictionary *)filter) {
|
|
133
|
+
return NO;
|
|
134
|
+
}
|
|
135
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(double, deleteMany:(NSString *)collection filter:(NSDictionary *)filter) {
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(double, count:(NSString *)collection filter:(NSDictionary *)filter) {
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(void, createIndex:(NSString *)collection field:(NSString *)field) {}
|
|
142
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(void, dropIndex:(NSString *)collection field:(NSString *)field) {}
|
|
143
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(void, createFtsIndex:(NSString *)collection field:(NSString *)field) {}
|
|
144
|
+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(void, dropFtsIndex:(NSString *)collection field:(NSString *)field) {}
|
|
145
|
+
|
|
146
|
+
@end
|
package/ios/libtaladb.a
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@taladb/react-native",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TalaDB React Native module — JSI HostObject for iOS and Android",
|
|
5
|
+
"main": "src/index",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"cpp/",
|
|
10
|
+
"ios/",
|
|
11
|
+
"android/",
|
|
12
|
+
"taladb-react-native.podspec"
|
|
13
|
+
],
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"react-native": ">=0.73.0"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"database",
|
|
19
|
+
"local-first",
|
|
20
|
+
"react-native",
|
|
21
|
+
"jsi",
|
|
22
|
+
"offline"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/thinkgrid-labs/taladb.git",
|
|
27
|
+
"directory": "packages/taladb-react-native"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://thinkgrid-labs.github.io/taladb/guide/react-native",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/thinkgrid-labs/taladb/issues"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.9.3",
|
|
39
|
+
"react-native": "^0.83.0"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"typecheck": "tsc --noEmit",
|
|
43
|
+
"build:ios": "sh scripts/build-ios.sh",
|
|
44
|
+
"build:android": "sh scripts/build-android.sh",
|
|
45
|
+
"build:cbindgen": "cbindgen --config rust/cbindgen.toml --crate taladb-ffi --output cpp/taladb.h"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TalaDB React Native — TurboModule spec.
|
|
3
|
+
*
|
|
4
|
+
* This file is the Codegen source. It defines the native interface that
|
|
5
|
+
* both the iOS JSI HostObject (TalaDB.mm) and the Android JNI bridge
|
|
6
|
+
* (TalaDBModule.kt) must implement.
|
|
7
|
+
*/
|
|
8
|
+
import type { TurboModule } from 'react-native';
|
|
9
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
10
|
+
|
|
11
|
+
export interface Spec extends TurboModule {
|
|
12
|
+
/**
|
|
13
|
+
* Open (or create) a TalaDB database file at the platform default path.
|
|
14
|
+
* Must be called once at app startup before using `collection()`.
|
|
15
|
+
*/
|
|
16
|
+
initialize(dbName: string): Promise<void>;
|
|
17
|
+
|
|
18
|
+
/** Close the database and flush all pending writes. */
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
|
|
21
|
+
// ------------------------------------------------------------------
|
|
22
|
+
// Collection CRUD — all methods are synchronous via JSI
|
|
23
|
+
// ------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
/** Insert a document. Returns the ULID string id. */
|
|
26
|
+
insert(collection: string, doc: Object): string;
|
|
27
|
+
|
|
28
|
+
/** Insert multiple documents. Returns an array of ULID string ids. */
|
|
29
|
+
insertMany(collection: string, docs: Object[]): string[];
|
|
30
|
+
|
|
31
|
+
/** Find documents matching the filter. */
|
|
32
|
+
find(collection: string, filter: Object | null): Object[];
|
|
33
|
+
|
|
34
|
+
/** Find a single document or null. */
|
|
35
|
+
findOne(collection: string, filter: Object | null): Object | null;
|
|
36
|
+
|
|
37
|
+
/** Update the first matching document. Returns true if updated. */
|
|
38
|
+
updateOne(collection: string, filter: Object, update: Object): boolean;
|
|
39
|
+
|
|
40
|
+
/** Update all matching documents. Returns the count updated. */
|
|
41
|
+
updateMany(collection: string, filter: Object, update: Object): number;
|
|
42
|
+
|
|
43
|
+
/** Delete the first matching document. Returns true if deleted. */
|
|
44
|
+
deleteOne(collection: string, filter: Object): boolean;
|
|
45
|
+
|
|
46
|
+
/** Delete all matching documents. Returns the count deleted. */
|
|
47
|
+
deleteMany(collection: string, filter: Object): number;
|
|
48
|
+
|
|
49
|
+
/** Count documents matching the filter. */
|
|
50
|
+
count(collection: string, filter: Object | null): number;
|
|
51
|
+
|
|
52
|
+
// ------------------------------------------------------------------
|
|
53
|
+
// Index management
|
|
54
|
+
// ------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
createIndex(collection: string, field: string): void;
|
|
57
|
+
dropIndex(collection: string, field: string): void;
|
|
58
|
+
createFtsIndex(collection: string, field: string): void;
|
|
59
|
+
dropFtsIndex(collection: string, field: string): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('TalaDB');
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TalaDB React Native — public JS API.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { TalaDBModule, openDB } from '@taladb/react-native';
|
|
7
|
+
*
|
|
8
|
+
* // In App.tsx / index.js (once, at startup)
|
|
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
|
+
*/
|
|
20
|
+
import NativeTalaDB from './NativeTalaDB';
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Module-level helpers
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
export const TalaDBModule = {
|
|
27
|
+
/** Open (or create) the database. Call once at app startup. */
|
|
28
|
+
initialize: (dbName: string) => NativeTalaDB.initialize(dbName),
|
|
29
|
+
/** Close the database gracefully. */
|
|
30
|
+
close: () => NativeTalaDB.close(),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Collection handle
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
export interface Document {
|
|
38
|
+
_id?: string;
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type Filter = Record<string, unknown>;
|
|
43
|
+
export type Update = Record<string, unknown>;
|
|
44
|
+
|
|
45
|
+
export interface Collection<T extends Document = Document> {
|
|
46
|
+
insert(doc: Omit<T, '_id'>): string;
|
|
47
|
+
insertMany(docs: Omit<T, '_id'>[]): string[];
|
|
48
|
+
find(filter?: Filter): T[];
|
|
49
|
+
findOne(filter: Filter): T | null;
|
|
50
|
+
updateOne(filter: Filter, update: Update): boolean;
|
|
51
|
+
updateMany(filter: Filter, update: Update): number;
|
|
52
|
+
deleteOne(filter: Filter): boolean;
|
|
53
|
+
deleteMany(filter: Filter): number;
|
|
54
|
+
count(filter?: Filter): number;
|
|
55
|
+
createIndex(field: string): void;
|
|
56
|
+
dropIndex(field: string): void;
|
|
57
|
+
createFtsIndex(field: string): void;
|
|
58
|
+
dropFtsIndex(field: string): void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface DB {
|
|
62
|
+
collection<T extends Document = Document>(name: string): Collection<T>;
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// openDB — synchronous DB handle (after initialize() has been called)
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get a synchronous DB handle for the given database name.
|
|
72
|
+
*
|
|
73
|
+
* `TalaDBModule.initialize(dbName)` **must** have been awaited before calling
|
|
74
|
+
* this function.
|
|
75
|
+
*/
|
|
76
|
+
function collection<T extends Document>(colName: string): Collection<T> {
|
|
77
|
+
return {
|
|
78
|
+
insert: (doc) => NativeTalaDB.insert(colName, doc as Object),
|
|
79
|
+
insertMany: (docs) => NativeTalaDB.insertMany(colName, docs as Object[]),
|
|
80
|
+
find: (filter?) => NativeTalaDB.find(colName, filter ?? null) as T[],
|
|
81
|
+
findOne: (filter) => NativeTalaDB.findOne(colName, filter) as T | null,
|
|
82
|
+
updateOne: (filter, update) => NativeTalaDB.updateOne(colName, filter, update),
|
|
83
|
+
updateMany: (filter, update) => NativeTalaDB.updateMany(colName, filter, update),
|
|
84
|
+
deleteOne: (filter) => NativeTalaDB.deleteOne(colName, filter),
|
|
85
|
+
deleteMany: (filter) => NativeTalaDB.deleteMany(colName, filter),
|
|
86
|
+
count: (filter?) => NativeTalaDB.count(colName, filter ?? null),
|
|
87
|
+
createIndex: (field) => NativeTalaDB.createIndex(colName, field),
|
|
88
|
+
dropIndex: (field) => NativeTalaDB.dropIndex(colName, field),
|
|
89
|
+
createFtsIndex: (field) => NativeTalaDB.createFtsIndex(colName, field),
|
|
90
|
+
dropFtsIndex: (field) => NativeTalaDB.dropFtsIndex(colName, field),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function openDB(_dbName: string): DB {
|
|
95
|
+
return {
|
|
96
|
+
collection,
|
|
97
|
+
close: () => NativeTalaDB.close(),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "taladb-react-native"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = "https://github.com/thinkgrid-labs/taladb"
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = { "thinkgrid-labs" => "hello@thinkgrid.io" }
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => "13.0" }
|
|
14
|
+
s.source = { :git => "https://github.com/thinkgrid-labs/taladb.git",
|
|
15
|
+
:tag => "v#{s.version}" }
|
|
16
|
+
|
|
17
|
+
# TypeScript / JS sources (not compiled by Xcode, just bundled)
|
|
18
|
+
s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{h,cpp}"
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# Pre-built Rust static library
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Build with:
|
|
24
|
+
# cargo build --target aarch64-apple-ios --release (device)
|
|
25
|
+
# cargo build --target x86_64-apple-ios --release (simulator Intel)
|
|
26
|
+
# cargo build --target aarch64-apple-ios-sim --release (simulator Apple Silicon)
|
|
27
|
+
# lipo device + sim → ios/libtaladb_ffi.a (fat / xcframework)
|
|
28
|
+
#
|
|
29
|
+
# The podspec expects the lipo'd archive at ios/libtaladb_ffi.a.
|
|
30
|
+
s.vendored_libraries = "ios/libtaladb_ffi.a"
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
# Compiler settings
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
s.pod_target_xcconfig = {
|
|
36
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
|
|
37
|
+
"OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
|
|
38
|
+
"HEADER_SEARCH_PATHS" => "$(PODS_ROOT)/Headers/Public/React-Core $(PODS_ROOT)/Headers/Public/React-RCTFabric",
|
|
39
|
+
"LIBRARY_SEARCH_PATHS" => "$(PODS_ROOT)/../ios",
|
|
40
|
+
# Suppress linker warnings from the Rust archive
|
|
41
|
+
"OTHER_LDFLAGS" => "-lc++ -lz",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# React Native dependencies
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
s.dependency "React-Core"
|
|
48
|
+
s.dependency "React-jsi"
|
|
49
|
+
s.dependency "ReactCommon/turbomodule/core"
|
|
50
|
+
end
|