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.
Files changed (80) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/android/CMakeLists.txt +2 -2
  3. package/android/build.gradle +50 -3
  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 +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 +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 +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 +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
  76. package/vendor/README.expo.md +0 -6
  77. package/vendor/shell.c +0 -28032
  78. package/vendor/sqlite3.c +0 -247629
  79. package/vendor/sqlite3.h +0 -13068
  80. 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
 
@@ -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.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 "11.8.0"
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
- 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) {
@@ -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
+ }