pomegranate-db 0.1.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.
Files changed (110) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +38 -0
  3. package/PomegranateDB.podspec +67 -0
  4. package/README.md +122 -0
  5. package/dist/adapters/expo-sqlite/ExpoSQLiteDriver.d.ts +34 -0
  6. package/dist/adapters/expo-sqlite/ExpoSQLiteDriver.js +155 -0
  7. package/dist/adapters/expo-sqlite/index.d.ts +2 -0
  8. package/dist/adapters/expo-sqlite/index.js +6 -0
  9. package/dist/adapters/index.d.ts +7 -0
  10. package/dist/adapters/index.js +13 -0
  11. package/dist/adapters/loki/LokiAdapter.d.ts +100 -0
  12. package/dist/adapters/loki/LokiAdapter.js +144 -0
  13. package/dist/adapters/loki/index.d.ts +6 -0
  14. package/dist/adapters/loki/index.js +12 -0
  15. package/dist/adapters/loki/worker/LokiDispatcher.d.ts +21 -0
  16. package/dist/adapters/loki/worker/LokiDispatcher.js +63 -0
  17. package/dist/adapters/loki/worker/LokiExecutor.d.ts +96 -0
  18. package/dist/adapters/loki/worker/LokiExecutor.js +462 -0
  19. package/dist/adapters/loki/worker/SynchronousWorker.d.ts +22 -0
  20. package/dist/adapters/loki/worker/SynchronousWorker.js +76 -0
  21. package/dist/adapters/loki/worker/loki.worker.d.ts +14 -0
  22. package/dist/adapters/loki/worker/loki.worker.js +112 -0
  23. package/dist/adapters/loki/worker/types.d.ts +44 -0
  24. package/dist/adapters/loki/worker/types.js +11 -0
  25. package/dist/adapters/native-sqlite/NativeSQLiteDriver.d.ts +55 -0
  26. package/dist/adapters/native-sqlite/NativeSQLiteDriver.js +145 -0
  27. package/dist/adapters/native-sqlite/index.d.ts +2 -0
  28. package/dist/adapters/native-sqlite/index.js +6 -0
  29. package/dist/adapters/op-sqlite/OpSQLiteDriver.d.ts +49 -0
  30. package/dist/adapters/op-sqlite/OpSQLiteDriver.js +140 -0
  31. package/dist/adapters/op-sqlite/index.d.ts +2 -0
  32. package/dist/adapters/op-sqlite/index.js +6 -0
  33. package/dist/adapters/sqlite/SQLiteAdapter.d.ts +70 -0
  34. package/dist/adapters/sqlite/SQLiteAdapter.js +264 -0
  35. package/dist/adapters/sqlite/index.d.ts +2 -0
  36. package/dist/adapters/sqlite/index.js +6 -0
  37. package/dist/adapters/sqlite/sql.d.ts +35 -0
  38. package/dist/adapters/sqlite/sql.js +258 -0
  39. package/dist/adapters/types.d.ts +93 -0
  40. package/dist/adapters/types.js +9 -0
  41. package/dist/collection/Collection.d.ts +103 -0
  42. package/dist/collection/Collection.js +245 -0
  43. package/dist/collection/index.d.ts +2 -0
  44. package/dist/collection/index.js +6 -0
  45. package/dist/database/Database.d.ts +128 -0
  46. package/dist/database/Database.js +245 -0
  47. package/dist/database/index.d.ts +2 -0
  48. package/dist/database/index.js +6 -0
  49. package/dist/encryption/index.d.ts +62 -0
  50. package/dist/encryption/index.js +276 -0
  51. package/dist/encryption/nodeCrypto.d.ts +18 -0
  52. package/dist/encryption/nodeCrypto.js +25 -0
  53. package/dist/encryption/nodeCrypto.native.d.ts +13 -0
  54. package/dist/encryption/nodeCrypto.native.js +26 -0
  55. package/dist/expo.d.ts +12 -0
  56. package/dist/expo.js +32 -0
  57. package/dist/hooks/index.d.ts +115 -0
  58. package/dist/hooks/index.js +285 -0
  59. package/dist/index.d.ts +29 -0
  60. package/dist/index.js +57 -0
  61. package/dist/model/Model.d.ts +92 -0
  62. package/dist/model/Model.js +251 -0
  63. package/dist/model/index.d.ts +2 -0
  64. package/dist/model/index.js +7 -0
  65. package/dist/observable/Subject.d.ts +60 -0
  66. package/dist/observable/Subject.js +132 -0
  67. package/dist/observable/index.d.ts +2 -0
  68. package/dist/observable/index.js +10 -0
  69. package/dist/query/QueryBuilder.d.ts +51 -0
  70. package/dist/query/QueryBuilder.js +165 -0
  71. package/dist/query/index.d.ts +2 -0
  72. package/dist/query/index.js +7 -0
  73. package/dist/query/types.d.ts +60 -0
  74. package/dist/query/types.js +9 -0
  75. package/dist/schema/builder.d.ts +68 -0
  76. package/dist/schema/builder.js +168 -0
  77. package/dist/schema/index.d.ts +2 -0
  78. package/dist/schema/index.js +7 -0
  79. package/dist/schema/types.d.ts +108 -0
  80. package/dist/schema/types.js +9 -0
  81. package/dist/sync/index.d.ts +2 -0
  82. package/dist/sync/index.js +6 -0
  83. package/dist/sync/sync.d.ts +15 -0
  84. package/dist/sync/sync.js +182 -0
  85. package/dist/sync/types.d.ts +41 -0
  86. package/dist/sync/types.js +6 -0
  87. package/dist/utils/index.d.ts +45 -0
  88. package/dist/utils/index.js +99 -0
  89. package/expo-plugin/index.d.ts +68 -0
  90. package/expo-plugin/index.js +83 -0
  91. package/native/android-jsi/build.gradle +45 -0
  92. package/native/android-jsi/src/main/AndroidManifest.xml +2 -0
  93. package/native/android-jsi/src/main/cpp/CMakeLists.txt +73 -0
  94. package/native/android-jsi/src/main/cpp/DatabasePlatformAndroid.cpp +107 -0
  95. package/native/android-jsi/src/main/cpp/DatabasePlatformAndroid.h +16 -0
  96. package/native/android-jsi/src/main/cpp/JSIInstaller.cpp +27 -0
  97. package/native/android-jsi/src/main/java/com/pomegranate/jsi/JSIInstaller.kt +43 -0
  98. package/native/android-jsi/src/main/java/com/pomegranate/jsi/PomegranateJSIModule.kt +39 -0
  99. package/native/android-jsi/src/main/java/com/pomegranate/jsi/PomegranateJSIPackage.kt +17 -0
  100. package/native/ios/DatabasePlatformIOS.mm +83 -0
  101. package/native/ios/PomegranateJSI.h +15 -0
  102. package/native/ios/PomegranateJSI.mm +59 -0
  103. package/native/shared/Database.cpp +283 -0
  104. package/native/shared/Database.h +84 -0
  105. package/native/shared/Sqlite.cpp +61 -0
  106. package/native/shared/Sqlite.h +67 -0
  107. package/native/shared/sqlite3/sqlite3.c +260493 -0
  108. package/native/shared/sqlite3/sqlite3.h +13583 -0
  109. package/package.json +127 -0
  110. package/react-native.config.js +28 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-present PomegranateDB contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,38 @@
1
+ # NOTICE
2
+
3
+ ## Acknowledgements
4
+
5
+ PomegranateDB was inspired by and developed with reference to
6
+ [WatermelonDB](https://github.com/Nozbe/WatermelonDB) by Nozbe.
7
+
8
+ Portions of this codebase were adapted from WatermelonDB's source code. Huge
9
+ thanks to the WatermelonDB team for their pioneering work on reactive,
10
+ offline-first databases for React Native and web applications.
11
+
12
+ ---
13
+
14
+ ## WatermelonDB License
15
+
16
+ ```
17
+ MIT License
18
+
19
+ Copyright (c) Nozbe
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining a copy
22
+ of this software and associated documentation files (the "Software"), to deal
23
+ in the Software without restriction, including without limitation the rights
24
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
+ copies of the Software, and to permit persons to whom the Software is
26
+ furnished to do so, subject to the following conditions:
27
+
28
+ The above copyright notice and this permission notice shall be included in all
29
+ copies or substantial portions of the Software.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37
+ SOFTWARE.
38
+ ```
@@ -0,0 +1,67 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "PomegranateDB"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.description = package["description"]
10
+ s.homepage = "https://github.com/#{package.dig("repository", "url") || "bobbyquantum/pomegranate"}"
11
+ s.license = { :type => "MIT", :file => "LICENSE" }
12
+ s.author = { "bobbyquantum" => "" }
13
+ s.platforms = { :ios => "13.0" }
14
+ s.source = { :git => "https://github.com/bobbyquantum/pomegranate.git",
15
+ :tag => "v#{s.version}" }
16
+
17
+ # ─── Source files ────────────────────────────────────────────────────────────
18
+ #
19
+ # iOS platform glue (Obj-C++ bridge + platform implementation)
20
+ # + shared C++ JSI core (Database.cpp/h, Sqlite.cpp/h)
21
+ #
22
+ # NOTE: We intentionally exclude native/shared/sqlite3/ here; iOS links the
23
+ # system SQLite via s.libraries below, so we must not compile the amalgamation
24
+ # twice.
25
+ s.source_files = [
26
+ "native/ios/**/*.{h,m,mm}",
27
+ "native/shared/*.{h,cpp}",
28
+ ]
29
+
30
+ s.public_header_files = [
31
+ "native/ios/PomegranateJSI.h",
32
+ ]
33
+
34
+ # ─── Compiler settings ───────────────────────────────────────────────────────
35
+
36
+ s.requires_arc = true
37
+
38
+ # Optimise for size/speed even in debug — JSI is noticeably slower without it.
39
+ s.compiler_flags = "-Os"
40
+
41
+ s.pod_target_xcconfig = {
42
+ # C++17 features (structured bindings, string_view, …)
43
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
44
+ "CLANG_CXX_LIBRARY" => "libc++",
45
+ # Find jsi/jsi.h from React Native's ReactCommon
46
+ "HEADER_SEARCH_PATHS" => [
47
+ '"$(PODS_ROOT)/Headers/Public/React-Core"',
48
+ '"$(PODS_ROOT)/Headers/Public"',
49
+ '"$(PODS_TARGET_SRCROOT)/native/shared"',
50
+ '"$(PODS_TARGET_SRCROOT)/native/ios"',
51
+ ].join(" "),
52
+ # Silence noise from mixing C and C++ TUs
53
+ "GCC_WARN_INHIBIT_ALL_WARNINGS" => "NO",
54
+ }
55
+
56
+ # ─── System libraries ────────────────────────────────────────────────────────
57
+
58
+ # Link the iOS/macOS system SQLite (sqlite3.h is in the SDK, no amalgamation needed)
59
+ s.libraries = "sqlite3"
60
+
61
+ # ─── Dependencies ────────────────────────────────────────────────────────────
62
+
63
+ # React-Core brings in React-jsi transitively (as of RN 0.71+).
64
+ # Specifying React-jsi directly fails pod spec lint because it isn't in the
65
+ # public trunk — it resolves from the consuming app's node_modules at install time.
66
+ s.dependency "React-Core"
67
+ end
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ <p align="center">
2
+ <img src="docs-website/static/img/logo.png" alt="PomegranateDB" width="200" />
3
+ </p>
4
+
5
+ <h2 align="center">PomegranateDB</h2>
6
+
7
+ <h4 align="center">
8
+ Reactive offline-first database for React Native & Expo
9
+ </h4>
10
+
11
+ <p align="center">
12
+ Build powerful React and React Native apps that scale from hundreds to tens of thousands of records and remain <em>fast</em> ⚡️
13
+ </p>
14
+
15
+ ---
16
+
17
+ ### ⚡️ Instant Launch
18
+ Lazy-loaded — only fetch data when you need it. Your app starts fast no matter how much data you have.
19
+
20
+ ### 📈 Highly Scalable
21
+ Handle hundreds to tens of thousands of records with consistent performance.
22
+
23
+ ### 🔄 Offline-First
24
+ Built-in sync protocol with push/pull reconciliation. Works offline, syncs when connected.
25
+
26
+ ### ⚛️ Optimized for React
27
+ Reactive hooks keep your UI in sync automatically. Zero boilerplate subscriptions.
28
+
29
+ ### 🔌 Pluggable Adapters
30
+ LokiJS, Expo SQLite, op-sqlite, or JSI C++. Swap storage backends without changing app code.
31
+
32
+ ### 🔐 Encryption at Rest
33
+ Optional AES-GCM encryption or SQLCipher via op-sqlite. Protect user data on-device.
34
+
35
+ ---
36
+
37
+ ## Why PomegranateDB?
38
+
39
+ - **Schema-first**: Define your models declaratively with full type inference
40
+ - **Reactive queries**: UI updates automatically when data changes — via hooks or observables
41
+ - **Offline-first sync**: Built-in pull/push protocol that works offline and reconciles on reconnect
42
+ - **Pluggable adapters**: Choose the right storage backend for your app — LokiJS (in-memory), Expo SQLite, op-sqlite, or our own JSI C++ adapter
43
+ - **TypeScript-native**: The whole codebase is idiomatic TypeScript. Types flow from schema to model to query to component
44
+
45
+ ## Quick Example
46
+
47
+ ```ts
48
+ import { m, Model, Database, LokiAdapter } from 'pomegranate-db';
49
+
50
+ // 1. Define your schema
51
+ const PostSchema = m.model('posts', {
52
+ title: m.text(),
53
+ body: m.text(),
54
+ status: m.text(),
55
+ createdAt: m.date('created_at').readonly(),
56
+ });
57
+
58
+ // 2. Create a model class
59
+ class Post extends Model<typeof PostSchema> {
60
+ static schema = PostSchema;
61
+ }
62
+
63
+ // 3. Initialize the database
64
+ const db = new Database({
65
+ adapter: new LokiAdapter({ databaseName: 'myapp' }),
66
+ models: [Post],
67
+ });
68
+
69
+ await db.initialize();
70
+
71
+ // 4. Write data
72
+ await db.write(async () => {
73
+ await db.get(Post).create({
74
+ title: 'Hello World',
75
+ body: 'My first post',
76
+ status: 'draft',
77
+ });
78
+ });
79
+
80
+ // 5. Query data
81
+ const posts = await db.get(Post)
82
+ .query()
83
+ .where('status', 'draft')
84
+ .fetch();
85
+ ```
86
+
87
+ ## React Integration
88
+
89
+ ```tsx
90
+ import { DatabaseProvider, useLiveQuery } from 'pomegranate-db';
91
+
92
+ function App() {
93
+ return (
94
+ <DatabaseProvider value={db}>
95
+ <PostList />
96
+ </DatabaseProvider>
97
+ );
98
+ }
99
+
100
+ function PostList() {
101
+ const { results: posts, isLoading } = useLiveQuery(Post, (q) =>
102
+ q.where('status', 'eq', 'published').orderBy('created_at', 'desc'),
103
+ );
104
+
105
+ if (isLoading) return <Text>Loading...</Text>;
106
+
107
+ return posts.map((post) => (
108
+ <Text key={post.id}>{post.title}</Text>
109
+ ));
110
+ }
111
+ ```
112
+
113
+ ## Next Steps
114
+
115
+ - [Installation](https://bobbyquantum.github.io/pomegranate/docs/installation) — add PomegranateDB to your project
116
+ - [Schema & Models](https://bobbyquantum.github.io/pomegranate/docs/schema) — define your data model
117
+ - [CRUD Operations](https://bobbyquantum.github.io/pomegranate/docs/crud) — create, read, update, delete
118
+ - [React Hooks](https://bobbyquantum.github.io/pomegranate/docs/react-hooks) — reactive UI integration
119
+
120
+ ## License
121
+
122
+ MIT
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Expo SQLite Driver.
3
+ *
4
+ * Implements the SQLiteDriver interface using expo-sqlite (v14+).
5
+ * This enables PomegranateDB to work seamlessly in Expo projects
6
+ * using the Expo managed SQLite library instead of requiring
7
+ * react-native-quick-sqlite or op-sqlite.
8
+ *
9
+ * Usage:
10
+ * import { createExpoSQLiteDriver } from 'pomegranate-db/expo';
11
+ * import { SQLiteAdapter } from 'pomegranate-db';
12
+ *
13
+ * const adapter = new SQLiteAdapter({
14
+ * databaseName: 'myapp',
15
+ * driver: createExpoSQLiteDriver(),
16
+ * });
17
+ */
18
+ import type { SQLiteDriver } from '../sqlite/SQLiteAdapter';
19
+ export interface ExpoSQLiteDriverConfig {
20
+ /**
21
+ * Options passed to expo-sqlite's openDatabaseAsync.
22
+ * @default {}
23
+ */
24
+ openOptions?: {
25
+ enableChangeListener?: boolean;
26
+ };
27
+ }
28
+ /**
29
+ * Create a SQLiteDriver backed by expo-sqlite.
30
+ *
31
+ * expo-sqlite must be installed in the consuming project:
32
+ * npx expo install expo-sqlite
33
+ */
34
+ export declare function createExpoSQLiteDriver(config?: ExpoSQLiteDriverConfig): SQLiteDriver;
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ /**
3
+ * Expo SQLite Driver.
4
+ *
5
+ * Implements the SQLiteDriver interface using expo-sqlite (v14+).
6
+ * This enables PomegranateDB to work seamlessly in Expo projects
7
+ * using the Expo managed SQLite library instead of requiring
8
+ * react-native-quick-sqlite or op-sqlite.
9
+ *
10
+ * Usage:
11
+ * import { createExpoSQLiteDriver } from 'pomegranate-db/expo';
12
+ * import { SQLiteAdapter } from 'pomegranate-db';
13
+ *
14
+ * const adapter = new SQLiteAdapter({
15
+ * databaseName: 'myapp',
16
+ * driver: createExpoSQLiteDriver(),
17
+ * });
18
+ */
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ var desc = Object.getOwnPropertyDescriptor(m, k);
22
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
+ desc = { enumerable: true, get: function() { return m[k]; } };
24
+ }
25
+ Object.defineProperty(o, k2, desc);
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || (function () {
36
+ var ownKeys = function(o) {
37
+ ownKeys = Object.getOwnPropertyNames || function (o) {
38
+ var ar = [];
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
+ return ar;
41
+ };
42
+ return ownKeys(o);
43
+ };
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ })();
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.createExpoSQLiteDriver = createExpoSQLiteDriver;
54
+ /**
55
+ * Create a SQLiteDriver backed by expo-sqlite.
56
+ *
57
+ * expo-sqlite must be installed in the consuming project:
58
+ * npx expo install expo-sqlite
59
+ */
60
+ function createExpoSQLiteDriver(config) {
61
+ let db = null;
62
+ let expoSQLite = null;
63
+ // Lazily import expo-sqlite so this module can be imported
64
+ // without expo-sqlite being installed (e.g. in tests).
65
+ async function getExpoSQLite() {
66
+ if (!expoSQLite) {
67
+ try {
68
+ // @ts-expect-error — expo-sqlite is an optional peer dependency
69
+ expoSQLite = (await Promise.resolve().then(() => __importStar(require('expo-sqlite'))));
70
+ }
71
+ catch {
72
+ throw new Error('expo-sqlite is not installed. Install it with: npx expo install expo-sqlite');
73
+ }
74
+ }
75
+ return expoSQLite;
76
+ }
77
+ function requireDb() {
78
+ if (!db) {
79
+ throw new Error('Database not open. Call open() first.');
80
+ }
81
+ return db;
82
+ }
83
+ return {
84
+ async open(name) {
85
+ const sqlite = await getExpoSQLite();
86
+ db = await sqlite.openDatabaseAsync(name.endsWith('.db') ? name : `${name}.db`, config?.openOptions);
87
+ // Enable WAL mode for better performance (may not be supported on web/wa-sqlite)
88
+ try {
89
+ await db.execAsync('PRAGMA journal_mode = WAL');
90
+ }
91
+ catch {
92
+ // WAL not supported on this platform (e.g. web wa-sqlite), continue without it
93
+ }
94
+ },
95
+ async execute(sql, bindings) {
96
+ const database = requireDb();
97
+ if (bindings && bindings.length > 0) {
98
+ await database.runAsync(sql, ...bindings);
99
+ }
100
+ else {
101
+ await database.execAsync(sql);
102
+ }
103
+ },
104
+ async query(sql, bindings) {
105
+ const database = requireDb();
106
+ if (bindings && bindings.length > 0) {
107
+ return database.getAllAsync(sql, ...bindings);
108
+ }
109
+ return database.getAllAsync(sql);
110
+ },
111
+ async executeInTransaction(fn) {
112
+ const database = requireDb();
113
+ // expo-sqlite's withExclusiveTransactionAsync is not supported on web.
114
+ // Fall back to manual BEGIN/COMMIT/ROLLBACK for web compatibility.
115
+ if (typeof database.withExclusiveTransactionAsync === 'function') {
116
+ try {
117
+ await database.withExclusiveTransactionAsync(async (_txn) => {
118
+ // expo-sqlite's exclusive transaction scopes all queries
119
+ // on this database connection to the transaction, so we
120
+ // can just call fn() which uses the same `db` reference.
121
+ await fn();
122
+ });
123
+ return;
124
+ }
125
+ catch (e) {
126
+ // On web, withExclusiveTransactionAsync throws even though the method exists.
127
+ // Detect this and fall through to manual transaction handling.
128
+ if (e instanceof Error && e.message.includes('not supported on web')) {
129
+ // Fall through to manual transaction below
130
+ }
131
+ else {
132
+ throw e;
133
+ }
134
+ }
135
+ }
136
+ // Manual transaction fallback (web, or platforms without exclusive transactions)
137
+ await database.execAsync('BEGIN TRANSACTION');
138
+ try {
139
+ await fn();
140
+ await database.execAsync('COMMIT');
141
+ }
142
+ catch (e) {
143
+ await database.execAsync('ROLLBACK');
144
+ throw e;
145
+ }
146
+ },
147
+ async close() {
148
+ if (db) {
149
+ await db.closeAsync();
150
+ db = null;
151
+ }
152
+ },
153
+ };
154
+ }
155
+ //# sourceMappingURL=ExpoSQLiteDriver.js.map
@@ -0,0 +1,2 @@
1
+ export { createExpoSQLiteDriver } from './ExpoSQLiteDriver';
2
+ export type { ExpoSQLiteDriverConfig } from './ExpoSQLiteDriver';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createExpoSQLiteDriver = void 0;
4
+ var ExpoSQLiteDriver_1 = require("./ExpoSQLiteDriver");
5
+ Object.defineProperty(exports, "createExpoSQLiteDriver", { enumerable: true, get: function () { return ExpoSQLiteDriver_1.createExpoSQLiteDriver; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ export type { StorageAdapter, AdapterConfig, EncryptionConfig, Migration, MigrationStep, } from './types';
2
+ export { SQLiteAdapter } from './sqlite';
3
+ export type { SQLiteAdapterConfig, SQLiteDriver } from './sqlite';
4
+ export { LokiAdapter, LokiExecutor, LokiDispatcher, SynchronousWorker } from './loki';
5
+ export type { LokiAdapterConfig, LokiExecutorConfig, WorkerInterface } from './loki';
6
+ export { createExpoSQLiteDriver } from './expo-sqlite';
7
+ export type { ExpoSQLiteDriverConfig } from './expo-sqlite';
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createExpoSQLiteDriver = exports.SynchronousWorker = exports.LokiDispatcher = exports.LokiExecutor = exports.LokiAdapter = exports.SQLiteAdapter = void 0;
4
+ var sqlite_1 = require("./sqlite");
5
+ Object.defineProperty(exports, "SQLiteAdapter", { enumerable: true, get: function () { return sqlite_1.SQLiteAdapter; } });
6
+ var loki_1 = require("./loki");
7
+ Object.defineProperty(exports, "LokiAdapter", { enumerable: true, get: function () { return loki_1.LokiAdapter; } });
8
+ Object.defineProperty(exports, "LokiExecutor", { enumerable: true, get: function () { return loki_1.LokiExecutor; } });
9
+ Object.defineProperty(exports, "LokiDispatcher", { enumerable: true, get: function () { return loki_1.LokiDispatcher; } });
10
+ Object.defineProperty(exports, "SynchronousWorker", { enumerable: true, get: function () { return loki_1.SynchronousWorker; } });
11
+ var expo_sqlite_1 = require("./expo-sqlite");
12
+ Object.defineProperty(exports, "createExpoSQLiteDriver", { enumerable: true, get: function () { return expo_sqlite_1.createExpoSQLiteDriver; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,100 @@
1
+ /**
2
+ * LokiJS Adapter.
3
+ *
4
+ * In-memory database adapter using LokiJS, suitable for web and testing.
5
+ * Supports running LokiJS in a Web Worker for better UI performance.
6
+ *
7
+ * Architecture:
8
+ * - Direct mode (default): LokiExecutor runs in the main thread.
9
+ * - Worker mode: All operations are dispatched via postMessage to a Web Worker
10
+ * (or SynchronousWorker for testing) that runs LokiExecutor internally.
11
+ *
12
+ * ```
13
+ * LokiAdapter ──▶ LokiExecutor (direct mode)
14
+ * │
15
+ * └──▶ LokiDispatcher ──▶ [Worker] ──▶ LokiExecutor (worker mode)
16
+ * ```
17
+ */
18
+ import type { StorageAdapter, AdapterConfig, Migration } from '../types';
19
+ import type { QueryDescriptor, SearchDescriptor, BatchOperation } from '../../query/types';
20
+ import type { DatabaseSchema, RawRecord } from '../../schema/types';
21
+ import type { WorkerInterface } from './worker/types';
22
+ export interface LokiAdapterConfig extends AdapterConfig {
23
+ /** Optional: provide your own Loki instance (direct mode only, not serializable). */
24
+ lokiInstance?: unknown;
25
+ /** Optional: LokiJS persistence adapter (e.g., IncrementalIndexedDBAdapter). Direct mode only. */
26
+ persistenceAdapter?: unknown;
27
+ /**
28
+ * When to persist data to storage. Only applies when `persistenceAdapter` is set
29
+ * (direct mode) or when running in a worker (which auto-creates IndexedDB persistence).
30
+ *
31
+ * - `'immediate'` — save after every mutation. Safest; data survives instant refresh.
32
+ * Slightly slower for rapid writes. **(default)**
33
+ * - `'auto'` — use LokiJS autosave timer (`autosaveInterval` ms). Faster for bulk
34
+ * writes but data written in the last interval may be lost on hard refresh.
35
+ */
36
+ saveStrategy?: 'immediate' | 'auto';
37
+ /** Autosave interval in ms when `saveStrategy: 'auto'`. Default: 500. */
38
+ autosaveInterval?: number;
39
+ /**
40
+ * Web Worker instance for off-main-thread LokiJS execution.
41
+ * When provided, all database operations dispatch to this worker via postMessage.
42
+ * The worker auto-creates IncrementalIDBAdapter for IndexedDB persistence.
43
+ *
44
+ * @example
45
+ * // Real Web Worker (bundler must support worker URLs):
46
+ * import { LokiAdapter } from 'pomegranate-db';
47
+ * const worker = new Worker(
48
+ * new URL('pomegranate-db/dist/adapters/loki/worker/loki.worker.js', import.meta.url),
49
+ * );
50
+ * const adapter = new LokiAdapter({ databaseName: 'app', worker });
51
+ *
52
+ * @example
53
+ * // Synchronous fallback (for testing the worker protocol):
54
+ * import { LokiAdapter, SynchronousWorker } from 'pomegranate-db';
55
+ * const adapter = new LokiAdapter({ databaseName: 'test', worker: new SynchronousWorker() });
56
+ */
57
+ worker?: WorkerInterface | Worker;
58
+ }
59
+ export declare class LokiAdapter implements StorageAdapter {
60
+ private _executor;
61
+ private _dispatcher;
62
+ private _config;
63
+ private _initialized;
64
+ constructor(config: LokiAdapterConfig);
65
+ initialize(schema: DatabaseSchema): Promise<void>;
66
+ /**
67
+ * Route a command to either the local executor or the remote worker.
68
+ * In worker mode, arguments are serialized via postMessage (structured cloning).
69
+ * In direct mode, the executor method is called directly.
70
+ */
71
+ private _call;
72
+ find(query: QueryDescriptor): Promise<RawRecord[]>;
73
+ count(query: QueryDescriptor): Promise<number>;
74
+ findById(table: string, id: string): Promise<RawRecord | null>;
75
+ insert(table: string, raw: RawRecord): Promise<void>;
76
+ update(table: string, raw: RawRecord): Promise<void>;
77
+ markAsDeleted(table: string, id: string): Promise<void>;
78
+ destroyPermanently(table: string, id: string): Promise<void>;
79
+ batch(operations: BatchOperation[]): Promise<void>;
80
+ search(descriptor: SearchDescriptor): Promise<{
81
+ records: RawRecord[];
82
+ total: number;
83
+ }>;
84
+ getLocalChanges(tables: string[]): Promise<Record<string, {
85
+ created: RawRecord[];
86
+ updated: RawRecord[];
87
+ deleted: string[];
88
+ }>>;
89
+ applyRemoteChanges(changes: Record<string, {
90
+ created: RawRecord[];
91
+ updated: RawRecord[];
92
+ deleted: string[];
93
+ }>): Promise<void>;
94
+ markAsSynced(table: string, ids: string[]): Promise<void>;
95
+ getSchemaVersion(): Promise<number>;
96
+ migrate(migrations: Migration[]): Promise<void>;
97
+ reset(): Promise<void>;
98
+ close(): Promise<void>;
99
+ }
100
+ export { type LokiExecutorConfig } from './worker/LokiExecutor';