@op-engineering/op-sqlite 2.0.20 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,3 @@
1
- //
2
- // PreparedStatementHostObject.cpp
3
- // op-sqlite
4
- //
5
- // Created by Oscar Franco on 5/12/23.
6
- //
7
-
8
1
  #include "PreparedStatementHostObject.h"
9
2
  #include "bridge.h"
10
3
  #include "macros.h"
@@ -31,7 +24,7 @@ jsi::Value PreparedStatementHostObject::get(jsi::Runtime &rt,
31
24
 
32
25
  if (name == "bind") {
33
26
  return HOSTFN("bind", 1) {
34
- if (_statement == NULL) {
27
+ if (_statement == nullptr) {
35
28
  throw std::runtime_error("statement has been freed");
36
29
  }
37
30
 
@@ -46,7 +39,7 @@ jsi::Value PreparedStatementHostObject::get(jsi::Runtime &rt,
46
39
 
47
40
  if (name == "execute") {
48
41
  return HOSTFN("execute", 1) {
49
- if (_statement == NULL) {
42
+ if (_statement == nullptr) {
50
43
  throw std::runtime_error("statement has been freed");
51
44
  }
52
45
  std::vector<DumbHostObject> results;
@@ -69,9 +62,9 @@ jsi::Value PreparedStatementHostObject::get(jsi::Runtime &rt,
69
62
  }
70
63
 
71
64
  PreparedStatementHostObject::~PreparedStatementHostObject() {
72
- if (_statement != NULL) {
65
+ if (_statement != nullptr) {
73
66
  sqlite3_finalize(_statement);
74
- _statement = NULL;
67
+ _statement = nullptr;
75
68
  }
76
69
  }
77
70
 
package/cpp/bindings.cpp CHANGED
@@ -8,7 +8,6 @@
8
8
  #include "sqlbatchexecutor.h"
9
9
  #include "utils.h"
10
10
  #include <iostream>
11
- #include <sqlite3.h>
12
11
  #include <string>
13
12
  #include <unordered_map>
14
13
  #include <vector>
@@ -55,32 +54,50 @@ void install(jsi::Runtime &rt,
55
54
  throw std::runtime_error("[op-sqlite][open] database name is required");
56
55
  }
57
56
 
58
- if (!args[0].isString()) {
59
- throw std::runtime_error(
60
- "[op-sqlite][open] database name must be a string");
61
- }
62
-
63
- std::string dbName = args[0].asString(rt).utf8(rt);
57
+ jsi::Object options = args[0].asObject(rt);
58
+ std::string dbName = options.getProperty(rt, "name").asString(rt).utf8(rt);
64
59
  std::string path = std::string(basePath);
60
+ std::string location;
61
+ std::string encryptionKey;
65
62
 
66
- if (count > 1 && !args[1].isUndefined() && !args[1].isNull()) {
67
- if (!args[1].isString()) {
68
- throw std::runtime_error(
69
- "[op-sqlite][open] database location must be a string");
70
- }
63
+ if (options.hasProperty(rt, "location")) {
64
+ location = options.getProperty(rt, "location").asString(rt).utf8(rt);
65
+ }
71
66
 
72
- std::string lastPath = args[1].asString(rt).utf8(rt);
67
+ if (options.hasProperty(rt, "encryptionKey")) {
68
+ encryptionKey =
69
+ options.getProperty(rt, "encryptionKey").asString(rt).utf8(rt);
70
+ }
73
71
 
74
- if (lastPath == ":memory:") {
72
+ #ifdef OP_SQLITE_USE_SQLCIPHER
73
+ if (encryptionKey.empty()) {
74
+ throw std::runtime_error(
75
+ "[OP SQLite] using SQLCipher encryption key is required");
76
+ }
77
+ // TODO(osp) find a way to display the yellow box from c++
78
+ #else
79
+ // if (!encryptionKey.empty()) {
80
+ // // RCTLogWarn(@"Your message")
81
+ // throw std::runtime_error("[OP SQLite] SQLCipher is not enabled, "
82
+ // "encryption key is not allowed");
83
+ // }
84
+ #endif
85
+
86
+ if (!location.empty()) {
87
+ if (location == ":memory:") {
75
88
  path = ":memory:";
76
- } else if (lastPath.rfind("/", 0) == 0) {
77
- path = lastPath;
89
+ } else if (location.rfind("/", 0) == 0) {
90
+ path = location;
78
91
  } else {
79
- path = path + "/" + lastPath;
92
+ path = path + "/" + location;
80
93
  }
81
94
  }
82
95
 
96
+ #ifdef OP_SQLITE_USE_SQLCIPHER
97
+ BridgeResult result = opsqlite_open(dbName, path, encryptionKey);
98
+ #else
83
99
  BridgeResult result = opsqlite_open(dbName, path);
100
+ #endif
84
101
 
85
102
  if (result.type == SQLiteError) {
86
103
  throw std::runtime_error(result.message);
package/cpp/bridge.cpp CHANGED
@@ -41,9 +41,15 @@ std::string get_db_path(std::string const &db_name,
41
41
  return location + "/" + db_name;
42
42
  }
43
43
 
44
+ #ifdef OP_SQLITE_USE_SQLCIPHER
44
45
  BridgeResult opsqlite_open(std::string const &dbName,
45
- std::string const &lastPath) {
46
- std::string dbPath = get_db_path(dbName, lastPath);
46
+ std::string const &last_path,
47
+ std::string const &encryptionKey) {
48
+ #else
49
+ BridgeResult opsqlite_open(std::string const &dbName,
50
+ std::string const &last_path) {
51
+ #endif
52
+ std::string dbPath = get_db_path(dbName, last_path);
47
53
 
48
54
  int sqlOpenFlags =
49
55
  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
@@ -57,7 +63,12 @@ BridgeResult opsqlite_open(std::string const &dbName,
57
63
  }
58
64
 
59
65
  dbMap[dbName] = db;
60
-
66
+ #ifdef OP_SQLITE_USE_SQLCIPHER
67
+ auto encryptionResult =
68
+ opsqlite_execute(dbName, "PRAGMA key = '" + encryptionKey + "'", nullptr,
69
+ nullptr, nullptr);
70
+ LOGD("Encrypting database");
71
+ #endif
61
72
  return BridgeResult{.type = SQLiteOk, .affectedRows = 0};
62
73
  }
63
74
 
@@ -80,14 +91,11 @@ BridgeResult opsqlite_attach(std::string const &mainDBName,
80
91
  std::string const &docPath,
81
92
  std::string const &databaseToAttach,
82
93
  std::string const &alias) {
83
- /**
84
- * There is no need to check if mainDBName is opened because
85
- * sqliteExecuteLiteral will do that.
86
- * */
87
94
  std::string dbPath = get_db_path(databaseToAttach, docPath);
88
95
  std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
89
96
 
90
- BridgeResult result = opsqlite_execute_literal(mainDBName, statement);
97
+ BridgeResult result =
98
+ opsqlite_execute(mainDBName, statement, nullptr, nullptr, nullptr);
91
99
 
92
100
  if (result.type == SQLiteError) {
93
101
  return {
@@ -103,12 +111,9 @@ BridgeResult opsqlite_attach(std::string const &mainDBName,
103
111
 
104
112
  BridgeResult opsqlite_detach(std::string const &mainDBName,
105
113
  std::string const &alias) {
106
- /**
107
- * There is no need to check if mainDBName is opened because
108
- * sqliteExecuteLiteral will do that.
109
- * */
110
114
  std::string statement = "DETACH DATABASE " + alias;
111
- BridgeResult result = opsqlite_execute_literal(mainDBName, statement);
115
+ BridgeResult result =
116
+ opsqlite_execute(mainDBName, statement, nullptr, nullptr, nullptr);
112
117
  if (result.type == SQLiteError) {
113
118
  return BridgeResult{
114
119
  .type = SQLiteError,
@@ -327,7 +332,7 @@ sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
327
332
 
328
333
  if (statementStatus == SQLITE_ERROR) {
329
334
  const char *message = sqlite3_errmsg(db);
330
- throw std::runtime_error("[op-sqlite] SQL statement error: " +
335
+ throw std::runtime_error("[op-sqlite] SQL prepare statement error: " +
331
336
  std::string(message));
332
337
  }
333
338
 
@@ -365,15 +370,15 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
365
370
  const char *message = sqlite3_errmsg(db);
366
371
  return {
367
372
  .type = SQLiteError,
368
- .message = "[op-sqlite] SQL statement error:" +
369
- std::to_string(statementStatus) +
370
- " description:" + std::string(message) +
373
+ .message = "[op-sqlite] SQL statement error on opsqlite_execute:\n" +
374
+ std::to_string(statementStatus) + " description:\n" +
375
+ std::string(message) +
371
376
  ". See error codes: https://www.sqlite.org/rescode.html",
372
377
  };
373
378
  }
374
379
 
375
- // The statement did not fail to parse but there is nothing to do, just skip
376
- // to the end
380
+ // The statement did not fail to parse but there is nothing to do, just
381
+ // skip to the end
377
382
  if (statement == NULL) {
378
383
  continue;
379
384
  }
@@ -508,8 +513,8 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
508
513
  .insertId = static_cast<double>(latestInsertRowId)};
509
514
  }
510
515
 
511
- /// Executes returning data in raw arrays, a small performance optimization for
512
- /// certain use cases
516
+ /// Executes returning data in raw arrays, a small performance optimization
517
+ /// for certain use cases
513
518
  BridgeResult
514
519
  opsqlite_execute_raw(std::string const &dbName, std::string const &query,
515
520
  const std::vector<JSVariant> *params,
@@ -526,7 +531,7 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
526
531
  bool isConsuming = true;
527
532
  bool isFailed = false;
528
533
 
529
- int result = SQLITE_OK;
534
+ int step = SQLITE_OK;
530
535
 
531
536
  do {
532
537
  const char *queryStr =
@@ -546,8 +551,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
546
551
  };
547
552
  }
548
553
 
549
- // The statement did not fail to parse but there is nothing to do, just skip
550
- // to the end
554
+ // The statement did not fail to parse but there is nothing to do, just
555
+ // skip to the end
551
556
  if (statement == NULL) {
552
557
  continue;
553
558
  }
@@ -562,13 +567,14 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
562
567
  std::string column_name, column_declared_type;
563
568
 
564
569
  while (isConsuming) {
565
- result = sqlite3_step(statement);
570
+ step = sqlite3_step(statement);
566
571
 
567
- switch (result) {
572
+ switch (step) {
568
573
  case SQLITE_ROW: {
569
- if (results == NULL) {
574
+ if (results == nullptr) {
570
575
  break;
571
576
  }
577
+
572
578
  std::vector<JSVariant> row;
573
579
 
574
580
  i = 0;
@@ -616,7 +622,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
616
622
  }
617
623
 
618
624
  case SQLITE_NULL:
619
- // Intentionally left blank
625
+ row.push_back(JSVariant(nullptr));
626
+ break;
620
627
 
621
628
  default:
622
629
  row.push_back(JSVariant(nullptr));
@@ -649,7 +656,7 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
649
656
 
650
657
  return {.type = SQLiteError,
651
658
  .message =
652
- "[op-sqlite] SQLite error code: " + std::to_string(result) +
659
+ "[op-sqlite] SQLite error code: " + std::to_string(step) +
653
660
  ", description: " + std::string(errorMessage) +
654
661
  ".\nSee SQLite error codes reference: "
655
662
  "https://www.sqlite.org/rescode.html"};
@@ -663,64 +670,10 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
663
670
  .insertId = static_cast<double>(latestInsertRowId)};
664
671
  }
665
672
 
666
- /// Executes without returning any results, Useful for performance critical
667
- /// operations
668
- BridgeResult opsqlite_execute_literal(std::string const &dbName,
669
- std::string const &query) {
670
- check_db_open(dbName);
671
-
672
- sqlite3 *db = dbMap[dbName];
673
- sqlite3_stmt *statement;
674
-
675
- int statementStatus =
676
- sqlite3_prepare_v2(db, query.c_str(), -1, &statement, NULL);
677
-
678
- if (statementStatus != SQLITE_OK) {
679
- const char *message = sqlite3_errmsg(db);
680
- return {SQLiteError,
681
- "[op-sqlite] SQL statement error: " + std::string(message), 0};
682
- }
683
-
684
- bool isConsuming = true;
685
- bool isFailed = false;
686
-
687
- int result;
688
- std::string column_name;
689
-
690
- while (isConsuming) {
691
- result = sqlite3_step(statement);
692
-
693
- switch (result) {
694
- case SQLITE_ROW:
695
- isConsuming = true;
696
- break;
697
-
698
- case SQLITE_DONE:
699
- isConsuming = false;
700
- break;
701
-
702
- default:
703
- isFailed = true;
704
- isConsuming = false;
705
- }
706
- }
707
-
708
- sqlite3_finalize(statement);
709
-
710
- if (isFailed) {
711
- const char *message = sqlite3_errmsg(db);
712
- return {SQLiteError,
713
- "[op-sqlite] SQL execution error: " + std::string(message), 0};
714
- }
715
-
716
- int changedRowCount = sqlite3_changes(db);
717
- return {SQLiteOk, "", changedRowCount};
718
- }
719
-
720
673
  void opsqlite_close_all() {
721
674
  for (auto const &x : dbMap) {
722
- // Interrupt will make all pending operations to fail with SQLITE_INTERRUPT
723
- // The ongoing work from threads will then fail ASAP
675
+ // Interrupt will make all pending operations to fail with
676
+ // SQLITE_INTERRUPT The ongoing work from threads will then fail ASAP
724
677
  sqlite3_interrupt(x.second);
725
678
  // Each DB connection can then be safely interrupted
726
679
  sqlite3_close_v2(x.second);
package/cpp/bridge.h CHANGED
@@ -19,8 +19,13 @@ typedef std::function<void(std::string dbName, std::string tableName,
19
19
  typedef std::function<void(std::string dbName)> CommitCallback;
20
20
  typedef std::function<void(std::string dbName)> RollbackCallback;
21
21
 
22
+ #ifdef OP_SQLITE_USE_SQLCIPHER
23
+ BridgeResult opsqlite_open(std::string const &dbName, std::string const &dbPath,
24
+ std::string const &encryptionKey);
25
+ #else
22
26
  BridgeResult opsqlite_open(std::string const &dbName,
23
27
  std::string const &dbPath);
28
+ #endif
24
29
 
25
30
  BridgeResult opsqlite_close(std::string const &dbName);
26
31
 
@@ -46,9 +51,6 @@ BridgeResult opsqlite_execute_raw(std::string const &dbName,
46
51
  const std::vector<JSVariant> *params,
47
52
  std::vector<std::vector<JSVariant>> *results);
48
53
 
49
- BridgeResult opsqlite_execute_literal(std::string const &dbName,
50
- std::string const &query);
51
-
52
54
  void opsqlite_close_all();
53
55
 
54
56
  BridgeResult opsqlite_register_update_hook(std::string const &dbName,
@@ -57,7 +57,8 @@ BatchResult sqliteExecuteBatch(std::string dbName,
57
57
 
58
58
  try {
59
59
  int affectedRows = 0;
60
- opsqlite_execute_literal(dbName, "BEGIN EXCLUSIVE TRANSACTION");
60
+ opsqlite_execute(dbName, "BEGIN EXCLUSIVE TRANSACTION", nullptr, nullptr,
61
+ nullptr);
61
62
  for (int i = 0; i < commandCount; i++) {
62
63
  auto command = commands->at(i);
63
64
  // We do not provide a datastructure to receive query data because we
@@ -65,7 +66,7 @@ BatchResult sqliteExecuteBatch(std::string dbName,
65
66
  auto result = opsqlite_execute(dbName, command.sql, command.params.get(),
66
67
  nullptr, nullptr);
67
68
  if (result.type == SQLiteError) {
68
- opsqlite_execute_literal(dbName, "ROLLBACK");
69
+ opsqlite_execute(dbName, "ROLLBACK", nullptr, nullptr, nullptr);
69
70
  return BatchResult{
70
71
  .type = SQLiteError,
71
72
  .message = result.message,
@@ -74,14 +75,14 @@ BatchResult sqliteExecuteBatch(std::string dbName,
74
75
  affectedRows += result.affectedRows;
75
76
  }
76
77
  }
77
- opsqlite_execute_literal(dbName, "COMMIT");
78
+ opsqlite_execute(dbName, "COMMIT", nullptr, nullptr, nullptr);
78
79
  return BatchResult{
79
80
  .type = SQLiteOk,
80
81
  .affectedRows = affectedRows,
81
82
  .commands = static_cast<int>(commandCount),
82
83
  };
83
84
  } catch (std::exception &exc) {
84
- opsqlite_execute_literal(dbName, "ROLLBACK");
85
+ opsqlite_execute(dbName, "ROLLBACK", nullptr, nullptr, nullptr);
85
86
  return BatchResult{
86
87
  .type = SQLiteError,
87
88
  .message = exc.what(),