@op-engineering/op-sqlite 15.0.7 → 15.1.1

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 (45) hide show
  1. package/android/CMakeLists.txt +1 -1
  2. package/android/build.gradle +1 -1
  3. package/android/cpp-adapter.cpp +1 -1
  4. package/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt +7 -9
  5. package/cpp/DBHostObject.cpp +469 -677
  6. package/cpp/DBHostObject.h +56 -58
  7. package/cpp/DumbHostObject.cpp +1 -1
  8. package/cpp/DumbHostObject.h +12 -13
  9. package/cpp/OPSqlite.cpp +207 -0
  10. package/cpp/OPThreadPool.cpp +79 -79
  11. package/cpp/OPThreadPool.h +28 -28
  12. package/cpp/PreparedStatementHostObject.cpp +87 -136
  13. package/cpp/PreparedStatementHostObject.h +16 -28
  14. package/cpp/SmartHostObject.cpp +1 -1
  15. package/cpp/SmartHostObject.h +6 -7
  16. package/cpp/bridge.cpp +639 -633
  17. package/cpp/bridge.h +2 -2
  18. package/cpp/libsql/LICENSE.txt +9 -0
  19. package/cpp/libsql/bridge.cpp +2 -2
  20. package/cpp/libsql/{bridge.h → bridge.hpp} +4 -4
  21. package/cpp/macros.hpp +21 -0
  22. package/cpp/sqlcipher/LICENSE.txt +24 -0
  23. package/cpp/types.hpp +42 -0
  24. package/cpp/utils.cpp +320 -255
  25. package/cpp/{utils.h → utils.hpp} +9 -1
  26. package/ios/OPSQLite.mm +104 -106
  27. package/lib/module/functions.js +52 -44
  28. package/lib/module/functions.js.map +1 -1
  29. package/lib/module/index.js +1 -1
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/typescript/src/functions.d.ts +5 -1
  32. package/lib/typescript/src/functions.d.ts.map +1 -1
  33. package/lib/typescript/src/index.d.ts +1 -1
  34. package/lib/typescript/src/index.d.ts.map +1 -1
  35. package/lib/typescript/src/types.d.ts +12 -1
  36. package/lib/typescript/src/types.d.ts.map +1 -1
  37. package/op-sqlite.podspec +1 -1
  38. package/package.json +10 -8
  39. package/src/functions.ts +64 -54
  40. package/src/index.ts +1 -12
  41. package/src/types.ts +9 -1
  42. package/cpp/bindings.cpp +0 -202
  43. package/cpp/macros.h +0 -15
  44. package/cpp/types.h +0 -33
  45. /package/cpp/{bindings.h → OPSqlite.hpp} +0 -0
package/cpp/utils.cpp CHANGED
@@ -1,327 +1,392 @@
1
- #include "utils.h"
1
+ #include "utils.hpp"
2
2
  #include "SmartHostObject.h"
3
+ #include "types.hpp"
3
4
  #ifndef OP_SQLITE_USE_LIBSQL
4
5
  #include "bridge.h"
5
6
  #endif
7
+ #include "OPThreadPool.h"
6
8
  #include <fstream>
7
9
  #include <sys/stat.h>
10
+ #include <utility>
8
11
 
9
12
  namespace opsqlite {
10
13
 
11
14
  namespace jsi = facebook::jsi;
15
+ namespace react = facebook::react;
12
16
 
13
- inline jsi::Value to_jsi(jsi::Runtime &rt, const JSVariant &value) {
14
- if (std::holds_alternative<bool>(value)) {
15
- return std::get<bool>(value);
16
- } else if (std::holds_alternative<int>(value)) {
17
- return jsi::Value(std::get<int>(value));
18
- } else if (std::holds_alternative<long long>(value)) {
19
- return jsi::Value(static_cast<double>(std::get<long long>(value)));
20
- } else if (std::holds_alternative<double>(value)) {
21
- return jsi::Value(std::get<double>(value));
22
- } else if (std::holds_alternative<std::string>(value)) {
23
- auto str = std::get<std::string>(value);
24
- return jsi::String::createFromUtf8(rt, str);
25
- } else if (std::holds_alternative<ArrayBuffer>(value)) {
26
- auto jsBuffer = std::get<ArrayBuffer>(value);
27
- jsi::Function array_buffer_ctor =
28
- rt.global().getPropertyAsFunction(rt, "ArrayBuffer");
29
- jsi::Object o =
30
- array_buffer_ctor.callAsConstructor(rt, (int)jsBuffer.size)
31
- .getObject(rt);
32
- jsi::ArrayBuffer buf = o.getArrayBuffer(rt);
33
- memcpy(buf.data(rt), jsBuffer.data.get(), jsBuffer.size);
34
- return o;
35
- }
17
+ auto __thread_pool = std::make_shared<ThreadPool>();
36
18
 
37
- return jsi::Value::null();
38
-
39
- // I wanted to use the visitor pattern here but on the ArrayBuffer case it
40
- // is somehow throwing a pointer exception Somehow the v.size or
41
- // v.data.get() is loosing the data when called from the lambda I'm guessing
42
- // the I created the shared pointer wrong and the memory is being freed
43
- // before the lambda is called
44
- // return std::visit(
45
- // [&](auto &&v) -> jsi::Value {
46
- // using T = std::decay_t<decltype(v)>;
47
- // if constexpr (std::is_same_v<T, bool>) {
48
- // return jsi::Value(v);
49
- // } else if constexpr (std::is_same_v<T, int>) {
50
- // return jsi::Value(v);
51
- // } else if constexpr (std::is_same_v<T, long long>) {
52
- // return jsi::Value(
53
- // static_cast<double>(v)); // JSI doesn't support long long
54
- // } else if constexpr (std::is_same_v<T, double>) {
55
- // return jsi::Value(v);
56
- // } else if constexpr (std::is_same_v<T, std::string>) {
57
- // return jsi::String::createFromUtf8(rt, v);
58
- // } else if constexpr (std::is_same_v<T, ArrayBuffer>) {
59
- // static jsi::Function buffer_constructor =
60
- // rt.global().getPropertyAsFunction(rt, "ArrayBuffer");
61
- // jsi::Object o =
62
- // buffer_constructor.callAsConstructor(rt,
63
- // static_cast<int>(v.size))
64
- // .getObject(rt);
65
- // jsi::ArrayBuffer buf = o.getArrayBuffer(rt);
66
- // memcpy(buf.data(rt), v.data.get(), v.size);
67
- // return o;
68
- // } else {
69
- // return jsi::Value::null();
70
- // }
71
- // },
72
- // value);
19
+ inline jsi::Value to_jsi(jsi::Runtime &rt, const JSVariant &value) {
20
+ if (std::holds_alternative<bool>(value)) {
21
+ return std::get<bool>(value);
22
+ } else if (std::holds_alternative<int>(value)) {
23
+ return jsi::Value(std::get<int>(value));
24
+ } else if (std::holds_alternative<long long>(value)) {
25
+ return jsi::Value(static_cast<double>(std::get<long long>(value)));
26
+ } else if (std::holds_alternative<double>(value)) {
27
+ return jsi::Value(std::get<double>(value));
28
+ } else if (std::holds_alternative<std::string>(value)) {
29
+ auto str = std::get<std::string>(value);
30
+ return jsi::String::createFromUtf8(rt, str);
31
+ } else if (std::holds_alternative<ArrayBuffer>(value)) {
32
+ auto jsBuffer = std::get<ArrayBuffer>(value);
33
+ jsi::Function array_buffer_ctor =
34
+ rt.global().getPropertyAsFunction(rt, "ArrayBuffer");
35
+ jsi::Object o = array_buffer_ctor.callAsConstructor(rt, (int)jsBuffer.size)
36
+ .getObject(rt);
37
+ jsi::ArrayBuffer buf = o.getArrayBuffer(rt);
38
+ memcpy(buf.data(rt), jsBuffer.data.get(), jsBuffer.size);
39
+ return o;
40
+ }
41
+
42
+ return jsi::Value::null();
43
+
44
+ // I wanted to use the visitor pattern here but on the ArrayBuffer case it
45
+ // is somehow throwing a pointer exception Somehow the v.size or
46
+ // v.data.get() is loosing the data when called from the lambda I'm guessing
47
+ // the I created the shared pointer wrong and the memory is being freed
48
+ // before the lambda is called
49
+ // return std::visit(
50
+ // [&](auto &&v) -> jsi::Value {
51
+ // using T = std::decay_t<decltype(v)>;
52
+ // if constexpr (std::is_same_v<T, bool>) {
53
+ // return jsi::Value(v);
54
+ // } else if constexpr (std::is_same_v<T, int>) {
55
+ // return jsi::Value(v);
56
+ // } else if constexpr (std::is_same_v<T, long long>) {
57
+ // return jsi::Value(
58
+ // static_cast<double>(v)); // JSI doesn't support long long
59
+ // } else if constexpr (std::is_same_v<T, double>) {
60
+ // return jsi::Value(v);
61
+ // } else if constexpr (std::is_same_v<T, std::string>) {
62
+ // return jsi::String::createFromUtf8(rt, v);
63
+ // } else if constexpr (std::is_same_v<T, ArrayBuffer>) {
64
+ // static jsi::Function buffer_constructor =
65
+ // rt.global().getPropertyAsFunction(rt, "ArrayBuffer");
66
+ // jsi::Object o =
67
+ // buffer_constructor.callAsConstructor(rt,
68
+ // static_cast<int>(v.size))
69
+ // .getObject(rt);
70
+ // jsi::ArrayBuffer buf = o.getArrayBuffer(rt);
71
+ // memcpy(buf.data(rt), v.data.get(), v.size);
72
+ // return o;
73
+ // } else {
74
+ // return jsi::Value::null();
75
+ // }
76
+ // },
77
+ // value);
73
78
  }
74
79
 
75
80
  inline JSVariant to_variant(jsi::Runtime &rt, const jsi::Value &value) {
76
- if (value.isNull() || value.isUndefined()) {
77
- return JSVariant(nullptr);
78
- } else if (value.isBool()) {
79
- return JSVariant(value.getBool());
80
- } else if (value.isNumber()) {
81
- double doubleVal = value.asNumber();
82
- int intVal = (int)doubleVal;
83
- long long longVal = (long)doubleVal;
84
- if (intVal == doubleVal) {
85
- return JSVariant(intVal);
86
- } else if (longVal == doubleVal) {
87
- return JSVariant(longVal);
88
- } else {
89
- return JSVariant(doubleVal);
90
- }
91
- } else if (value.isString()) {
92
- std::string strVal = value.asString(rt).utf8(rt);
93
- return JSVariant(strVal);
94
- } else if (value.isObject()) {
95
- auto obj = value.asObject(rt);
96
-
97
- if (!obj.isArrayBuffer(rt)) {
98
- throw std::runtime_error(
99
- "Object is not an ArrayBuffer, cannot bind to SQLite");
100
- }
81
+ if (value.isNull() || value.isUndefined()) {
82
+ return JSVariant(nullptr);
83
+ } else if (value.isBool()) {
84
+ return JSVariant(value.getBool());
85
+ } else if (value.isNumber()) {
86
+ double doubleVal = value.asNumber();
87
+ int intVal = (int)doubleVal;
88
+ long long longVal = (long)doubleVal;
89
+ if (intVal == doubleVal) {
90
+ return JSVariant(intVal);
91
+ } else if (longVal == doubleVal) {
92
+ return JSVariant(longVal);
93
+ } else {
94
+ return JSVariant(doubleVal);
95
+ }
96
+ } else if (value.isString()) {
97
+ std::string strVal = value.asString(rt).utf8(rt);
98
+ return JSVariant(strVal);
99
+ } else if (value.isObject()) {
100
+ auto obj = value.asObject(rt);
101
+
102
+ if (!obj.isArrayBuffer(rt)) {
103
+ throw std::runtime_error(
104
+ "Object is not an ArrayBuffer, cannot bind to SQLite");
105
+ }
101
106
 
102
- auto buffer = obj.getArrayBuffer(rt);
103
- uint8_t *data = new uint8_t[buffer.size(rt)];
104
- memcpy(data, buffer.data(rt), buffer.size(rt));
107
+ auto buffer = obj.getArrayBuffer(rt);
108
+ uint8_t *data = new uint8_t[buffer.size(rt)];
109
+ memcpy(data, buffer.data(rt), buffer.size(rt));
105
110
 
106
- return JSVariant(ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
107
- .size = buffer.size(rt)});
108
- }
111
+ return JSVariant(ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
112
+ .size = buffer.size(rt)});
113
+ }
109
114
 
110
- throw std::runtime_error("Cannot convert JSI value to C++ Variant value");
115
+ throw std::runtime_error("Cannot convert JSI value to C++ Variant value");
111
116
  }
112
117
 
113
118
  std::vector<std::string> to_string_vec(jsi::Runtime &rt, jsi::Value const &xs) {
114
- jsi::Array values = xs.asObject(rt).asArray(rt);
115
- std::vector<std::string> res;
116
- for (int ii = 0; ii < values.length(rt); ii++) {
117
- std::string value =
118
- values.getValueAtIndex(rt, ii).asString(rt).utf8(rt);
119
- res.emplace_back(value);
120
- }
121
- return res;
119
+ jsi::Array values = xs.asObject(rt).asArray(rt);
120
+ std::vector<std::string> res;
121
+ for (int ii = 0; ii < values.length(rt); ii++) {
122
+ std::string value = values.getValueAtIndex(rt, ii).asString(rt).utf8(rt);
123
+ res.emplace_back(value);
124
+ }
125
+ return res;
122
126
  }
123
127
 
124
128
  std::vector<int> to_int_vec(jsi::Runtime &rt, jsi::Value const &xs) {
125
- jsi::Array values = xs.asObject(rt).asArray(rt);
126
- std::vector<int> res;
127
- for (int ii = 0; ii < values.length(rt); ii++) {
128
- int value = static_cast<int>(values.getValueAtIndex(rt, ii).asNumber());
129
- res.emplace_back(value);
130
- }
131
- return res;
129
+ jsi::Array values = xs.asObject(rt).asArray(rt);
130
+ std::vector<int> res;
131
+ for (int ii = 0; ii < values.length(rt); ii++) {
132
+ int value = static_cast<int>(values.getValueAtIndex(rt, ii).asNumber());
133
+ res.emplace_back(value);
134
+ }
135
+ return res;
132
136
  }
133
137
 
134
138
  std::vector<JSVariant> to_variant_vec(jsi::Runtime &rt, jsi::Value const &xs) {
135
- std::vector<JSVariant> res;
136
- jsi::Array values = xs.asObject(rt).asArray(rt);
139
+ std::vector<JSVariant> res;
140
+ jsi::Array values = xs.asObject(rt).asArray(rt);
137
141
 
138
- for (int ii = 0; ii < values.length(rt); ii++) {
139
- jsi::Value value = values.getValueAtIndex(rt, ii);
140
- res.emplace_back(to_variant(rt, value));
141
- }
142
+ for (int ii = 0; ii < values.length(rt); ii++) {
143
+ jsi::Value value = values.getValueAtIndex(rt, ii);
144
+ res.emplace_back(to_variant(rt, value));
145
+ }
142
146
 
143
- return res;
147
+ return res;
144
148
  }
145
149
 
146
150
  jsi::Value create_js_rows(jsi::Runtime &rt, const BridgeResult &status) {
147
- jsi::Object res = jsi::Object(rt);
148
-
149
- res.setProperty(rt, "rowsAffected", status.affectedRows);
150
- if (status.affectedRows > 0 && status.insertId != 0) {
151
- res.setProperty(rt, "insertId", jsi::Value(status.insertId));
152
- }
153
-
154
- size_t row_count = status.rows.size();
155
- auto rows = jsi::Array(rt, row_count);
156
-
157
- if (row_count > 0) {
158
- for (int i = 0; i < row_count; i++) {
159
- auto row = jsi::Array(rt, status.column_names.size());
160
- std::vector<JSVariant> native_row = status.rows[i];
161
- for (int j = 0; j < native_row.size(); j++) {
162
- auto value = to_jsi(rt, native_row[j]);
163
- row.setValueAtIndex(rt, j, value);
164
- }
165
- rows.setValueAtIndex(rt, i, row);
166
- }
151
+ jsi::Object res = jsi::Object(rt);
152
+
153
+ res.setProperty(rt, "rowsAffected", status.affectedRows);
154
+ if (status.affectedRows > 0 && status.insertId != 0) {
155
+ res.setProperty(rt, "insertId", jsi::Value(status.insertId));
156
+ }
157
+
158
+ size_t row_count = status.rows.size();
159
+ size_t column_count = status.column_names.size();
160
+
161
+ std::vector<jsi::PropNameID> column_prop_ids;
162
+ column_prop_ids.reserve(column_count);
163
+ for (size_t i = 0; i < column_count; i++) {
164
+ column_prop_ids.emplace_back(
165
+ jsi::PropNameID::forUtf8(rt, status.column_names[i]));
166
+ }
167
+
168
+ auto rows = jsi::Array(rt, row_count);
169
+ for (int i = 0; i < row_count; i++) {
170
+ auto row = jsi::Object(rt);
171
+ for (int j = 0; j < column_count; j++) {
172
+ row.setProperty(rt, column_prop_ids[j], to_jsi(rt, status.rows[i][j]));
167
173
  }
168
- res.setProperty(rt, "rawRows", rows);
174
+ rows.setValueAtIndex(rt, i, std::move(row));
175
+ }
176
+ res.setProperty(rt, "rows", std::move(rows));
169
177
 
170
- size_t column_count = status.column_names.size();
171
- auto column_array = jsi::Array(rt, column_count);
172
- for (int i = 0; i < column_count; i++) {
173
- auto column = status.column_names.at(i);
174
- column_array.setValueAtIndex(rt, i, to_jsi(rt, column));
175
- }
176
- res.setProperty(rt, "columnNames", std::move(column_array));
177
- return res;
178
+ return res;
178
179
  }
179
180
 
180
181
  jsi::Value
181
182
  create_result(jsi::Runtime &rt, const BridgeResult &status,
182
183
  std::vector<DumbHostObject> *results,
183
184
  std::shared_ptr<std::vector<SmartHostObject>> metadata) {
184
- jsi::Object res = jsi::Object(rt);
185
-
186
- res.setProperty(rt, "rowsAffected", status.affectedRows);
187
- if (status.affectedRows > 0 && status.insertId != 0) {
188
- res.setProperty(rt, "insertId", jsi::Value(status.insertId));
189
- }
190
-
191
- size_t rowCount = results->size();
192
-
193
- auto array = jsi::Array(rt, rowCount);
194
- for (int i = 0; i < rowCount; i++) {
195
- auto obj = results->at(i);
196
- array.setValueAtIndex(rt, i,
197
- jsi::Object::createFromHostObject(
198
- rt, std::make_shared<DumbHostObject>(obj)));
199
- }
200
- res.setProperty(rt, "rows", std::move(array));
201
-
202
- size_t column_count = metadata->size();
203
- auto column_array = jsi::Array(rt, column_count);
204
- for (int i = 0; i < column_count; i++) {
205
- auto column = metadata->at(i);
206
- column_array.setValueAtIndex(
207
- rt, i,
208
- jsi::Object::createFromHostObject(
209
- rt, std::make_shared<SmartHostObject>(column)));
210
- }
211
- res.setProperty(rt, "metadata", std::move(column_array));
212
-
213
- return std::move(res);
185
+ jsi::Object res = jsi::Object(rt);
186
+
187
+ res.setProperty(rt, "rowsAffected", status.affectedRows);
188
+ if (status.affectedRows > 0 && status.insertId != 0) {
189
+ res.setProperty(rt, "insertId", jsi::Value(status.insertId));
190
+ }
191
+
192
+ size_t rowCount = results->size();
193
+
194
+ auto array = jsi::Array(rt, rowCount);
195
+ for (int i = 0; i < rowCount; i++) {
196
+ auto obj = results->at(i);
197
+ array.setValueAtIndex(rt, i,
198
+ jsi::Object::createFromHostObject(
199
+ rt, std::make_shared<DumbHostObject>(obj)));
200
+ }
201
+ res.setProperty(rt, "rows", std::move(array));
202
+
203
+ size_t column_count = metadata->size();
204
+ auto column_array = jsi::Array(rt, column_count);
205
+ for (int i = 0; i < column_count; i++) {
206
+ auto column = metadata->at(i);
207
+ column_array.setValueAtIndex(
208
+ rt, i,
209
+ jsi::Object::createFromHostObject(
210
+ rt, std::make_shared<SmartHostObject>(column)));
211
+ }
212
+ res.setProperty(rt, "metadata", std::move(column_array));
213
+
214
+ return std::move(res);
214
215
  }
215
216
 
216
217
  jsi::Value
217
218
  create_raw_result(jsi::Runtime &rt, const BridgeResult &status,
218
219
  const std::vector<std::vector<JSVariant>> *results) {
219
- size_t row_count = results->size();
220
- jsi::Array res = jsi::Array(rt, row_count);
221
- for (int i = 0; i < row_count; i++) {
222
- auto row = results->at(i);
223
- auto array = jsi::Array(rt, row.size());
224
- for (int j = 0; j < row.size(); j++) {
225
- array.setValueAtIndex(rt, j, to_jsi(rt, row[j]));
226
- }
227
- res.setValueAtIndex(rt, i, array);
220
+ size_t row_count = results->size();
221
+ jsi::Array res = jsi::Array(rt, row_count);
222
+ for (int i = 0; i < row_count; i++) {
223
+ auto row = results->at(i);
224
+ auto array = jsi::Array(rt, row.size());
225
+ for (int j = 0; j < row.size(); j++) {
226
+ array.setValueAtIndex(rt, j, to_jsi(rt, row[j]));
228
227
  }
229
- return res;
228
+ res.setValueAtIndex(rt, i, array);
229
+ }
230
+ return res;
230
231
  }
231
232
 
232
233
  void to_batch_arguments(jsi::Runtime &rt, jsi::Array const &tuples,
233
234
  std::vector<BatchArguments> *commands) {
234
- for (int i = 0; i < tuples.length(rt); i++) {
235
- const jsi::Array &tuple =
236
- tuples.getValueAtIndex(rt, i).asObject(rt).asArray(rt);
237
- const size_t length = tuple.length(rt);
238
- if (length == 0) {
239
- continue;
240
- }
235
+ for (int i = 0; i < tuples.length(rt); i++) {
236
+ const jsi::Array &tuple =
237
+ tuples.getValueAtIndex(rt, i).asObject(rt).asArray(rt);
238
+ const size_t length = tuple.length(rt);
239
+ if (length == 0) {
240
+ continue;
241
+ }
241
242
 
242
- const std::string query =
243
- tuple.getValueAtIndex(rt, 0).asString(rt).utf8(rt);
244
- if (length == 1) {
245
- commands->push_back({query});
246
- continue;
247
- }
243
+ const std::string query =
244
+ tuple.getValueAtIndex(rt, 0).asString(rt).utf8(rt);
245
+ if (length == 1) {
246
+ commands->push_back({query});
247
+ continue;
248
+ }
248
249
 
249
- const jsi::Value &tuple_params = tuple.getValueAtIndex(rt, 1);
250
-
251
- if (!tuple_params.isUndefined() &&
252
- tuple_params.asObject(rt).isArray(rt) &&
253
- tuple_params.asObject(rt).asArray(rt).length(rt) > 0 &&
254
- tuple_params.asObject(rt)
255
- .asArray(rt)
256
- .getValueAtIndex(rt, 0)
257
- .isObject()) {
258
- // The params for this tuple is an array itself
259
- // The query should repeat for each element in the array
260
- const jsi::Array &params_array =
261
- tuple_params.asObject(rt).asArray(rt);
262
- for (int x = 0; x < params_array.length(rt); x++) {
263
- const jsi::Value &p = params_array.getValueAtIndex(rt, x);
264
- auto params = std::vector<JSVariant>(to_variant_vec(rt, p));
265
- commands->push_back({query, params});
266
- }
267
- } else {
268
- auto params =
269
- std::vector<JSVariant>(to_variant_vec(rt, tuple_params));
270
- commands->push_back({query, params});
271
- }
250
+ const jsi::Value &tuple_params = tuple.getValueAtIndex(rt, 1);
251
+
252
+ if (!tuple_params.isUndefined() && tuple_params.asObject(rt).isArray(rt) &&
253
+ tuple_params.asObject(rt).asArray(rt).length(rt) > 0 &&
254
+ tuple_params.asObject(rt)
255
+ .asArray(rt)
256
+ .getValueAtIndex(rt, 0)
257
+ .isObject()) {
258
+ // The params for this tuple is an array itself
259
+ // The query should repeat for each element in the array
260
+ const jsi::Array &params_array = tuple_params.asObject(rt).asArray(rt);
261
+ for (int x = 0; x < params_array.length(rt); x++) {
262
+ const jsi::Value &p = params_array.getValueAtIndex(rt, x);
263
+ auto params = std::vector<JSVariant>(to_variant_vec(rt, p));
264
+ commands->push_back({query, params});
265
+ }
266
+ } else {
267
+ auto params = std::vector<JSVariant>(to_variant_vec(rt, tuple_params));
268
+ commands->push_back({query, params});
272
269
  }
270
+ }
273
271
  }
274
272
 
275
273
  #ifndef OP_SQLITE_USE_LIBSQL
276
274
  BatchResult import_sql_file(sqlite3 *db, std::string path) {
277
- std::string line;
278
- std::ifstream sqFile(path);
279
- if (!sqFile.is_open()) {
280
- throw std::runtime_error("Could not open file: " + path);
281
- }
282
-
283
- try {
284
- int affectedRows = 0;
285
- int commands = 0;
286
- opsqlite_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
287
- while (std::getline(sqFile, line, '\n')) {
288
- if (!line.empty()) {
289
- try {
290
- auto result = opsqlite_execute(db, line, nullptr);
291
- affectedRows += result.affectedRows;
292
- commands++;
293
- } catch (std::exception &exc) {
294
- opsqlite_execute(db, "ROLLBACK", nullptr);
295
- sqFile.close();
296
- throw exc;
297
- }
298
- }
275
+ std::string line;
276
+ std::ifstream sqFile(path);
277
+ if (!sqFile.is_open()) {
278
+ throw std::runtime_error("Could not open file: " + path);
279
+ }
280
+
281
+ try {
282
+ int affectedRows = 0;
283
+ int commands = 0;
284
+ opsqlite_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
285
+ while (std::getline(sqFile, line, '\n')) {
286
+ if (!line.empty()) {
287
+ try {
288
+ auto result = opsqlite_execute(db, line, nullptr);
289
+ affectedRows += result.affectedRows;
290
+ commands++;
291
+ } catch (std::exception &exc) {
292
+ opsqlite_execute(db, "ROLLBACK", nullptr);
293
+ sqFile.close();
294
+ throw exc;
299
295
  }
300
- sqFile.close();
301
- opsqlite_execute(db, "COMMIT", nullptr);
302
- return {"", affectedRows, commands};
303
- } catch (std::exception &exc) {
304
- sqFile.close();
305
- opsqlite_execute(db, "ROLLBACK", nullptr);
306
- throw exc;
296
+ }
307
297
  }
298
+ sqFile.close();
299
+ opsqlite_execute(db, "COMMIT", nullptr);
300
+ return {"", affectedRows, commands};
301
+ } catch (std::exception &exc) {
302
+ sqFile.close();
303
+ opsqlite_execute(db, "ROLLBACK", nullptr);
304
+ throw exc;
305
+ }
308
306
  }
309
307
  #endif
310
308
 
311
309
  bool folder_exists(const std::string &name) {
312
- struct stat buffer;
313
- return (stat(name.c_str(), &buffer) == 0);
310
+ struct stat buffer;
311
+ return (stat(name.c_str(), &buffer) == 0);
314
312
  }
315
313
 
316
314
  bool file_exists(const std::string &path) {
317
- struct stat buffer;
318
- return (stat(path.c_str(), &buffer) == 0);
315
+ struct stat buffer;
316
+ return (stat(path.c_str(), &buffer) == 0);
319
317
  }
320
318
 
321
319
  void log_to_console(jsi::Runtime &runtime, const std::string &message) {
322
- auto console = runtime.global().getPropertyAsObject(runtime, "console");
323
- auto log = console.getPropertyAsFunction(runtime, "log");
324
- log.call(runtime, jsi::String::createFromUtf8(runtime, message));
320
+ auto console = runtime.global().getPropertyAsObject(runtime, "console");
321
+ auto log = console.getPropertyAsFunction(runtime, "log");
322
+ log.call(runtime, jsi::String::createFromUtf8(runtime, message));
323
+ }
324
+
325
+ inline jsi::Function host_fn(jsi::Runtime &rt, jsi::HostFunctionType lambda) {
326
+ return jsi::Function::createFromHostFunction(
327
+ rt, jsi::PropNameID::forAscii(rt, ""), 0, std::move(lambda));
328
+ };
329
+
330
+ jsi::Value
331
+ promisify(jsi::Runtime &rt, std::function<std::any()> lambda,
332
+ std::function<jsi::Value(jsi::Runtime &rt, std::any result)>
333
+ resolve_callback) {
334
+ auto promise_constructor = rt.global().getPropertyAsFunction(rt, "Promise");
335
+
336
+ auto executor = host_fn(rt, [lambda = std::move(lambda),
337
+ resolve_callback = std::move(resolve_callback)](
338
+ jsi::Runtime &rt, const jsi::Value &thiz,
339
+ const jsi::Value *args, size_t count) {
340
+ auto resolve = std::make_shared<jsi::Value>(rt, args[0]);
341
+ auto reject = std::make_shared<jsi::Value>(rt, args[1]);
342
+
343
+ auto task = [lambda = lambda, resolve_callback = resolve_callback,
344
+ resolve = std::move(resolve), reject = std::move(reject)]() {
345
+ try {
346
+ std::any result = lambda();
347
+
348
+ if (opsqlite::invalidated) {
349
+ return;
350
+ }
351
+
352
+ opsqlite::invoker->invokeAsync(
353
+ [result = std::move(result), resolve = resolve,
354
+ resolve_callback = resolve_callback](jsi::Runtime &rt) {
355
+ auto jsi_result = resolve_callback(rt, result);
356
+ resolve->asObject(rt).asFunction(rt).call(rt, jsi_result);
357
+ });
358
+ } catch (std::runtime_error &e) {
359
+ // On Android RN is broken and does not correctly match
360
+ // runtime_error to the generic exception We have to
361
+ // explicitly catch it
362
+ // https://github.com/facebook/react-native/issues/48027
363
+ auto what = e.what();
364
+ opsqlite::invoker->invokeAsync(
365
+ [what = std::string(what), reject = reject](jsi::Runtime &rt) {
366
+ auto errorCtr = rt.global().getPropertyAsFunction(rt, "Error");
367
+ auto error = errorCtr.callAsConstructor(
368
+ rt, jsi::String::createFromAscii(rt, what));
369
+ reject->asObject(rt).asFunction(rt).call(rt, error);
370
+ });
371
+ } catch (std::exception &exc) {
372
+ auto what = exc.what();
373
+ opsqlite::invoker->invokeAsync(
374
+ [what = std::string(what), reject = reject](jsi::Runtime &rt) {
375
+ auto errorCtr = rt.global().getPropertyAsFunction(rt, "Error");
376
+ auto error = errorCtr.callAsConstructor(
377
+ rt, jsi::String::createFromAscii(rt, what));
378
+ reject->asObject(rt).asFunction(rt).call(rt, error);
379
+ });
380
+ }
381
+ };
382
+
383
+ __thread_pool->queueWork(task);
384
+
385
+ return jsi::Value(nullptr);
386
+ });
387
+
388
+ auto promise = promise_constructor.callAsConstructor(rt, executor);
389
+ return promise;
325
390
  }
326
391
 
327
392
  } // namespace opsqlite