@op-engineering/op-sqlite 3.0.1 → 3.0.2

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/cpp/bindings.cpp CHANGED
@@ -511,8 +511,7 @@ void install(jsi::Runtime &rt,
511
511
  auto callback = std::make_shared<jsi::Value>(rt, args[1]);
512
512
 
513
513
  if (callback->isUndefined() || callback->isNull()) {
514
- opsqlite_deregister_update_hook(dbName);
515
- return {};
514
+ throw std::runtime_error("[op-sqlite][updateHook] callback is required");
516
515
  }
517
516
 
518
517
  updateHooks[dbName] = callback;
@@ -552,9 +551,13 @@ void install(jsi::Runtime &rt,
552
551
  });
553
552
  };
554
553
 
555
- opsqlite_register_update_hook(dbName, std::move(hook));
554
+ auto register_result =
555
+ opsqlite_register_update_hook(dbName, std::move(hook));
556
556
 
557
- return {};
557
+ return HOSTFN("remove", 0) {
558
+ opsqlite_deregister_update_hook(dbName, register_result.identifier);
559
+ return {};
560
+ });
558
561
  });
559
562
 
560
563
  auto commit_hook = HOSTFN("commitHook", 2) {
@@ -567,8 +570,7 @@ void install(jsi::Runtime &rt,
567
570
  auto dbName = args[0].asString(rt).utf8(rt);
568
571
  auto callback = std::make_shared<jsi::Value>(rt, args[1]);
569
572
  if (callback->isUndefined() || callback->isNull()) {
570
- opsqlite_deregister_commit_hook(dbName);
571
- return {};
573
+ throw std::runtime_error("Callback is needed");
572
574
  }
573
575
  commitHooks[dbName] = callback;
574
576
 
@@ -577,9 +579,13 @@ void install(jsi::Runtime &rt,
577
579
  [&rt, callback] { callback->asObject(rt).asFunction(rt).call(rt); });
578
580
  };
579
581
 
580
- opsqlite_register_commit_hook(dbName, std::move(hook));
582
+ auto register_result =
583
+ opsqlite_register_commit_hook(dbName, std::move(hook));
581
584
 
582
- return {};
585
+ return HOSTFN("remove", 0) {
586
+ opsqlite_deregister_commit_hook(dbName, register_result.identifier);
587
+ return {};
588
+ });
583
589
  });
584
590
 
585
591
  auto rollback_hook = HOSTFN("rollbackHook", 2) {
@@ -594,7 +600,7 @@ void install(jsi::Runtime &rt,
594
600
  auto callback = std::make_shared<jsi::Value>(rt, args[1]);
595
601
 
596
602
  if (callback->isUndefined() || callback->isNull()) {
597
- opsqlite_deregister_rollback_hook(dbName);
603
+ throw std::runtime_error("Callback is needed");
598
604
  return {};
599
605
  }
600
606
  rollbackHooks[dbName] = callback;
@@ -604,8 +610,13 @@ void install(jsi::Runtime &rt,
604
610
  [&rt, callback] { callback->asObject(rt).asFunction(rt).call(rt); });
605
611
  };
606
612
 
607
- opsqlite_register_rollback_hook(dbName, std::move(hook));
608
- return {};
613
+ auto register_result =
614
+ opsqlite_register_rollback_hook(dbName, std::move(hook));
615
+
616
+ return HOSTFN("remove", 0) {
617
+ opsqlite_deregister_rollback_hook(dbName, register_result.identifier);
618
+ return {};
619
+ });
609
620
  });
610
621
 
611
622
  auto prepare_statement = HOSTFN("prepareStatement", 1) {
package/cpp/bridge.cpp CHANGED
@@ -8,17 +8,25 @@
8
8
 
9
9
  namespace opsqlite {
10
10
 
11
+ // TODO this has gotten unweildy, using a HostObject abstraction would be better
11
12
  /// Maps to hold the different objects
12
13
  std::unordered_map<std::string, sqlite3 *> dbMap =
13
14
  std::unordered_map<std::string, sqlite3 *>();
14
- std::unordered_map<std::string, UpdateCallback> updateCallbackMap =
15
- std::unordered_map<std::string, UpdateCallback>();
16
-
17
- std::unordered_map<std::string, CommitCallback> commitCallbackMap =
18
- std::unordered_map<std::string, CommitCallback>();
19
-
20
- std::unordered_map<std::string, RollbackCallback> rollbackCallbackMap =
21
- std::unordered_map<std::string, RollbackCallback>();
15
+ std::unordered_map<std::string, std::unordered_map<std::string, UpdateCallback>>
16
+ updateCallbackMap =
17
+ std::unordered_map<std::string,
18
+ std::unordered_map<std::string, UpdateCallback>>();
19
+
20
+ std::unordered_map<std::string, std::unordered_map<std::string, CommitCallback>>
21
+ commitCallbackMap =
22
+ std::unordered_map<std::string,
23
+ std::unordered_map<std::string, CommitCallback>>();
24
+
25
+ std::unordered_map<std::string,
26
+ std::unordered_map<std::string, RollbackCallback>>
27
+ rollbackCallbackMap =
28
+ std::unordered_map<std::string,
29
+ std::unordered_map<std::string, RollbackCallback>>();
22
30
 
23
31
  inline void check_db_open(std::string const &db_name) {
24
32
  if (dbMap.count(db_name) == 0) {
@@ -26,6 +34,38 @@ inline void check_db_open(std::string const &db_name) {
26
34
  }
27
35
  }
28
36
 
37
+ // Hook native callbacks
38
+ void update_callback(void *user_data, int operation_type, char const *database,
39
+ char const *table, sqlite3_int64 rowid) {
40
+ std::string db_name(database);
41
+ auto callbacks = updateCallbackMap[db_name];
42
+ // iterate over the callback map and call them
43
+
44
+ for (auto &cb : callbacks) {
45
+ cb.second(db_name, std::string(table),
46
+ sqlite_operation_to_string(operation_type),
47
+ static_cast<long long>(rowid));
48
+ }
49
+ }
50
+
51
+ int commit_callback(void *database) {
52
+ std::string db_name(static_cast<char const *>(database));
53
+ auto callbacks = commitCallbackMap[db_name];
54
+ for (auto &cb : callbacks) {
55
+ cb.second(db_name);
56
+ }
57
+ // You need to return 0 to allow commits to continue
58
+ return 0;
59
+ }
60
+
61
+ void rollback_callback(void *database) {
62
+ std::string db_name(static_cast<char const *>(database));
63
+ auto callbacks = rollbackCallbackMap[db_name];
64
+ for (auto &cb : callbacks) {
65
+ cb.second(db_name);
66
+ }
67
+ }
68
+
29
69
  /// Start of api
30
70
 
31
71
  /// Returns the completely formed db path, but it also creates any sub-folders
@@ -69,6 +109,12 @@ BridgeResult opsqlite_open(std::string const &dbName,
69
109
  nullptr, nullptr);
70
110
  #endif
71
111
 
112
+ // On connection we register the native hooks, so on JS people can create
113
+ // reactive queries and their own hooks
114
+ sqlite3_update_hook(db, &update_callback, nullptr);
115
+ sqlite3_commit_hook(db, &commit_callback, nullptr);
116
+ sqlite3_rollback_hook(db, &rollback_callback, nullptr);
117
+
72
118
  return BridgeResult{.type = SQLiteOk, .affectedRows = 0};
73
119
  }
74
120
 
@@ -684,132 +730,83 @@ void opsqlite_close_all() {
684
730
  commitCallbackMap.clear();
685
731
  }
686
732
 
687
- std::string operation_to_string(int operation_type) {
688
- switch (operation_type) {
689
- case SQLITE_INSERT:
690
- return "INSERT";
691
-
692
- case SQLITE_DELETE:
693
- return "DELETE";
694
-
695
- case SQLITE_UPDATE:
696
- return "UPDATE";
697
-
698
- default:
699
- throw std::invalid_argument("Uknown SQLite operation on hook");
700
- }
701
- }
702
-
703
- void update_callback(void *dbName, int operation_type, char const *database,
704
- char const *table, sqlite3_int64 rowid) {
705
- std::string &strDbName = *(static_cast<std::string *>(dbName));
706
- auto callback = updateCallbackMap[strDbName];
707
- callback(strDbName, std::string(table), operation_to_string(operation_type),
708
- static_cast<int>(rowid));
709
- }
710
-
711
- BridgeResult opsqlite_register_update_hook(std::string const &dbName,
733
+ BridgeResult opsqlite_register_update_hook(std::string const &db_name,
712
734
  UpdateCallback const callback) {
713
- check_db_open(dbName);
735
+ check_db_open(db_name);
714
736
 
715
- sqlite3 *db = dbMap[dbName];
716
- updateCallbackMap[dbName] = callback;
717
- const std::string *key = nullptr;
737
+ sqlite3 *db = dbMap[db_name];
738
+ std::string id = get_uuid();
718
739
 
719
- // TODO find a more elegant way to retrieve a reference to the key
720
- for (auto const &element : dbMap) {
721
- if (element.first == dbName) {
722
- key = &element.first;
723
- }
740
+ if (!updateCallbackMap.count(db_name)) {
741
+ updateCallbackMap[db_name] =
742
+ std::unordered_map<std::string, UpdateCallback>();
724
743
  }
725
744
 
726
- sqlite3_update_hook(db, &update_callback, (void *)key);
745
+ updateCallbackMap[db_name][id] = callback;
727
746
 
728
- return {SQLiteOk};
747
+ return {.type = SQLiteOk, .identifier = id};
729
748
  }
730
749
 
731
- BridgeResult opsqlite_deregister_update_hook(std::string const &dbName) {
732
- check_db_open(dbName);
733
-
734
- sqlite3 *db = dbMap[dbName];
735
- updateCallbackMap.erase(dbName);
736
-
737
- sqlite3_update_hook(db, NULL, NULL);
750
+ BridgeResult opsqlite_deregister_update_hook(std::string const &db_name,
751
+ std::string const &id) {
752
+ check_db_open(db_name);
753
+ updateCallbackMap[db_name].erase(id);
738
754
 
739
755
  return {SQLiteOk};
740
756
  }
741
757
 
742
- int commit_callback(void *dbName) {
743
- std::string &strDbName = *(static_cast<std::string *>(dbName));
744
- auto callback = commitCallbackMap[strDbName];
745
- callback(strDbName);
746
- // You need to return 0 to allow commits to continue
747
- return 0;
748
- }
749
-
750
- BridgeResult opsqlite_register_commit_hook(std::string const &dbName,
758
+ BridgeResult opsqlite_register_commit_hook(std::string const &db_name,
751
759
  CommitCallback const callback) {
752
- check_db_open(dbName);
760
+ check_db_open(db_name);
753
761
 
754
- sqlite3 *db = dbMap[dbName];
755
- commitCallbackMap[dbName] = callback;
756
- const std::string *key = nullptr;
762
+ sqlite3 *db = dbMap[db_name];
763
+ std::string id = get_uuid();
757
764
 
758
- // TODO find a more elegant way to retrieve a reference to the key
759
- for (auto const &element : dbMap) {
760
- if (element.first == dbName) {
761
- key = &element.first;
762
- }
765
+ if (!commitCallbackMap.count(db_name)) {
766
+ commitCallbackMap[db_name] =
767
+ std::unordered_map<std::string, CommitCallback>();
763
768
  }
764
769
 
765
- sqlite3_commit_hook(db, &commit_callback, (void *)key);
770
+ commitCallbackMap[db_name][id] = callback;
766
771
 
767
- return {SQLiteOk};
772
+ return {.type = SQLiteOk, .identifier = id};
768
773
  }
769
774
 
770
- BridgeResult opsqlite_deregister_commit_hook(std::string const &dbName) {
771
- check_db_open(dbName);
775
+ BridgeResult opsqlite_deregister_commit_hook(std::string const &db_name,
776
+ std::string const &id) {
777
+ check_db_open(db_name);
772
778
 
773
- sqlite3 *db = dbMap[dbName];
774
- commitCallbackMap.erase(dbName);
779
+ sqlite3 *db = dbMap[db_name];
780
+ commitCallbackMap[db_name].erase(id);
775
781
  sqlite3_commit_hook(db, NULL, NULL);
776
782
 
777
783
  return {SQLiteOk};
778
784
  }
779
785
 
780
- void rollback_callback(void *dbName) {
781
- std::string &strDbName = *(static_cast<std::string *>(dbName));
782
- auto callback = rollbackCallbackMap[strDbName];
783
- callback(strDbName);
784
- }
785
-
786
- BridgeResult opsqlite_register_rollback_hook(std::string const &dbName,
786
+ BridgeResult opsqlite_register_rollback_hook(std::string const &db_name,
787
787
  RollbackCallback const callback) {
788
- check_db_open(dbName);
788
+ check_db_open(db_name);
789
789
 
790
- sqlite3 *db = dbMap[dbName];
791
- rollbackCallbackMap[dbName] = callback;
792
- const std::string *key = nullptr;
790
+ sqlite3 *db = dbMap[db_name];
791
+ std::string id = get_uuid();
793
792
 
794
- // TODO find a more elegant way to retrieve a reference to the key
795
- for (auto const &element : dbMap) {
796
- if (element.first == dbName) {
797
- key = &element.first;
798
- }
793
+ if (!rollbackCallbackMap.count(db_name)) {
794
+ rollbackCallbackMap[db_name] =
795
+ std::unordered_map<std::string, RollbackCallback>();
799
796
  }
800
797
 
801
- sqlite3_rollback_hook(db, &rollback_callback, (void *)key);
798
+ rollbackCallbackMap[db_name][id] = callback;
802
799
 
803
- return {SQLiteOk};
800
+ return {.type = SQLiteOk, .identifier = id};
804
801
  }
805
802
 
806
- BridgeResult opsqlite_deregister_rollback_hook(std::string const &dbName) {
807
- check_db_open(dbName);
808
-
809
- sqlite3 *db = dbMap[dbName];
810
- rollbackCallbackMap.erase(dbName);
803
+ BridgeResult opsqlite_deregister_rollback_hook(std::string const &db_name,
804
+ std::string const &id) {
805
+ check_db_open(db_name);
811
806
 
812
- sqlite3_rollback_hook(db, NULL, NULL);
807
+ sqlite3 *db = dbMap[db_name];
808
+ rollbackCallbackMap[db_name].erase(id);
809
+ sqlite3_commit_hook(db, NULL, NULL);
813
810
 
814
811
  return {SQLiteOk};
815
812
  }
package/cpp/bridge.h CHANGED
@@ -58,13 +58,16 @@ void opsqlite_close_all();
58
58
 
59
59
  BridgeResult opsqlite_register_update_hook(std::string const &dbName,
60
60
  UpdateCallback const callback);
61
- BridgeResult opsqlite_deregister_update_hook(std::string const &dbName);
61
+ BridgeResult opsqlite_deregister_update_hook(std::string const &dbName,
62
+ std::string const &id);
62
63
  BridgeResult opsqlite_register_commit_hook(std::string const &dbName,
63
64
  CommitCallback const callback);
64
- BridgeResult opsqlite_deregister_commit_hook(std::string const &dbName);
65
+ BridgeResult opsqlite_deregister_commit_hook(std::string const &dbName,
66
+ std::string const &id);
65
67
  BridgeResult opsqlite_register_rollback_hook(std::string const &dbName,
66
68
  RollbackCallback const callback);
67
- BridgeResult opsqlite_deregister_rollback_hook(std::string const &dbName);
69
+ BridgeResult opsqlite_deregister_rollback_hook(std::string const &dbName,
70
+ std::string const &id);
68
71
 
69
72
  sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
70
73
  std::string const &query);
package/cpp/types.h CHANGED
@@ -12,6 +12,7 @@ struct BridgeResult {
12
12
  std::string message;
13
13
  int affectedRows;
14
14
  double insertId;
15
+ std::string identifier;
15
16
  };
16
17
 
17
18
  struct BatchResult {
package/cpp/utils.cpp CHANGED
@@ -3,6 +3,7 @@
3
3
  #include "bridge.h"
4
4
  #include <fstream>
5
5
  #include <iostream>
6
+ #include <random>
6
7
  #include <sstream>
7
8
  #include <sys/stat.h>
8
9
  #include <unistd.h>
@@ -252,4 +253,40 @@ int mkdir(std::string const &path) {
252
253
  return 0;
253
254
  }
254
255
 
256
+ // Semi random function, more than enough for our purposes
257
+ std::string get_uuid() {
258
+ static std::random_device dev;
259
+ static std::mt19937 rng(dev());
260
+
261
+ std::uniform_int_distribution<int> dist(0, 15);
262
+
263
+ const char *v = "0123456789abcdef";
264
+ const bool dash[] = {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0};
265
+
266
+ std::string res;
267
+ for (int i = 0; i < 16; i++) {
268
+ if (dash[i])
269
+ res += "-";
270
+ res += v[dist(rng)];
271
+ res += v[dist(rng)];
272
+ }
273
+ return res;
274
+ }
275
+
276
+ std::string sqlite_operation_to_string(int operation_type) {
277
+ switch (operation_type) {
278
+ case SQLITE_INSERT:
279
+ return "INSERT";
280
+
281
+ case SQLITE_DELETE:
282
+ return "DELETE";
283
+
284
+ case SQLITE_UPDATE:
285
+ return "UPDATE";
286
+
287
+ default:
288
+ throw std::invalid_argument("Uknown SQLite operation on hook");
289
+ }
290
+ }
291
+
255
292
  } // namespace opsqlite
package/cpp/utils.h CHANGED
@@ -37,6 +37,10 @@ bool folder_exists(const std::string &foldername);
37
37
 
38
38
  bool file_exists(const std::string &path);
39
39
 
40
+ std::string get_uuid();
41
+
42
+ std::string sqlite_operation_to_string(int operation_type);
43
+
40
44
  } // namespace opsqlite
41
45
 
42
46
  #endif /* utils_h */
package/op-sqlite.podspec CHANGED
@@ -28,7 +28,7 @@ Pod::Spec.new do |s|
28
28
  if ENV['OP_SQLITE_USE_SQLCIPHER'] == '1' then
29
29
  puts "OP-SQLITE using SQLCipher! 🔒\n"
30
30
  s.exclude_files = "cpp/sqlite3.c", "cpp/sqlite3.h"
31
- xcconfig[:GCC_PREPROCESSOR_DEFINITIONS] += " OP_SQLITE_USE_SQLCIPHER=1"
31
+ xcconfig[:GCC_PREPROCESSOR_DEFINITIONS] += " OP_SQLITE_USE_SQLCIPHER=1 SQLITE_HAS_CODEC SQLITE_TEMP_STORE=2"
32
32
  else
33
33
  puts "OP-SQLITE using SQLite! 📦\n"
34
34
  s.exclude_files = "cpp/sqlcipher/sqlite3.c", "cpp/sqlcipher/sqlite3.h"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@op-engineering/op-sqlite",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Next generation SQLite for React Native",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",