@op-engineering/op-sqlite 2.0.7 → 2.0.9

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.
package/README.md CHANGED
@@ -119,10 +119,49 @@ const db = open({
119
119
  db.execute('PRAGMA mmap_size=268435456');
120
120
  ```
121
121
 
122
- If you use prepared statements plus memory mapping, you can get to inches of MMKV for the most performance critical queries, here is a simple example writing/reading a single value.
122
+ You can also set journaling to memory (or even OFF if you are kinda crazy) to gain even more speed. Journaling is what allows SQLite to ROLLBACK statements and it is dangerous, so do it at your own risk
123
+
124
+ ```ts
125
+ db.execute('PRAGMA journal_mode = MEMORY;'); // or OFF
126
+ ```
127
+
128
+ If you use [prepared statements](#prepared-statements) plus memory mapping and set journaling to memory, you can get to inches of MMKV for the most performance critical queries, here is a simple example writing/reading a single value.
123
129
 
124
130
  ![mmkv comparison](mmkv.png)
125
131
 
132
+ # SQLite Gotchas
133
+
134
+ ## Strictness
135
+
136
+ It's important to notice SQLite unlike other databases by default does not strictly check for types, if you want true type safety when you declare your tables you need to use the `STRICT` keyword.
137
+
138
+ ```ts
139
+ db.execute('CREATE TABLE Test (
140
+ id INT PRIMARY KEY,
141
+ name TEXT
142
+ ) STRICT;');
143
+ ```
144
+
145
+ If you don't set it, SQLite will happily write whatever you insert in your table, independtly of the declared type.
146
+
147
+ ## Foreign constraints
148
+
149
+ When SQLite evaluates your query and you have forgein key constraints, it keeps track of the satisfied relations via a counter. Once your statement finishes executing and the counter is not 0, it throws a foreign key constraint failed error. Unfortunately, this simple design means it is impossible to catch which foreign constraint is failed and you will receive a generic error. Nothing op-sqlite can do about it, it's a design flaw in SQLite.
150
+
151
+ In order to catch foreign key errors, you also need to execute the pragma when you open your connection:
152
+
153
+ ```
154
+ PRAGMA foreign_keys = true
155
+ ```
156
+
157
+ ## Error codes
158
+
159
+ Sometimes you might be using valid SQL syntax for other engines or you might be doing something else wrong. The errors returned by op-sqlite contain the raw error code returned by SQLite and you should check [the reference](https://www.sqlite.org/rescode.html) for more detailed information.
160
+
161
+ ## Quirks
162
+
163
+ See the [full list of SQLite quirks](https://www.sqlite.org/quirks.html).
164
+
126
165
  # API
127
166
 
128
167
  ```typescript
@@ -36,7 +36,35 @@ jsi::Value DumbHostObject::get(jsi::Runtime &rt,
36
36
  }
37
37
  }
38
38
 
39
+ for (auto pairField : ownValues) {
40
+ if (name == pairField.first) {
41
+ return toJSI(rt, pairField.second);
42
+ }
43
+ }
44
+
39
45
  return {};
40
46
  }
41
47
 
48
+ void DumbHostObject::set(jsi::Runtime &rt, const jsi::PropNameID &name,
49
+ const jsi::Value &value) {
50
+ auto key = name.utf8(rt);
51
+ auto fields = metadata.get();
52
+ for (int i = 0; i < fields->size(); i++) {
53
+ auto fieldName = std::get<std::string>(fields->at(i).fields[0].second);
54
+ if (fieldName == key) {
55
+ values[i] = toVariant(rt, value);
56
+ return;
57
+ }
58
+ }
59
+
60
+ for (auto pairField : ownValues) {
61
+ if (key == pairField.first) {
62
+ pairField.second = toVariant(rt, value);
63
+ return;
64
+ }
65
+ }
66
+
67
+ ownValues.push_back(std::make_pair(key, toVariant(rt, value)));
68
+ }
69
+
42
70
  } // namespace opsqlite
@@ -23,9 +23,14 @@ public:
23
23
 
24
24
  jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propNameID);
25
25
 
26
+ void set(jsi::Runtime &rt, const jsi::PropNameID &name,
27
+ const jsi::Value &value);
28
+
26
29
  std::vector<JSVariant> values;
27
30
 
28
31
  std::shared_ptr<std::vector<SmartHostObject>> metadata;
32
+
33
+ std::vector<std::pair<std::string, JSVariant>> ownValues;
29
34
  };
30
35
 
31
36
  } // namespace opsqlite
package/cpp/bindings.cpp CHANGED
@@ -35,7 +35,7 @@ bool invalidated = false;
35
35
  void clearState() {
36
36
  invalidated = true;
37
37
  // Will terminate all operations and database connections
38
- sqliteCloseAll();
38
+ sqlite_close_all();
39
39
  // We then join all the threads before the context gets invalidated
40
40
  pool.restartPool();
41
41
 
@@ -81,7 +81,7 @@ void install(jsi::Runtime &rt,
81
81
  }
82
82
  }
83
83
 
84
- BridgeResult result = sqliteOpenDb(dbName, path);
84
+ BridgeResult result = sqlite_open(dbName, path);
85
85
 
86
86
  if (result.type == SQLiteError) {
87
87
  throw std::runtime_error(result.message);
@@ -115,7 +115,7 @@ void install(jsi::Runtime &rt,
115
115
  std::string databaseToAttach = args[1].asString(rt).utf8(rt);
116
116
  std::string alias = args[2].asString(rt).utf8(rt);
117
117
  BridgeResult result =
118
- sqliteAttachDb(dbName, tempDocPath, databaseToAttach, alias);
118
+ sqlite_attach(dbName, tempDocPath, databaseToAttach, alias);
119
119
 
120
120
  if (result.type == SQLiteError) {
121
121
  throw std::runtime_error(result.message);
@@ -137,7 +137,7 @@ void install(jsi::Runtime &rt,
137
137
 
138
138
  std::string dbName = args[0].asString(rt).utf8(rt);
139
139
  std::string alias = args[1].asString(rt).utf8(rt);
140
- BridgeResult result = sqliteDetachDb(dbName, alias);
140
+ BridgeResult result = sqlite_detach(dbName, alias);
141
141
 
142
142
  if (result.type == SQLiteError) {
143
143
  throw jsi::JSError(rt, result.message.c_str());
@@ -158,7 +158,7 @@ void install(jsi::Runtime &rt,
158
158
 
159
159
  std::string dbName = args[0].asString(rt).utf8(rt);
160
160
 
161
- BridgeResult result = sqliteCloseDb(dbName);
161
+ BridgeResult result = sqlite_close(dbName);
162
162
 
163
163
  if (result.type == SQLiteError) {
164
164
  throw jsi::JSError(rt, result.message.c_str());
@@ -190,7 +190,7 @@ void install(jsi::Runtime &rt,
190
190
  tempDocPath = tempDocPath + "/" + args[1].asString(rt).utf8(rt);
191
191
  }
192
192
 
193
- BridgeResult result = sqliteRemoveDb(dbName, tempDocPath);
193
+ BridgeResult result = sqlite_remove(dbName, tempDocPath);
194
194
 
195
195
  if (result.type == SQLiteError) {
196
196
  throw std::runtime_error(result.message);
@@ -213,7 +213,7 @@ void install(jsi::Runtime &rt,
213
213
  std::shared_ptr<std::vector<SmartHostObject>> metadata =
214
214
  std::make_shared<std::vector<SmartHostObject>>();
215
215
 
216
- auto status = sqliteExecute(dbName, query, &params, &results, metadata);
216
+ auto status = sqlite_execute(dbName, query, &params, &results, metadata);
217
217
 
218
218
  if (status.type == SQLiteError) {
219
219
  throw std::runtime_error(status.message);
@@ -249,7 +249,7 @@ void install(jsi::Runtime &rt,
249
249
  std::make_shared<std::vector<SmartHostObject>>();
250
250
 
251
251
  auto status =
252
- sqliteExecute(dbName, query, &params, &results, metadata);
252
+ sqlite_execute(dbName, query, &params, &results, metadata);
253
253
 
254
254
  if (invalidated) {
255
255
  return;
@@ -432,7 +432,7 @@ void install(jsi::Runtime &rt,
432
432
  auto callback = std::make_shared<jsi::Value>(rt, args[1]);
433
433
 
434
434
  if (callback->isUndefined() || callback->isNull()) {
435
- unregisterUpdateHook(dbName);
435
+ sqlite_deregister_update_hook(dbName);
436
436
  return {};
437
437
  }
438
438
 
@@ -449,7 +449,7 @@ void install(jsi::Runtime &rt,
449
449
  if (operation != "DELETE") {
450
450
  std::string query = "SELECT * FROM " + tableName +
451
451
  " where rowid = " + std::to_string(rowId) + ";";
452
- sqliteExecute(dbName, query, &params, &results, metadata);
452
+ sqlite_execute(dbName, query, &params, &results, metadata);
453
453
  }
454
454
 
455
455
  invoker->invokeAsync(
@@ -474,7 +474,7 @@ void install(jsi::Runtime &rt,
474
474
  });
475
475
  };
476
476
 
477
- registerUpdateHook(dbName, std::move(hook));
477
+ sqlite_register_update_hook(dbName, std::move(hook));
478
478
 
479
479
  return {};
480
480
  });
@@ -490,7 +490,7 @@ void install(jsi::Runtime &rt,
490
490
  auto dbName = args[0].asString(rt).utf8(rt);
491
491
  auto callback = std::make_shared<jsi::Value>(rt, args[1]);
492
492
  if (callback->isUndefined() || callback->isNull()) {
493
- unregisterCommitHook(dbName);
493
+ sqlite_deregister_commit_hook(dbName);
494
494
  return {};
495
495
  }
496
496
  commitHooks[dbName] = callback;
@@ -500,7 +500,7 @@ void install(jsi::Runtime &rt,
500
500
  [&rt, callback] { callback->asObject(rt).asFunction(rt).call(rt); });
501
501
  };
502
502
 
503
- registerCommitHook(dbName, std::move(hook));
503
+ sqlite_register_commit_hook(dbName, std::move(hook));
504
504
 
505
505
  return {};
506
506
  });
@@ -517,7 +517,7 @@ void install(jsi::Runtime &rt,
517
517
  auto callback = std::make_shared<jsi::Value>(rt, args[1]);
518
518
 
519
519
  if (callback->isUndefined() || callback->isNull()) {
520
- unregisterRollbackHook(dbName);
520
+ sqlite_deregister_rollback_hook(dbName);
521
521
  return {};
522
522
  }
523
523
  rollbackHooks[dbName] = callback;
@@ -527,7 +527,7 @@ void install(jsi::Runtime &rt,
527
527
  [&rt, callback] { callback->asObject(rt).asFunction(rt).call(rt); });
528
528
  };
529
529
 
530
- registerRollbackHook(dbName, std::move(hook));
530
+ sqlite_register_rollback_hook(dbName, std::move(hook));
531
531
  return {};
532
532
  });
533
533
 
package/cpp/bridge.cpp CHANGED
@@ -2,10 +2,8 @@
2
2
  #include "DumbHostObject.h"
3
3
  #include "SmartHostObject.h"
4
4
  #include "logs.h"
5
+ #include "utils.h"
5
6
  #include <ctime>
6
- #include <sstream>
7
- #include <sys/stat.h>
8
- #include <unistd.h>
9
7
  #include <unordered_map>
10
8
  #include <variant>
11
9
 
@@ -31,63 +29,16 @@ std::unordered_map<std::string, std::function<void(std::string dbName)>>
31
29
  std::unordered_map<std::string,
32
30
  std::function<void(std::string dbName)>>();
33
31
 
34
- bool folder_exists(const std::string &foldername) {
35
- struct stat buffer;
36
- return (stat(foldername.c_str(), &buffer) == 0);
37
- }
38
-
39
- /**
40
- * Portable wrapper for mkdir. Internally used by mkdir()
41
- * @param[in] path the full path of the directory to create.
42
- * @return zero on success, otherwise -1.
43
- */
44
- int _mkdir(const char *path) {
45
- #if _POSIX_C_SOURCE
46
- return mkdir(path);
47
- #else
48
- return mkdir(path, 0755); // not sure if this works on mac
49
- #endif
50
- }
51
-
52
- /**
53
- * Recursive, portable wrapper for mkdir.
54
- * @param[in] path the full path of the directory to create.
55
- * @return zero on success, otherwise -1.
56
- */
57
- int mkdir(const char *path) {
58
- std::string current_level = "/";
59
- std::string level;
60
- std::stringstream ss(path);
61
- // First line is empty because it starts with /User
62
- getline(ss, level, '/');
63
- // split path using slash as a separator
64
- while (getline(ss, level, '/')) {
65
- current_level += level; // append folder to the current level
66
- // create current level
67
- if (!folder_exists(current_level) && _mkdir(current_level.c_str()) != 0)
68
- return -1;
69
-
70
- current_level += "/"; // don't forget to append a slash
71
- }
72
-
73
- return 0;
74
- }
75
-
76
- inline bool file_exists(const std::string &path) {
77
- struct stat buffer;
78
- return (stat(path.c_str(), &buffer) == 0);
79
- }
80
-
81
32
  std::string get_db_path(std::string const dbName, std::string const lastPath) {
82
33
  if (lastPath == ":memory:") {
83
34
  return lastPath;
84
35
  }
85
- mkdir(lastPath.c_str());
36
+ mkdir(lastPath);
86
37
  return lastPath + "/" + dbName;
87
38
  }
88
39
 
89
- BridgeResult sqliteOpenDb(std::string const dbName,
90
- std::string const lastPath) {
40
+ BridgeResult sqlite_open(std::string const &dbName,
41
+ std::string const &lastPath) {
91
42
  std::string dbPath = get_db_path(dbName, lastPath);
92
43
 
93
44
  int sqlOpenFlags =
@@ -106,7 +57,7 @@ BridgeResult sqliteOpenDb(std::string const dbName,
106
57
  return BridgeResult{.type = SQLiteOk, .affectedRows = 0};
107
58
  }
108
59
 
109
- BridgeResult sqliteCloseDb(std::string const dbName) {
60
+ BridgeResult sqlite_close(std::string const &dbName) {
110
61
 
111
62
  if (dbMap.count(dbName) == 0) {
112
63
  return {
@@ -126,10 +77,10 @@ BridgeResult sqliteCloseDb(std::string const dbName) {
126
77
  };
127
78
  }
128
79
 
129
- BridgeResult sqliteAttachDb(std::string const mainDBName,
130
- std::string const docPath,
131
- std::string const databaseToAttach,
132
- std::string const alias) {
80
+ BridgeResult sqlite_attach(std::string const &mainDBName,
81
+ std::string const &docPath,
82
+ std::string const &databaseToAttach,
83
+ std::string const &alias) {
133
84
  /**
134
85
  * There is no need to check if mainDBName is opened because
135
86
  * sqliteExecuteLiteral will do that.
@@ -137,7 +88,7 @@ BridgeResult sqliteAttachDb(std::string const mainDBName,
137
88
  std::string dbPath = get_db_path(databaseToAttach, docPath);
138
89
  std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
139
90
 
140
- BridgeResult result = sqliteExecuteLiteral(mainDBName, statement);
91
+ BridgeResult result = sqlite_execute_literal(mainDBName, statement);
141
92
 
142
93
  if (result.type == SQLiteError) {
143
94
  return {
@@ -151,14 +102,14 @@ BridgeResult sqliteAttachDb(std::string const mainDBName,
151
102
  };
152
103
  }
153
104
 
154
- BridgeResult sqliteDetachDb(std::string const mainDBName,
155
- std::string const alias) {
105
+ BridgeResult sqlite_detach(std::string const &mainDBName,
106
+ std::string const &alias) {
156
107
  /**
157
108
  * There is no need to check if mainDBName is opened because
158
109
  * sqliteExecuteLiteral will do that.
159
110
  * */
160
111
  std::string statement = "DETACH DATABASE " + alias;
161
- BridgeResult result = sqliteExecuteLiteral(mainDBName, statement);
112
+ BridgeResult result = sqlite_execute_literal(mainDBName, statement);
162
113
  if (result.type == SQLiteError) {
163
114
  return BridgeResult{
164
115
  .type = SQLiteError,
@@ -171,10 +122,10 @@ BridgeResult sqliteDetachDb(std::string const mainDBName,
171
122
  };
172
123
  }
173
124
 
174
- BridgeResult sqliteRemoveDb(std::string const dbName,
175
- std::string const docPath) {
125
+ BridgeResult sqlite_remove(std::string const &dbName,
126
+ std::string const &docPath) {
176
127
  if (dbMap.count(dbName) == 1) {
177
- BridgeResult closeResult = sqliteCloseDb(dbName);
128
+ BridgeResult closeResult = sqlite_close(dbName);
178
129
  if (closeResult.type == SQLiteError) {
179
130
  return closeResult;
180
131
  }
@@ -230,7 +181,7 @@ void sqlite_bind_statement(sqlite3_stmt *statement,
230
181
  }
231
182
 
232
183
  BridgeResult sqlite_execute_prepared_statement(
233
- std::string const dbName, sqlite3_stmt *statement,
184
+ std::string const &dbName, sqlite3_stmt *statement,
234
185
  std::vector<DumbHostObject> *results,
235
186
  std::shared_ptr<std::vector<SmartHostObject>> metadatas) {
236
187
  if (dbMap.find(dbName) == dbMap.end()) {
@@ -368,7 +319,7 @@ BridgeResult sqlite_execute_prepared_statement(
368
319
  .insertId = static_cast<double>(latestInsertRowId)};
369
320
  }
370
321
 
371
- sqlite3_stmt *sqlite_prepare_statement(std::string const dbName,
322
+ sqlite3_stmt *sqlite_prepare_statement(std::string const &dbName,
372
323
  std::string const &query) {
373
324
  if (dbMap.find(dbName) == dbMap.end()) {
374
325
  throw std::runtime_error("Database not opened");
@@ -392,10 +343,10 @@ sqlite3_stmt *sqlite_prepare_statement(std::string const dbName,
392
343
  }
393
344
 
394
345
  BridgeResult
395
- sqliteExecute(std::string const dbName, std::string const &query,
396
- const std::vector<JSVariant> *params,
397
- std::vector<DumbHostObject> *results,
398
- std::shared_ptr<std::vector<SmartHostObject>> metadatas) {
346
+ sqlite_execute(std::string const &dbName, std::string const &query,
347
+ const std::vector<JSVariant> *params,
348
+ std::vector<DumbHostObject> *results,
349
+ std::shared_ptr<std::vector<SmartHostObject>> metadatas) {
399
350
 
400
351
  if (dbMap.find(dbName) == dbMap.end()) {
401
352
  return {.type = SQLiteError,
@@ -427,7 +378,7 @@ sqliteExecute(std::string const dbName, std::string const &query,
427
378
  .message = "[op-sqlite] SQL statement error:" +
428
379
  std::to_string(statementStatus) +
429
380
  " description:" + std::string(message) +
430
- "see error codes: https://www.sqlite.org/rescode.html",
381
+ ". See error codes: https://www.sqlite.org/rescode.html",
431
382
  };
432
383
  }
433
384
 
@@ -567,8 +518,8 @@ sqliteExecute(std::string const dbName, std::string const &query,
567
518
  .insertId = static_cast<double>(latestInsertRowId)};
568
519
  }
569
520
 
570
- BridgeResult sqliteExecuteLiteral(std::string const dbName,
571
- std::string const &query) {
521
+ BridgeResult sqlite_execute_literal(std::string const &dbName,
522
+ std::string const &query) {
572
523
  if (dbMap.count(dbName) == 0) {
573
524
  return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
574
525
  }
@@ -621,7 +572,7 @@ BridgeResult sqliteExecuteLiteral(std::string const dbName,
621
572
  return {SQLiteOk, "", changedRowCount};
622
573
  }
623
574
 
624
- void sqliteCloseAll() {
575
+ void sqlite_close_all() {
625
576
  for (auto const &x : dbMap) {
626
577
  // Interrupt will make all pending operations to fail with SQLITE_INTERRUPT
627
578
  // The ongoing work from threads will then fail ASAP
@@ -632,7 +583,7 @@ void sqliteCloseAll() {
632
583
  dbMap.clear();
633
584
  }
634
585
 
635
- std::string operationToString(int operation_type) {
586
+ std::string operation_to_string(int operation_type) {
636
587
  switch (operation_type) {
637
588
  case SQLITE_INSERT:
638
589
  return "INSERT";
@@ -652,12 +603,12 @@ void update_callback(void *dbName, int operation_type, char const *database,
652
603
  char const *table, sqlite3_int64 rowid) {
653
604
  std::string &strDbName = *(static_cast<std::string *>(dbName));
654
605
  auto callback = updateCallbackMap[strDbName];
655
- callback(strDbName, std::string(table), operationToString(operation_type),
606
+ callback(strDbName, std::string(table), operation_to_string(operation_type),
656
607
  static_cast<int>(rowid));
657
608
  }
658
609
 
659
- BridgeResult registerUpdateHook(
660
- std::string const dbName,
610
+ BridgeResult sqlite_register_update_hook(
611
+ std::string const &dbName,
661
612
  std::function<void(std::string dbName, std::string tableName,
662
613
  std::string operation, int rowId)> const callback) {
663
614
  if (dbMap.count(dbName) == 0) {
@@ -680,7 +631,7 @@ BridgeResult registerUpdateHook(
680
631
  return {SQLiteOk};
681
632
  }
682
633
 
683
- BridgeResult unregisterUpdateHook(std::string const dbName) {
634
+ BridgeResult sqlite_deregister_update_hook(std::string const &dbName) {
684
635
  if (dbMap.count(dbName) == 0) {
685
636
  return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
686
637
  }
@@ -701,9 +652,9 @@ int commit_callback(void *dbName) {
701
652
  return 0;
702
653
  }
703
654
 
704
- BridgeResult
705
- registerCommitHook(std::string const dbName,
706
- std::function<void(std::string dbName)> const callback) {
655
+ BridgeResult sqlite_register_commit_hook(
656
+ std::string const &dbName,
657
+ std::function<void(std::string dbName)> const callback) {
707
658
  if (dbMap.count(dbName) == 0) {
708
659
  return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
709
660
  }
@@ -724,7 +675,7 @@ registerCommitHook(std::string const dbName,
724
675
  return {SQLiteOk};
725
676
  }
726
677
 
727
- BridgeResult unregisterCommitHook(std::string const dbName) {
678
+ BridgeResult sqlite_deregister_commit_hook(std::string const &dbName) {
728
679
  if (dbMap.count(dbName) == 0) {
729
680
  return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
730
681
  }
@@ -742,9 +693,9 @@ void rollback_callback(void *dbName) {
742
693
  callback(strDbName);
743
694
  }
744
695
 
745
- BridgeResult
746
- registerRollbackHook(std::string const dbName,
747
- std::function<void(std::string dbName)> const callback) {
696
+ BridgeResult sqlite_register_rollback_hook(
697
+ std::string const &dbName,
698
+ std::function<void(std::string dbName)> const callback) {
748
699
  if (dbMap.count(dbName) == 0) {
749
700
  return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
750
701
  }
@@ -765,7 +716,7 @@ registerRollbackHook(std::string const dbName,
765
716
  return {SQLiteOk};
766
717
  }
767
718
 
768
- BridgeResult unregisterRollbackHook(std::string const dbName) {
719
+ BridgeResult sqlite_deregister_rollback_hook(std::string const &dbName) {
769
720
  if (dbMap.count(dbName) == 0) {
770
721
  return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
771
722
  }
package/cpp/bridge.h CHANGED
@@ -12,54 +12,54 @@ namespace opsqlite {
12
12
 
13
13
  namespace jsi = facebook::jsi;
14
14
 
15
- BridgeResult sqliteOpenDb(std::string const dbName, std::string const dbPath);
15
+ BridgeResult sqlite_open(std::string const &dbName, std::string const &dbPath);
16
16
 
17
- BridgeResult sqliteCloseDb(std::string const dbName);
17
+ BridgeResult sqlite_close(std::string const &dbName);
18
18
 
19
- BridgeResult sqliteRemoveDb(std::string const dbName,
20
- std::string const docPath);
19
+ BridgeResult sqlite_remove(std::string const &dbName,
20
+ std::string const &docPath);
21
21
 
22
- BridgeResult sqliteAttachDb(std::string const mainDBName,
23
- std::string const docPath,
24
- std::string const databaseToAttach,
25
- std::string const alias);
22
+ BridgeResult sqlite_attach(std::string const &mainDBName,
23
+ std::string const &docPath,
24
+ std::string const &databaseToAttach,
25
+ std::string const &alias);
26
26
 
27
- BridgeResult sqliteDetachDb(std::string const mainDBName,
28
- std::string const alias);
27
+ BridgeResult sqlite_detach(std::string const &mainDBName,
28
+ std::string const &alias);
29
29
 
30
30
  BridgeResult
31
- sqliteExecute(std::string const dbName, std::string const &query,
32
- const std::vector<JSVariant> *params,
33
- std::vector<DumbHostObject> *results,
34
- std::shared_ptr<std::vector<SmartHostObject>> metadatas);
31
+ sqlite_execute(std::string const &dbName, std::string const &query,
32
+ const std::vector<JSVariant> *params,
33
+ std::vector<DumbHostObject> *results,
34
+ std::shared_ptr<std::vector<SmartHostObject>> metadatas);
35
35
 
36
- BridgeResult sqliteExecuteLiteral(std::string const dbName,
37
- std::string const &query);
36
+ BridgeResult sqlite_execute_literal(std::string const &dbName,
37
+ std::string const &query);
38
38
 
39
- void sqliteCloseAll();
39
+ void sqlite_close_all();
40
40
 
41
- BridgeResult registerUpdateHook(
42
- std::string const dbName,
41
+ BridgeResult sqlite_register_update_hook(
42
+ std::string const &dbName,
43
43
  std::function<void(std::string dbName, std::string tableName,
44
44
  std::string operation, int rowId)> const callback);
45
- BridgeResult unregisterUpdateHook(std::string const dbName);
46
- BridgeResult
47
- registerCommitHook(std::string const dbName,
48
- std::function<void(std::string dbName)> const callback);
49
- BridgeResult unregisterCommitHook(std::string const dbName);
50
- BridgeResult
51
- registerRollbackHook(std::string const dbName,
52
- std::function<void(std::string dbName)> const callback);
53
- BridgeResult unregisterRollbackHook(std::string const dbName);
54
-
55
- sqlite3_stmt *sqlite_prepare_statement(std::string const dbName,
45
+ BridgeResult sqlite_deregister_update_hook(std::string const &dbName);
46
+ BridgeResult sqlite_register_commit_hook(
47
+ std::string const &dbName,
48
+ std::function<void(std::string dbName)> const callback);
49
+ BridgeResult sqlite_deregister_commit_hook(std::string const &dbName);
50
+ BridgeResult sqlite_register_rollback_hook(
51
+ std::string const &dbName,
52
+ std::function<void(std::string dbName)> const callback);
53
+ BridgeResult sqlite_deregister_rollback_hook(std::string const &dbName);
54
+
55
+ sqlite3_stmt *sqlite_prepare_statement(std::string const &dbName,
56
56
  std::string const &query);
57
57
 
58
58
  void sqlite_bind_statement(sqlite3_stmt *statement,
59
59
  const std::vector<JSVariant> *params);
60
60
 
61
61
  BridgeResult sqlite_execute_prepared_statement(
62
- std::string const dbName, sqlite3_stmt *statement,
62
+ std::string const &dbName, sqlite3_stmt *statement,
63
63
  std::vector<DumbHostObject> *results,
64
64
  std::shared_ptr<std::vector<SmartHostObject>> metadatas);
65
65
  } // namespace opsqlite
@@ -57,15 +57,15 @@ BatchResult sqliteExecuteBatch(std::string dbName,
57
57
 
58
58
  try {
59
59
  int affectedRows = 0;
60
- sqliteExecuteLiteral(dbName, "BEGIN EXCLUSIVE TRANSACTION");
60
+ sqlite_execute_literal(dbName, "BEGIN EXCLUSIVE TRANSACTION");
61
61
  for (int i = 0; i < commandCount; i++) {
62
62
  auto command = commands->at(i);
63
63
  // We do not provide a datastructure to receive query data because we
64
64
  // don't need/want to handle this results in a batch execution
65
- auto result = sqliteExecute(dbName, command.sql, command.params.get(),
66
- nullptr, nullptr);
65
+ auto result = sqlite_execute(dbName, command.sql, command.params.get(),
66
+ nullptr, nullptr);
67
67
  if (result.type == SQLiteError) {
68
- sqliteExecuteLiteral(dbName, "ROLLBACK");
68
+ sqlite_execute_literal(dbName, "ROLLBACK");
69
69
  return BatchResult{
70
70
  .type = SQLiteError,
71
71
  .message = result.message,
@@ -74,14 +74,14 @@ BatchResult sqliteExecuteBatch(std::string dbName,
74
74
  affectedRows += result.affectedRows;
75
75
  }
76
76
  }
77
- sqliteExecuteLiteral(dbName, "COMMIT");
77
+ sqlite_execute_literal(dbName, "COMMIT");
78
78
  return BatchResult{
79
79
  .type = SQLiteOk,
80
80
  .affectedRows = affectedRows,
81
81
  .commands = static_cast<int>(commandCount),
82
82
  };
83
83
  } catch (std::exception &exc) {
84
- sqliteExecuteLiteral(dbName, "ROLLBACK");
84
+ sqlite_execute_literal(dbName, "ROLLBACK");
85
85
  return BatchResult{
86
86
  .type = SQLiteError,
87
87
  .message = exc.what(),
package/cpp/utils.cpp CHANGED
@@ -3,6 +3,9 @@
3
3
  #include "bridge.h"
4
4
  #include <fstream>
5
5
  #include <iostream>
6
+ #include <sstream>
7
+ #include <sys/stat.h>
8
+ #include <unistd.h>
6
9
 
7
10
  namespace opsqlite {
8
11
 
@@ -38,6 +41,49 @@ jsi::Value toJSI(jsi::Runtime &rt, JSVariant value) {
38
41
  return jsi::Value::null();
39
42
  }
40
43
 
44
+ JSVariant toVariant(jsi::Runtime &rt, const jsi::Value &value) {
45
+ if (value.isNull() || value.isUndefined()) {
46
+ return JSVariant(nullptr);
47
+ } else if (value.isBool()) {
48
+ return JSVariant(value.getBool());
49
+ } else if (value.isNumber()) {
50
+ double doubleVal = value.asNumber();
51
+ int intVal = (int)doubleVal;
52
+ long long longVal = (long)doubleVal;
53
+ if (intVal == doubleVal) {
54
+ return JSVariant(intVal);
55
+ } else if (longVal == doubleVal) {
56
+ return JSVariant(longVal);
57
+ } else {
58
+ return JSVariant(doubleVal);
59
+ }
60
+ } else if (value.isString()) {
61
+ std::string strVal = value.asString(rt).utf8(rt);
62
+ return JSVariant(strVal);
63
+ } else if (value.isObject()) {
64
+ auto obj = value.asObject(rt);
65
+ if (obj.isArrayBuffer(rt)) {
66
+ auto buffer = obj.getArrayBuffer(rt);
67
+
68
+ uint8_t *data = new uint8_t[buffer.size(rt)];
69
+ // You cannot share raw memory between native and JS
70
+ // always copy the data
71
+ // see https://github.com/facebook/hermes/pull/419 and
72
+ // https://github.com/facebook/hermes/issues/564.
73
+ memcpy(data, buffer.data(rt), buffer.size(rt));
74
+
75
+ return JSVariant(ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
76
+ .size = buffer.size(rt)});
77
+ } else {
78
+ throw std::invalid_argument(
79
+ "Unknown JSI ArrayBuffer to variant value conversion, received "
80
+ "object instead of ArrayBuffer");
81
+ }
82
+ } else {
83
+ throw std::invalid_argument("Unknown JSI to variant value conversion");
84
+ }
85
+ }
86
+
41
87
  std::vector<JSVariant> toVariantVec(jsi::Runtime &rt,
42
88
  jsi::Value const &params) {
43
89
  std::vector<JSVariant> res;
@@ -148,12 +194,12 @@ BatchResult importSQLFile(std::string dbName, std::string fileLocation) {
148
194
  try {
149
195
  int affectedRows = 0;
150
196
  int commands = 0;
151
- sqliteExecuteLiteral(dbName, "BEGIN EXCLUSIVE TRANSACTION");
197
+ sqlite_execute_literal(dbName, "BEGIN EXCLUSIVE TRANSACTION");
152
198
  while (std::getline(sqFile, line, '\n')) {
153
199
  if (!line.empty()) {
154
- BridgeResult result = sqliteExecuteLiteral(dbName, line);
200
+ BridgeResult result = sqlite_execute_literal(dbName, line);
155
201
  if (result.type == SQLiteError) {
156
- sqliteExecuteLiteral(dbName, "ROLLBACK");
202
+ sqlite_execute_literal(dbName, "ROLLBACK");
157
203
  sqFile.close();
158
204
  return {SQLiteError, result.message, 0, commands};
159
205
  } else {
@@ -163,11 +209,11 @@ BatchResult importSQLFile(std::string dbName, std::string fileLocation) {
163
209
  }
164
210
  }
165
211
  sqFile.close();
166
- sqliteExecuteLiteral(dbName, "COMMIT");
212
+ sqlite_execute_literal(dbName, "COMMIT");
167
213
  return {SQLiteOk, "", affectedRows, commands};
168
214
  } catch (...) {
169
215
  sqFile.close();
170
- sqliteExecuteLiteral(dbName, "ROLLBACK");
216
+ sqlite_execute_literal(dbName, "ROLLBACK");
171
217
  return {SQLiteError,
172
218
  "[op-sqlite][loadSQLFile] Unexpected error, transaction was "
173
219
  "rolledback",
@@ -178,4 +224,19 @@ BatchResult importSQLFile(std::string dbName, std::string fileLocation) {
178
224
  }
179
225
  }
180
226
 
227
+ bool folder_exists(const std::string &foldername) {
228
+ struct stat buffer;
229
+ return (stat(foldername.c_str(), &buffer) == 0);
230
+ }
231
+
232
+ bool file_exists(const std::string &path) {
233
+ struct stat buffer;
234
+ return (stat(path.c_str(), &buffer) == 0);
235
+ }
236
+
237
+ int mkdir(std::string const &path) {
238
+ std::filesystem::create_directories(path);
239
+ return 0;
240
+ }
241
+
181
242
  } // namespace opsqlite
package/cpp/utils.h CHANGED
@@ -33,6 +33,8 @@ struct BatchResult {
33
33
 
34
34
  jsi::Value toJSI(jsi::Runtime &rt, JSVariant value);
35
35
 
36
+ JSVariant toVariant(jsi::Runtime &rt, jsi::Value const &value);
37
+
36
38
  std::vector<JSVariant> toVariantVec(jsi::Runtime &rt, jsi::Value const &args);
37
39
 
38
40
  jsi::Value createResult(jsi::Runtime &rt, BridgeResult status,
@@ -41,6 +43,12 @@ jsi::Value createResult(jsi::Runtime &rt, BridgeResult status,
41
43
 
42
44
  BatchResult importSQLFile(std::string dbName, std::string fileLocation);
43
45
 
46
+ int mkdir(const std::string &path);
47
+
48
+ bool folder_exists(const std::string &foldername);
49
+
50
+ bool file_exists(const std::string &path);
51
+
44
52
  } // namespace opsqlite
45
53
 
46
54
  #endif /* utils_h */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@op-engineering/op-sqlite",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
4
  "description": "Next generation SQLite for React Native",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -26,7 +26,7 @@
26
26
  "typescript": "tsc --noEmit",
27
27
  "prepare": "bob build",
28
28
  "example": "yarn --cwd example",
29
- "pods": "cd example && npx pod-install --quiet",
29
+ "pods": "cd example && yarn pods",
30
30
  "bootstrap": "yarn example && yarn && yarn pods",
31
31
  "bump": "./bump-version.sh"
32
32
  },
@@ -48,7 +48,7 @@
48
48
  "devDependencies": {
49
49
  "lefthook": "^1.5.5",
50
50
  "react": "18.2.0",
51
- "react-native": "0.73.0",
51
+ "react-native": "0.73.1",
52
52
  "react-native-builder-bob": "^0.23.2",
53
53
  "typescript": "5.0.4"
54
54
  },