expo-sqlite 12.2.1 → 13.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 (68) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/android/CMakeLists.txt +1 -1
  3. package/android/build.gradle +2 -2
  4. package/android/src/main/cpp/NativeDatabaseBinding.cpp +4 -4
  5. package/android/src/main/cpp/NativeDatabaseBinding.h +2 -2
  6. package/android/src/main/cpp/NativeStatementBinding.cpp +22 -15
  7. package/android/src/main/cpp/NativeStatementBinding.h +1 -0
  8. package/android/src/main/java/expo/modules/sqlite/NativeDatabase.kt +3 -1
  9. package/android/src/main/java/expo/modules/sqlite/NativeDatabaseBinding.kt +4 -4
  10. package/android/src/main/java/expo/modules/sqlite/NativeStatement.kt +2 -0
  11. package/android/src/main/java/expo/modules/sqlite/NativeStatementBinding.kt +5 -4
  12. package/android/src/main/java/expo/modules/sqlite/SQLExceptions.kt +6 -0
  13. package/android/src/main/java/expo/modules/sqlite/SQLiteModule.kt +21 -21
  14. package/android/src/main/java/expo/modules/sqlite/SQLiteModuleNext.kt +122 -132
  15. package/build/next/ExpoSQLiteNext.d.ts +4 -4
  16. package/build/next/ExpoSQLiteNext.d.ts.map +1 -1
  17. package/build/next/ExpoSQLiteNext.js +3 -3
  18. package/build/next/ExpoSQLiteNext.js.map +1 -1
  19. package/build/next/NativeDatabase.d.ts +3 -3
  20. package/build/next/NativeDatabase.d.ts.map +1 -1
  21. package/build/next/NativeDatabase.js.map +1 -1
  22. package/build/next/NativeStatement.d.ts +37 -35
  23. package/build/next/NativeStatement.d.ts.map +1 -1
  24. package/build/next/NativeStatement.js.map +1 -1
  25. package/build/next/SQLiteDatabase.d.ts +266 -0
  26. package/build/next/SQLiteDatabase.d.ts.map +1 -0
  27. package/build/next/{Database.js → SQLiteDatabase.js} +69 -59
  28. package/build/next/SQLiteDatabase.js.map +1 -0
  29. package/build/next/SQLiteStatement.d.ts +190 -0
  30. package/build/next/SQLiteStatement.d.ts.map +1 -0
  31. package/build/next/SQLiteStatement.js +275 -0
  32. package/build/next/SQLiteStatement.js.map +1 -0
  33. package/build/next/hooks.d.ts +26 -14
  34. package/build/next/hooks.d.ts.map +1 -1
  35. package/build/next/hooks.js +121 -33
  36. package/build/next/hooks.js.map +1 -1
  37. package/build/next/index.d.ts +2 -2
  38. package/build/next/index.d.ts.map +1 -1
  39. package/build/next/index.js +2 -2
  40. package/build/next/index.js.map +1 -1
  41. package/build/next/paramUtils.d.ts +18 -0
  42. package/build/next/paramUtils.d.ts.map +1 -0
  43. package/build/next/paramUtils.js +72 -0
  44. package/build/next/paramUtils.js.map +1 -0
  45. package/ios/Exceptions.swift +12 -0
  46. package/ios/NativeDatabase.swift +4 -3
  47. package/ios/NativeStatement.swift +1 -0
  48. package/ios/SQLiteModule.swift +20 -21
  49. package/ios/SQLiteModuleNext.swift +126 -131
  50. package/ios/crsqlite.xcframework/Info.plist +4 -0
  51. package/ios/crsqlite.xcframework/ios-arm64/crsqlite.framework/Info.plist +4 -0
  52. package/package.json +4 -3
  53. package/src/next/ExpoSQLiteNext.ts +4 -4
  54. package/src/next/NativeDatabase.ts +3 -3
  55. package/src/next/NativeStatement.ts +43 -48
  56. package/src/next/{Database.ts → SQLiteDatabase.ts} +134 -112
  57. package/src/next/SQLiteStatement.ts +528 -0
  58. package/src/next/hooks.tsx +202 -51
  59. package/src/next/index.ts +2 -2
  60. package/src/next/paramUtils.ts +94 -0
  61. package/build/next/Database.d.ts +0 -272
  62. package/build/next/Database.d.ts.map +0 -1
  63. package/build/next/Database.js.map +0 -1
  64. package/build/next/Statement.d.ts +0 -142
  65. package/build/next/Statement.d.ts.map +0 -1
  66. package/build/next/Statement.js +0 -184
  67. package/build/next/Statement.js.map +0 -1
  68. package/src/next/Statement.ts +0 -310
package/CHANGELOG.md CHANGED
@@ -10,6 +10,28 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 13.1.0 — 2023-12-13
14
+
15
+ ### 🛠 Breaking changes
16
+
17
+ - Refactor `expo-sqlite/next` API to be more React idiomatic. ([#25657](https://github.com/expo/expo/pull/25657) by [@kudo](https://github.com/kudo))
18
+
19
+ ## 13.0.0 — 2023-12-12
20
+
21
+ ### 🎉 New features
22
+
23
+ - Added binary data support to the `expo-sqlite/next` API through the `Uint8Array`. ([#25787](https://github.com/expo/expo/pull/25787) by [@kudo](https://github.com/kudo))
24
+
25
+ ### 🐛 Bug fixes
26
+
27
+ - Fixed `expo-sqlite/next` crashes when access to finalized statements. ([#25623](https://github.com/expo/expo/pull/25623) by [@kudo](https://github.com/kudo))
28
+ - Fixed `expo-sqlite/next` UTF-8 text issue and `:memory:` database issue. ([#25637](https://github.com/expo/expo/pull/25637) by [@kudo](https://github.com/kudo))
29
+
30
+ ### 💡 Others
31
+
32
+ - [iOS] Replace legacy `FileSystem` interfaces usage with core `FileSystemUtilities`. ([#25495](https://github.com/expo/expo/pull/25495) by [@alanhughes](https://github.com/alanjhughes))
33
+ - Bump C++ compiler setting to C++20. ([#25548](https://github.com/expo/expo/pull/25548) by [@kudo](https://github.com/kudo))
34
+
13
35
  ## 12.2.1 — 2023-11-18
14
36
 
15
37
  ### 🐛 Bug fixes
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.4.1)
3
3
  project(expo-sqlite)
4
4
 
5
5
  set(CMAKE_VERBOSE_MAKEFILE ON)
6
- set(CMAKE_CXX_STANDARD 17)
6
+ set(CMAKE_CXX_STANDARD 20)
7
7
  set(PACKAGE_NAME "expo-sqlite")
8
8
  set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
9
9
 
@@ -4,7 +4,7 @@ apply plugin: 'maven-publish'
4
4
  apply plugin: 'de.undercouch.download'
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '12.2.1'
7
+ version = '13.1.0'
8
8
 
9
9
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
10
  if (expoModulesCorePlugin.exists()) {
@@ -106,7 +106,7 @@ android {
106
106
  namespace "expo.modules.sqlite"
107
107
  defaultConfig {
108
108
  versionCode 18
109
- versionName "12.2.1"
109
+ versionName "13.1.0"
110
110
 
111
111
  externalNativeBuild {
112
112
  cmake {
@@ -49,8 +49,8 @@ int NativeDatabaseBinding::sqlite3_close() {
49
49
  }
50
50
 
51
51
  std::string
52
- NativeDatabaseBinding::sqlite3_db_filename(const std::string &dbName) {
53
- return ::sqlite3_db_filename(db, dbName.c_str());
52
+ NativeDatabaseBinding::sqlite3_db_filename(const std::string &databaseName) {
53
+ return ::sqlite3_db_filename(db, databaseName.c_str());
54
54
  }
55
55
 
56
56
  int NativeDatabaseBinding::sqlite3_enable_load_extension(int onoff) {
@@ -128,14 +128,14 @@ NativeDatabaseBinding::initHybrid(jni::alias_ref<jhybridobject> jThis) {
128
128
 
129
129
  // static
130
130
  void NativeDatabaseBinding::OnUpdateHook(void *arg, int action,
131
- char const *dbName,
131
+ char const *databaseName,
132
132
  char const *tableName,
133
133
  sqlite3_int64 rowId) {
134
134
  NativeDatabaseBinding *pThis = reinterpret_cast<NativeDatabaseBinding *>(arg);
135
135
  static const auto method =
136
136
  jni::findClassStatic("expo/modules/sqlite/NativeDatabaseBinding")
137
137
  ->getMethod<void(jint, jstring, jstring, jlong)>("onUpdate");
138
- method(pThis->javaPart_, action, jni::make_jstring(dbName).get(),
138
+ method(pThis->javaPart_, action, jni::make_jstring(databaseName).get(),
139
139
  jni::make_jstring(tableName).get(), rowId);
140
140
  }
141
141
 
@@ -22,7 +22,7 @@ public:
22
22
  // sqlite3 bindings
23
23
  int sqlite3_changes();
24
24
  int sqlite3_close();
25
- std::string sqlite3_db_filename(const std::string &dbName);
25
+ std::string sqlite3_db_filename(const std::string &databaseName);
26
26
  int sqlite3_enable_load_extension(int onoff);
27
27
  int sqlite3_exec(const std::string &source);
28
28
  int sqlite3_get_autocommit();
@@ -47,7 +47,7 @@ private:
47
47
  static jni::local_ref<jhybriddata>
48
48
  initHybrid(jni::alias_ref<jhybridobject> jThis);
49
49
 
50
- static void OnUpdateHook(void *arg, int action, char const *dbName,
50
+ static void OnUpdateHook(void *arg, int action, char const *databaseName,
51
51
  char const *tableName, sqlite3_int64 rowId);
52
52
 
53
53
  private:
@@ -20,6 +20,8 @@ void NativeStatementBinding::registerNatives() {
20
20
  makeNativeMethod("initHybrid", NativeStatementBinding::initHybrid),
21
21
  makeNativeMethod("sqlite3_bind_parameter_index",
22
22
  NativeStatementBinding::sqlite3_bind_parameter_index),
23
+ makeNativeMethod("sqlite3_clear_bindings",
24
+ NativeStatementBinding::sqlite3_clear_bindings),
23
25
  makeNativeMethod("sqlite3_column_count",
24
26
  NativeStatementBinding::sqlite3_column_count),
25
27
  makeNativeMethod("sqlite3_column_name",
@@ -42,6 +44,10 @@ int NativeStatementBinding::sqlite3_bind_parameter_index(
42
44
  return ::sqlite3_bind_parameter_index(stmt, name.c_str());
43
45
  }
44
46
 
47
+ int NativeStatementBinding::sqlite3_clear_bindings() {
48
+ return ::sqlite3_clear_bindings(stmt);
49
+ }
50
+
45
51
  int NativeStatementBinding::sqlite3_column_count() {
46
52
  return ::sqlite3_column_count(stmt);
47
53
  }
@@ -60,31 +66,30 @@ int NativeStatementBinding::sqlite3_step() { return ::sqlite3_step(stmt); }
60
66
 
61
67
  int NativeStatementBinding::bindStatementParam(
62
68
  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
69
  int ret = -1;
70
70
  if (param == nullptr) {
71
71
  ret = sqlite3_bind_null(stmt, index);
72
- } else if (param->isInstanceOf(integerClass)) {
72
+ } else if (param->isInstanceOf(jni::JInteger::javaClassStatic())) {
73
73
  ret = sqlite3_bind_int(stmt, index,
74
74
  jni::static_ref_cast<jni::JInteger>(param)->value());
75
- } else if (param->isInstanceOf(longClass)) {
75
+ } else if (param->isInstanceOf(jni::JLong::javaClassStatic())) {
76
76
  ret = sqlite3_bind_int64(stmt, index,
77
77
  jni::static_ref_cast<jni::JLong>(param)->value());
78
- } else if (param->isInstanceOf(doubleClass)) {
78
+ } else if (param->isInstanceOf(jni::JDouble::javaClassStatic())) {
79
79
  ret = sqlite3_bind_double(
80
80
  stmt, index, jni::static_ref_cast<jni::JDouble>(param)->value());
81
- } else if (param->isInstanceOf(booleanClass)) {
81
+ } else if (param->isInstanceOf(jni::JBoolean::javaClassStatic())) {
82
82
  ret = sqlite3_bind_int(
83
83
  stmt, index,
84
84
  jni::static_ref_cast<jni::JBoolean>(param)->value() ? 1 : 0);
85
+ } else if (param->isInstanceOf(jni::JArrayByte::javaClassStatic())) {
86
+ auto byteArray = jni::static_ref_cast<jni::JArrayByte>(param);
87
+ auto data = byteArray->getRegion(0, byteArray->size());
88
+ ret = sqlite3_bind_blob(stmt, index, data.get(), byteArray->size(),
89
+ SQLITE_TRANSIENT);
85
90
  } else {
86
91
  std::string stringArg;
87
- if (param->isInstanceOf(stringClass)) {
92
+ if (param->isInstanceOf(jni::JString::javaClassStatic())) {
88
93
  stringArg = jni::static_ref_cast<jni::JString>(param)->toStdString();
89
94
  } else {
90
95
  stringArg = param->toString();
@@ -137,10 +142,12 @@ jni::local_ref<jni::JObject> NativeStatementBinding::getColumnValue(int index) {
137
142
  return jni::make_jstring(text);
138
143
  }
139
144
  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))));
145
+ size_t length = static_cast<size_t>(sqlite3_column_bytes(stmt, index));
146
+ auto byteArray = jni::JArrayByte::newArray(length);
147
+ byteArray->setRegion(
148
+ 0, length,
149
+ static_cast<const signed char *>(sqlite3_column_blob(stmt, index)));
150
+ return byteArray;
144
151
  }
145
152
  case SQLITE_NULL: {
146
153
  return nullptr;
@@ -22,6 +22,7 @@ public:
22
22
 
23
23
  // sqlite3 bindings
24
24
  int sqlite3_bind_parameter_index(const std::string &name);
25
+ int sqlite3_clear_bindings();
25
26
  int sqlite3_column_count();
26
27
  std::string sqlite3_column_name(int index);
27
28
  int sqlite3_finalize();
@@ -4,7 +4,9 @@ package expo.modules.sqlite
4
4
 
5
5
  import expo.modules.kotlin.sharedobjects.SharedRef
6
6
 
7
- internal class NativeDatabase(val dbName: String, val openOptions: OpenDatabaseOptions) : SharedRef<NativeDatabaseBinding>(NativeDatabaseBinding()) {
7
+ internal class NativeDatabase(val databaseName: String, val openOptions: OpenDatabaseOptions) : SharedRef<NativeDatabaseBinding>(NativeDatabaseBinding()) {
8
+ var isClosed = false
9
+
8
10
  override fun equals(other: Any?): Boolean {
9
11
  return other is NativeDatabase && this.ref == other.ref
10
12
  }
@@ -5,7 +5,7 @@ package expo.modules.sqlite
5
5
  import com.facebook.jni.HybridData
6
6
  import expo.modules.core.interfaces.DoNotStrip
7
7
 
8
- private typealias UpdateListener = (dbName: String, tableName: String, operationType: Int, rowID: Long) -> Unit
8
+ private typealias UpdateListener = (databaseName: String, tableName: String, operationType: Int, rowID: Long) -> Unit
9
9
 
10
10
  @Suppress("KotlinJniMissingFunction")
11
11
  @DoNotStrip
@@ -39,7 +39,7 @@ internal class NativeDatabaseBinding {
39
39
 
40
40
  external fun sqlite3_changes(): Int
41
41
  external fun sqlite3_close(): Int
42
- external fun sqlite3_db_filename(dbName: String): String
42
+ external fun sqlite3_db_filename(databaseName: String): String
43
43
  external fun sqlite3_enable_load_extension(onoff: Int): Int
44
44
  external fun sqlite3_exec(source: String): Int
45
45
  external fun sqlite3_get_autocommit(): Int
@@ -59,8 +59,8 @@ internal class NativeDatabaseBinding {
59
59
 
60
60
  @Suppress("unused")
61
61
  @DoNotStrip
62
- private fun onUpdate(action: Int, dbName: String, tableName: String, rowId: Long) {
63
- mUpdateListener?.invoke(dbName, tableName, action, rowId)
62
+ private fun onUpdate(action: Int, databaseName: String, tableName: String, rowId: Long) {
63
+ mUpdateListener?.invoke(databaseName, tableName, action, rowId)
64
64
  }
65
65
 
66
66
  // endregion
@@ -5,6 +5,8 @@ package expo.modules.sqlite
5
5
  import expo.modules.kotlin.sharedobjects.SharedRef
6
6
 
7
7
  internal class NativeStatement : SharedRef<NativeStatementBinding>(NativeStatementBinding()) {
8
+ var isFinalized = false
9
+
8
10
  override fun equals(other: Any?): Boolean {
9
11
  return other is NativeStatement && this.ref == other.ref
10
12
  }
@@ -5,8 +5,8 @@ package expo.modules.sqlite
5
5
  import com.facebook.jni.HybridData
6
6
  import expo.modules.core.interfaces.DoNotStrip
7
7
 
8
- internal typealias ColumnNames = ArrayList<String>
9
- internal typealias ColumnValues = ArrayList<Any>
8
+ internal typealias SQLiteColumnNames = ArrayList<String>
9
+ internal typealias SQLiteColumnValues = ArrayList<Any>
10
10
 
11
11
  @Suppress("KotlinJniMissingFunction")
12
12
  @DoNotStrip
@@ -21,6 +21,7 @@ internal class NativeStatementBinding {
21
21
  // region sqlite3 bindings
22
22
 
23
23
  external fun sqlite3_bind_parameter_index(name: String): Int
24
+ external fun sqlite3_clear_bindings(): Int
24
25
  external fun sqlite3_column_count(): Int
25
26
  external fun sqlite3_column_name(index: Int): String
26
27
  external fun sqlite3_finalize(): Int
@@ -28,8 +29,8 @@ internal class NativeStatementBinding {
28
29
  external fun sqlite3_step(): Int
29
30
 
30
31
  external fun bindStatementParam(index: Int, param: Any): Int
31
- external fun getColumnNames(): ColumnNames
32
- external fun getColumnValues(): ColumnValues
32
+ external fun getColumnNames(): SQLiteColumnNames
33
+ external fun getColumnValues(): SQLiteColumnValues
33
34
 
34
35
  // endregion
35
36
 
@@ -24,3 +24,9 @@ internal class SQLiteErrorException(message: String) :
24
24
  @DoNotStrip
25
25
  internal class InvalidConvertibleException(message: String) :
26
26
  CodedException(message)
27
+
28
+ internal class AccessClosedResourceException :
29
+ CodedException("Access to closed resource")
30
+
31
+ internal class InvalidBindParameterException :
32
+ CodedException("Invalid bind parameter")
@@ -19,36 +19,36 @@ class SQLiteModule : Module() {
19
19
  override fun definition() = ModuleDefinition {
20
20
  Name("ExpoSQLite")
21
21
 
22
- AsyncFunction("exec") { dbName: String, queries: List<Query>, readOnly: Boolean ->
23
- return@AsyncFunction execute(dbName, queries, readOnly)
22
+ AsyncFunction("exec") { databaseName: String, queries: List<Query>, readOnly: Boolean ->
23
+ return@AsyncFunction execute(databaseName, queries, readOnly)
24
24
  }
25
25
 
26
- AsyncFunction("execRawQuery") { dbName: String, queries: List<Query>, readOnly: Boolean ->
27
- return@AsyncFunction execute(dbName, queries, readOnly)
26
+ AsyncFunction("execRawQuery") { databaseName: String, queries: List<Query>, readOnly: Boolean ->
27
+ return@AsyncFunction execute(databaseName, queries, readOnly)
28
28
  }
29
29
 
30
- AsyncFunction("close") { dbName: String ->
30
+ AsyncFunction("close") { databaseName: String ->
31
31
  cachedDatabase
32
- .remove(dbName)
32
+ .remove(databaseName)
33
33
  ?.sqlite3_close()
34
34
  }
35
35
 
36
- Function("closeSync") { dbName: String ->
36
+ Function("closeSync") { databaseName: String ->
37
37
  cachedDatabase
38
- .remove(dbName)
38
+ .remove(databaseName)
39
39
  ?.sqlite3_close()
40
40
  }
41
41
 
42
- AsyncFunction("deleteAsync") { dbName: String ->
43
- if (cachedDatabase[dbName] != null) {
44
- throw DeleteDatabaseException(dbName)
42
+ AsyncFunction("deleteAsync") { databaseName: String ->
43
+ if (cachedDatabase[databaseName] != null) {
44
+ throw DeleteDatabaseException(databaseName)
45
45
  }
46
- val dbFile = File(pathForDatabaseName(dbName))
46
+ val dbFile = File(pathForDatabaseName(databaseName))
47
47
  if (!dbFile.exists()) {
48
- throw DatabaseNotFoundException(dbName)
48
+ throw DatabaseNotFoundException(databaseName)
49
49
  }
50
50
  if (!dbFile.delete()) {
51
- throw DeleteDatabaseFileException(dbName)
51
+ throw DeleteDatabaseFileException(databaseName)
52
52
  }
53
53
  }
54
54
 
@@ -66,28 +66,28 @@ class SQLiteModule : Module() {
66
66
  return "$directory${File.separator}$name"
67
67
  }
68
68
 
69
- private fun openDatabase(dbName: String): SQLite3Wrapper? {
69
+ private fun openDatabase(databaseName: String): SQLite3Wrapper? {
70
70
  val path: String
71
71
  try {
72
- path = pathForDatabaseName(dbName)
72
+ path = pathForDatabaseName(databaseName)
73
73
  } catch (_: IOException) {
74
74
  return null
75
75
  }
76
76
 
77
77
  if (File(path).exists()) {
78
- cachedDatabase[dbName]?.let {
78
+ cachedDatabase[databaseName]?.let {
79
79
  return it
80
80
  }
81
81
  }
82
82
 
83
- cachedDatabase.remove(dbName)
83
+ cachedDatabase.remove(databaseName)
84
84
  val db = SQLite3Wrapper.open(path) ?: return null
85
- cachedDatabase[dbName] = db
85
+ cachedDatabase[databaseName] = db
86
86
  return db
87
87
  }
88
88
 
89
- private fun execute(dbName: String, queries: List<Query>, readOnly: Boolean): List<Any> {
90
- val db = openDatabase(dbName) ?: throw OpenDatabaseException(dbName)
89
+ private fun execute(databaseName: String, queries: List<Query>, readOnly: Boolean): List<Any> {
90
+ val db = openDatabase(databaseName) ?: throw OpenDatabaseException(databaseName)
91
91
  return queries.map { db.executeSql(it.sql, it.args, readOnly) }
92
92
  }
93
93