@op-engineering/op-sqlite 0.0.0-resolution-test

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 (99) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +31 -0
  3. package/android/.project +17 -0
  4. package/android/.settings/org.eclipse.buildship.core.prefs +13 -0
  5. package/android/CMakeLists.txt +141 -0
  6. package/android/build.gradle +266 -0
  7. package/android/c_sources/tokenizers.cpp +88 -0
  8. package/android/c_sources/tokenizers.h +15 -0
  9. package/android/cpp-adapter.cpp +46 -0
  10. package/android/gradle.properties +1 -0
  11. package/android/jniLibs/arm64-v8a/libsql_experimental.a +0 -0
  12. package/android/jniLibs/armeabi-v7a/libsql_experimental.a +0 -0
  13. package/android/jniLibs/x86/libsql_experimental.a +0 -0
  14. package/android/jniLibs/x86_64/libsql_experimental.a +0 -0
  15. package/android/src/main/AndroidManifest.xml +1 -0
  16. package/android/src/main/java/com/op/sqlite/OPSQLiteBridge.kt +37 -0
  17. package/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt +119 -0
  18. package/android/src/main/java/com/op/sqlite/OPSQLitePackage.kt +18 -0
  19. package/android/src/main/jniLibs/arm64-v8a/libcrsqlite.so +0 -0
  20. package/android/src/main/jniLibs/arm64-v8a/libsqlite_vec.so +0 -0
  21. package/android/src/main/jniLibs/armeabi-v7a/libcrsqlite.so +0 -0
  22. package/android/src/main/jniLibs/armeabi-v7a/libsqlite_vec.so +0 -0
  23. package/android/src/main/jniLibs/x86/libcrsqlite.so +0 -0
  24. package/android/src/main/jniLibs/x86/libsqlite_vec.so +0 -0
  25. package/android/src/main/jniLibs/x86_64/libcrsqlite.so +0 -0
  26. package/android/src/main/jniLibs/x86_64/libsqlite_vec.so +0 -0
  27. package/android/src/paper/java/com/op/sqlite/NativeOPSQLiteSpec.java +77 -0
  28. package/cpp/DBHostObject.cpp +852 -0
  29. package/cpp/DBHostObject.h +99 -0
  30. package/cpp/DumbHostObject.cpp +72 -0
  31. package/cpp/DumbHostObject.h +36 -0
  32. package/cpp/OPThreadPool.cpp +120 -0
  33. package/cpp/OPThreadPool.h +44 -0
  34. package/cpp/PreparedStatementHostObject.cpp +151 -0
  35. package/cpp/PreparedStatementHostObject.h +59 -0
  36. package/cpp/SmartHostObject.cpp +34 -0
  37. package/cpp/SmartHostObject.h +24 -0
  38. package/cpp/bindings.cpp +182 -0
  39. package/cpp/bindings.h +19 -0
  40. package/cpp/bridge.cpp +873 -0
  41. package/cpp/bridge.h +80 -0
  42. package/cpp/libsql/bridge.cpp +738 -0
  43. package/cpp/libsql/bridge.h +85 -0
  44. package/cpp/libsql/libsql.h +172 -0
  45. package/cpp/logs.h +40 -0
  46. package/cpp/macros.h +15 -0
  47. package/cpp/sqlcipher/sqlite3.c +262970 -0
  48. package/cpp/sqlcipher/sqlite3.h +13485 -0
  49. package/cpp/sqlite3.c +261454 -0
  50. package/cpp/sqlite3.h +13715 -0
  51. package/cpp/types.h +33 -0
  52. package/cpp/utils.cpp +327 -0
  53. package/cpp/utils.h +47 -0
  54. package/generate_tokenizers_header_file.rb +29 -0
  55. package/ios/OPSQLite.h +7 -0
  56. package/ios/OPSQLite.mm +157 -0
  57. package/ios/OPSQLite.xcodeproj/project.pbxproj +275 -0
  58. package/ios/crsqlite.xcframework/Info.plist +46 -0
  59. package/ios/crsqlite.xcframework/ios-arm64/crsqlite.framework/Info.plist +24 -0
  60. package/ios/crsqlite.xcframework/ios-arm64/crsqlite.framework/crsqlite +0 -0
  61. package/ios/crsqlite.xcframework/ios-arm64_x86_64-simulator/crsqlite.framework/Info.plist +24 -0
  62. package/ios/crsqlite.xcframework/ios-arm64_x86_64-simulator/crsqlite.framework/crsqlite +0 -0
  63. package/ios/libsql.xcframework/Info.plist +48 -0
  64. package/ios/libsql.xcframework/ios-arm64/Headers/libsql.h +172 -0
  65. package/ios/libsql.xcframework/ios-arm64/libsql_experimental.a +0 -0
  66. package/ios/libsql.xcframework/ios-arm64_x86_64-simulator/Headers/libsql.h +172 -0
  67. package/ios/libsql.xcframework/ios-arm64_x86_64-simulator/libsql_experimental.a +0 -0
  68. package/ios/sqlitevec.xcframework/Info.plist +71 -0
  69. package/ios/sqlitevec.xcframework/ios-arm64/sqlitevec.framework/Info.plist +24 -0
  70. package/ios/sqlitevec.xcframework/ios-arm64/sqlitevec.framework/sqlitevec +0 -0
  71. package/ios/sqlitevec.xcframework/ios-arm64_x86_64-simulator/sqlitevec.framework/Info.plist +24 -0
  72. package/ios/sqlitevec.xcframework/ios-arm64_x86_64-simulator/sqlitevec.framework/sqlitevec +0 -0
  73. package/ios/sqlitevec.xcframework/tvos-arm64/sqlitevec.framework/Info.plist +24 -0
  74. package/ios/sqlitevec.xcframework/tvos-arm64/sqlitevec.framework/sqlitevec +0 -0
  75. package/ios/sqlitevec.xcframework/tvos-arm64_x86_64-simulator/sqlitevec.framework/Info.plist +24 -0
  76. package/ios/sqlitevec.xcframework/tvos-arm64_x86_64-simulator/sqlitevec.framework/sqlitevec +0 -0
  77. package/lib/commonjs/NativeOPSQLite.js +9 -0
  78. package/lib/commonjs/NativeOPSQLite.js.map +1 -0
  79. package/lib/commonjs/Storage.js +60 -0
  80. package/lib/commonjs/Storage.js.map +1 -0
  81. package/lib/commonjs/index.js +365 -0
  82. package/lib/commonjs/index.js.map +1 -0
  83. package/lib/module/NativeOPSQLite.js +3 -0
  84. package/lib/module/NativeOPSQLite.js.map +1 -0
  85. package/lib/module/Storage.js +53 -0
  86. package/lib/module/Storage.js.map +1 -0
  87. package/lib/module/index.js +340 -0
  88. package/lib/module/index.js.map +1 -0
  89. package/lib/typescript/src/NativeOPSQLite.d.ts +15 -0
  90. package/lib/typescript/src/NativeOPSQLite.d.ts.map +1 -0
  91. package/lib/typescript/src/Storage.d.ts +23 -0
  92. package/lib/typescript/src/Storage.d.ts.map +1 -0
  93. package/lib/typescript/src/index.d.ts +319 -0
  94. package/lib/typescript/src/index.d.ts.map +1 -0
  95. package/op-sqlite.podspec +212 -0
  96. package/package.json +85 -0
  97. package/src/NativeOPSQLite.ts +17 -0
  98. package/src/Storage.ts +85 -0
  99. package/src/index.ts +722 -0
@@ -0,0 +1,738 @@
1
+ #include "bridge.h"
2
+ #include "DumbHostObject.h"
3
+ #include "SmartHostObject.h"
4
+ #include "logs.h"
5
+ #include "utils.h"
6
+ #include <filesystem>
7
+ #include <iostream>
8
+ #include <unordered_map>
9
+ #include <variant>
10
+
11
+ namespace opsqlite {
12
+
13
+ // _____ _____
14
+ // /\ | __ \_ _|
15
+ // / \ | |__) || |
16
+ // / /\ \ | ___/ | |
17
+ // / ____ \| | _| |_
18
+ // /_/ \_\_| |_____|
19
+
20
+ /// Returns the completely formed db path, but it also creates any sub-folders
21
+ /// along the way
22
+ std::string opsqlite_get_db_path(std::string const &db_name,
23
+ std::string const &location) {
24
+
25
+ if (location == ":memory:") {
26
+ return location;
27
+ }
28
+
29
+ // Will return false if the directory already exists, no need to check
30
+ std::filesystem::create_directories(location);
31
+
32
+ if (!location.empty() && location.back() != '/') {
33
+ return location + "/" + db_name;
34
+ }
35
+
36
+ return location + db_name;
37
+ }
38
+
39
+ DB opsqlite_libsql_open_sync(std::string const &name,
40
+ std::string const &base_path,
41
+ std::string const &url,
42
+ std::string const &auth_token, int sync_interval) {
43
+ std::string path = opsqlite_get_db_path(name, base_path);
44
+
45
+ int status;
46
+ libsql_database_t db;
47
+ libsql_connection_t c;
48
+ const char *err = nullptr;
49
+
50
+ libsql_config config = {.db_path = path.c_str(),
51
+ .primary_url = url.c_str(),
52
+ .auth_token = auth_token.c_str(),
53
+ .read_your_writes = '1',
54
+ .encryption_key = nullptr,
55
+ .sync_interval = sync_interval,
56
+ .with_webpki = '1'};
57
+ status = libsql_open_sync_with_config(config, &db, &err);
58
+ if (status != 0) {
59
+ throw std::runtime_error(err);
60
+ }
61
+
62
+ status = libsql_connect(db, &c, &err);
63
+
64
+ if (status != 0) {
65
+ throw std::runtime_error(err);
66
+ }
67
+
68
+ return {.db = db, .c = c};
69
+ }
70
+
71
+ DB opsqlite_libsql_open(std::string const &name, std::string const &last_path,
72
+ std::string const &crsqlitePath) {
73
+ std::string path = opsqlite_get_db_path(name, last_path);
74
+
75
+ int status;
76
+ libsql_database_t db;
77
+ libsql_connection_t c;
78
+ const char *err = nullptr;
79
+
80
+ status = libsql_open_file(path.c_str(), &db, &err);
81
+
82
+ if (status != 0) {
83
+ throw std::runtime_error(err);
84
+ }
85
+
86
+ status = libsql_connect(db, &c, &err);
87
+
88
+ if (status != 0) {
89
+ throw std::runtime_error(err);
90
+ }
91
+
92
+ #ifdef OP_SQLITE_USE_CRSQLITE
93
+ const char *errMsg;
94
+ const char *crsqliteEntryPoint = "sqlite3_crsqlite_init";
95
+
96
+ status = libsql_load_extension(c, crsqlitePath.c_str(), crsqliteEntryPoint,
97
+ &errMsg);
98
+
99
+ if (status != 0) {
100
+ return {.type = SQLiteError, .message = errMsg};
101
+ } else {
102
+ LOGI("Loaded CRSQlite successfully");
103
+ }
104
+ #endif
105
+
106
+ return {.db = db, .c = c};
107
+ }
108
+
109
+ DB opsqlite_libsql_open_remote(std::string const &url,
110
+ std::string const &auth_token) {
111
+ int status;
112
+ libsql_database_t db;
113
+ libsql_connection_t c;
114
+ const char *err = nullptr;
115
+
116
+ status = libsql_open_remote_with_webpki(url.c_str(), auth_token.c_str(),
117
+ &db, &err);
118
+
119
+ if (status != 0) {
120
+ throw std::runtime_error(err);
121
+ }
122
+
123
+ status = libsql_connect(db, &c, &err);
124
+
125
+ if (status != 0) {
126
+ throw std::runtime_error(err);
127
+ }
128
+
129
+ return {.db = db, .c = c};
130
+ }
131
+
132
+ void opsqlite_libsql_close(DB &db) {
133
+ if (db.c != nullptr) {
134
+ libsql_disconnect(db.c);
135
+ db.c = nullptr;
136
+ }
137
+ if (db.db != nullptr) {
138
+ libsql_close(db.db);
139
+ db.db = nullptr;
140
+ }
141
+ }
142
+
143
+ void opsqlite_libsql_attach(DB const &db, std::string const &docPath,
144
+ std::string const &databaseToAttach,
145
+ std::string const &alias) {
146
+ std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath);
147
+ std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
148
+
149
+ opsqlite_libsql_execute(db, statement, nullptr);
150
+ }
151
+
152
+ void opsqlite_libsql_detach(DB const &db, std::string const &alias) {
153
+ std::string statement = "DETACH DATABASE " + alias;
154
+ opsqlite_libsql_execute(db, statement, nullptr);
155
+ }
156
+
157
+ void opsqlite_libsql_sync(DB const &db) {
158
+ const char *err = nullptr;
159
+
160
+ int status = libsql_sync(db.db, &err);
161
+
162
+ if (status != 0) {
163
+ throw std::runtime_error(err);
164
+ }
165
+ }
166
+
167
+ void opsqlite_libsql_remove(DB &db, std::string const &name,
168
+ std::string const &path) {
169
+ opsqlite_libsql_close(db);
170
+
171
+ std::string full_path = opsqlite_get_db_path(name, path);
172
+
173
+ if (!file_exists(full_path)) {
174
+ throw std::runtime_error("[op-sqlite]: Database file not found" +
175
+ full_path);
176
+ }
177
+
178
+ remove(full_path.c_str());
179
+ }
180
+
181
+ void opsqlite_libsql_bind_statement(libsql_stmt_t statement,
182
+ const std::vector<JSVariant> *values) {
183
+ const char *err;
184
+ size_t size = values->size();
185
+
186
+ for (int ii = 0; ii < size; ii++) {
187
+ int index = ii + 1;
188
+ JSVariant value = values->at(ii);
189
+ int status;
190
+
191
+ if (std::holds_alternative<bool>(value)) {
192
+ status =
193
+ libsql_bind_int(statement, index,
194
+ static_cast<int>(std::get<bool>(value)), &err);
195
+ } else if (std::holds_alternative<int>(value)) {
196
+ status =
197
+ libsql_bind_int(statement, index, std::get<int>(value), &err);
198
+ } else if (std::holds_alternative<long long>(value)) {
199
+ status = libsql_bind_int(statement, index,
200
+ std::get<long long>(value), &err);
201
+ } else if (std::holds_alternative<double>(value)) {
202
+ status = libsql_bind_float(statement, index,
203
+ std::get<double>(value), &err);
204
+ } else if (std::holds_alternative<std::string>(value)) {
205
+ std::string str = std::get<std::string>(value);
206
+ status = libsql_bind_string(statement, index, str.c_str(), &err);
207
+ } else if (std::holds_alternative<ArrayBuffer>(value)) {
208
+ ArrayBuffer buffer = std::get<ArrayBuffer>(value);
209
+ status = libsql_bind_blob(statement, index, buffer.data.get(),
210
+ static_cast<int>(buffer.size), &err);
211
+ } else {
212
+ status = libsql_bind_null(statement, index, &err);
213
+ }
214
+
215
+ if (status != 0) {
216
+ throw std::runtime_error(err);
217
+ }
218
+ }
219
+ }
220
+
221
+ BridgeResult opsqlite_libsql_execute_prepared_statement(
222
+ DB const &db, libsql_stmt_t stmt, std::vector<DumbHostObject> *results,
223
+ const std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
224
+
225
+ libsql_rows_t rows;
226
+ libsql_row_t row;
227
+
228
+ int status;
229
+ const char *err = nullptr;
230
+
231
+ status = libsql_query_stmt(stmt, &rows, &err);
232
+
233
+ if (status != 0) {
234
+ throw std::runtime_error(err);
235
+ }
236
+
237
+ bool metadata_set = false;
238
+
239
+ int num_cols = libsql_column_count(rows);
240
+ while ((status = libsql_next_row(rows, &row, &err)) == 0) {
241
+
242
+ if (!err && !row) {
243
+ break;
244
+ }
245
+
246
+ DumbHostObject row_host_object = DumbHostObject(metadatas);
247
+
248
+ for (int col = 0; col < num_cols; col++) {
249
+ int type;
250
+
251
+ libsql_column_type(rows, row, col, &type, &err);
252
+
253
+ switch (type) {
254
+ case LIBSQL_INT:
255
+ long long int_value;
256
+ status = libsql_get_int(row, col, &int_value, &err);
257
+ row_host_object.values.emplace_back(int_value);
258
+ break;
259
+
260
+ case LIBSQL_FLOAT:
261
+ double float_value;
262
+ status = libsql_get_float(row, col, &float_value, &err);
263
+ row_host_object.values.emplace_back(float_value);
264
+ break;
265
+
266
+ case LIBSQL_TEXT:
267
+ const char *text_value;
268
+ status = libsql_get_string(row, col, &text_value, &err);
269
+ row_host_object.values.emplace_back(text_value);
270
+ break;
271
+
272
+ case LIBSQL_BLOB: {
273
+ blob value_blob;
274
+ libsql_get_blob(row, col, &value_blob, &err);
275
+ auto *data = new uint8_t[value_blob.len];
276
+ // You cannot share raw memory between native and JS
277
+ // always copy the data
278
+ memcpy(data, value_blob.ptr, value_blob.len);
279
+ libsql_free_blob(value_blob);
280
+ row_host_object.values.emplace_back(
281
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
282
+ .size = static_cast<size_t>(value_blob.len)});
283
+ break;
284
+ }
285
+
286
+ case LIBSQL_NULL:
287
+ // intentional fall-through
288
+ default:
289
+ row_host_object.values.emplace_back(nullptr);
290
+ break;
291
+ }
292
+
293
+ if (status != 0) {
294
+ fprintf(stderr, "%s\n", err);
295
+ throw std::runtime_error("libsql error");
296
+ }
297
+
298
+ // On the first interation through the columns, set the metadata
299
+ if (!metadata_set && metadatas != nullptr) {
300
+ const char *col_name;
301
+ status = libsql_column_name(rows, col, &col_name, &err);
302
+
303
+ auto metadata = SmartHostObject();
304
+ metadata.fields.emplace_back("name", col_name);
305
+ metadata.fields.emplace_back("index", col);
306
+ metadata.fields.emplace_back("type", "UNKNOWN");
307
+ // metadata.fields.push_back(
308
+ // std::make_pair("type", type == -1 ?
309
+ // "UNKNOWN" : type));
310
+
311
+ metadatas->push_back(metadata);
312
+ }
313
+ }
314
+
315
+ if (results != nullptr) {
316
+ results->push_back(row_host_object);
317
+ }
318
+
319
+ metadata_set = true;
320
+ err = nullptr;
321
+ }
322
+
323
+ if (status != 0) {
324
+ fprintf(stderr, "%s\n", err);
325
+ }
326
+
327
+ libsql_free_rows(rows);
328
+
329
+ unsigned long long changes = libsql_changes(db.c);
330
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
331
+
332
+ libsql_reset_stmt(stmt, &err);
333
+
334
+ return {.affectedRows = static_cast<int>(changes),
335
+ .insertId = static_cast<double>(insert_row_id)};
336
+ }
337
+
338
+ libsql_stmt_t opsqlite_libsql_prepare_statement(DB const &db,
339
+ std::string const &query) {
340
+ libsql_stmt_t stmt;
341
+
342
+ const char *err;
343
+
344
+ int status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
345
+
346
+ if (status != 0) {
347
+ throw std::runtime_error(err);
348
+ }
349
+
350
+ return stmt;
351
+ }
352
+
353
+ BridgeResult opsqlite_libsql_execute(DB const &db, std::string const &query,
354
+ const std::vector<JSVariant> *params) {
355
+
356
+ std::vector<std::string> column_names;
357
+ std::vector<std::vector<JSVariant>> out_rows;
358
+ std::vector<JSVariant> out_row;
359
+ libsql_rows_t rows;
360
+ libsql_row_t row;
361
+ libsql_stmt_t stmt;
362
+ int status;
363
+ const char *err = nullptr;
364
+
365
+ status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
366
+
367
+ if (status != 0) {
368
+ throw std::runtime_error(err);
369
+ }
370
+
371
+ if (params != nullptr && !params->empty()) {
372
+ opsqlite_libsql_bind_statement(stmt, params);
373
+ }
374
+
375
+ status = libsql_query_stmt(stmt, &rows, &err);
376
+
377
+ if (status != 0) {
378
+ throw std::runtime_error(err);
379
+ }
380
+
381
+ // Get the column names on the first pass
382
+ int column_count = libsql_column_count(rows);
383
+ const char *col_name;
384
+
385
+ for (int i = 0; i < column_count; i++) {
386
+ status = libsql_column_name(rows, i, &col_name, &err);
387
+ if (status != 0) {
388
+ throw std::runtime_error(err);
389
+ }
390
+ column_names.emplace_back(col_name);
391
+ }
392
+
393
+ long long int_value;
394
+ double float_value;
395
+ const char *text_value;
396
+ blob blob_value;
397
+
398
+ status = libsql_next_row(rows, &row, &err);
399
+ while (status == 0) {
400
+ out_row = std::vector<JSVariant>();
401
+
402
+ if (!err && !row) {
403
+ break;
404
+ }
405
+
406
+ for (int col = 0; col < column_count; col++) {
407
+ int type;
408
+
409
+ libsql_column_type(rows, row, col, &type, &err);
410
+
411
+ switch (type) {
412
+ case LIBSQL_INT:
413
+ status = libsql_get_int(row, col, &int_value, &err);
414
+ out_row.emplace_back(int_value);
415
+ break;
416
+
417
+ case LIBSQL_FLOAT:
418
+ status = libsql_get_float(row, col, &float_value, &err);
419
+ out_row.emplace_back(float_value);
420
+ break;
421
+
422
+ case LIBSQL_TEXT:
423
+ status = libsql_get_string(row, col, &text_value, &err);
424
+ out_row.emplace_back(text_value);
425
+ break;
426
+
427
+ case LIBSQL_BLOB: {
428
+ libsql_get_blob(row, col, &blob_value, &err);
429
+ auto data = new uint8_t[blob_value.len];
430
+ // You cannot share raw memory between native and JS
431
+ // always copy the data
432
+ memcpy(data, blob_value.ptr, blob_value.len);
433
+ libsql_free_blob(blob_value);
434
+ out_row.emplace_back(
435
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
436
+ .size = static_cast<size_t>(blob_value.len)});
437
+ break;
438
+ }
439
+
440
+ case LIBSQL_NULL:
441
+ // intentional fall-through
442
+ default:
443
+ out_row.emplace_back(nullptr);
444
+ break;
445
+ }
446
+
447
+ if (status != 0) {
448
+ throw std::runtime_error(err);
449
+ }
450
+ }
451
+
452
+ out_rows.emplace_back(out_row);
453
+ err = nullptr;
454
+ status = libsql_next_row(rows, &row, &err);
455
+ }
456
+
457
+ libsql_free_rows(rows);
458
+ libsql_free_stmt(stmt);
459
+
460
+ unsigned long long changes = libsql_changes(db.c);
461
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
462
+
463
+ return {.affectedRows = static_cast<int>(changes),
464
+ .insertId = static_cast<double>(insert_row_id),
465
+ .rows = std::move(out_rows),
466
+ .column_names = std::move(column_names)};
467
+ }
468
+
469
+ BridgeResult opsqlite_libsql_execute_with_host_objects(
470
+ DB const &db, std::string const &query,
471
+ const std::vector<JSVariant> *params, std::vector<DumbHostObject> *results,
472
+ const std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
473
+
474
+ libsql_rows_t rows;
475
+ libsql_row_t row;
476
+ libsql_stmt_t stmt;
477
+ int status;
478
+ const char *err = nullptr;
479
+
480
+ status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
481
+
482
+ if (status != 0) {
483
+ throw std::runtime_error(err);
484
+ }
485
+
486
+ if (params != nullptr && !params->empty()) {
487
+ opsqlite_libsql_bind_statement(stmt, params);
488
+ }
489
+
490
+ status = libsql_query_stmt(stmt, &rows, &err);
491
+
492
+ if (status != 0) {
493
+ throw std::runtime_error(err);
494
+ }
495
+
496
+ bool metadata_set = false;
497
+
498
+ int num_cols = libsql_column_count(rows);
499
+ while ((status = libsql_next_row(rows, &row, &err)) == 0) {
500
+
501
+ if (!err && !row) {
502
+ break;
503
+ }
504
+
505
+ DumbHostObject row_host_object = DumbHostObject(metadatas);
506
+
507
+ for (int col = 0; col < num_cols; col++) {
508
+ int type;
509
+
510
+ libsql_column_type(rows, row, col, &type, &err);
511
+
512
+ switch (type) {
513
+ case LIBSQL_INT:
514
+ long long int_value;
515
+ status = libsql_get_int(row, col, &int_value, &err);
516
+ row_host_object.values.emplace_back(int_value);
517
+ break;
518
+
519
+ case LIBSQL_FLOAT:
520
+ double float_value;
521
+ status = libsql_get_float(row, col, &float_value, &err);
522
+ row_host_object.values.emplace_back(float_value);
523
+ break;
524
+
525
+ case LIBSQL_TEXT:
526
+ const char *text_value;
527
+ status = libsql_get_string(row, col, &text_value, &err);
528
+ row_host_object.values.emplace_back(text_value);
529
+ break;
530
+
531
+ case LIBSQL_BLOB: {
532
+ blob value_blob;
533
+ libsql_get_blob(row, col, &value_blob, &err);
534
+ auto *data = new uint8_t[value_blob.len];
535
+ // You cannot share raw memory between native and JS
536
+ // always copy the data
537
+ memcpy(data, value_blob.ptr, value_blob.len);
538
+ libsql_free_blob(value_blob);
539
+ row_host_object.values.emplace_back(
540
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
541
+ .size = static_cast<size_t>(value_blob.len)});
542
+ break;
543
+ }
544
+
545
+ case LIBSQL_NULL:
546
+ // intentional fall-through
547
+ default:
548
+ row_host_object.values.emplace_back(nullptr);
549
+ break;
550
+ }
551
+
552
+ if (status != 0) {
553
+ fprintf(stderr, "%s\n", err);
554
+ throw std::runtime_error(err);
555
+ }
556
+
557
+ // On the first interation through the columns, set the metadata
558
+ if (!metadata_set && metadatas != nullptr) {
559
+ const char *col_name;
560
+ status = libsql_column_name(rows, col, &col_name, &err);
561
+
562
+ auto metadata = SmartHostObject();
563
+ metadata.fields.emplace_back("name", col_name);
564
+ metadata.fields.emplace_back("index", col);
565
+ metadata.fields.emplace_back("type", "UNKNOWN");
566
+ // metadata.fields.push_back(
567
+ // std::make_pair("type", type == -1 ?
568
+ // "UNKNOWN" : type));
569
+
570
+ metadatas->push_back(metadata);
571
+ }
572
+ }
573
+
574
+ if (results != nullptr) {
575
+ results->push_back(row_host_object);
576
+ }
577
+
578
+ metadata_set = true;
579
+ err = nullptr;
580
+ }
581
+
582
+ if (status != 0) {
583
+ fprintf(stderr, "%s\n", err);
584
+ }
585
+
586
+ libsql_free_rows(rows);
587
+ libsql_free_stmt(stmt);
588
+
589
+ unsigned long long changes = libsql_changes(db.c);
590
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
591
+
592
+ return {.affectedRows = static_cast<int>(changes),
593
+ .insertId = static_cast<double>(insert_row_id)};
594
+ }
595
+
596
+ /// Executes returning data in raw arrays, a small performance optimization
597
+ /// for certain use cases
598
+ BridgeResult
599
+ opsqlite_libsql_execute_raw(DB const &db, std::string const &query,
600
+ const std::vector<JSVariant> *params,
601
+ std::vector<std::vector<JSVariant>> *results) {
602
+
603
+ libsql_rows_t rows;
604
+ libsql_row_t row;
605
+ libsql_stmt_t stmt;
606
+ int status;
607
+ const char *err = nullptr;
608
+
609
+ status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
610
+
611
+ if (status != 0) {
612
+ throw std::runtime_error(err);
613
+ }
614
+
615
+ if (params != nullptr && !params->empty()) {
616
+ opsqlite_libsql_bind_statement(stmt, params);
617
+ }
618
+
619
+ status = libsql_query_stmt(stmt, &rows, &err);
620
+
621
+ if (status != 0) {
622
+ throw std::runtime_error(err);
623
+ }
624
+
625
+ int num_cols = libsql_column_count(rows);
626
+ while ((status = libsql_next_row(rows, &row, &err)) == 0) {
627
+
628
+ if (!err && !row) {
629
+ break;
630
+ }
631
+
632
+ std::vector<JSVariant> row_vector;
633
+
634
+ for (int col = 0; col < num_cols; col++) {
635
+ int type;
636
+
637
+ libsql_column_type(rows, row, col, &type, &err);
638
+
639
+ switch (type) {
640
+ case LIBSQL_INT:
641
+ long long int_value;
642
+ status = libsql_get_int(row, col, &int_value, &err);
643
+ row_vector.emplace_back(int_value);
644
+ break;
645
+
646
+ case LIBSQL_FLOAT:
647
+ double float_value;
648
+ status = libsql_get_float(row, col, &float_value, &err);
649
+ row_vector.emplace_back(float_value);
650
+ break;
651
+
652
+ case LIBSQL_TEXT:
653
+ const char *text_value;
654
+ status = libsql_get_string(row, col, &text_value, &err);
655
+ row_vector.emplace_back(text_value);
656
+ break;
657
+
658
+ case LIBSQL_BLOB: {
659
+ blob value_blob;
660
+ libsql_get_blob(row, col, &value_blob, &err);
661
+ auto *data = new uint8_t[value_blob.len];
662
+ // You cannot share raw memory between native and JS
663
+ // always copy the data
664
+ memcpy(data, value_blob.ptr, value_blob.len);
665
+ libsql_free_blob(value_blob);
666
+ row_vector.emplace_back(
667
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
668
+ .size = static_cast<size_t>(value_blob.len)});
669
+ break;
670
+ }
671
+
672
+ case LIBSQL_NULL:
673
+ // intentional fall-through
674
+ default:
675
+ row_vector.emplace_back(nullptr);
676
+ break;
677
+ }
678
+
679
+ if (status != 0) {
680
+ fprintf(stderr, "%s\n", err);
681
+ throw std::runtime_error("libsql error");
682
+ }
683
+ }
684
+
685
+ if (results != nullptr) {
686
+ results->push_back(row_vector);
687
+ }
688
+
689
+ err = nullptr;
690
+ }
691
+
692
+ if (status != 0) {
693
+ fprintf(stderr, "%s\n", err);
694
+ }
695
+
696
+ libsql_free_rows(rows);
697
+ libsql_free_stmt(stmt);
698
+
699
+ unsigned long long changes = libsql_changes(db.c);
700
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
701
+
702
+ return {.affectedRows = static_cast<int>(changes),
703
+ .insertId = static_cast<double>(insert_row_id)};
704
+ }
705
+
706
+ BatchResult
707
+ opsqlite_libsql_execute_batch(DB const &db,
708
+ const std::vector<BatchArguments> *commands) {
709
+ size_t commandCount = commands->size();
710
+ if (commandCount <= 0) {
711
+ throw std::runtime_error("No SQL commands provided");
712
+ }
713
+
714
+ try {
715
+ int affectedRows = 0;
716
+ opsqlite_libsql_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
717
+ for (int i = 0; i < commandCount; i++) {
718
+ auto command = commands->at(i);
719
+ // We do not provide a datastructure to receive query data because
720
+ // we don't need/want to handle this results in a batch execution
721
+ auto result =
722
+ opsqlite_libsql_execute(db, command.sql, &command.params);
723
+ affectedRows += result.affectedRows;
724
+ }
725
+ opsqlite_libsql_execute(db, "COMMIT", nullptr);
726
+ return BatchResult{
727
+ .affectedRows = affectedRows,
728
+ .commands = static_cast<int>(commandCount),
729
+ };
730
+ } catch (std::exception &exc) {
731
+ opsqlite_libsql_execute(db, "ROLLBACK", nullptr);
732
+ return BatchResult{
733
+ .message = exc.what(),
734
+ };
735
+ }
736
+ }
737
+
738
+ } // namespace opsqlite