expo-sqlite 11.8.0 → 12.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/android/CMakeLists.txt +2 -2
  3. package/android/build.gradle +52 -5
  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 +157 -0
  7. package/android/src/main/cpp/NativeStatementBinding.h +83 -0
  8. package/android/src/main/cpp/SQLite3Main.cpp +7 -2
  9. package/android/src/main/cpp/SQLite3Wrapper.cpp +0 -30
  10. package/android/src/main/cpp/SQLite3Wrapper.h +0 -4
  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 +41 -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 +0 -30
  18. package/android/src/main/java/expo/modules/sqlite/SQLiteHelpers.kt +0 -79
  19. package/android/src/main/java/expo/modules/sqlite/SQLiteModule.kt +2 -55
  20. package/android/src/main/java/expo/modules/sqlite/SQLiteModuleNext.kt +454 -0
  21. package/android/src/main/java/expo/modules/sqlite/SQLiteOptions.kt +20 -0
  22. package/build/SQLite.d.ts +2 -2
  23. package/build/SQLite.d.ts.map +1 -1
  24. package/build/SQLite.js.map +1 -1
  25. package/build/SQLite.types.d.ts +3 -2
  26. package/build/SQLite.types.d.ts.map +1 -1
  27. package/build/SQLite.types.js.map +1 -1
  28. package/build/next/Database.d.ts +254 -0
  29. package/build/next/Database.d.ts.map +1 -0
  30. package/build/next/Database.js +320 -0
  31. package/build/next/Database.js.map +1 -0
  32. package/build/next/ExpoSQLiteNext.d.ts +12 -0
  33. package/build/next/ExpoSQLiteNext.d.ts.map +1 -0
  34. package/build/next/ExpoSQLiteNext.js +26 -0
  35. package/build/next/ExpoSQLiteNext.js.map +1 -0
  36. package/build/next/ExpoSQLiteNext.native.d.ts +3 -0
  37. package/build/next/ExpoSQLiteNext.native.d.ts.map +1 -0
  38. package/build/next/ExpoSQLiteNext.native.js +3 -0
  39. package/build/next/ExpoSQLiteNext.native.js.map +1 -0
  40. package/build/next/NativeDatabase.d.ts +44 -0
  41. package/build/next/NativeDatabase.d.ts.map +1 -0
  42. package/build/next/NativeDatabase.js +2 -0
  43. package/build/next/NativeDatabase.js.map +1 -0
  44. package/build/next/NativeStatement.d.ts +71 -0
  45. package/build/next/NativeStatement.d.ts.map +1 -0
  46. package/build/next/NativeStatement.js +2 -0
  47. package/build/next/NativeStatement.js.map +1 -0
  48. package/build/next/Statement.d.ts +138 -0
  49. package/build/next/Statement.d.ts.map +1 -0
  50. package/build/next/Statement.js +184 -0
  51. package/build/next/Statement.js.map +1 -0
  52. package/build/next/hooks.d.ts +35 -0
  53. package/build/next/hooks.d.ts.map +1 -0
  54. package/build/next/hooks.js +60 -0
  55. package/build/next/hooks.js.map +1 -0
  56. package/build/next/index.d.ts +4 -0
  57. package/build/next/index.d.ts.map +1 -0
  58. package/build/next/index.js +4 -0
  59. package/build/next/index.js.map +1 -0
  60. package/expo-module.config.json +2 -2
  61. package/ios/CRSQLiteLoader.h +3 -1
  62. package/ios/CRSQLiteLoader.m +11 -6
  63. package/ios/Exceptions.swift +13 -0
  64. package/ios/ExpoSQLite.podspec +2 -2
  65. package/ios/NativeDatabase.swift +26 -0
  66. package/ios/NativeStatement.swift +13 -0
  67. package/ios/SQLAction.swift +23 -0
  68. package/ios/SQLiteModule.swift +0 -53
  69. package/ios/SQLiteModuleNext.swift +555 -0
  70. package/ios/SQLiteOptions.swift +26 -0
  71. package/next.d.ts +1 -0
  72. package/next.js +1 -0
  73. package/package.json +4 -2
  74. package/src/SQLite.ts +2 -1
  75. package/src/SQLite.types.ts +5 -2
  76. package/src/next/Database.ts +442 -0
  77. package/src/next/ExpoSQLiteNext.native.ts +2 -0
  78. package/src/next/ExpoSQLiteNext.ts +34 -0
  79. package/src/next/NativeDatabase.ts +58 -0
  80. package/src/next/NativeStatement.ts +96 -0
  81. package/src/next/Statement.ts +306 -0
  82. package/src/next/hooks.tsx +111 -0
  83. package/src/next/index.ts +3 -0
  84. package/vendor/README.expo.md +0 -6
  85. package/vendor/shell.c +0 -28032
  86. package/vendor/sqlite3.c +0 -247629
  87. package/vendor/sqlite3.h +0 -13068
  88. package/vendor/sqlite3ext.h +0 -709
package/CHANGELOG.md CHANGED
@@ -10,6 +10,39 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 12.1.0 — 2023-11-10
14
+
15
+ ### 🎉 New features
16
+
17
+ - Improved performance on the `expo-sqlite/next` API. ([#25314](https://github.com/expo/expo/pull/25314) by [@kudo](https://github.com/kudo))
18
+
19
+ ### 🐛 Bug fixes
20
+
21
+ - Fix crash issues in `sqlite/next`. ([#25295](https://github.com/expo/expo/pull/25295) by [@kudo](https://github.com/kudo))
22
+ - Fix `executeSqlAsync` to accept null properly as arguments. ([#24761](https://github.com/expo/expo/pull/24761) by [@spencerc99](https://github.com/spencerc99))
23
+ - Fixed `useSQLiteContext()` and `finalizeUnusedStatementsBeforeClosing` issues in `expo-sqlite/next` API. ([#25328](https://github.com/expo/expo/pull/25328) by [@kudo](https://github.com/kudo))
24
+
25
+ ## 12.0.0 — 2023-11-06
26
+
27
+ ### 🛠 Breaking changes
28
+
29
+ - Bumped iOS deployment target to 13.4. ([#25063](https://github.com/expo/expo/pull/25063) by [@gabrieldonadel](https://github.com/gabrieldonadel))
30
+ - Remove CRSQLite support on legacy API. ([#25092](https://github.com/expo/expo/pull/25092) by [@kudo](https://github.com/kudo))
31
+ - On `Android` bump `compileSdkVersion` and `targetSdkVersion` to `34`. ([#24708](https://github.com/expo/expo/pull/24708) by [@alanjhughes](https://github.com/alanjhughes))
32
+
33
+ ### 🎉 New features
34
+
35
+ - Added Android implementation for `sqlite/next` APIs. ([#25021](https://github.com/expo/expo/pull/25021) by [@kudo](https://github.com/kudo))
36
+ - Added the `useSQLiteContext` hook that can be used across components. ([#25129](https://github.com/expo/expo/pull/25129) by [@kudo](https://github.com/kudo))
37
+
38
+ ### 🐛 Bug fixes
39
+
40
+ - [ios] Fix some issues for `sqlite/next`. ([#25022](https://github.com/expo/expo/pull/25022) by [@kudo](https://github.com/kudo))
41
+
42
+ ### 💡 Others
43
+
44
+ - [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))
45
+
13
46
  ## 11.8.0 — 2023-10-17
14
47
 
15
48
  ### 🛠 Breaking changes
@@ -19,6 +52,7 @@
19
52
  ### 🎉 New features
20
53
 
21
54
  - [Android] Rewrite implementations from low-level SQLite bindings. ([#24730](https://github.com/expo/expo/pull/24730) by [@kudo](https://github.com/kudo))
55
+ - Introduced `expo-sqlite/next` new APIs. ([#24812](https://github.com/expo/expo/pull/24812) by [@kudo](https://github.com/kudo))
22
56
 
23
57
  ## 11.7.1 — 2023-09-18
24
58
 
@@ -14,14 +14,14 @@ add_library(
14
14
  ${PACKAGE_NAME}
15
15
  SHARED
16
16
  ${SOURCES}
17
- "${CMAKE_SOURCE_DIR}/../vendor/sqlite3.c"
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
- "${CMAKE_SOURCE_DIR}/../vendor"
24
+ "${SQLITE3_SRC_DIR}"
25
25
  )
26
26
 
27
27
  find_library(LOG_LIB log)
@@ -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 = '11.8.0'
7
+ version = '12.1.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
 
@@ -66,11 +73,11 @@ if (!safeExtGet("expoProvidesDefaultConfig", false)) {
66
73
  android {
67
74
  // Remove this if and it's contents, when support for SDK49 is dropped
68
75
  if (!safeExtGet("expoProvidesDefaultConfig", false)) {
69
- compileSdkVersion safeExtGet("compileSdkVersion", 33)
76
+ compileSdkVersion safeExtGet("compileSdkVersion", 34)
70
77
 
71
78
  defaultConfig {
72
79
  minSdkVersion safeExtGet("minSdkVersion", 23)
73
- targetSdkVersion safeExtGet("targetSdkVersion", 33)
80
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
74
81
  }
75
82
 
76
83
  publishing {
@@ -99,12 +106,13 @@ android {
99
106
  namespace "expo.modules.sqlite"
100
107
  defaultConfig {
101
108
  versionCode 18
102
- versionName "11.8.0"
109
+ versionName "12.1.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,157 @@
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("getColumnNames",
34
+ NativeStatementBinding::getColumnNames),
35
+ makeNativeMethod("getColumnValues",
36
+ NativeStatementBinding::getColumnValues),
37
+ });
38
+ }
39
+
40
+ int NativeStatementBinding::sqlite3_bind_parameter_index(
41
+ const std::string &name) {
42
+ return ::sqlite3_bind_parameter_index(stmt, name.c_str());
43
+ }
44
+
45
+ int NativeStatementBinding::sqlite3_column_count() {
46
+ return ::sqlite3_column_count(stmt);
47
+ }
48
+
49
+ std::string NativeStatementBinding::sqlite3_column_name(int index) {
50
+ return ::sqlite3_column_name(stmt, index);
51
+ }
52
+
53
+ int NativeStatementBinding::sqlite3_finalize() {
54
+ return ::sqlite3_finalize(stmt);
55
+ }
56
+
57
+ int NativeStatementBinding::sqlite3_reset() { return ::sqlite3_reset(stmt); }
58
+
59
+ int NativeStatementBinding::sqlite3_step() { return ::sqlite3_step(stmt); }
60
+
61
+ int NativeStatementBinding::bindStatementParam(
62
+ int index, jni::alias_ref<jni::JObject> param) {
63
+ static const auto integerClass = jni::JInteger::javaClassStatic();
64
+ static const auto longClass = jni::JLong::javaClassStatic();
65
+ static const auto doubleClass = jni::JDouble::javaClassStatic();
66
+ static const auto stringClass = jni::JString::javaClassStatic();
67
+ static const auto booleanClass = jni::JBoolean::javaClassStatic();
68
+
69
+ int ret = -1;
70
+ if (param == nullptr) {
71
+ ret = sqlite3_bind_null(stmt, index);
72
+ } else if (param->isInstanceOf(integerClass)) {
73
+ ret = sqlite3_bind_int(stmt, index,
74
+ jni::static_ref_cast<jni::JInteger>(param)->value());
75
+ } else if (param->isInstanceOf(longClass)) {
76
+ ret = sqlite3_bind_int64(stmt, index,
77
+ jni::static_ref_cast<jni::JLong>(param)->value());
78
+ } else if (param->isInstanceOf(doubleClass)) {
79
+ ret = sqlite3_bind_double(
80
+ stmt, index, jni::static_ref_cast<jni::JDouble>(param)->value());
81
+ } else if (param->isInstanceOf(booleanClass)) {
82
+ ret = sqlite3_bind_int(
83
+ stmt, index,
84
+ jni::static_ref_cast<jni::JBoolean>(param)->value() ? 1 : 0);
85
+ } else {
86
+ std::string stringArg;
87
+ if (param->isInstanceOf(stringClass)) {
88
+ stringArg = jni::static_ref_cast<jni::JString>(param)->toStdString();
89
+ } else {
90
+ stringArg = param->toString();
91
+ }
92
+ ret = sqlite3_bind_text(stmt, index, stringArg.c_str(), stringArg.length(),
93
+ SQLITE_TRANSIENT);
94
+ }
95
+ return ret;
96
+ }
97
+
98
+ jni::local_ref<jni::JArrayList<jni::JString>>
99
+ NativeStatementBinding::getColumnNames() {
100
+ int columnCount = sqlite3_column_count();
101
+ auto columnNames = jni::JArrayList<jni::JString>::create(columnCount);
102
+ for (int i = 0; i < columnCount; ++i) {
103
+ columnNames->add(jni::make_jstring(sqlite3_column_name(i)));
104
+ }
105
+ return columnNames;
106
+ }
107
+
108
+ jni::local_ref<jni::JArrayList<jni::JObject>>
109
+ NativeStatementBinding::getColumnValues() {
110
+ int columnCount = sqlite3_column_count();
111
+ auto columnValues = jni::JArrayList<jni::JObject>::create(columnCount);
112
+ for (int i = 0; i < columnCount; ++i) {
113
+ columnValues->add(getColumnValue(i));
114
+ }
115
+ return columnValues;
116
+ }
117
+
118
+ // static
119
+ jni::local_ref<NativeStatementBinding::jhybriddata>
120
+ NativeStatementBinding::initHybrid(jni::alias_ref<jhybridobject> jThis) {
121
+ return makeCxxInstance(jThis);
122
+ }
123
+
124
+ jni::local_ref<jni::JObject> NativeStatementBinding::getColumnValue(int index) {
125
+ int type = ::sqlite3_column_type(stmt, index);
126
+ switch (type) {
127
+ case SQLITE_INTEGER: {
128
+ return jni::JLong::valueOf(sqlite3_column_int64(stmt, index));
129
+ }
130
+ case SQLITE_FLOAT: {
131
+ return jni::JDouble::valueOf(sqlite3_column_double(stmt, index));
132
+ }
133
+ case SQLITE_TEXT: {
134
+ std::string text(
135
+ reinterpret_cast<const char *>(sqlite3_column_text(stmt, index)),
136
+ static_cast<size_t>(sqlite3_column_bytes(stmt, index)));
137
+ return jni::make_jstring(text);
138
+ }
139
+ case SQLITE_BLOB: {
140
+ JNIEnv *env = jni::Environment::current();
141
+ return jni::adopt_local(env->NewString(
142
+ reinterpret_cast<const jchar *>(sqlite3_column_blob(stmt, index)),
143
+ static_cast<size_t>(sqlite3_column_bytes(stmt, index))));
144
+ }
145
+ case SQLITE_NULL: {
146
+ return nullptr;
147
+ }
148
+ default: {
149
+ std::string errorMessage =
150
+ "Unsupported parameter type: " + std::to_string(type);
151
+ jni::throwNewJavaException(
152
+ InvalidConvertibleException::create(errorMessage).get());
153
+ }
154
+ }
155
+ }
156
+
157
+ } // namespace expo
@@ -0,0 +1,83 @@
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
+ class NativeStatementBinding : public jni::HybridClass<NativeStatementBinding> {
17
+ public:
18
+ static constexpr auto kJavaDescriptor =
19
+ "Lexpo/modules/sqlite/NativeStatementBinding;";
20
+
21
+ static void registerNatives();
22
+
23
+ // sqlite3 bindings
24
+ int sqlite3_bind_parameter_index(const std::string &name);
25
+ int sqlite3_column_count();
26
+ std::string sqlite3_column_name(int index);
27
+ int sqlite3_finalize();
28
+ int sqlite3_reset();
29
+ int sqlite3_step();
30
+
31
+ // helpers
32
+ int bindStatementParam(int index, jni::alias_ref<jni::JObject> param);
33
+ jni::local_ref<jni::JArrayList<jni::JString>> getColumnNames();
34
+ jni::local_ref<jni::JArrayList<jni::JObject>> getColumnValues();
35
+
36
+ private:
37
+ explicit NativeStatementBinding(
38
+ jni::alias_ref<NativeStatementBinding::jhybridobject> jThis)
39
+ : javaPart_(jni::make_global(jThis)) {}
40
+
41
+ jni::local_ref<jni::JObject> getColumnValue(int index);
42
+
43
+ private:
44
+ static jni::local_ref<jhybriddata>
45
+ initHybrid(jni::alias_ref<jhybridobject> jThis);
46
+
47
+ private:
48
+ friend HybridBase;
49
+ friend NativeDatabaseBinding;
50
+
51
+ jni::global_ref<NativeStatementBinding::javaobject> javaPart_;
52
+ sqlite3_stmt *stmt;
53
+ };
54
+
55
+ /**
56
+ * A convenient wrapper for the Kotlin CodedException.
57
+ * TODO: Add prefabPublishing from expo-modules-core and remove the duplicated
58
+ * definition.
59
+ */
60
+ class CodedException : public jni::JavaClass<CodedException, jni::JThrowable> {
61
+ public:
62
+ static auto constexpr kJavaDescriptor =
63
+ "Lexpo/modules/kotlin/exception/CodedException;";
64
+
65
+ static jni::local_ref<CodedException> create(const std::string &message);
66
+ };
67
+
68
+ /**
69
+ * A convenient wrapper for the Kotlin InvalidConvertibleException.
70
+ */
71
+ class InvalidConvertibleException
72
+ : public jni::JavaClass<InvalidConvertibleException, CodedException> {
73
+ public:
74
+ static auto constexpr kJavaDescriptor =
75
+ "Lexpo/modules/sqlite/InvalidConvertibleException;";
76
+
77
+ static jni::local_ref<InvalidConvertibleException>
78
+ create(const std::string &message) {
79
+ return InvalidConvertibleException::newInstance(jni::make_jstring(message));
80
+ }
81
+ };
82
+
83
+ } // 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
- vm, [] { expo::SQLite3Wrapper::registerNatives(); });
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) {