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.
- package/LICENSE +21 -0
- package/NOTICE.md +38 -0
- package/PomegranateDB.podspec +67 -0
- package/README.md +122 -0
- package/dist/adapters/expo-sqlite/ExpoSQLiteDriver.d.ts +34 -0
- package/dist/adapters/expo-sqlite/ExpoSQLiteDriver.js +155 -0
- package/dist/adapters/expo-sqlite/index.d.ts +2 -0
- package/dist/adapters/expo-sqlite/index.js +6 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.js +13 -0
- package/dist/adapters/loki/LokiAdapter.d.ts +100 -0
- package/dist/adapters/loki/LokiAdapter.js +144 -0
- package/dist/adapters/loki/index.d.ts +6 -0
- package/dist/adapters/loki/index.js +12 -0
- package/dist/adapters/loki/worker/LokiDispatcher.d.ts +21 -0
- package/dist/adapters/loki/worker/LokiDispatcher.js +63 -0
- package/dist/adapters/loki/worker/LokiExecutor.d.ts +96 -0
- package/dist/adapters/loki/worker/LokiExecutor.js +462 -0
- package/dist/adapters/loki/worker/SynchronousWorker.d.ts +22 -0
- package/dist/adapters/loki/worker/SynchronousWorker.js +76 -0
- package/dist/adapters/loki/worker/loki.worker.d.ts +14 -0
- package/dist/adapters/loki/worker/loki.worker.js +112 -0
- package/dist/adapters/loki/worker/types.d.ts +44 -0
- package/dist/adapters/loki/worker/types.js +11 -0
- package/dist/adapters/native-sqlite/NativeSQLiteDriver.d.ts +55 -0
- package/dist/adapters/native-sqlite/NativeSQLiteDriver.js +145 -0
- package/dist/adapters/native-sqlite/index.d.ts +2 -0
- package/dist/adapters/native-sqlite/index.js +6 -0
- package/dist/adapters/op-sqlite/OpSQLiteDriver.d.ts +49 -0
- package/dist/adapters/op-sqlite/OpSQLiteDriver.js +140 -0
- package/dist/adapters/op-sqlite/index.d.ts +2 -0
- package/dist/adapters/op-sqlite/index.js +6 -0
- package/dist/adapters/sqlite/SQLiteAdapter.d.ts +70 -0
- package/dist/adapters/sqlite/SQLiteAdapter.js +264 -0
- package/dist/adapters/sqlite/index.d.ts +2 -0
- package/dist/adapters/sqlite/index.js +6 -0
- package/dist/adapters/sqlite/sql.d.ts +35 -0
- package/dist/adapters/sqlite/sql.js +258 -0
- package/dist/adapters/types.d.ts +93 -0
- package/dist/adapters/types.js +9 -0
- package/dist/collection/Collection.d.ts +103 -0
- package/dist/collection/Collection.js +245 -0
- package/dist/collection/index.d.ts +2 -0
- package/dist/collection/index.js +6 -0
- package/dist/database/Database.d.ts +128 -0
- package/dist/database/Database.js +245 -0
- package/dist/database/index.d.ts +2 -0
- package/dist/database/index.js +6 -0
- package/dist/encryption/index.d.ts +62 -0
- package/dist/encryption/index.js +276 -0
- package/dist/encryption/nodeCrypto.d.ts +18 -0
- package/dist/encryption/nodeCrypto.js +25 -0
- package/dist/encryption/nodeCrypto.native.d.ts +13 -0
- package/dist/encryption/nodeCrypto.native.js +26 -0
- package/dist/expo.d.ts +12 -0
- package/dist/expo.js +32 -0
- package/dist/hooks/index.d.ts +115 -0
- package/dist/hooks/index.js +285 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +57 -0
- package/dist/model/Model.d.ts +92 -0
- package/dist/model/Model.js +251 -0
- package/dist/model/index.d.ts +2 -0
- package/dist/model/index.js +7 -0
- package/dist/observable/Subject.d.ts +60 -0
- package/dist/observable/Subject.js +132 -0
- package/dist/observable/index.d.ts +2 -0
- package/dist/observable/index.js +10 -0
- package/dist/query/QueryBuilder.d.ts +51 -0
- package/dist/query/QueryBuilder.js +165 -0
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +7 -0
- package/dist/query/types.d.ts +60 -0
- package/dist/query/types.js +9 -0
- package/dist/schema/builder.d.ts +68 -0
- package/dist/schema/builder.js +168 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +7 -0
- package/dist/schema/types.d.ts +108 -0
- package/dist/schema/types.js +9 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.js +6 -0
- package/dist/sync/sync.d.ts +15 -0
- package/dist/sync/sync.js +182 -0
- package/dist/sync/types.d.ts +41 -0
- package/dist/sync/types.js +6 -0
- package/dist/utils/index.d.ts +45 -0
- package/dist/utils/index.js +99 -0
- package/expo-plugin/index.d.ts +68 -0
- package/expo-plugin/index.js +83 -0
- package/native/android-jsi/build.gradle +45 -0
- package/native/android-jsi/src/main/AndroidManifest.xml +2 -0
- package/native/android-jsi/src/main/cpp/CMakeLists.txt +73 -0
- package/native/android-jsi/src/main/cpp/DatabasePlatformAndroid.cpp +107 -0
- package/native/android-jsi/src/main/cpp/DatabasePlatformAndroid.h +16 -0
- package/native/android-jsi/src/main/cpp/JSIInstaller.cpp +27 -0
- package/native/android-jsi/src/main/java/com/pomegranate/jsi/JSIInstaller.kt +43 -0
- package/native/android-jsi/src/main/java/com/pomegranate/jsi/PomegranateJSIModule.kt +39 -0
- package/native/android-jsi/src/main/java/com/pomegranate/jsi/PomegranateJSIPackage.kt +17 -0
- package/native/ios/DatabasePlatformIOS.mm +83 -0
- package/native/ios/PomegranateJSI.h +15 -0
- package/native/ios/PomegranateJSI.mm +59 -0
- package/native/shared/Database.cpp +283 -0
- package/native/shared/Database.h +84 -0
- package/native/shared/Sqlite.cpp +61 -0
- package/native/shared/Sqlite.h +67 -0
- package/native/shared/sqlite3/sqlite3.c +260493 -0
- package/native/shared/sqlite3/sqlite3.h +13583 -0
- package/package.json +127 -0
- 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,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';
|