expo-sqlite 58.0.10 → 58.0.11

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 (72) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/android/build.gradle +6 -2
  3. package/android/src/main/cpp/NativeDatabaseBinding.cpp +11 -8
  4. package/android/src/main/cpp/NativeStatementBinding.cpp +43 -2
  5. package/android/src/main/cpp/NativeStatementBinding.h +3 -0
  6. package/android/src/main/cpp/SQLiteError.h +34 -0
  7. package/android/src/main/java/expo/modules/sqlite/DatabaseConnection.kt +68 -0
  8. package/android/src/main/java/expo/modules/sqlite/NativeDatabase.kt +135 -22
  9. package/android/src/main/java/expo/modules/sqlite/NativeSession.kt +126 -6
  10. package/android/src/main/java/expo/modules/sqlite/NativeStatement.kt +199 -14
  11. package/android/src/main/java/expo/modules/sqlite/NativeStatementBinding.kt +1 -0
  12. package/android/src/main/java/expo/modules/sqlite/SQLRecords.kt +19 -13
  13. package/android/src/main/java/expo/modules/sqlite/SQLiteModule.kt +176 -577
  14. package/android/src/main/java/expo/modules/sqlite/SQLiteOptions.kt +3 -10
  15. package/android/src/main/java/expo/modules/sqlite/SQLiteValues.kt +47 -0
  16. package/build/NativeDatabase.d.ts +2 -2
  17. package/build/SQLiteDatabase.js +9 -3
  18. package/build/SQLiteDatabase.js.map +1 -1
  19. package/dev-plugin-dist/+not-found.html +1 -1
  20. package/dev-plugin-dist/_expo/static/js/web/{__common-9b94dd2fbdbb825a662f42cf8d2077ee.js → __common-8b6d10c7ab64ecfd128d45105ef5590b.js} +51 -48
  21. package/dev-plugin-dist/_expo/static/js/web/{_layout-b2894030c1dfbd95b717a85901b6c271.js → _layout-1da259c4109daa50bd04899675f5d333.js} +23 -23
  22. package/dev-plugin-dist/_expo/static/js/web/{entry-04fdb7d857a65c0ed638ef2d774a4b6e.js → entry-5e24130038c41e25d9a78d08664ef6cb.js} +753 -753
  23. package/dev-plugin-dist/_expo/static/js/web/{index-4bf2da199f699eb47a42074d5e183c07.js → index-17ca77580cae7c249688c43b3b3e0949.js} +1740 -1740
  24. package/dev-plugin-dist/_expo/static/js/web/{worker-d51aa6be89e271e571111274ab8e7f5c.js → worker-cc2e40fb110f53b73733dd7e24d9d8f6.js} +17 -17
  25. package/dev-plugin-dist/_sitemap.html +1 -1
  26. package/dev-plugin-dist/index.html +1 -1
  27. package/expo-module.config.json +0 -1
  28. package/ios/NativeDatabase.swift +5 -8
  29. package/ios/NativeStatement.swift +20 -13
  30. package/ios/SQLiteResult.swift +31 -0
  31. package/ios/Tests/test_ErrorReporting.swift +25 -0
  32. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11-sources.jar +0 -0
  33. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11-sources.jar.md5 +1 -0
  34. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11-sources.jar.sha1 +1 -0
  35. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11-sources.jar.sha256 +1 -0
  36. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11-sources.jar.sha512 +1 -0
  37. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.aar +0 -0
  38. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.aar.md5 +1 -0
  39. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.aar.sha1 +1 -0
  40. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.aar.sha256 +1 -0
  41. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.aar.sha512 +1 -0
  42. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/{58.0.10/expo.modules.sqlite-58.0.10.module → 58.0.11/expo.modules.sqlite-58.0.11.module} +22 -22
  43. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.module.md5 +1 -0
  44. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.module.sha1 +1 -0
  45. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.module.sha256 +1 -0
  46. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.module.sha512 +1 -0
  47. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/{58.0.10/expo.modules.sqlite-58.0.10.pom → 58.0.11/expo.modules.sqlite-58.0.11.pom} +1 -1
  48. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.pom.md5 +1 -0
  49. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.pom.sha1 +1 -0
  50. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.pom.sha256 +1 -0
  51. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.11/expo.modules.sqlite-58.0.11.pom.sha512 +1 -0
  52. package/package.json +4 -4
  53. package/src/NativeDatabase.ts +2 -2
  54. package/src/SQLiteDatabase.ts +11 -3
  55. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10-sources.jar +0 -0
  56. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10-sources.jar.md5 +0 -1
  57. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10-sources.jar.sha1 +0 -1
  58. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10-sources.jar.sha256 +0 -1
  59. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10-sources.jar.sha512 +0 -1
  60. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.aar +0 -0
  61. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.aar.md5 +0 -1
  62. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.aar.sha1 +0 -1
  63. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.aar.sha256 +0 -1
  64. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.aar.sha512 +0 -1
  65. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.module.md5 +0 -1
  66. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.module.sha1 +0 -1
  67. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.module.sha256 +0 -1
  68. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.module.sha512 +0 -1
  69. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.pom.md5 +0 -1
  70. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.pom.sha1 +0 -1
  71. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.pom.sha256 +0 -1
  72. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/58.0.10/expo.modules.sqlite-58.0.10.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 58.0.11
4
+
5
+ ### Patch Changes
6
+
7
+ - [Internal] Bump `react-native-web` to `~0.21.4`. ([#51260](https://github.com/expo/expo/pull/51260) by [@zoontek](https://github.com/zoontek))
8
+ - Preserve statement error codes and messages when queries run concurrently on Android and iOS, and format Android SQLite error codes as numbers. ([#51082](https://github.com/expo/expo/pull/51082) by [@savv](https://github.com/savv))
9
+ - [Android] Migrate to the Expo Modules API 2.0. Reloading the app now closes the databases that are still open, and `lastInsertRowId` is no longer truncated to 32 bits. ([#51208](https://github.com/expo/expo/pull/51208) by [@lukmccall](https://github.com/lukmccall))
10
+
3
11
  ## 58.0.10
4
12
 
5
13
  ### Patch Changes
@@ -47,13 +47,17 @@ def reactNativeArchitectures() {
47
47
  }
48
48
 
49
49
  group = 'host.exp.exponent'
50
- version = '58.0.10'
50
+ version = '58.0.11'
51
+
52
+ expoModule {
53
+ v2 true
54
+ }
51
55
 
52
56
  android {
53
57
  namespace "expo.modules.sqlite"
54
58
  defaultConfig {
55
59
  versionCode 18
56
- versionName "58.0.10"
60
+ versionName "58.0.11"
57
61
  buildConfigField "boolean", "WITH_SQLITE_VEC", project.ext.WITH_SQLITE_VEC.toString()
58
62
 
59
63
  externalNativeBuild {
@@ -1,6 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
3
  #include "NativeDatabaseBinding.h"
4
+ #include "SQLiteError.h"
4
5
 
5
6
  #include "Exceptions.h"
6
7
 
@@ -101,8 +102,15 @@ int NativeDatabaseBinding::sqlite3_prepare_v2(
101
102
  const std::string &source,
102
103
  jni::alias_ref<NativeStatementBinding::javaobject> statement) {
103
104
  NativeStatementBinding *cStatement = cthis(statement);
104
- return ::exsqlite3_prepare_v2(db, source.c_str(), source.size(),
105
+ SQLiteDatabaseLock lock(db);
106
+ cStatement->db = db;
107
+ int ret = ::exsqlite3_prepare_v2(db, source.c_str(), source.size(),
105
108
  &cStatement->stmt, nullptr);
109
+ if (ret != SQLITE_OK) {
110
+ jni::throwNewJavaException(
111
+ SQLiteErrorException::create(sqliteErrorMessage(db, ret)).get());
112
+ }
113
+ return ret;
106
114
  }
107
115
 
108
116
  jni::local_ref<jni::JArrayByte>
@@ -173,13 +181,8 @@ int NativeDatabaseBinding::sqlite3_backup(
173
181
  }
174
182
 
175
183
  std::string NativeDatabaseBinding::convertSqlLiteErrorToSTLString() {
176
- int code = exsqlite3_errcode(db);
177
- const char *message = exsqlite3_errmsg(db);
178
- std::string result("Error code ");
179
- result += code;
180
- result += ": ";
181
- result += message;
182
- return result;
184
+ SQLiteDatabaseLock lock(db);
185
+ return sqliteErrorMessage(db, exsqlite3_errcode(db));
183
186
  }
184
187
 
185
188
  jni::local_ref<jni::JString>
@@ -5,6 +5,7 @@
5
5
 
6
6
  #include <android/log.h>
7
7
  #include "Exceptions.h"
8
+ #include "SQLiteError.h"
8
9
 
9
10
  namespace jni = facebook::jni;
10
11
 
@@ -34,6 +35,8 @@ void NativeStatementBinding::registerNatives() {
34
35
  makeNativeMethod("sqlite3_step", NativeStatementBinding::sqlite3_step),
35
36
  makeNativeMethod("bindStatementParam",
36
37
  NativeStatementBinding::bindStatementParam),
38
+ makeNativeMethod("getLastErrorMessage",
39
+ NativeStatementBinding::getLastErrorMessage),
37
40
  makeNativeMethod("getColumnNames",
38
41
  NativeStatementBinding::getColumnNames),
39
42
  makeNativeMethod("getColumnValues",
@@ -59,14 +62,52 @@ std::string NativeStatementBinding::sqlite3_column_name(int index) {
59
62
  }
60
63
 
61
64
  int NativeStatementBinding::sqlite3_finalize() {
65
+ if (!stmt) {
66
+ lastErrorMessage.clear();
67
+ return SQLITE_OK;
68
+ }
69
+ if (!db) {
70
+ lastErrorMessage = sqliteErrorMessage(SQLITE_MISUSE);
71
+ return SQLITE_MISUSE;
72
+ }
73
+ SQLiteDatabaseLock lock(db);
62
74
  int ret = ::exsqlite3_finalize(stmt);
63
75
  stmt = nullptr;
76
+ lastErrorMessage = ret == SQLITE_OK ? "" : sqliteErrorMessage(db, ret);
64
77
  return ret;
65
78
  }
66
79
 
67
- int NativeStatementBinding::sqlite3_reset() { return ::exsqlite3_reset(stmt); }
80
+ int NativeStatementBinding::sqlite3_reset() {
81
+ if (!stmt) {
82
+ lastErrorMessage.clear();
83
+ return SQLITE_OK;
84
+ }
85
+ if (!db) {
86
+ lastErrorMessage = sqliteErrorMessage(SQLITE_MISUSE);
87
+ return SQLITE_MISUSE;
88
+ }
89
+ SQLiteDatabaseLock lock(db);
90
+ int ret = ::exsqlite3_reset(stmt);
91
+ lastErrorMessage = ret == SQLITE_OK ? "" : sqliteErrorMessage(db, ret);
92
+ return ret;
93
+ }
68
94
 
69
- int NativeStatementBinding::sqlite3_step() { return ::exsqlite3_step(stmt); }
95
+ int NativeStatementBinding::sqlite3_step() {
96
+ if (!stmt || !db) {
97
+ lastErrorMessage = sqliteErrorMessage(SQLITE_MISUSE);
98
+ return SQLITE_MISUSE;
99
+ }
100
+ SQLiteDatabaseLock lock(db);
101
+ int ret = ::exsqlite3_step(stmt);
102
+ lastErrorMessage = ret == SQLITE_ROW || ret == SQLITE_DONE
103
+ ? ""
104
+ : sqliteErrorMessage(db, ret);
105
+ return ret;
106
+ }
107
+
108
+ std::string NativeStatementBinding::getLastErrorMessage() {
109
+ return lastErrorMessage;
110
+ }
70
111
 
71
112
  int NativeStatementBinding::bindStatementParam(
72
113
  int index, jni::alias_ref<jni::JObject> param) {
@@ -30,6 +30,7 @@ public:
30
30
  int sqlite3_step();
31
31
 
32
32
  // helpers
33
+ std::string getLastErrorMessage();
33
34
  int bindStatementParam(int index, jni::alias_ref<jni::JObject> param);
34
35
  jni::local_ref<jni::JArrayList<jni::JString>> getColumnNames();
35
36
  jni::local_ref<jni::JArrayList<jni::JObject>> getColumnValues();
@@ -47,7 +48,9 @@ private:
47
48
  friend HybridBase;
48
49
  friend NativeDatabaseBinding;
49
50
 
51
+ sqlite3 *db = nullptr;
50
52
  exsqlite3_stmt *stmt = nullptr;
53
+ std::string lastErrorMessage;
51
54
  };
52
55
 
53
56
  } // namespace expo
@@ -0,0 +1,34 @@
1
+ // Copyright 2026-present 650 Industries. All rights reserved.
2
+
3
+ #pragma once
4
+
5
+ #include <string>
6
+ #include "sqlite3.h"
7
+
8
+ namespace expo {
9
+
10
+ // Keep SQLite's connection error state stable until its message has been copied.
11
+ // SQLite's database mutex is recursive, so the operation can acquire it internally too.
12
+ class SQLiteDatabaseLock {
13
+ public:
14
+ explicit SQLiteDatabaseLock(sqlite3 *db) : mutex(exsqlite3_db_mutex(db)) {
15
+ exsqlite3_mutex_enter(mutex);
16
+ }
17
+ ~SQLiteDatabaseLock() { exsqlite3_mutex_leave(mutex); }
18
+ SQLiteDatabaseLock(const SQLiteDatabaseLock &) = delete;
19
+ SQLiteDatabaseLock &operator=(const SQLiteDatabaseLock &) = delete;
20
+
21
+ private:
22
+ exsqlite3_mutex *mutex;
23
+ };
24
+
25
+ // Call while holding SQLiteDatabaseLock; use the operation's returned code, not a later errcode().
26
+ inline std::string sqliteErrorMessage(sqlite3 *db, int code) {
27
+ return "Error code " + std::to_string(code) + ": " + exsqlite3_errmsg(db);
28
+ }
29
+
30
+ inline std::string sqliteErrorMessage(int code) {
31
+ return "Error code " + std::to_string(code) + ": " + exsqlite3_errstr(code);
32
+ }
33
+
34
+ } // namespace expo
@@ -0,0 +1,68 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ package expo.modules.sqlite
4
+
5
+ import java.util.concurrent.atomic.AtomicInteger
6
+ import java.util.concurrent.locks.ReentrantLock
7
+
8
+ internal class DatabaseConnection(
9
+ val databasePath: String,
10
+ val openOptions: OpenDatabaseOptions
11
+ ) {
12
+ val ref = NativeDatabaseBinding()
13
+
14
+ @Volatile
15
+ var isClosed = false
16
+ private set
17
+
18
+ val closeLock = ReentrantLock()
19
+
20
+ val statementLifecycleLock = Any()
21
+ val statements = mutableListOf<NativeStatement>()
22
+
23
+ /** How many times JavaScript opened this connection without closing it yet. */
24
+ private val refCount = AtomicInteger(1)
25
+
26
+ /** How many `NativeDatabase` objects that use this connection JavaScript still holds. */
27
+ private var holders = 0
28
+ private var isBindingReleased = false
29
+
30
+ @Throws(AccessClosedResourceException::class)
31
+ fun maybeThrowForClosed() {
32
+ if (isClosed) {
33
+ throw AccessClosedResourceException()
34
+ }
35
+ }
36
+
37
+ fun addRef(): Int = refCount.incrementAndGet()
38
+
39
+ fun release(): Int = refCount.decrementAndGet()
40
+
41
+ @Synchronized
42
+ fun addHolder() {
43
+ holders++
44
+ }
45
+
46
+ /** JavaScript let go of a `NativeDatabase` that uses this connection. */
47
+ @Synchronized
48
+ fun removeHolder() {
49
+ holders--
50
+ releaseBindingIfUnused()
51
+ }
52
+
53
+ @Synchronized
54
+ fun markClosed() {
55
+ isClosed = true
56
+ releaseBindingIfUnused()
57
+ }
58
+
59
+ // The binding goes once the connection is closed and nothing in JavaScript can reach it. A
60
+ // connection JavaScript dropped while it was open stays usable, so it can still be reopened from
61
+ // the cache, or closed when the module is destroyed.
62
+ private fun releaseBindingIfUnused() {
63
+ if (isClosed && holders == 0 && !isBindingReleased) {
64
+ isBindingReleased = true
65
+ ref.close()
66
+ }
67
+ }
68
+ }
@@ -2,38 +2,151 @@
2
2
 
3
3
  package expo.modules.sqlite
4
4
 
5
- import expo.modules.kotlin.sharedobjects.SharedRef
6
- import java.util.concurrent.atomic.AtomicInteger
7
- import java.util.concurrent.locks.ReentrantLock
5
+ import io.github.expo.modules.v2.ExpoSharedObject
6
+ import io.github.expo.modules.v2.JS
7
+ import io.github.expo.modules.v2.SharedObject
8
+ import io.github.expo.modules.v2.module
8
9
 
9
- internal class NativeDatabase(val databasePath: String, val openOptions: OpenDatabaseOptions) : SharedRef<NativeDatabaseBinding>(NativeDatabaseBinding()) {
10
- var isClosed = false
11
- val closeLock = ReentrantLock()
10
+ /**
11
+ * A database JavaScript opened. Opening a database that is already open, without asking for a new
12
+ * connection, gives a new `NativeDatabase` over the same [DatabaseConnection], so the data and the
13
+ * open count are shared, as one cached object shared them before.
14
+ */
15
+ @ExpoSharedObject
16
+ internal class NativeDatabase @JS constructor(
17
+ databasePath: String,
18
+ options: OpenDatabaseOptions,
19
+ serializedData: ByteArray?
20
+ ) : SharedObject() {
21
+ private val module: SQLiteModule = context.module<SQLiteModule>()
22
+ ?: throw IllegalStateException(
23
+ "Cannot open the database because the ExpoSQLite module is not installed in this app. " +
24
+ "Rebuild the app after installing expo-sqlite."
25
+ )
12
26
 
13
- // Protect statement registration and cleanup through the final close attempt.
14
- // Running statements use their own locks, so interruption need not wait for them.
15
- val statementLifecycleLock = Any()
16
- val statements = mutableListOf<NativeStatement>()
17
- private val refCount = AtomicInteger(1)
27
+ val connection: DatabaseConnection = module.openConnection(
28
+ databasePath,
29
+ options,
30
+ serializedData
31
+ )
32
+ .also {
33
+ it.addHolder()
34
+ }
18
35
 
19
- internal fun addRef(): Int {
20
- return refCount.incrementAndGet()
36
+ override fun sharedObjectDidRelease() {
37
+ super.sharedObjectDidRelease()
38
+ connection.removeHolder()
21
39
  }
22
40
 
23
- internal fun release(): Int {
24
- return refCount.decrementAndGet()
41
+ @JS
42
+ suspend fun initAsync(): Unit = io { module.initDb(connection) }
43
+
44
+ @JS
45
+ fun initSync() {
46
+ module.initDb(connection)
25
47
  }
26
48
 
27
- override fun equals(other: Any?): Boolean {
28
- return other is NativeDatabase && this.ref == other.ref
49
+ @JS
50
+ suspend fun isInTransactionAsync(): Boolean = io { isInTransaction() }
51
+
52
+ @JS
53
+ fun isInTransactionSync(): Boolean = isInTransaction()
54
+
55
+ @JS
56
+ suspend fun closeAsync(): Unit = io { module.closeDatabaseIfNeeded(connection) }
57
+
58
+ // Interrupt must reach SQLite immediately, without waiting for the running query's queue.
59
+ @JS
60
+ fun interruptSync() {
61
+ // Do not block the JS thread or touch a connection being closed on another thread.
62
+ if (!connection.closeLock.tryLock()) {
63
+ throw DatabaseClosingException()
64
+ }
65
+ try {
66
+ connection.maybeThrowForClosed()
67
+ connection.ref.sqlite3_interrupt()
68
+ } finally {
69
+ connection.closeLock.unlock()
70
+ }
29
71
  }
30
72
 
31
- override fun hashCode(): Int {
32
- return ref.hashCode()
73
+ @JS
74
+ fun closeSync(): Unit = module.closeDatabaseIfNeeded(connection)
75
+
76
+ @JS
77
+ suspend fun execAsync(source: String): Unit = io { exec(source) }
78
+
79
+ @JS
80
+ fun execSync(source: String): Unit = exec(source)
81
+
82
+ @JS
83
+ suspend fun serializeAsync(databaseName: String): ByteArray = io { serialize(databaseName) }
84
+
85
+ @JS
86
+ fun serializeSync(databaseName: String): ByteArray = serialize(databaseName)
87
+
88
+ @JS
89
+ suspend fun prepareAsync(statement: NativeStatement, source: String): Unit =
90
+ io { prepare(statement, source) }
91
+
92
+ @JS
93
+ fun prepareSync(statement: NativeStatement, source: String): Unit =
94
+ prepare(statement, source)
95
+
96
+ @JS
97
+ suspend fun createSessionAsync(session: NativeSession, dbName: String): Unit =
98
+ io { session.create(connection, dbName) }
99
+
100
+ @JS
101
+ fun createSessionSync(session: NativeSession, dbName: String): Unit =
102
+ session.create(connection, dbName)
103
+
104
+ @JS
105
+ suspend fun loadExtensionAsync(libPath: String, entryPoint: String?): Unit =
106
+ io { loadExtension(libPath, entryPoint) }
107
+
108
+ @JS
109
+ fun loadExtensionSync(libPath: String, entryPoint: String?): Unit =
110
+ loadExtension(libPath, entryPoint)
111
+
112
+ @Throws(AccessClosedResourceException::class)
113
+ private fun isInTransaction(): Boolean {
114
+ connection.maybeThrowForClosed()
115
+ return connection.ref.sqlite3_get_autocommit() == 0
33
116
  }
34
117
 
35
- override fun sharedObjectDidRelease() {
36
- super.sharedObjectDidRelease()
37
- this.ref.close()
118
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
119
+ private fun exec(source: String) {
120
+ connection.maybeThrowForClosed()
121
+ connection.ref.sqlite3_exec(source)
122
+ }
123
+
124
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
125
+ private fun serialize(databaseName: String): ByteArray {
126
+ connection.maybeThrowForClosed()
127
+ return connection.ref.sqlite3_serialize(databaseName)
128
+ }
129
+
130
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
131
+ private fun prepare(statement: NativeStatement, source: String) {
132
+ synchronized(connection.statementLifecycleLock) {
133
+ synchronized(statement) {
134
+ statement.maybeThrowForFinalized()
135
+ connection.maybeThrowForClosed()
136
+ connection.ref.sqlite3_prepare_v2(source, statement.ref)
137
+ statement.isPrepared = true
138
+ connection.statements.add(statement)
139
+ }
140
+ }
141
+ }
142
+
143
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
144
+ private fun loadExtension(libPath: String, entryPoint: String?) {
145
+ connection.maybeThrowForClosed()
146
+ connection.ref.sqlite3_enable_load_extension(1)
147
+ val ret = connection.ref.sqlite3_load_extension(libPath, entryPoint ?: "")
148
+ if (ret != NativeDatabaseBinding.SQLITE_OK) {
149
+ throw SQLiteErrorException(connection.ref.convertSqlLiteErrorToString())
150
+ }
38
151
  }
39
152
  }
@@ -2,19 +2,139 @@
2
2
 
3
3
  package expo.modules.sqlite
4
4
 
5
- import expo.modules.kotlin.sharedobjects.SharedRef
5
+ import io.github.expo.modules.v2.ExpoSharedObject
6
+ import io.github.expo.modules.v2.JS
7
+ import io.github.expo.modules.v2.SharedRef
6
8
 
7
- internal class NativeSession : SharedRef<NativeSessionBinding>(NativeSessionBinding()) {
9
+ @ExpoSharedObject
10
+ internal class NativeSession @JS constructor() : SharedRef<NativeSessionBinding>(NativeSessionBinding()) {
8
11
  override fun sharedObjectDidRelease() {
9
12
  super.sharedObjectDidRelease()
10
13
  this.ref.close()
11
14
  }
12
15
 
13
- override fun equals(other: Any?): Boolean {
14
- return other is NativeSession && this.ref == other.ref
16
+ // region JavaScript members
17
+
18
+ @JS
19
+ suspend fun attachAsync(database: NativeDatabase, table: String?) {
20
+ io { attach(database.connection, table) }
21
+ }
22
+
23
+ @JS
24
+ fun attachSync(database: NativeDatabase, table: String?) {
25
+ attach(database.connection, table)
26
+ }
27
+
28
+ @JS
29
+ suspend fun enableAsync(database: NativeDatabase, enabled: Boolean) {
30
+ io { enable(database.connection, enabled) }
31
+ }
32
+
33
+ @JS
34
+ fun enableSync(database: NativeDatabase, enabled: Boolean) {
35
+ enable(database.connection, enabled)
36
+ }
37
+
38
+ @JS
39
+ suspend fun closeAsync(database: NativeDatabase) {
40
+ io { close(database.connection) }
41
+ }
42
+
43
+ @JS
44
+ fun closeSync(database: NativeDatabase) {
45
+ close(database.connection)
46
+ }
47
+
48
+ @JS
49
+ suspend fun createChangesetAsync(database: NativeDatabase): ByteArray = io { createChangeset(database.connection) }
50
+
51
+ @JS
52
+ fun createChangesetSync(database: NativeDatabase): ByteArray = createChangeset(database.connection)
53
+
54
+ @JS
55
+ suspend fun createInvertedChangesetAsync(database: NativeDatabase): ByteArray =
56
+ io { createInvertedChangeset(database.connection) }
57
+
58
+ @JS
59
+ fun createInvertedChangesetSync(database: NativeDatabase): ByteArray = createInvertedChangeset(database.connection)
60
+
61
+ @JS
62
+ suspend fun applyChangesetAsync(database: NativeDatabase, changeset: ByteArray) {
63
+ io { applyChangeset(database.connection, changeset) }
64
+ }
65
+
66
+ @JS
67
+ fun applyChangesetSync(database: NativeDatabase, changeset: ByteArray) {
68
+ applyChangeset(database.connection, changeset)
69
+ }
70
+
71
+ @JS
72
+ suspend fun invertChangesetAsync(database: NativeDatabase, changeset: ByteArray): ByteArray =
73
+ io { invertChangeset(database.connection, changeset) }
74
+
75
+ @JS
76
+ fun invertChangesetSync(database: NativeDatabase, changeset: ByteArray): ByteArray =
77
+ invertChangeset(database.connection, changeset)
78
+
79
+ // endregion
80
+
81
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
82
+ fun create(connection: DatabaseConnection, dbName: String) {
83
+ connection.maybeThrowForClosed()
84
+ if (ref.sqlite3session_create(connection.ref, dbName) != NativeDatabaseBinding.SQLITE_OK) {
85
+ throw SQLiteErrorException(connection.ref.convertSqlLiteErrorToString())
86
+ }
87
+ }
88
+
89
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
90
+ private fun attach(connection: DatabaseConnection, table: String?) {
91
+ connection.maybeThrowForClosed()
92
+ if (ref.sqlite3session_attach(table) != NativeDatabaseBinding.SQLITE_OK) {
93
+ throw SQLiteErrorException(connection.ref.convertSqlLiteErrorToString())
94
+ }
95
+ }
96
+
97
+ @Throws(AccessClosedResourceException::class)
98
+ private fun enable(connection: DatabaseConnection, enabled: Boolean) {
99
+ connection.maybeThrowForClosed()
100
+ ref.sqlite3session_enable(enabled)
101
+ }
102
+
103
+ @Throws(AccessClosedResourceException::class)
104
+ private fun close(connection: DatabaseConnection) {
105
+ connection.maybeThrowForClosed()
106
+ ref.sqlite3session_delete()
107
+ }
108
+
109
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
110
+ private fun createChangeset(connection: DatabaseConnection): ByteArray {
111
+ connection.maybeThrowForClosed()
112
+ val byteBuffer = ref.sqlite3session_changeset()
113
+ ?: throw SQLiteErrorException(connection.ref.convertSqlLiteErrorToString())
114
+ return byteBuffer.toByteArray()
115
+ }
116
+
117
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
118
+ private fun createInvertedChangeset(connection: DatabaseConnection): ByteArray {
119
+ connection.maybeThrowForClosed()
120
+ val byteBuffer = ref.sqlite3session_changeset_inverted()
121
+ ?: throw SQLiteErrorException(connection.ref.convertSqlLiteErrorToString())
122
+ return byteBuffer.toByteArray()
123
+ }
124
+
125
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
126
+ private fun applyChangeset(connection: DatabaseConnection, changeset: ByteArray) {
127
+ connection.maybeThrowForClosed()
128
+ if (ref.sqlite3changeset_apply(connection.ref, changeset.toDirectBuffer()) != NativeDatabaseBinding.SQLITE_OK) {
129
+ throw SQLiteErrorException(connection.ref.convertSqlLiteErrorToString())
130
+ }
15
131
  }
16
132
 
17
- override fun hashCode(): Int {
18
- return ref.hashCode()
133
+ @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
134
+ private fun invertChangeset(connection: DatabaseConnection, changeset: ByteArray): ByteArray {
135
+ connection.maybeThrowForClosed()
136
+ val byteBuffer = ref.sqlite3changeset_invert(changeset.toDirectBuffer())
137
+ ?: throw SQLiteErrorException(connection.ref.convertSqlLiteErrorToString())
138
+ return byteBuffer.toByteArray()
19
139
  }
20
140
  }