expo-sqlite 11.7.1 → 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.
Files changed (75) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/android/CMakeLists.txt +35 -0
  3. package/android/build.gradle +114 -29
  4. package/android/src/main/cpp/NativeDatabaseBinding.cpp +142 -0
  5. package/android/src/main/cpp/NativeDatabaseBinding.h +75 -0
  6. package/android/src/main/cpp/NativeStatementBinding.cpp +146 -0
  7. package/android/src/main/cpp/NativeStatementBinding.h +95 -0
  8. package/android/src/main/cpp/SQLite3Main.cpp +15 -0
  9. package/android/src/main/cpp/SQLite3Wrapper.cpp +223 -0
  10. package/android/src/main/cpp/SQLite3Wrapper.h +55 -0
  11. package/android/src/main/java/expo/modules/sqlite/NativeDatabase.kt +11 -0
  12. package/android/src/main/java/expo/modules/sqlite/NativeDatabaseBinding.kt +79 -0
  13. package/android/src/main/java/expo/modules/sqlite/NativeStatement.kt +11 -0
  14. package/android/src/main/java/expo/modules/sqlite/NativeStatementBinding.kt +40 -0
  15. package/android/src/main/java/expo/modules/sqlite/SQLExceptions.kt +17 -6
  16. package/android/src/main/java/expo/modules/sqlite/SQLRecords.kt +16 -3
  17. package/android/src/main/java/expo/modules/sqlite/SQLite3Wrapper.kt +51 -0
  18. package/android/src/main/java/expo/modules/sqlite/SQLiteHelpers.kt +0 -79
  19. package/android/src/main/java/expo/modules/sqlite/SQLiteModule.kt +31 -222
  20. package/android/src/main/java/expo/modules/sqlite/SQLiteModuleNext.kt +447 -0
  21. package/android/src/main/java/expo/modules/sqlite/SQLiteOptions.kt +20 -0
  22. package/build/next/Database.d.ts +254 -0
  23. package/build/next/Database.d.ts.map +1 -0
  24. package/build/next/Database.js +324 -0
  25. package/build/next/Database.js.map +1 -0
  26. package/build/next/ExpoSQLiteNext.d.ts +12 -0
  27. package/build/next/ExpoSQLiteNext.d.ts.map +1 -0
  28. package/build/next/ExpoSQLiteNext.js +26 -0
  29. package/build/next/ExpoSQLiteNext.js.map +1 -0
  30. package/build/next/ExpoSQLiteNext.native.d.ts +3 -0
  31. package/build/next/ExpoSQLiteNext.native.d.ts.map +1 -0
  32. package/build/next/ExpoSQLiteNext.native.js +3 -0
  33. package/build/next/ExpoSQLiteNext.native.js.map +1 -0
  34. package/build/next/NativeDatabase.d.ts +44 -0
  35. package/build/next/NativeDatabase.d.ts.map +1 -0
  36. package/build/next/NativeDatabase.js +2 -0
  37. package/build/next/NativeDatabase.js.map +1 -0
  38. package/build/next/NativeStatement.d.ts +68 -0
  39. package/build/next/NativeStatement.d.ts.map +1 -0
  40. package/build/next/NativeStatement.js +2 -0
  41. package/build/next/NativeStatement.js.map +1 -0
  42. package/build/next/Statement.d.ts +120 -0
  43. package/build/next/Statement.d.ts.map +1 -0
  44. package/build/next/Statement.js +135 -0
  45. package/build/next/Statement.js.map +1 -0
  46. package/build/next/hooks.d.ts +35 -0
  47. package/build/next/hooks.d.ts.map +1 -0
  48. package/build/next/hooks.js +57 -0
  49. package/build/next/hooks.js.map +1 -0
  50. package/build/next/index.d.ts +4 -0
  51. package/build/next/index.d.ts.map +1 -0
  52. package/build/next/index.js +4 -0
  53. package/build/next/index.js.map +1 -0
  54. package/expo-module.config.json +2 -2
  55. package/ios/CRSQLiteLoader.h +3 -1
  56. package/ios/CRSQLiteLoader.m +11 -6
  57. package/ios/Exceptions.swift +13 -0
  58. package/ios/ExpoSQLite.podspec +2 -2
  59. package/ios/NativeDatabase.swift +26 -0
  60. package/ios/NativeStatement.swift +13 -0
  61. package/ios/SQLAction.swift +23 -0
  62. package/ios/SQLiteModule.swift +0 -53
  63. package/ios/SQLiteModuleNext.swift +538 -0
  64. package/ios/SQLiteOptions.swift +26 -0
  65. package/next.d.ts +1 -0
  66. package/next.js +1 -0
  67. package/package.json +4 -2
  68. package/src/next/Database.ts +446 -0
  69. package/src/next/ExpoSQLiteNext.native.ts +2 -0
  70. package/src/next/ExpoSQLiteNext.ts +34 -0
  71. package/src/next/NativeDatabase.ts +58 -0
  72. package/src/next/NativeStatement.ts +85 -0
  73. package/src/next/Statement.ts +243 -0
  74. package/src/next/hooks.tsx +108 -0
  75. package/src/next/index.ts +3 -0
package/CHANGELOG.md CHANGED
@@ -10,6 +10,37 @@
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
+
33
+ ## 11.8.0 — 2023-10-17
34
+
35
+ ### 🛠 Breaking changes
36
+
37
+ - Dropped support for Android SDK 21 and 22. ([#24201](https://github.com/expo/expo/pull/24201) by [@behenate](https://github.com/behenate))
38
+
39
+ ### 🎉 New features
40
+
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))
43
+
13
44
  ## 11.7.1 — 2023-09-18
14
45
 
15
46
  ### 🐛 Bug fixes
@@ -0,0 +1,35 @@
1
+ cmake_minimum_required(VERSION 3.4.1)
2
+
3
+ project(expo-sqlite)
4
+
5
+ set(CMAKE_VERBOSE_MAKEFILE ON)
6
+ set(CMAKE_CXX_STANDARD 17)
7
+ set(PACKAGE_NAME "expo-sqlite")
8
+ set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
9
+
10
+ set(SRC_DIR "${CMAKE_SOURCE_DIR}/src/main/cpp")
11
+ file(GLOB SOURCES "${SRC_DIR}/*.cpp")
12
+
13
+ add_library(
14
+ ${PACKAGE_NAME}
15
+ SHARED
16
+ ${SOURCES}
17
+ "${SQLITE3_SRC_DIR}/sqlite3.c"
18
+ )
19
+
20
+ target_include_directories(
21
+ ${PACKAGE_NAME}
22
+ PRIVATE
23
+ ${SRC_DIR}
24
+ "${SQLITE3_SRC_DIR}"
25
+ )
26
+
27
+ find_library(LOG_LIB log)
28
+ find_package(fbjni REQUIRED CONFIG)
29
+
30
+ target_link_libraries(
31
+ ${PACKAGE_NAME}
32
+ ${LOG_LIB}
33
+ fbjni::fbjni
34
+ android
35
+ )
@@ -1,17 +1,33 @@
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 = '11.7.1'
7
+ version = '12.0.0'
7
8
 
8
- buildscript {
9
- def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
- if (expoModulesCorePlugin.exists()) {
11
- apply from: expoModulesCorePlugin
12
- applyKotlinExpoModulesCorePlugin()
9
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
+ if (expoModulesCorePlugin.exists()) {
11
+ apply from: expoModulesCorePlugin
12
+ applyKotlinExpoModulesCorePlugin()
13
+ // Remove this check, but keep the contents after SDK49 support is dropped
14
+ if (safeExtGet("expoProvidesDefaultConfig", false)) {
15
+ useExpoPublishing()
16
+ useCoreDependencies()
13
17
  }
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
+
25
+ def reactNativeArchitectures() {
26
+ def value = project.getProperties().get("reactNativeArchitectures")
27
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
28
+ }
14
29
 
30
+ buildscript {
15
31
  // Simple helper that allows the root project to override versions declared by this library.
16
32
  ext.safeExtGet = { prop, fallback ->
17
33
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
@@ -32,26 +48,48 @@ buildscript {
32
48
 
33
49
  dependencies {
34
50
  classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
51
+ classpath("de.undercouch:gradle-download-task:5.5.0")
35
52
  }
36
53
  }
37
54
 
38
- afterEvaluate {
39
- publishing {
40
- publications {
41
- release(MavenPublication) {
42
- from components.release
55
+ // Remove this if and it's contents, when support for SDK49 is dropped
56
+ if (!safeExtGet("expoProvidesDefaultConfig", false)) {
57
+ afterEvaluate {
58
+ publishing {
59
+ publications {
60
+ release(MavenPublication) {
61
+ from components.release
62
+ }
43
63
  }
44
- }
45
- repositories {
46
- maven {
47
- url = mavenLocal().url
64
+ repositories {
65
+ maven {
66
+ url = mavenLocal().url
67
+ }
48
68
  }
49
69
  }
50
70
  }
51
71
  }
52
72
 
53
73
  android {
54
- compileSdkVersion safeExtGet("compileSdkVersion", 33)
74
+ // Remove this if and it's contents, when support for SDK49 is dropped
75
+ if (!safeExtGet("expoProvidesDefaultConfig", false)) {
76
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
77
+
78
+ defaultConfig {
79
+ minSdkVersion safeExtGet("minSdkVersion", 23)
80
+ targetSdkVersion safeExtGet("targetSdkVersion", 33)
81
+ }
82
+
83
+ publishing {
84
+ singleVariant("release") {
85
+ withSourcesJar()
86
+ }
87
+ }
88
+
89
+ lintOptions {
90
+ abortOnError false
91
+ }
92
+ }
55
93
 
56
94
  def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
57
95
  if (agpVersion.tokenize('.')[0].toInteger() < 8) {
@@ -67,25 +105,72 @@ android {
67
105
 
68
106
  namespace "expo.modules.sqlite"
69
107
  defaultConfig {
70
- minSdkVersion safeExtGet("minSdkVersion", 21)
71
- targetSdkVersion safeExtGet("targetSdkVersion", 33)
72
108
  versionCode 18
73
- versionName "11.7.1"
74
- }
75
- lintOptions {
76
- abortOnError false
109
+ versionName "12.0.0"
110
+
111
+ externalNativeBuild {
112
+ cmake {
113
+ abiFilters (*reactNativeArchitectures())
114
+ arguments "-DANDROID_STL=c++_shared",
115
+ "-DSQLITE3_SRC_DIR=${SQLITE3_SRC_DIR}"
116
+ }
117
+ }
77
118
  }
78
- publishing {
79
- singleVariant("release") {
80
- withSourcesJar()
119
+ externalNativeBuild {
120
+ cmake {
121
+ path "CMakeLists.txt"
81
122
  }
82
123
  }
124
+ buildFeatures {
125
+ prefab true
126
+ }
83
127
  }
84
128
 
85
129
  dependencies {
86
- implementation project(':expo-modules-core')
130
+ // Remove this if and it's contents, when support for SDK49 is dropped
131
+ if (!safeExtGet("expoProvidesDefaultConfig", false)) {
132
+ implementation project(':expo-modules-core')
133
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
134
+ }
135
+
136
+ compileOnly 'com.facebook.fbjni:fbjni:0.3.0'
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
+ }
87
151
 
88
- implementation 'com.github.alanjhughes:sqlite-android:0.0.3'
89
- implementation "androidx.sqlite:sqlite-ktx:2.3.1"
90
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
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)
91
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