expo-sqlite 11.8.0 → 12.0.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/CHANGELOG.md +21 -0
- package/android/CMakeLists.txt +2 -2
- package/android/build.gradle +50 -3
- package/android/src/main/cpp/NativeDatabaseBinding.cpp +142 -0
- package/android/src/main/cpp/NativeDatabaseBinding.h +75 -0
- package/android/src/main/cpp/NativeStatementBinding.cpp +146 -0
- package/android/src/main/cpp/NativeStatementBinding.h +95 -0
- package/android/src/main/cpp/SQLite3Main.cpp +7 -2
- package/android/src/main/cpp/SQLite3Wrapper.cpp +0 -30
- package/android/src/main/cpp/SQLite3Wrapper.h +0 -4
- package/android/src/main/java/expo/modules/sqlite/NativeDatabase.kt +11 -0
- package/android/src/main/java/expo/modules/sqlite/NativeDatabaseBinding.kt +79 -0
- package/android/src/main/java/expo/modules/sqlite/NativeStatement.kt +11 -0
- package/android/src/main/java/expo/modules/sqlite/NativeStatementBinding.kt +40 -0
- package/android/src/main/java/expo/modules/sqlite/SQLExceptions.kt +17 -6
- package/android/src/main/java/expo/modules/sqlite/SQLRecords.kt +16 -3
- package/android/src/main/java/expo/modules/sqlite/SQLite3Wrapper.kt +0 -30
- package/android/src/main/java/expo/modules/sqlite/SQLiteHelpers.kt +0 -79
- package/android/src/main/java/expo/modules/sqlite/SQLiteModule.kt +2 -55
- package/android/src/main/java/expo/modules/sqlite/SQLiteModuleNext.kt +447 -0
- package/android/src/main/java/expo/modules/sqlite/SQLiteOptions.kt +20 -0
- package/build/next/Database.d.ts +254 -0
- package/build/next/Database.d.ts.map +1 -0
- package/build/next/Database.js +324 -0
- package/build/next/Database.js.map +1 -0
- package/build/next/ExpoSQLiteNext.d.ts +12 -0
- package/build/next/ExpoSQLiteNext.d.ts.map +1 -0
- package/build/next/ExpoSQLiteNext.js +26 -0
- package/build/next/ExpoSQLiteNext.js.map +1 -0
- package/build/next/ExpoSQLiteNext.native.d.ts +3 -0
- package/build/next/ExpoSQLiteNext.native.d.ts.map +1 -0
- package/build/next/ExpoSQLiteNext.native.js +3 -0
- package/build/next/ExpoSQLiteNext.native.js.map +1 -0
- package/build/next/NativeDatabase.d.ts +44 -0
- package/build/next/NativeDatabase.d.ts.map +1 -0
- package/build/next/NativeDatabase.js +2 -0
- package/build/next/NativeDatabase.js.map +1 -0
- package/build/next/NativeStatement.d.ts +68 -0
- package/build/next/NativeStatement.d.ts.map +1 -0
- package/build/next/NativeStatement.js +2 -0
- package/build/next/NativeStatement.js.map +1 -0
- package/build/next/Statement.d.ts +120 -0
- package/build/next/Statement.d.ts.map +1 -0
- package/build/next/Statement.js +135 -0
- package/build/next/Statement.js.map +1 -0
- package/build/next/hooks.d.ts +35 -0
- package/build/next/hooks.d.ts.map +1 -0
- package/build/next/hooks.js +57 -0
- package/build/next/hooks.js.map +1 -0
- package/build/next/index.d.ts +4 -0
- package/build/next/index.d.ts.map +1 -0
- package/build/next/index.js +4 -0
- package/build/next/index.js.map +1 -0
- package/expo-module.config.json +2 -2
- package/ios/CRSQLiteLoader.h +3 -1
- package/ios/CRSQLiteLoader.m +11 -6
- package/ios/Exceptions.swift +13 -0
- package/ios/ExpoSQLite.podspec +2 -2
- package/ios/NativeDatabase.swift +26 -0
- package/ios/NativeStatement.swift +13 -0
- package/ios/SQLAction.swift +23 -0
- package/ios/SQLiteModule.swift +0 -53
- package/ios/SQLiteModuleNext.swift +538 -0
- package/ios/SQLiteOptions.swift +26 -0
- package/next.d.ts +1 -0
- package/next.js +1 -0
- package/package.json +4 -2
- package/src/next/Database.ts +446 -0
- package/src/next/ExpoSQLiteNext.native.ts +2 -0
- package/src/next/ExpoSQLiteNext.ts +34 -0
- package/src/next/NativeDatabase.ts +58 -0
- package/src/next/NativeStatement.ts +85 -0
- package/src/next/Statement.ts +243 -0
- package/src/next/hooks.tsx +108 -0
- package/src/next/index.ts +3 -0
- package/vendor/README.expo.md +0 -6
- package/vendor/shell.c +0 -28032
- package/vendor/sqlite3.c +0 -247629
- package/vendor/sqlite3.h +0 -13068
- package/vendor/sqlite3ext.h +0 -709
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,26 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 12.0.0 — 2023-11-06
|
|
14
|
+
|
|
15
|
+
### 🛠 Breaking changes
|
|
16
|
+
|
|
17
|
+
- Bumped iOS deployment target to 13.4. ([#25063](https://github.com/expo/expo/pull/25063) by [@gabrieldonadel](https://github.com/gabrieldonadel))
|
|
18
|
+
- Remove CRSQLite support on legacy API. ([#25092](https://github.com/expo/expo/pull/25092) by [@kudo](https://github.com/kudo))
|
|
19
|
+
|
|
20
|
+
### 🎉 New features
|
|
21
|
+
|
|
22
|
+
- Added Android implementation for `sqlite/next` APIs. ([#25021](https://github.com/expo/expo/pull/25021) by [@kudo](https://github.com/kudo))
|
|
23
|
+
- Added the `useSQLiteContext` hook that can be used across components. ([#25129](https://github.com/expo/expo/pull/25129) by [@kudo](https://github.com/kudo))
|
|
24
|
+
|
|
25
|
+
### 🐛 Bug fixes
|
|
26
|
+
|
|
27
|
+
- [ios] Fix some issues for `sqlite/next`. ([#25022](https://github.com/expo/expo/pull/25022) by [@kudo](https://github.com/kudo))
|
|
28
|
+
|
|
29
|
+
### 💡 Others
|
|
30
|
+
|
|
31
|
+
- [Android] Removed the package included SQLite source and download in build time. ([#25186](https://github.com/expo/expo/pull/25186) by [@kudo](https://github.com/kudo))
|
|
32
|
+
|
|
13
33
|
## 11.8.0 — 2023-10-17
|
|
14
34
|
|
|
15
35
|
### 🛠 Breaking changes
|
|
@@ -19,6 +39,7 @@
|
|
|
19
39
|
### 🎉 New features
|
|
20
40
|
|
|
21
41
|
- [Android] Rewrite implementations from low-level SQLite bindings. ([#24730](https://github.com/expo/expo/pull/24730) by [@kudo](https://github.com/kudo))
|
|
42
|
+
- Introduced `expo-sqlite/next` new APIs. ([#24812](https://github.com/expo/expo/pull/24812) by [@kudo](https://github.com/kudo))
|
|
22
43
|
|
|
23
44
|
## 11.7.1 — 2023-09-18
|
|
24
45
|
|
package/android/CMakeLists.txt
CHANGED
|
@@ -14,14 +14,14 @@ add_library(
|
|
|
14
14
|
${PACKAGE_NAME}
|
|
15
15
|
SHARED
|
|
16
16
|
${SOURCES}
|
|
17
|
-
"${
|
|
17
|
+
"${SQLITE3_SRC_DIR}/sqlite3.c"
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
target_include_directories(
|
|
21
21
|
${PACKAGE_NAME}
|
|
22
22
|
PRIVATE
|
|
23
23
|
${SRC_DIR}
|
|
24
|
-
"${
|
|
24
|
+
"${SQLITE3_SRC_DIR}"
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
find_library(LOG_LIB log)
|
package/android/build.gradle
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
apply plugin: 'kotlin-android'
|
|
3
3
|
apply plugin: 'maven-publish'
|
|
4
|
+
apply plugin: 'de.undercouch.download'
|
|
4
5
|
|
|
5
6
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '
|
|
7
|
+
version = '12.0.0'
|
|
7
8
|
|
|
8
9
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
9
10
|
if (expoModulesCorePlugin.exists()) {
|
|
@@ -16,6 +17,11 @@ if (expoModulesCorePlugin.exists()) {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
def SQLITE_VERSION = '3420000'
|
|
21
|
+
def customDownloadsDir = System.getenv("REACT_NATIVE_DOWNLOADS_DIR")
|
|
22
|
+
def downloadsDir = customDownloadsDir ? new File(customDownloadsDir) : new File("$buildDir/downloads")
|
|
23
|
+
def SQLITE3_SRC_DIR = new File("$buildDir/sqlite3_src")
|
|
24
|
+
|
|
19
25
|
def reactNativeArchitectures() {
|
|
20
26
|
def value = project.getProperties().get("reactNativeArchitectures")
|
|
21
27
|
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
|
@@ -42,6 +48,7 @@ buildscript {
|
|
|
42
48
|
|
|
43
49
|
dependencies {
|
|
44
50
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
|
|
51
|
+
classpath("de.undercouch:gradle-download-task:5.5.0")
|
|
45
52
|
}
|
|
46
53
|
}
|
|
47
54
|
|
|
@@ -99,12 +106,13 @@ android {
|
|
|
99
106
|
namespace "expo.modules.sqlite"
|
|
100
107
|
defaultConfig {
|
|
101
108
|
versionCode 18
|
|
102
|
-
versionName "
|
|
109
|
+
versionName "12.0.0"
|
|
103
110
|
|
|
104
111
|
externalNativeBuild {
|
|
105
112
|
cmake {
|
|
106
113
|
abiFilters (*reactNativeArchitectures())
|
|
107
|
-
arguments "-DANDROID_STL=c++_shared"
|
|
114
|
+
arguments "-DANDROID_STL=c++_shared",
|
|
115
|
+
"-DSQLITE3_SRC_DIR=${SQLITE3_SRC_DIR}"
|
|
108
116
|
}
|
|
109
117
|
}
|
|
110
118
|
}
|
|
@@ -127,3 +135,42 @@ dependencies {
|
|
|
127
135
|
|
|
128
136
|
compileOnly 'com.facebook.fbjni:fbjni:0.3.0'
|
|
129
137
|
}
|
|
138
|
+
|
|
139
|
+
def createNativeDepsDirectories = tasks.register('createNativeDepsDirectories') {
|
|
140
|
+
downloadsDir.mkdirs()
|
|
141
|
+
SQLITE3_SRC_DIR.mkdirs()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
def downloadSQLite = tasks.create('downloadSQLite', Download) {
|
|
145
|
+
dependsOn(createNativeDepsDirectories)
|
|
146
|
+
src("https://www.sqlite.org/2023/sqlite-amalgamation-${SQLITE_VERSION}.zip")
|
|
147
|
+
onlyIfNewer(true)
|
|
148
|
+
overwrite(false)
|
|
149
|
+
dest(new File(downloadsDir, "sqlite-amalgamation-${SQLITE_VERSION}.zip"))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
def prepareSQLite = tasks.register('prepareSQLite', Copy) {
|
|
153
|
+
dependsOn(downloadSQLite)
|
|
154
|
+
from(zipTree(downloadSQLite.dest))
|
|
155
|
+
into(SQLITE3_SRC_DIR)
|
|
156
|
+
eachFile {
|
|
157
|
+
// flatten files
|
|
158
|
+
path = name
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
void nativeBuildDependsOn(project, dependsOnTask) {
|
|
163
|
+
def buildTasks = project.tasks.findAll { task ->
|
|
164
|
+
def taskName = task.name
|
|
165
|
+
if (taskName.contains("Clean")) { return false }
|
|
166
|
+
if (taskName.contains("externalNative") || taskName.contains("CMake") || taskName.contains("generateJsonModel")) {
|
|
167
|
+
return true
|
|
168
|
+
}
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
buildTasks.forEach { task -> task.dependsOn(dependsOnTask) }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
afterEvaluate {
|
|
175
|
+
nativeBuildDependsOn(project, prepareSQLite)
|
|
176
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#include "NativeDatabaseBinding.h"
|
|
4
|
+
|
|
5
|
+
namespace jni = facebook::jni;
|
|
6
|
+
|
|
7
|
+
namespace expo {
|
|
8
|
+
|
|
9
|
+
namespace {
|
|
10
|
+
|
|
11
|
+
constexpr char TAG[] = "expo-sqlite";
|
|
12
|
+
|
|
13
|
+
} // namespace
|
|
14
|
+
|
|
15
|
+
// static
|
|
16
|
+
void NativeDatabaseBinding::registerNatives() {
|
|
17
|
+
registerHybrid({
|
|
18
|
+
makeNativeMethod("initHybrid", NativeDatabaseBinding::initHybrid),
|
|
19
|
+
makeNativeMethod("sqlite3_changes",
|
|
20
|
+
NativeDatabaseBinding::sqlite3_changes),
|
|
21
|
+
makeNativeMethod("sqlite3_close", NativeDatabaseBinding::sqlite3_close),
|
|
22
|
+
makeNativeMethod("sqlite3_db_filename",
|
|
23
|
+
NativeDatabaseBinding::sqlite3_db_filename),
|
|
24
|
+
makeNativeMethod("sqlite3_enable_load_extension",
|
|
25
|
+
NativeDatabaseBinding::sqlite3_enable_load_extension),
|
|
26
|
+
makeNativeMethod("sqlite3_exec", NativeDatabaseBinding::sqlite3_exec),
|
|
27
|
+
makeNativeMethod("sqlite3_get_autocommit",
|
|
28
|
+
NativeDatabaseBinding::sqlite3_get_autocommit),
|
|
29
|
+
makeNativeMethod("sqlite3_last_insert_rowid",
|
|
30
|
+
NativeDatabaseBinding::sqlite3_last_insert_rowid),
|
|
31
|
+
makeNativeMethod("sqlite3_load_extension",
|
|
32
|
+
NativeDatabaseBinding::sqlite3_load_extension),
|
|
33
|
+
makeNativeMethod("sqlite3_open", NativeDatabaseBinding::sqlite3_open),
|
|
34
|
+
makeNativeMethod("sqlite3_prepare_v2",
|
|
35
|
+
NativeDatabaseBinding::sqlite3_prepare_v2),
|
|
36
|
+
makeNativeMethod("sqlite3_update_hook",
|
|
37
|
+
NativeDatabaseBinding::sqlite3_update_hook),
|
|
38
|
+
makeNativeMethod("convertSqlLiteErrorToString",
|
|
39
|
+
NativeDatabaseBinding::convertSqlLiteErrorToString),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
int NativeDatabaseBinding::sqlite3_changes() { return ::sqlite3_changes(db); }
|
|
44
|
+
|
|
45
|
+
int NativeDatabaseBinding::sqlite3_close() {
|
|
46
|
+
// Not setting `db = nullptr` here because we may need the db pointer to get
|
|
47
|
+
// error messages if sqlite3_close has errors.
|
|
48
|
+
return ::sqlite3_close(db);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
std::string
|
|
52
|
+
NativeDatabaseBinding::sqlite3_db_filename(const std::string &dbName) {
|
|
53
|
+
return ::sqlite3_db_filename(db, dbName.c_str());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
int NativeDatabaseBinding::sqlite3_enable_load_extension(int onoff) {
|
|
57
|
+
return ::sqlite3_enable_load_extension(db, onoff);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
int NativeDatabaseBinding::sqlite3_exec(const std::string &source) {
|
|
61
|
+
char *error;
|
|
62
|
+
int ret = ::sqlite3_exec(db, source.c_str(), nullptr, nullptr, &error);
|
|
63
|
+
if (ret != SQLITE_OK && error) {
|
|
64
|
+
std::string errorString(error);
|
|
65
|
+
::sqlite3_free(error);
|
|
66
|
+
jni::throwNewJavaException(SQLiteErrorException::create(errorString).get());
|
|
67
|
+
}
|
|
68
|
+
return ret;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
int NativeDatabaseBinding::sqlite3_get_autocommit() {
|
|
72
|
+
return ::sqlite3_get_autocommit(db);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
int64_t NativeDatabaseBinding::sqlite3_last_insert_rowid() {
|
|
76
|
+
return ::sqlite3_last_insert_rowid(db);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
int NativeDatabaseBinding::sqlite3_load_extension(
|
|
80
|
+
const std::string &libPath, const std::string &entryProc) {
|
|
81
|
+
char *error;
|
|
82
|
+
int ret =
|
|
83
|
+
::sqlite3_load_extension(db, libPath.c_str(), entryProc.c_str(), &error);
|
|
84
|
+
if (ret != SQLITE_OK && error) {
|
|
85
|
+
std::string errorString(error);
|
|
86
|
+
::sqlite3_free(error);
|
|
87
|
+
jni::throwNewJavaException(SQLiteErrorException::create(errorString).get());
|
|
88
|
+
}
|
|
89
|
+
return ret;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
int NativeDatabaseBinding::sqlite3_open(const std::string &dbPath) {
|
|
93
|
+
return ::sqlite3_open(dbPath.c_str(), &db);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
int NativeDatabaseBinding::sqlite3_prepare_v2(
|
|
97
|
+
const std::string &source,
|
|
98
|
+
jni::alias_ref<NativeStatementBinding::javaobject> statement) {
|
|
99
|
+
NativeStatementBinding *cStatement = cthis(statement);
|
|
100
|
+
return ::sqlite3_prepare_v2(db, source.c_str(), source.size(),
|
|
101
|
+
&cStatement->stmt, nullptr);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
void NativeDatabaseBinding::sqlite3_update_hook(bool enabled) {
|
|
105
|
+
if (enabled) {
|
|
106
|
+
::sqlite3_update_hook(db, NativeDatabaseBinding::OnUpdateHook, this);
|
|
107
|
+
} else {
|
|
108
|
+
::sqlite3_update_hook(db, nullptr, nullptr);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
jni::local_ref<jni::JString>
|
|
113
|
+
NativeDatabaseBinding::convertSqlLiteErrorToString() {
|
|
114
|
+
int code = sqlite3_errcode(db);
|
|
115
|
+
const char *message = sqlite3_errmsg(db);
|
|
116
|
+
std::string result("Error code ");
|
|
117
|
+
result += code;
|
|
118
|
+
result += ": ";
|
|
119
|
+
result += message;
|
|
120
|
+
return jni::make_jstring(result);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// static
|
|
124
|
+
jni::local_ref<NativeDatabaseBinding::jhybriddata>
|
|
125
|
+
NativeDatabaseBinding::initHybrid(jni::alias_ref<jhybridobject> jThis) {
|
|
126
|
+
return makeCxxInstance(jThis);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// static
|
|
130
|
+
void NativeDatabaseBinding::OnUpdateHook(void *arg, int action,
|
|
131
|
+
char const *dbName,
|
|
132
|
+
char const *tableName,
|
|
133
|
+
sqlite3_int64 rowId) {
|
|
134
|
+
NativeDatabaseBinding *pThis = reinterpret_cast<NativeDatabaseBinding *>(arg);
|
|
135
|
+
static const auto method =
|
|
136
|
+
jni::findClassStatic("expo/modules/sqlite/NativeDatabaseBinding")
|
|
137
|
+
->getMethod<void(jint, jstring, jstring, jlong)>("onUpdate");
|
|
138
|
+
method(pThis->javaPart_, action, jni::make_jstring(dbName).get(),
|
|
139
|
+
jni::make_jstring(tableName).get(), rowId);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
} // namespace expo
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include <fbjni/fbjni.h>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
#include "NativeStatementBinding.h"
|
|
9
|
+
#include "sqlite3.h"
|
|
10
|
+
|
|
11
|
+
namespace jni = facebook::jni;
|
|
12
|
+
|
|
13
|
+
namespace expo {
|
|
14
|
+
|
|
15
|
+
class NativeDatabaseBinding : public jni::HybridClass<NativeDatabaseBinding> {
|
|
16
|
+
public:
|
|
17
|
+
static constexpr auto kJavaDescriptor =
|
|
18
|
+
"Lexpo/modules/sqlite/NativeDatabaseBinding;";
|
|
19
|
+
|
|
20
|
+
static void registerNatives();
|
|
21
|
+
|
|
22
|
+
// sqlite3 bindings
|
|
23
|
+
int sqlite3_changes();
|
|
24
|
+
int sqlite3_close();
|
|
25
|
+
std::string sqlite3_db_filename(const std::string &dbName);
|
|
26
|
+
int sqlite3_enable_load_extension(int onoff);
|
|
27
|
+
int sqlite3_exec(const std::string &source);
|
|
28
|
+
int sqlite3_get_autocommit();
|
|
29
|
+
int64_t sqlite3_last_insert_rowid();
|
|
30
|
+
int sqlite3_load_extension(const std::string &libPath,
|
|
31
|
+
const std::string &entryProc);
|
|
32
|
+
int sqlite3_open(const std::string &dbPath);
|
|
33
|
+
int sqlite3_prepare_v2(
|
|
34
|
+
const std::string &source,
|
|
35
|
+
jni::alias_ref<NativeStatementBinding::javaobject> statement);
|
|
36
|
+
void sqlite3_update_hook(bool enabled);
|
|
37
|
+
|
|
38
|
+
// helpers
|
|
39
|
+
jni::local_ref<jni::JString> convertSqlLiteErrorToString();
|
|
40
|
+
|
|
41
|
+
private:
|
|
42
|
+
explicit NativeDatabaseBinding(
|
|
43
|
+
jni::alias_ref<NativeDatabaseBinding::jhybridobject> jThis)
|
|
44
|
+
: javaPart_(jni::make_global(jThis)) {}
|
|
45
|
+
|
|
46
|
+
private:
|
|
47
|
+
static jni::local_ref<jhybriddata>
|
|
48
|
+
initHybrid(jni::alias_ref<jhybridobject> jThis);
|
|
49
|
+
|
|
50
|
+
static void OnUpdateHook(void *arg, int action, char const *dbName,
|
|
51
|
+
char const *tableName, sqlite3_int64 rowId);
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
friend HybridBase;
|
|
55
|
+
|
|
56
|
+
jni::global_ref<NativeDatabaseBinding::javaobject> javaPart_;
|
|
57
|
+
sqlite3 *db;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A convenient wrapper for the Kotlin SQLiteErrorException.
|
|
62
|
+
*/
|
|
63
|
+
class SQLiteErrorException
|
|
64
|
+
: public jni::JavaClass<SQLiteErrorException, CodedException> {
|
|
65
|
+
public:
|
|
66
|
+
static auto constexpr kJavaDescriptor =
|
|
67
|
+
"Lexpo/modules/sqlite/SQLiteErrorException;";
|
|
68
|
+
|
|
69
|
+
static jni::local_ref<SQLiteErrorException>
|
|
70
|
+
create(const std::string &message) {
|
|
71
|
+
return SQLiteErrorException::newInstance(jni::make_jstring(message));
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
} // namespace expo
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#include "NativeStatementBinding.h"
|
|
4
|
+
|
|
5
|
+
#include <android/log.h>
|
|
6
|
+
|
|
7
|
+
namespace jni = facebook::jni;
|
|
8
|
+
|
|
9
|
+
namespace expo {
|
|
10
|
+
|
|
11
|
+
namespace {
|
|
12
|
+
|
|
13
|
+
constexpr char TAG[] = "expo-sqlite";
|
|
14
|
+
|
|
15
|
+
} // namespace
|
|
16
|
+
|
|
17
|
+
// static
|
|
18
|
+
void NativeStatementBinding::registerNatives() {
|
|
19
|
+
registerHybrid({
|
|
20
|
+
makeNativeMethod("initHybrid", NativeStatementBinding::initHybrid),
|
|
21
|
+
makeNativeMethod("sqlite3_bind_parameter_index",
|
|
22
|
+
NativeStatementBinding::sqlite3_bind_parameter_index),
|
|
23
|
+
makeNativeMethod("sqlite3_column_count",
|
|
24
|
+
NativeStatementBinding::sqlite3_column_count),
|
|
25
|
+
makeNativeMethod("sqlite3_column_name",
|
|
26
|
+
NativeStatementBinding::sqlite3_column_name),
|
|
27
|
+
makeNativeMethod("sqlite3_finalize",
|
|
28
|
+
NativeStatementBinding::sqlite3_finalize),
|
|
29
|
+
makeNativeMethod("sqlite3_reset", NativeStatementBinding::sqlite3_reset),
|
|
30
|
+
makeNativeMethod("sqlite3_step", NativeStatementBinding::sqlite3_step),
|
|
31
|
+
makeNativeMethod("bindStatementParam",
|
|
32
|
+
NativeStatementBinding::bindStatementParam),
|
|
33
|
+
makeNativeMethod("getRow", NativeStatementBinding::getRow),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
int NativeStatementBinding::sqlite3_bind_parameter_index(
|
|
38
|
+
const std::string &name) {
|
|
39
|
+
return ::sqlite3_bind_parameter_index(stmt, name.c_str());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
int NativeStatementBinding::sqlite3_column_count() {
|
|
43
|
+
return ::sqlite3_column_count(stmt);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
std::string NativeStatementBinding::sqlite3_column_name(int index) {
|
|
47
|
+
return ::sqlite3_column_name(stmt, index);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
int NativeStatementBinding::sqlite3_finalize() {
|
|
51
|
+
return ::sqlite3_finalize(stmt);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
int NativeStatementBinding::sqlite3_reset() { return ::sqlite3_reset(stmt); }
|
|
55
|
+
|
|
56
|
+
int NativeStatementBinding::sqlite3_step() { return ::sqlite3_step(stmt); }
|
|
57
|
+
|
|
58
|
+
int NativeStatementBinding::bindStatementParam(
|
|
59
|
+
int index, jni::alias_ref<jni::JObject> param) {
|
|
60
|
+
static const auto integerClass = jni::JInteger::javaClassStatic();
|
|
61
|
+
static const auto longClass = jni::JLong::javaClassStatic();
|
|
62
|
+
static const auto doubleClass = jni::JDouble::javaClassStatic();
|
|
63
|
+
static const auto stringClass = jni::JString::javaClassStatic();
|
|
64
|
+
static const auto booleanClass = jni::JBoolean::javaClassStatic();
|
|
65
|
+
|
|
66
|
+
int ret = -1;
|
|
67
|
+
if (param == nullptr) {
|
|
68
|
+
ret = sqlite3_bind_null(stmt, index);
|
|
69
|
+
} else if (param->isInstanceOf(integerClass)) {
|
|
70
|
+
ret = sqlite3_bind_int(stmt, index,
|
|
71
|
+
jni::static_ref_cast<jni::JInteger>(param)->value());
|
|
72
|
+
} else if (param->isInstanceOf(longClass)) {
|
|
73
|
+
ret = sqlite3_bind_int64(stmt, index,
|
|
74
|
+
jni::static_ref_cast<jni::JLong>(param)->value());
|
|
75
|
+
} else if (param->isInstanceOf(doubleClass)) {
|
|
76
|
+
ret = sqlite3_bind_double(
|
|
77
|
+
stmt, index, jni::static_ref_cast<jni::JDouble>(param)->value());
|
|
78
|
+
} else if (param->isInstanceOf(booleanClass)) {
|
|
79
|
+
ret = sqlite3_bind_int(
|
|
80
|
+
stmt, index,
|
|
81
|
+
jni::static_ref_cast<jni::JBoolean>(param)->value() ? 1 : 0);
|
|
82
|
+
} else {
|
|
83
|
+
std::string stringArg;
|
|
84
|
+
if (param->isInstanceOf(stringClass)) {
|
|
85
|
+
stringArg = jni::static_ref_cast<jni::JString>(param)->toStdString();
|
|
86
|
+
} else {
|
|
87
|
+
stringArg = param->toString();
|
|
88
|
+
}
|
|
89
|
+
ret = sqlite3_bind_text(stmt, index, stringArg.c_str(), stringArg.length(),
|
|
90
|
+
SQLITE_TRANSIENT);
|
|
91
|
+
}
|
|
92
|
+
return ret;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
jni::local_ref<ArrayMap<jni::JString, jni::JObject>>
|
|
96
|
+
NativeStatementBinding::getRow() {
|
|
97
|
+
int columnCount = sqlite3_column_count();
|
|
98
|
+
auto row = ArrayMap<jni::JString, jni::JObject>::create(columnCount);
|
|
99
|
+
for (int i = 0; i < columnCount; ++i) {
|
|
100
|
+
auto name = sqlite3_column_name(i);
|
|
101
|
+
auto value = getColumnValue(i);
|
|
102
|
+
row->put(jni::make_jstring(name), value);
|
|
103
|
+
}
|
|
104
|
+
return row;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// static
|
|
108
|
+
jni::local_ref<NativeStatementBinding::jhybriddata>
|
|
109
|
+
NativeStatementBinding::initHybrid(jni::alias_ref<jhybridobject> jThis) {
|
|
110
|
+
return makeCxxInstance(jThis);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
jni::local_ref<jni::JObject> NativeStatementBinding::getColumnValue(int index) {
|
|
114
|
+
int type = ::sqlite3_column_type(stmt, index);
|
|
115
|
+
switch (type) {
|
|
116
|
+
case SQLITE_INTEGER: {
|
|
117
|
+
return jni::JLong::valueOf(sqlite3_column_int64(stmt, index));
|
|
118
|
+
}
|
|
119
|
+
case SQLITE_FLOAT: {
|
|
120
|
+
return jni::JDouble::valueOf(sqlite3_column_double(stmt, index));
|
|
121
|
+
}
|
|
122
|
+
case SQLITE_TEXT: {
|
|
123
|
+
std::string text(
|
|
124
|
+
reinterpret_cast<const char *>(sqlite3_column_text(stmt, index)),
|
|
125
|
+
static_cast<size_t>(sqlite3_column_bytes(stmt, index)));
|
|
126
|
+
return jni::make_jstring(text);
|
|
127
|
+
}
|
|
128
|
+
case SQLITE_BLOB: {
|
|
129
|
+
JNIEnv *env = jni::Environment::current();
|
|
130
|
+
return jni::adopt_local(env->NewString(
|
|
131
|
+
reinterpret_cast<const jchar *>(sqlite3_column_blob(stmt, index)),
|
|
132
|
+
static_cast<size_t>(sqlite3_column_bytes(stmt, index))));
|
|
133
|
+
}
|
|
134
|
+
case SQLITE_NULL: {
|
|
135
|
+
return nullptr;
|
|
136
|
+
}
|
|
137
|
+
default: {
|
|
138
|
+
std::string errorMessage =
|
|
139
|
+
"Unsupported parameter type: " + std::to_string(type);
|
|
140
|
+
jni::throwNewJavaException(
|
|
141
|
+
InvalidConvertibleException::create(errorMessage).get());
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
} // namespace expo
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include <fbjni/fbjni.h>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
#include "sqlite3.h"
|
|
9
|
+
|
|
10
|
+
namespace jni = facebook::jni;
|
|
11
|
+
|
|
12
|
+
namespace expo {
|
|
13
|
+
|
|
14
|
+
class NativeDatabaseBinding;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A convenient wrapper for the ArrayMap
|
|
18
|
+
*/
|
|
19
|
+
template <typename K = jobject, typename V = jobject>
|
|
20
|
+
struct ArrayMap : public jni::JavaClass<ArrayMap<K, V>, jni::JMap<K, V>> {
|
|
21
|
+
static auto constexpr kJavaDescriptor = "Landroid/util/ArrayMap;";
|
|
22
|
+
|
|
23
|
+
static jni::local_ref<typename ArrayMap<K, V>::javaobject>
|
|
24
|
+
create(int capacity) {
|
|
25
|
+
return ArrayMap<K, V>::newInstance(capacity);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
class NativeStatementBinding : public jni::HybridClass<NativeStatementBinding> {
|
|
30
|
+
public:
|
|
31
|
+
static constexpr auto kJavaDescriptor =
|
|
32
|
+
"Lexpo/modules/sqlite/NativeStatementBinding;";
|
|
33
|
+
|
|
34
|
+
static void registerNatives();
|
|
35
|
+
|
|
36
|
+
// sqlite3 bindings
|
|
37
|
+
int sqlite3_bind_parameter_index(const std::string &name);
|
|
38
|
+
int sqlite3_column_count();
|
|
39
|
+
std::string sqlite3_column_name(int index);
|
|
40
|
+
int sqlite3_finalize();
|
|
41
|
+
int sqlite3_reset();
|
|
42
|
+
int sqlite3_step();
|
|
43
|
+
|
|
44
|
+
// helpers
|
|
45
|
+
int bindStatementParam(int index, jni::alias_ref<jni::JObject> param);
|
|
46
|
+
jni::local_ref<ArrayMap<jni::JString, jni::JObject>> getRow();
|
|
47
|
+
|
|
48
|
+
private:
|
|
49
|
+
explicit NativeStatementBinding(
|
|
50
|
+
jni::alias_ref<NativeStatementBinding::jhybridobject> jThis)
|
|
51
|
+
: javaPart_(jni::make_global(jThis)) {}
|
|
52
|
+
|
|
53
|
+
jni::local_ref<jni::JObject> getColumnValue(int index);
|
|
54
|
+
|
|
55
|
+
private:
|
|
56
|
+
static jni::local_ref<jhybriddata>
|
|
57
|
+
initHybrid(jni::alias_ref<jhybridobject> jThis);
|
|
58
|
+
|
|
59
|
+
private:
|
|
60
|
+
friend HybridBase;
|
|
61
|
+
friend NativeDatabaseBinding;
|
|
62
|
+
|
|
63
|
+
jni::global_ref<NativeStatementBinding::javaobject> javaPart_;
|
|
64
|
+
sqlite3_stmt *stmt;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A convenient wrapper for the Kotlin CodedException.
|
|
69
|
+
* TODO: Add prefabPublishing from expo-modules-core and remove the duplicated
|
|
70
|
+
* definition.
|
|
71
|
+
*/
|
|
72
|
+
class CodedException : public jni::JavaClass<CodedException, jni::JThrowable> {
|
|
73
|
+
public:
|
|
74
|
+
static auto constexpr kJavaDescriptor =
|
|
75
|
+
"Lexpo/modules/kotlin/exception/CodedException;";
|
|
76
|
+
|
|
77
|
+
static jni::local_ref<CodedException> create(const std::string &message);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A convenient wrapper for the Kotlin InvalidConvertibleException.
|
|
82
|
+
*/
|
|
83
|
+
class InvalidConvertibleException
|
|
84
|
+
: public jni::JavaClass<InvalidConvertibleException, CodedException> {
|
|
85
|
+
public:
|
|
86
|
+
static auto constexpr kJavaDescriptor =
|
|
87
|
+
"Lexpo/modules/sqlite/InvalidConvertibleException;";
|
|
88
|
+
|
|
89
|
+
static jni::local_ref<InvalidConvertibleException>
|
|
90
|
+
create(const std::string &message) {
|
|
91
|
+
return InvalidConvertibleException::newInstance(jni::make_jstring(message));
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
} // namespace expo
|
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
#include <fbjni/fbjni.h>
|
|
4
4
|
|
|
5
|
+
#include "NativeDatabaseBinding.h"
|
|
6
|
+
#include "NativeStatementBinding.h"
|
|
5
7
|
#include "SQLite3Wrapper.h"
|
|
6
8
|
|
|
7
9
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
|
|
8
|
-
return facebook::jni::initialize(
|
|
9
|
-
|
|
10
|
+
return facebook::jni::initialize(vm, [] {
|
|
11
|
+
expo::NativeDatabaseBinding::registerNatives();
|
|
12
|
+
expo::NativeStatementBinding::registerNatives();
|
|
13
|
+
expo::SQLite3Wrapper::registerNatives();
|
|
14
|
+
});
|
|
10
15
|
}
|
|
@@ -21,12 +21,6 @@ void SQLite3Wrapper::registerNatives() {
|
|
|
21
21
|
makeNativeMethod("executeSql", SQLite3Wrapper::executeSql),
|
|
22
22
|
makeNativeMethod("sqlite3_open", SQLite3Wrapper::sqlite3_open),
|
|
23
23
|
makeNativeMethod("sqlite3_close", SQLite3Wrapper::sqlite3_close),
|
|
24
|
-
makeNativeMethod("sqlite3_enable_load_extension",
|
|
25
|
-
SQLite3Wrapper::sqlite3_enable_load_extension),
|
|
26
|
-
makeNativeMethod("sqlite3_load_extension",
|
|
27
|
-
SQLite3Wrapper::sqlite3_load_extension),
|
|
28
|
-
makeNativeMethod("sqlite3_update_hook",
|
|
29
|
-
SQLite3Wrapper::sqlite3_update_hook),
|
|
30
24
|
});
|
|
31
25
|
}
|
|
32
26
|
|
|
@@ -136,30 +130,6 @@ int SQLite3Wrapper::sqlite3_close() {
|
|
|
136
130
|
return ret;
|
|
137
131
|
}
|
|
138
132
|
|
|
139
|
-
int SQLite3Wrapper::sqlite3_enable_load_extension(int onoff) {
|
|
140
|
-
return ::sqlite3_enable_load_extension(db, onoff);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
int SQLite3Wrapper::sqlite3_load_extension(const std::string &libPath,
|
|
144
|
-
const std::string &entryProc) {
|
|
145
|
-
char *errorMessage;
|
|
146
|
-
int ret = ::sqlite3_load_extension(db, libPath.c_str(), entryProc.c_str(),
|
|
147
|
-
&errorMessage);
|
|
148
|
-
if (errorMessage) {
|
|
149
|
-
__android_log_write(ANDROID_LOG_ERROR, TAG, errorMessage);
|
|
150
|
-
::sqlite3_free(errorMessage);
|
|
151
|
-
}
|
|
152
|
-
return ret;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
void SQLite3Wrapper::sqlite3_update_hook(bool enabled) {
|
|
156
|
-
if (enabled) {
|
|
157
|
-
::sqlite3_update_hook(db, SQLite3Wrapper::OnUpdateHook, this);
|
|
158
|
-
} else {
|
|
159
|
-
::sqlite3_update_hook(db, nullptr, nullptr);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
133
|
// static
|
|
164
134
|
jni::local_ref<SQLite3Wrapper::jhybriddata>
|
|
165
135
|
SQLite3Wrapper::initHybrid(jni::alias_ref<jhybridobject> jThis) {
|
|
@@ -25,10 +25,6 @@ public:
|
|
|
25
25
|
// sqlite3 bindings
|
|
26
26
|
int sqlite3_open(const std::string &dbPath);
|
|
27
27
|
int sqlite3_close();
|
|
28
|
-
int sqlite3_enable_load_extension(int onoff);
|
|
29
|
-
int sqlite3_load_extension(const std::string &libPath,
|
|
30
|
-
const std::string &entryProc);
|
|
31
|
-
void sqlite3_update_hook(bool enabled);
|
|
32
28
|
|
|
33
29
|
private:
|
|
34
30
|
explicit SQLite3Wrapper(jni::alias_ref<SQLite3Wrapper::jhybridobject> jThis)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
package expo.modules.sqlite
|
|
4
|
+
|
|
5
|
+
import expo.modules.kotlin.sharedobjects.SharedRef
|
|
6
|
+
|
|
7
|
+
internal class NativeDatabase(val dbName: String, val openOptions: OpenDatabaseOptions) : SharedRef<NativeDatabaseBinding>(NativeDatabaseBinding()) {
|
|
8
|
+
override fun equals(other: Any?): Boolean {
|
|
9
|
+
return other is NativeDatabase && this.ref == other.ref
|
|
10
|
+
}
|
|
11
|
+
}
|