diff --git a/.bundle/config b/.bundle/config
new file mode 100644
index 0000000..d137d24
--- /dev/null
+++ b/.bundle/config
@@ -0,0 +1,2 @@
+BUNDLE_PATH: "vendor/bundle"
+BUNDLE_FORCE_RUBY_PLATFORM: 1
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 6ee6576..59510ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,7 +34,8 @@ project.xcworkspace
.idea
.gradle
local.properties
-android.iml
+*.iml
+*.hprof
# Cocoapods
#
@@ -59,3 +60,6 @@ android/.cxx
# generated by bob
lib/
+# Gradle
+android/gradle/
+android/gradle*
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..bbba14a
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
+ruby '2.7.4'
+gem 'cocoapods', '~> 1.11', '>= 1.11.2'
\ No newline at end of file
diff --git a/README.md b/README.md
index d0989db..42c6375 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
React Native Quick SQLite
-Fast SQLite for react-native.
+Fast SQLite for React-Native.
-
+
-This library uses [JSI](https://formidable.com/blog/2019/jsi-jsc-part-2) to directly call C++ code from JS. It provides a low-level API to execute SQL queries, therefore I recommend you use it with TypeORM.
+This library provides a low-level API to execute SQL queries, fast bindings via [JSI](https://formidable.com/blog/2019/jsi-jsc-part-2).
Inspired/compatible with [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage) and [react-native-sqlite2](https://github.com/craftzdog/react-native-sqlite-2).
@@ -30,21 +30,9 @@ Inspired/compatible with [react-native-sqlite-storage](https://github.com/andpor
- **Javascript cannot represent intergers larger than 53 bits**, be careful when loading data if it came from other systems. [Read more](https://github.com/ospfranco/react-native-quick-sqlite/issues/16#issuecomment-1018412991).
- **It's not possible to use a browser to debug a JSI app**, use [Flipper](https://github.com/facebook/flipper) (for android Flipper also has SQLite Database explorer).
- Your app will now include C++, you will need to install the NDK on your machine for android.
-- This library supports SQLite BLOBs which are mapped to JS ArrayBuffers, check out the sample project on how to use it
-- From version 2.0.0 onwards errors are no longer thrown on invalid SQL statements. The response contains a `status` number, `0` signals correct execution, `1` signals an error.
-- From version 3.0.0 onwards no JS errors are thown, every operation returns an object with a `status` field.
-- If you want to run the example project on android, you will have to change the paths on the android/CMakeLists.txt file, they are already there, just uncomment them.
-
-## Use TypeORM
-
-This package offers a low-level API to raw execute SQL queries. I strongly recommend to use [TypeORM](https://github.com/typeorm/typeorm) (with [patch-package](https://github.com/ds300/patch-package)). TypeORM already has a sqlite-storage driver. In the `example` project on the `patch` folder you can a find a [patch for TypeORM](https://github.com/ospfranco/react-native-quick-sqlite/blob/main/example/patches/typeorm%2B0.2.31.patch).
-
-Follow the instructions to make TypeORM work with React Native (enable decorators, configure babel, etc), then apply the patch via patch-package and you should be good to go.
## API
-It is also possible to directly execute SQL against the db:
-
```typescript
interface QueryResult {
status: 0 | 1; // 0 for correct execution
@@ -60,23 +48,41 @@ interface BatchQueryResult {
}
interface ISQLite {
- open: (dbName: string, location?: string) => any;
- close: (dbName: string) => any;
+ open: (dbName: string, location?: string) => { status: 0 | 1 };
+ close: (dbName: string) => { status: 0 | 1 };
executeSql: (
dbName: string,
query: string,
params: any[] | undefined
) => QueryResult;
+ asyncExecuteSql: (
+ dbName: string,
+ query: string,
+ params: any[] | undefined,
+ cb: (res: QueryResult) => void
+ ) => void;
executeSqlBatch: (
dbName: string,
commands: SQLBatchParams[]
) => BatchQueryResult;
+ asyncExecuteSqlBatch: (
+ dbName: string,
+ commands: SQLBatchParams[],
+ cb: (res: BatchQueryResult) => void
+ ) => void;
+ loadSqlFile: (dbName: string, location: string) => FileLoadResult;
+ asyncLoadSqlFile: (
+ dbName: string,
+ location: string,
+ cb: (res: FileLoadResult) => void
+ ) => void;
}
```
-In your code
+# Usage
```typescript
+// Import as early as possible, auto-installs bindings
import 'react-native-quick-sqlite';
// `sqlite` is a globally registered object, so you can directly call it from anywhere in your javascript
@@ -128,9 +134,25 @@ if (!result.status) {
}
```
+Async versions are also available if you have too much SQL to execute
+
+```ts
+sqlite.asyncExecuteSql('myDatabase', 'SELECT * FROM "User";', [], (result) => {
+ if (result.status === 0) {
+ console.log('users', result.rows);
+ }
+});
+```
+
+## Use TypeORM
+
+This package offers a low-level API to raw execute SQL queries. I strongly recommend to use [TypeORM](https://github.com/typeorm/typeorm) (with [patch-package](https://github.com/ds300/patch-package)). TypeORM already has a sqlite-storage driver. In the `example` project on the `patch` folder you can a find a [patch for TypeORM](https://github.com/ospfranco/react-native-quick-sqlite/blob/main/example/patches/typeorm%2B0.2.31.patch).
+
+Follow the instructions to make TypeORM work with React Native (enable decorators, configure babel, etc), then apply the example patch via patch-package.
+
## Learn React Native JSI
-If you want to learn how to make your own JSI module buy my [JSI/C++ Cheatsheet](http://ospfranco.gumroad.com/l/IeeIvl), I'm also available for [freelance work](mailto:ospfranco@protonmail.com?subject=Freelance)!
+If you want to learn how to make your own JSI module buy my [JSI/C++ Cheatsheet](http://ospfranco.gumroad.com/l/jsi_guide), I'm also available for [freelance work](mailto:ospfranco@protonmail.com?subject=Freelance)!
## License
diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt
index 0f2edbb..b0956e0 100644
--- a/android/CMakeLists.txt
+++ b/android/CMakeLists.txt
@@ -1,49 +1,121 @@
-cmake_minimum_required(VERSION 3.4.1)
+cmake_minimum_required(VERSION 3.9.0)
set (CMAKE_VERBOSE_MAKEFILE ON)
-set (CMAKE_CXX_STANDARD 11)
-
-# Uncomment the following lines to compile the example project
-# include_directories(
-# ../cpp
-# ../node_modules/react-native/React
-# ../node_modules/react-native/React/Base
-# ../node_modules/react-native/ReactCommon/jsi
-# )
-
-# add_library(sequel
-# SHARED
-
-# ../node_modules/react-native/ReactCommon/jsi/jsi/jsi.cpp
-# ../cpp/sequel.cpp
-# ../cpp/sequel.h
-# ../cpp/SequelResult.h
-# ../cpp/react-native-quick-sqlite.cpp
-# ../cpp/react-native-quick-sqlite.h
-# ../cpp/sqlite3.h
-# ../cpp/sqlite3.c
-# cpp-adapter.cpp
-# )
+set (CMAKE_CXX_STANDARD 14)
+#set (CMAKE_CXX_FLAGS "-DFOLLY_NO_CONFIG=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_HAVE_MEMRCHR=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_MOBILE=1 -DON_ANDROID -DONANDROID -DFOR_HERMES=${FOR_HERMES}")
+
+set (PACKAGE_NAME "react-native-quick-sqlite")
+set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
+set (RN_SO_DIR ${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/first-party/react/jni)
+
+if(${REACT_NATIVE_VERSION} LESS 66)
+ set (
+ INCLUDE_JSI_CPP
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi/jsi/jsi.cpp"
+ )
+ set (
+ INCLUDE_JSIDYNAMIC_CPP
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp"
+ )
+endif()
+
+file (GLOB LIBFBJNI_INCLUDE_DIR "${BUILD_DIR}/fbjni-*-headers.jar/")
include_directories(
../cpp
- ../../react-native/React
- ../../react-native/React/Base
- ../../react-native/ReactCommon/jsi
+ "${NODE_MODULES_DIR}/react-native/React"
+ "${NODE_MODULES_DIR}/react-native/React/Base"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker"
+ "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi"
+ "${NODE_MODULES_DIR}/hermes-engine/android/include/"
+ ${INCLUDE_JSI_CPP} # only on older RN versions
+ ${INCLUDE_JSIDYNAMIC_CPP} # only on older RN versions
)
-add_library(sequel
+add_library(
+ ${PACKAGE_NAME}
SHARED
- ../../react-native/ReactCommon/jsi/jsi/jsi.cpp
- ../cpp/sequel.cpp
- ../cpp/sequel.h
- ../cpp/SequelResult.h
- ../cpp/react-native-quick-sqlite.cpp
- ../cpp/react-native-quick-sqlite.h
+ ../cpp/sqliteBridge.cpp
+ ../cpp/sqliteBridge.h
+ ../cpp/installer.cpp
+ ../cpp/installer.h
../cpp/sqlite3.h
../cpp/sqlite3.c
+ ../cpp/JSIHelper.h
+ ../cpp/JSIHelper.cpp
+ ../cpp/ThreadPool.h
+ ../cpp/ThreadPool.cpp
+ ../cpp/sqlfileloader.h
+ ../cpp/sqlfileloader.cpp
+ ../cpp/sqlbatchexecutor.h
+ ../cpp/sqlbatchexecutor.cpp
cpp-adapter.cpp
)
+# find fbjni package
+file (GLOB LIBFBJNI_INCLUDE_DIR "${BUILD_DIR}/fbjni-*-headers.jar/")
-target_link_libraries(sequel android log)
+target_include_directories(
+ ${PACKAGE_NAME}
+ PRIVATE
+ # --- fbjni ---
+ "${LIBFBJNI_INCLUDE_DIR}"
+ # --- React Native ---
+ "${NODE_MODULES_DIR}/react-native/React"
+ "${NODE_MODULES_DIR}/react-native/React/Base"
+ "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni"
+ "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker"
+ "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi"
+ "${NODE_MODULES_DIR}/hermes-engine/android/include/"
+ ${INCLUDE_JSI_CPP} # only on older RN versions
+ ${INCLUDE_JSIDYNAMIC_CPP} # only on older RN versions
+)
+
+file (GLOB LIBRN_DIR "${BUILD_DIR}/react-native-0*/jni/${ANDROID_ABI}")
+
+find_library(
+ FBJNI_LIB
+ fbjni
+ PATHS ${LIBRN_DIR}
+ NO_CMAKE_FIND_ROOT_PATH
+)
+
+find_library(
+ REACT_NATIVE_JNI_LIB
+ reactnativejni
+ PATHS ${LIBRN_DIR}
+ NO_CMAKE_FIND_ROOT_PATH
+)
+if(${REACT_NATIVE_VERSION} LESS 66)
+ # JSI lib didn't exist on RN 0.65 and before. Simply omit it.
+ set (JSI_LIB "")
+else()
+ # RN 0.66 distributes libjsi.so, can be used instead of compiling jsi.cpp manually.
+ find_library(
+ JSI_LIB
+ jsi
+ PATHS ${LIBRN_DIR}
+ NO_CMAKE_FIND_ROOT_PATH
+ )
+endif()
+
+find_library(
+ LOG_LIB
+ log
+)
+
+# target_link_libraries(sequel fbjni::fbjni android log)
+target_link_libraries(
+ ${PACKAGE_NAME}
+ ${LOG_LIB}
+ ${JSI_LIB}
+ ${REACT_NATIVE_JNI_LIB}
+ ${FBJNI_LIB}
+ android
+)
diff --git a/android/build.gradle b/android/build.gradle
index 1097713..1be1a1f 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,21 +1,21 @@
-buildscript {
- // Buildscript is evaluated before everything else so we can't use getExtOrDefault
- def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['Sequel_kotlinVersion']
+import org.apache.tools.ant.filters.ReplaceTokens
+import java.nio.file.Paths
+buildscript {
repositories {
google()
jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
- // noinspection DifferentKotlinGradleVersion
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.android.tools.build:gradle:4.2.2'
+ classpath 'de.undercouch:gradle-download-task:4.1.2'
}
}
apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
+apply plugin: 'de.undercouch.download'
def getExtOrDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['Sequel_' + name]
@@ -25,20 +25,48 @@ def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['Sequel_' + name]).toInteger()
}
+static def findNodeModules(baseDir) {
+ def basePath = baseDir.toPath().normalize()
+ // Node's module resolution algorithm searches up to the root directory,
+ // after which the base path will be null
+ while (basePath) {
+ def nodeModulesPath = Paths.get(basePath.toString(), "node_modules")
+ def reactNativePath = Paths.get(nodeModulesPath.toString(), "react-native")
+ if (nodeModulesPath.toFile().exists() && reactNativePath.toFile().exists()) {
+ return nodeModulesPath.toString()
+ }
+ basePath = basePath.getParent()
+ }
+ throw new GradleException("react-native-quick-sqlite: Failed to find node_modules/ path!")
+}
+
+def nodeModules = findNodeModules(projectDir);
+logger.warn("react-native-quick-sqlite: node_modules/ found at: ${nodeModules}");
+
+def reactNative = new File("$nodeModules/react-native")
+
+def reactProperties = new Properties()
+file("$nodeModules/react-native/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) }
+def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME").split("\\.")[1].toInteger()
+
android {
+
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
buildToolsVersion getExtOrDefault('buildToolsVersion')
+
defaultConfig {
- minSdkVersion 16
+ minSdkVersion 21
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
- cppFlags "-O2 -frtti -fexceptions -Wall -Wno-unused-variable -fstack-protector-all"
- arguments "-DDEV_CMAKE=true"
+ cppFlags "-O2", "-fexceptions", "-frtti", "-std=c++1y", "-DONANDROID"
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
+ arguments '-DANDROID_STL=c++_shared',
+ "-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}",
+ "-DNODE_MODULES_DIR=${nodeModules}"
}
}
@@ -49,6 +77,12 @@ android {
path "CMakeLists.txt"
}
}
+
+ packagingOptions {
+ // Exclude all Libraries that are already present in the user's app (through React Native or by him installing REA)
+ excludes = ["**/libc++_shared.so", "**/libfbjni.so", "**/libjsi.so", "**/libreactnativejni.so", "**/libfolly_json.so", "**/libjscexecutor.so", "**/libhermes.so"]
+ exclude "META-INF/**"
+ }
buildTypes {
release {
@@ -62,11 +96,15 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ configurations {
+ extractHeaders
+ extractJNI
+ }
}
repositories {
mavenCentral()
- jcenter()
google()
def found = false
@@ -76,10 +114,7 @@ repositories {
if (rootProject.ext.has('reactNativeAndroidRoot')) {
defaultDir = rootProject.ext.get('reactNativeAndroidRoot')
} else {
- defaultDir = new File(
- projectDir,
- '/../../../node_modules/react-native/android'
- )
+ defaultDir = file("$nodeModules/react-native/android")
}
if (defaultDir.exists()) {
@@ -135,10 +170,68 @@ repositories {
}
}
-def kotlin_version = getExtOrDefault('kotlinVersion')
dependencies {
// noinspection GradleDynamicVersion
api 'com.facebook.react:react-native:+'
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+
+ //noinspection GradleDynamicVersion
+ extractHeaders("com.facebook.fbjni:fbjni:+:headers")
+ //noinspection GradleDynamicVersion
+ extractJNI("com.facebook.fbjni:fbjni:+")
+
+ def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include "**/**/*.aar" }).singleFile
+ def jscAAR = fileTree("${nodeModules}/jsc-android/dist/org/webkit/android-jsc").matching({ it.include "**/**/*.aar" }).singleFile
+
+
+ extractJNI(files(rnAAR, jscAAR))
}
+
+def downloadsDir = new File("$buildDir/downloads")
+
+task createNativeDepsDirectories {
+ doLast {
+ downloadsDir.mkdirs()
+ }
+}
+
+
+task extractAARHeaders {
+ doLast {
+ configurations.extractHeaders.files.each {
+ def file = it.absoluteFile
+ copy {
+ from zipTree(file)
+ into "$buildDir/$file.name"
+ include "**/*.h"
+ }
+ }
+ }
+}
+
+extractAARHeaders.mustRunAfter createNativeDepsDirectories
+
+task extractJNIFiles {
+ doLast {
+ configurations.extractJNI.files.each {
+ def file = it.absoluteFile
+
+ copy {
+ from zipTree(file)
+ into "$buildDir/$file.name"
+ include "jni/**/*"
+ }
+ }
+ }
+}
+
+extractJNIFiles.mustRunAfter extractAARHeaders
+
+// pre-native build pipeline
+
+tasks.whenTaskAdded { task ->
+ if (!task.name.contains('Clean') && (task.name.contains('externalNative') || task.name.contains('CMake'))) {
+ task.dependsOn(extractAARHeaders)
+ task.dependsOn(extractJNIFiles)
+ }
+}
\ No newline at end of file
diff --git a/android/cpp-adapter.cpp b/android/cpp-adapter.cpp
index 7d82f88..9e8f570 100644
--- a/android/cpp-adapter.cpp
+++ b/android/cpp-adapter.cpp
@@ -1,17 +1,37 @@
#include
-#include "react-native-quick-sqlite.h"
+#include
+#include
+#include
+#include "installer.h"
+#include "logs.h"
+#include
-extern "C" JNIEXPORT void JNICALL
-Java_com_reactnativequicksqlite_SequelModule_initialize(JNIEnv *env, jclass clazz, jlong jsiPtr, jstring docPath)
+struct QuickSQLiteBridge : jni::JavaClass
{
- jboolean isCopy;
- const char *docPathString = (env)->GetStringUTFChars(docPath, &isCopy);
+ static constexpr auto kJavaDescriptor = "Lcom/reactnativequicksqlite/QuickSQLiteBridge;";
- installSequel(*reinterpret_cast(jsiPtr), docPathString);
-}
+ static void registerNatives()
+ {
+ javaClassStatic()->registerNatives({// initialization for JSI
+ makeNativeMethod("installNativeJsi", QuickSQLiteBridge::installNativeJsi)});
+ }
-extern "C" JNIEXPORT void JNICALL
-Java_com_reactnativequicksqlite_SequelModule_destruct(JNIEnv *env, jclass clazz)
+private:
+ static void installNativeJsi(jni::alias_ref thiz,
+ jlong jsiRuntimePtr,
+ jni::alias_ref jsCallInvokerHolder,
+ jni::alias_ref docPath)
+ {
+ auto jsiRuntime = reinterpret_cast(jsiRuntimePtr);
+ auto jsCallInvoker = jsCallInvokerHolder->cthis()->getCallInvoker();
+ std::string docPathString = docPath->toStdString();
+
+ install(*jsiRuntime, jsCallInvoker, docPathString.c_str());
+ }
+};
+
+JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *)
{
- cleanUpSequel();
+ return jni::initialize(vm, []
+ { QuickSQLiteBridge::registerNatives(); });
}
\ No newline at end of file
diff --git a/android/gradle.properties b/android/gradle.properties
index 0619cef..3dd260a 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,4 +1,4 @@
-Sequel_kotlinVersion=1.3.50
-Sequel_compileSdkVersion=29
-Sequel_buildToolsVersion=29.0.2
-Sequel_targetSdkVersion=29
\ No newline at end of file
+Sequel_kotlinVersion=1.6.0
+Sequel_compileSdkVersion=30
+Sequel_buildToolsVersion=30
+Sequel_targetSdkVersion=30
\ No newline at end of file
diff --git a/android/src/main/java/com/reactnativequicksqlite/QuickSQLiteBridge.java b/android/src/main/java/com/reactnativequicksqlite/QuickSQLiteBridge.java
new file mode 100644
index 0000000..9ca5bf8
--- /dev/null
+++ b/android/src/main/java/com/reactnativequicksqlite/QuickSQLiteBridge.java
@@ -0,0 +1,24 @@
+package com.reactnativequicksqlite;
+
+import android.util.Log;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
+
+public class QuickSQLiteBridge {
+ private native void installNativeJsi(long jsContextNativePointer, CallInvokerHolderImpl jsCallInvokerHolder, String docPath);
+ public static final QuickSQLiteBridge instance = new QuickSQLiteBridge();
+
+ public void install(ReactContext context) {
+ long jsContextPointer = context.getJavaScriptContextHolder().get();
+ CallInvokerHolderImpl jsCallInvokerHolder = (CallInvokerHolderImpl)context.getCatalystInstance().getJSCallInvokerHolder();
+ final String path = context.getFilesDir().getAbsolutePath();
+
+ installNativeJsi(
+ jsContextPointer,
+ jsCallInvokerHolder,
+ path
+ );
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/reactnativequicksqlite/SequelModule.java b/android/src/main/java/com/reactnativequicksqlite/SequelModule.java
new file mode 100644
index 0000000..bec3079
--- /dev/null
+++ b/android/src/main/java/com/reactnativequicksqlite/SequelModule.java
@@ -0,0 +1,37 @@
+package com.reactnativequicksqlite;
+
+import androidx.annotation.NonNull;
+import android.util.Log;
+
+import com.facebook.jni.HybridData;
+import com.facebook.jni.annotations.DoNotStrip;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
+
+class SequelModule extends ReactContextBaseJavaModule {
+ public static final String NAME = "QuickSQLite";
+
+ public SequelModule(ReactApplicationContext context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @ReactMethod(isBlockingSynchronousMethod = true)
+ public boolean install() {
+ try {
+ System.loadLibrary("react-native-quick-sqlite");
+ QuickSQLiteBridge.instance.install(getReactApplicationContext());
+ return true;
+ } catch (Exception exception) {
+ Log.e(NAME, "Failed to install JSI Bindings!", exception);
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/reactnativesequel/SequelPackage.java b/android/src/main/java/com/reactnativequicksqlite/SequelPackage.java
similarity index 90%
rename from android/src/main/java/com/reactnativesequel/SequelPackage.java
rename to android/src/main/java/com/reactnativequicksqlite/SequelPackage.java
index 49eeadb..ec16dd5 100644
--- a/android/src/main/java/com/reactnativesequel/SequelPackage.java
+++ b/android/src/main/java/com/reactnativequicksqlite/SequelPackage.java
@@ -16,7 +16,7 @@ public class SequelPackage implements ReactPackage {
@NonNull
@Override
public List createNativeModules(@NonNull ReactApplicationContext reactContext) {
- return Arrays.asList(new SequelModule(reactContext));
+ return Collections.singletonList(new SequelModule(reactContext));
}
@NonNull
diff --git a/android/src/main/java/com/reactnativesequel/SequelModule.java b/android/src/main/java/com/reactnativesequel/SequelModule.java
deleted file mode 100644
index aeb7bcf..0000000
--- a/android/src/main/java/com/reactnativesequel/SequelModule.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.reactnativequicksqlite;
-
-import androidx.annotation.NonNull;
-
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContextBaseJavaModule;
-
-class SequelModule extends ReactContextBaseJavaModule {
- static {
- System.loadLibrary("sequel");
- }
-
- private static native void initialize(long jsiPtr, String docDir);
- private static native void destruct();
-
- public SequelModule(ReactApplicationContext reactContext) {
- super(reactContext);
- }
-
- @NonNull
- @Override
- public String getName() {
- return "Sequel";
- }
-
-
- @NonNull
- @Override
- public void initialize() {
- super.initialize();
-
- // LEFT HERE:
- // Convert the second arg into a std::string in the cpp-adapter file
- // https://stackoverflow.com/questions/41820039/jstringjni-to-stdstringc-with-utf8-characters
- SequelModule.initialize(
- this.getReactApplicationContext().getJavaScriptContextHolder().get(),
- this.getReactApplicationContext().getFilesDir().getAbsolutePath()
- );
- }
-
- @Override
- public void onCatalystInstanceDestroy() {
- SequelModule.destruct();
- }
-}
\ No newline at end of file
diff --git a/cpp/JSIHelper.cpp b/cpp/JSIHelper.cpp
new file mode 100644
index 0000000..c46ef46
--- /dev/null
+++ b/cpp/JSIHelper.cpp
@@ -0,0 +1,196 @@
+//
+// JSIHelper.cpp
+// react-native-quick-sqlite
+//
+// Created by Oscar on 13.03.22.
+//
+
+#include "JSIHelper.h"
+
+using namespace std;
+using namespace facebook;
+
+QuickValue createNullQuickValue()
+{
+ return QuickValue{
+ .dataType = NULL_VALUE};
+}
+
+QuickValue createBooleanQuickValue(bool value)
+{
+ return QuickValue{
+ .dataType = BOOLEAN,
+ .booleanValue = int(value)};
+}
+
+QuickValue createTextQuickValue(string value)
+{
+ return QuickValue{
+ .dataType = TEXT,
+ .textValue = value};
+}
+
+QuickValue createIntegerQuickValue(int value)
+{
+ return QuickValue{
+ .dataType = INTEGER,
+ .doubleOrIntValue = static_cast(value)};
+}
+
+QuickValue createIntegerQuickValue(double value)
+{
+ return QuickValue{
+ .dataType = INTEGER,
+ .doubleOrIntValue = value};
+}
+
+QuickValue createInt64QuickValue(long long value)
+{
+ return QuickValue{
+ .dataType = INT64,
+ .int64Value = value};
+}
+
+QuickValue createDoubleQuickValue(double value)
+{
+ return QuickValue{
+ .dataType = DOUBLE,
+ .doubleOrIntValue = value};
+}
+
+QuickValue createArrayBufferQuickValue(uint8_t *arrayBufferValue, size_t arrayBufferSize)
+{
+ return QuickValue{
+ .dataType = ARRAY_BUFFER,
+ .arrayBufferValue = shared_ptr{arrayBufferValue},
+ .arrayBufferSize = arrayBufferSize};
+}
+
+void jsiQueryArgumentsToSequelParam(jsi::Runtime &rt, jsi::Value const ¶ms, vector *target)
+{
+ if (params.isNull() || params.isUndefined())
+ {
+ return;
+ }
+
+ jsi::Array values = params.asObject(rt).asArray(rt);
+
+ for (int ii = 0; ii < values.length(rt); ii++)
+ {
+
+ jsi::Value value = values.getValueAtIndex(rt, ii);
+ if (value.isNull() || value.isUndefined())
+ {
+ target->push_back(createNullQuickValue());
+ }
+ else if (value.isBool())
+ {
+ target->push_back(createBooleanQuickValue(value.getBool()));
+ }
+ else if (value.isNumber())
+ {
+ double doubleVal = value.asNumber();
+ int intVal = (int)doubleVal;
+ long long longVal = (long)doubleVal;
+ if (intVal == doubleVal)
+ {
+ target->push_back(createIntegerQuickValue(intVal));
+ }
+ else if (longVal == doubleVal)
+ {
+ target->push_back(createInt64QuickValue(longVal));
+ }
+ else
+ {
+ target->push_back(createDoubleQuickValue(doubleVal));
+ }
+ }
+ else if (value.isString())
+ {
+ string strVal = value.asString(rt).utf8(rt);
+ target->push_back(createTextQuickValue(strVal));
+ }
+ else if (value.isObject())
+ {
+ auto obj = value.asObject(rt);
+ if (obj.isArrayBuffer(rt))
+ {
+ auto buf = obj.getArrayBuffer(rt);
+ target->push_back(createArrayBufferQuickValue(buf.data(rt), buf.size(rt)));
+ }
+ }
+ else
+ {
+ target->push_back(createNullQuickValue());
+ }
+ }
+}
+
+jsi::Value createSequelQueryExecutionResult(jsi::Runtime &rt, SQLiteOPResult status, vector