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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the LokiJS Web Worker message protocol.
|
|
3
|
+
*
|
|
4
|
+
* Communication follows an RPC-over-postMessage pattern:
|
|
5
|
+
* - Main thread sends WorkerAction messages
|
|
6
|
+
* - Worker processes them sequentially and returns WorkerResponse messages
|
|
7
|
+
* - Matching is done via monotonically increasing message IDs (FIFO order)
|
|
8
|
+
*/
|
|
9
|
+
/** All valid command types that can be sent to the worker */
|
|
10
|
+
export type WorkerCommandType = 'setUp' | 'find' | 'count' | 'findById' | 'insert' | 'update' | 'markAsDeleted' | 'destroyPermanently' | 'batch' | 'search' | 'getLocalChanges' | 'applyRemoteChanges' | 'markAsSynced' | 'getSchemaVersion' | 'migrate' | 'reset' | 'close';
|
|
11
|
+
/** Message sent from main thread to worker */
|
|
12
|
+
export interface WorkerAction {
|
|
13
|
+
id: number;
|
|
14
|
+
type: WorkerCommandType;
|
|
15
|
+
payload: unknown[];
|
|
16
|
+
}
|
|
17
|
+
/** Discriminated union for success/error results */
|
|
18
|
+
export type WorkerResult<T = unknown> = {
|
|
19
|
+
value: T;
|
|
20
|
+
} | {
|
|
21
|
+
error: {
|
|
22
|
+
message: string;
|
|
23
|
+
stack?: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/** Message sent from worker back to main thread */
|
|
27
|
+
export interface WorkerResponse {
|
|
28
|
+
id: number;
|
|
29
|
+
result: WorkerResult;
|
|
30
|
+
}
|
|
31
|
+
/** Serializable configuration passed to the worker during setUp */
|
|
32
|
+
export interface WorkerSetupPayload {
|
|
33
|
+
databaseName: string;
|
|
34
|
+
saveStrategy?: 'immediate' | 'auto';
|
|
35
|
+
autosaveInterval?: number;
|
|
36
|
+
}
|
|
37
|
+
/** Interface matching what Worker and SynchronousWorker both implement */
|
|
38
|
+
export interface WorkerInterface {
|
|
39
|
+
postMessage(data: unknown): void;
|
|
40
|
+
onmessage: ((event: {
|
|
41
|
+
data: unknown;
|
|
42
|
+
}) => void) | null;
|
|
43
|
+
terminate?(): void;
|
|
44
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared types for the LokiJS Web Worker message protocol.
|
|
4
|
+
*
|
|
5
|
+
* Communication follows an RPC-over-postMessage pattern:
|
|
6
|
+
* - Main thread sends WorkerAction messages
|
|
7
|
+
* - Worker processes them sequentially and returns WorkerResponse messages
|
|
8
|
+
* - Matching is done via monotonically increasing message IDs (FIFO order)
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native SQLite Driver (JSI).
|
|
3
|
+
*
|
|
4
|
+
* Implements the SQLiteDriver interface using PomegranateDB's own JSI
|
|
5
|
+
* C++ bridge. This is the fastest possible option — direct synchronous
|
|
6
|
+
* calls from JS to C++ SQLite with zero bridge overhead.
|
|
7
|
+
*
|
|
8
|
+
* Requires:
|
|
9
|
+
* - PomegranateJSIPackage added to MainApplication (Android)
|
|
10
|
+
* - The native C++ module built and linked (via android-jsi module)
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* import { SQLiteAdapter } from 'pomegranate-db';
|
|
14
|
+
* import { createNativeSQLiteDriver } from 'pomegranate-db/src/adapters/native-sqlite';
|
|
15
|
+
*
|
|
16
|
+
* const adapter = new SQLiteAdapter({
|
|
17
|
+
* databaseName: 'myapp',
|
|
18
|
+
* driver: createNativeSQLiteDriver(),
|
|
19
|
+
* });
|
|
20
|
+
*/
|
|
21
|
+
import type { SQLiteDriver } from '../sqlite/SQLiteAdapter';
|
|
22
|
+
/**
|
|
23
|
+
* The shape of the JSI adapter object returned by nativePomegranateCreateAdapter.
|
|
24
|
+
* All methods are synchronous JSI calls.
|
|
25
|
+
*/
|
|
26
|
+
interface NativeJSIAdapter {
|
|
27
|
+
execute(sql: string, args: unknown[]): void;
|
|
28
|
+
query(sql: string, args: unknown[]): Record<string, unknown>[];
|
|
29
|
+
executeBatch(commands: Array<{
|
|
30
|
+
sql: string;
|
|
31
|
+
args: unknown[];
|
|
32
|
+
}>): number;
|
|
33
|
+
close(): void;
|
|
34
|
+
}
|
|
35
|
+
declare global {
|
|
36
|
+
var nativePomegranateCreateAdapter: ((dbName: string) => NativeJSIAdapter) | undefined;
|
|
37
|
+
}
|
|
38
|
+
export interface NativeSQLiteDriverConfig {
|
|
39
|
+
/**
|
|
40
|
+
* If true, will attempt to auto-install the JSI binding by calling
|
|
41
|
+
* NativeModules.PomegranateJSIBridge.install().
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
autoInstall?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Create a SQLiteDriver backed by PomegranateDB's native JSI C++ bridge.
|
|
48
|
+
*
|
|
49
|
+
* This adapter communicates with C++ SQLite directly through JSI — no
|
|
50
|
+
* React Native bridge, no JSON serialization, no async queues.
|
|
51
|
+
* All calls are synchronous under the hood, wrapped in Promises for
|
|
52
|
+
* the SQLiteDriver interface.
|
|
53
|
+
*/
|
|
54
|
+
export declare function createNativeSQLiteDriver(config?: NativeSQLiteDriverConfig): SQLiteDriver;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Native SQLite Driver (JSI).
|
|
4
|
+
*
|
|
5
|
+
* Implements the SQLiteDriver interface using PomegranateDB's own JSI
|
|
6
|
+
* C++ bridge. This is the fastest possible option — direct synchronous
|
|
7
|
+
* calls from JS to C++ SQLite with zero bridge overhead.
|
|
8
|
+
*
|
|
9
|
+
* Requires:
|
|
10
|
+
* - PomegranateJSIPackage added to MainApplication (Android)
|
|
11
|
+
* - The native C++ module built and linked (via android-jsi module)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* import { SQLiteAdapter } from 'pomegranate-db';
|
|
15
|
+
* import { createNativeSQLiteDriver } from 'pomegranate-db/src/adapters/native-sqlite';
|
|
16
|
+
*
|
|
17
|
+
* const adapter = new SQLiteAdapter({
|
|
18
|
+
* databaseName: 'myapp',
|
|
19
|
+
* driver: createNativeSQLiteDriver(),
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
39
|
+
var ownKeys = function(o) {
|
|
40
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
41
|
+
var ar = [];
|
|
42
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
43
|
+
return ar;
|
|
44
|
+
};
|
|
45
|
+
return ownKeys(o);
|
|
46
|
+
};
|
|
47
|
+
return function (mod) {
|
|
48
|
+
if (mod && mod.__esModule) return mod;
|
|
49
|
+
var result = {};
|
|
50
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
51
|
+
__setModuleDefault(result, mod);
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
})();
|
|
55
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
+
exports.createNativeSQLiteDriver = createNativeSQLiteDriver;
|
|
57
|
+
// ─── Driver ───────────────────────────────────────────────────────────────
|
|
58
|
+
/**
|
|
59
|
+
* Create a SQLiteDriver backed by PomegranateDB's native JSI C++ bridge.
|
|
60
|
+
*
|
|
61
|
+
* This adapter communicates with C++ SQLite directly through JSI — no
|
|
62
|
+
* React Native bridge, no JSON serialization, no async queues.
|
|
63
|
+
* All calls are synchronous under the hood, wrapped in Promises for
|
|
64
|
+
* the SQLiteDriver interface.
|
|
65
|
+
*/
|
|
66
|
+
function createNativeSQLiteDriver(config) {
|
|
67
|
+
let adapter = null;
|
|
68
|
+
const autoInstall = config?.autoInstall !== false;
|
|
69
|
+
/**
|
|
70
|
+
* Ensure the JSI binding is installed.
|
|
71
|
+
* On Android, this requires calling NativeModules.PomegranateJSIBridge.install()
|
|
72
|
+
* which loads the .so and registers the global function.
|
|
73
|
+
*/
|
|
74
|
+
async function ensureInstalled() {
|
|
75
|
+
if (typeof globalThis.nativePomegranateCreateAdapter === 'function') {
|
|
76
|
+
return; // Already installed
|
|
77
|
+
}
|
|
78
|
+
if (!autoInstall) {
|
|
79
|
+
throw new Error('PomegranateDB JSI binding is not installed. ' +
|
|
80
|
+
'Call NativeModules.PomegranateJSIBridge.install() first, ' +
|
|
81
|
+
'or pass autoInstall: true to createNativeSQLiteDriver().');
|
|
82
|
+
}
|
|
83
|
+
// Auto-install by calling the native module
|
|
84
|
+
try {
|
|
85
|
+
const { NativeModules } = await Promise.resolve().then(() => __importStar(require('react-native')));
|
|
86
|
+
const bridge = NativeModules.PomegranateJSIBridge;
|
|
87
|
+
if (!bridge) {
|
|
88
|
+
throw new Error('PomegranateJSIBridge native module not found. ' +
|
|
89
|
+
'Make sure PomegranateJSIPackage is added to your MainApplication.');
|
|
90
|
+
}
|
|
91
|
+
const success = bridge.install();
|
|
92
|
+
if (!success) {
|
|
93
|
+
throw new Error('PomegranateJSIBridge.install() returned false');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
98
|
+
throw new Error('Failed to install PomegranateDB JSI binding: ' + message, { cause: error });
|
|
99
|
+
}
|
|
100
|
+
if (typeof globalThis.nativePomegranateCreateAdapter !== 'function') {
|
|
101
|
+
throw new TypeError('PomegranateDB JSI binding installation succeeded but ' +
|
|
102
|
+
'global.nativePomegranateCreateAdapter is not available. ' +
|
|
103
|
+
'This may indicate a native build issue.');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function requireAdapter() {
|
|
107
|
+
if (!adapter) {
|
|
108
|
+
throw new Error('Database not open. Call open() first.');
|
|
109
|
+
}
|
|
110
|
+
return adapter;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
async open(name) {
|
|
114
|
+
await ensureInstalled();
|
|
115
|
+
adapter = globalThis.nativePomegranateCreateAdapter(name);
|
|
116
|
+
},
|
|
117
|
+
async execute(sql, bindings) {
|
|
118
|
+
const db = requireAdapter();
|
|
119
|
+
db.execute(sql, bindings ?? []);
|
|
120
|
+
},
|
|
121
|
+
async query(sql, bindings) {
|
|
122
|
+
const db = requireAdapter();
|
|
123
|
+
return db.query(sql, bindings ?? []);
|
|
124
|
+
},
|
|
125
|
+
async executeInTransaction(fn) {
|
|
126
|
+
const db = requireAdapter();
|
|
127
|
+
db.execute('BEGIN EXCLUSIVE TRANSACTION', []);
|
|
128
|
+
try {
|
|
129
|
+
await fn();
|
|
130
|
+
db.execute('COMMIT', []);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
db.execute('ROLLBACK', []);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
async close() {
|
|
138
|
+
if (adapter) {
|
|
139
|
+
adapter.close();
|
|
140
|
+
adapter = null;
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=NativeSQLiteDriver.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNativeSQLiteDriver = void 0;
|
|
4
|
+
var NativeSQLiteDriver_1 = require("./NativeSQLiteDriver");
|
|
5
|
+
Object.defineProperty(exports, "createNativeSQLiteDriver", { enumerable: true, get: function () { return NativeSQLiteDriver_1.createNativeSQLiteDriver; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* op-sqlite Driver.
|
|
3
|
+
*
|
|
4
|
+
* Implements the SQLiteDriver interface using @op-engineering/op-sqlite.
|
|
5
|
+
* Provides JSI-based synchronous SQLite access for React Native apps
|
|
6
|
+
* — the fastest SQLite option for bare RN projects.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - JSI synchronous execution (no bridge overhead)
|
|
10
|
+
* - SQLCipher encryption support (via encryptionKey)
|
|
11
|
+
* - Prepared statement support
|
|
12
|
+
* - Batch execution in transactions
|
|
13
|
+
* - Update hooks for reactive queries
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* import { SQLiteAdapter } from 'pomegranate-db';
|
|
17
|
+
* import { createOpSQLiteDriver } from 'pomegranate-db/src/adapters/op-sqlite';
|
|
18
|
+
*
|
|
19
|
+
* const adapter = new SQLiteAdapter({
|
|
20
|
+
* databaseName: 'myapp',
|
|
21
|
+
* driver: createOpSQLiteDriver({ encryptionKey: 'secret' }),
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
import type { SQLiteDriver } from '../sqlite/SQLiteAdapter';
|
|
25
|
+
export interface OpSQLiteDriverConfig {
|
|
26
|
+
/**
|
|
27
|
+
* SQLCipher encryption key.
|
|
28
|
+
* If provided, the database will be encrypted at rest.
|
|
29
|
+
* Requires op-sqlite to be compiled with SQLCipher support.
|
|
30
|
+
*/
|
|
31
|
+
encryptionKey?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Custom storage location for the database file.
|
|
34
|
+
* If not specified, uses the app's default database directory.
|
|
35
|
+
*/
|
|
36
|
+
location?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Optional callback invoked on every database write.
|
|
39
|
+
* Useful for driving reactive queries / cache invalidation.
|
|
40
|
+
*/
|
|
41
|
+
onTableChanged?: (table: string, operation: 'INSERT' | 'UPDATE' | 'DELETE') => void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create a SQLiteDriver backed by @op-engineering/op-sqlite.
|
|
45
|
+
*
|
|
46
|
+
* @param config Optional driver configuration (encryption, hooks, etc.)
|
|
47
|
+
* @returns A SQLiteDriver that can be passed to SQLiteAdapter.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createOpSQLiteDriver(config?: OpSQLiteDriverConfig): SQLiteDriver;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* op-sqlite Driver.
|
|
4
|
+
*
|
|
5
|
+
* Implements the SQLiteDriver interface using @op-engineering/op-sqlite.
|
|
6
|
+
* Provides JSI-based synchronous SQLite access for React Native apps
|
|
7
|
+
* — the fastest SQLite option for bare RN projects.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - JSI synchronous execution (no bridge overhead)
|
|
11
|
+
* - SQLCipher encryption support (via encryptionKey)
|
|
12
|
+
* - Prepared statement support
|
|
13
|
+
* - Batch execution in transactions
|
|
14
|
+
* - Update hooks for reactive queries
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* import { SQLiteAdapter } from 'pomegranate-db';
|
|
18
|
+
* import { createOpSQLiteDriver } from 'pomegranate-db/src/adapters/op-sqlite';
|
|
19
|
+
*
|
|
20
|
+
* const adapter = new SQLiteAdapter({
|
|
21
|
+
* databaseName: 'myapp',
|
|
22
|
+
* driver: createOpSQLiteDriver({ encryptionKey: 'secret' }),
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
28
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
29
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
30
|
+
}
|
|
31
|
+
Object.defineProperty(o, k2, desc);
|
|
32
|
+
}) : (function(o, m, k, k2) {
|
|
33
|
+
if (k2 === undefined) k2 = k;
|
|
34
|
+
o[k2] = m[k];
|
|
35
|
+
}));
|
|
36
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
37
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
38
|
+
}) : function(o, v) {
|
|
39
|
+
o["default"] = v;
|
|
40
|
+
});
|
|
41
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
42
|
+
var ownKeys = function(o) {
|
|
43
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
44
|
+
var ar = [];
|
|
45
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
46
|
+
return ar;
|
|
47
|
+
};
|
|
48
|
+
return ownKeys(o);
|
|
49
|
+
};
|
|
50
|
+
return function (mod) {
|
|
51
|
+
if (mod && mod.__esModule) return mod;
|
|
52
|
+
var result = {};
|
|
53
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
54
|
+
__setModuleDefault(result, mod);
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
57
|
+
})();
|
|
58
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
|
+
exports.createOpSQLiteDriver = createOpSQLiteDriver;
|
|
60
|
+
// ─── Driver Factory ───────────────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Create a SQLiteDriver backed by @op-engineering/op-sqlite.
|
|
63
|
+
*
|
|
64
|
+
* @param config Optional driver configuration (encryption, hooks, etc.)
|
|
65
|
+
* @returns A SQLiteDriver that can be passed to SQLiteAdapter.
|
|
66
|
+
*/
|
|
67
|
+
function createOpSQLiteDriver(config) {
|
|
68
|
+
let db = null;
|
|
69
|
+
let opSQLite = null;
|
|
70
|
+
async function getOpSQLite() {
|
|
71
|
+
if (!opSQLite) {
|
|
72
|
+
try {
|
|
73
|
+
// @ts-expect-error — @op-engineering/op-sqlite is an optional peer dependency
|
|
74
|
+
opSQLite = (await Promise.resolve().then(() => __importStar(require('@op-engineering/op-sqlite'))));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new Error('@op-engineering/op-sqlite is not installed. Install it with:\n' +
|
|
78
|
+
' npm install @op-engineering/op-sqlite\n' +
|
|
79
|
+
'Then rebuild your native app.');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return opSQLite;
|
|
83
|
+
}
|
|
84
|
+
function requireDb() {
|
|
85
|
+
if (!db) {
|
|
86
|
+
throw new Error('Database not open. Call open() first.');
|
|
87
|
+
}
|
|
88
|
+
return db;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
async open(name) {
|
|
92
|
+
const sqlite = await getOpSQLite();
|
|
93
|
+
const dbName = name.endsWith('.db') ? name : `${name}.db`;
|
|
94
|
+
const openOptions = { name: dbName };
|
|
95
|
+
if (config?.location) {
|
|
96
|
+
openOptions.location = config.location;
|
|
97
|
+
}
|
|
98
|
+
if (config?.encryptionKey) {
|
|
99
|
+
openOptions.encryptionKey = config.encryptionKey;
|
|
100
|
+
}
|
|
101
|
+
db = sqlite.open(openOptions);
|
|
102
|
+
// Enable WAL mode for better concurrent read performance
|
|
103
|
+
db.executeSync('PRAGMA journal_mode = WAL');
|
|
104
|
+
// Busy timeout for concurrent access
|
|
105
|
+
db.executeSync('PRAGMA busy_timeout = 5000');
|
|
106
|
+
// Install update hook if requested
|
|
107
|
+
if (config?.onTableChanged) {
|
|
108
|
+
const callback = config.onTableChanged;
|
|
109
|
+
db.updateHook(({ table, operation }) => {
|
|
110
|
+
callback(table, operation);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
async execute(sql, bindings) {
|
|
115
|
+
const database = requireDb();
|
|
116
|
+
await database.execute(sql, bindings);
|
|
117
|
+
},
|
|
118
|
+
async query(sql, bindings) {
|
|
119
|
+
const database = requireDb();
|
|
120
|
+
const result = await database.execute(sql, bindings);
|
|
121
|
+
return result.rows;
|
|
122
|
+
},
|
|
123
|
+
async executeInTransaction(fn) {
|
|
124
|
+
const database = requireDb();
|
|
125
|
+
await database.transaction(async (_tx) => {
|
|
126
|
+
// op-sqlite's transaction scopes all operations on the
|
|
127
|
+
// connection to the transaction, similar to expo-sqlite.
|
|
128
|
+
await fn();
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
async close() {
|
|
132
|
+
if (db) {
|
|
133
|
+
db.updateHook(null); // Remove hook before closing
|
|
134
|
+
db.close();
|
|
135
|
+
db = null;
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=OpSQLiteDriver.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createOpSQLiteDriver = void 0;
|
|
4
|
+
var OpSQLiteDriver_1 = require("./OpSQLiteDriver");
|
|
5
|
+
Object.defineProperty(exports, "createOpSQLiteDriver", { enumerable: true, get: function () { return OpSQLiteDriver_1.createOpSQLiteDriver; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite Adapter.
|
|
3
|
+
*
|
|
4
|
+
* Implements the StorageAdapter interface using a SQL driver.
|
|
5
|
+
* The actual SQLite driver is injected — this adapter generates SQL
|
|
6
|
+
* and delegates execution, enabling different drivers for
|
|
7
|
+
* React Native (react-native-sqlite-storage) and web (sql.js).
|
|
8
|
+
*
|
|
9
|
+
* The driver interface is intentionally minimal so it can wrap
|
|
10
|
+
* any SQLite library.
|
|
11
|
+
*/
|
|
12
|
+
import type { StorageAdapter, AdapterConfig, EncryptionConfig, Migration } from '../types';
|
|
13
|
+
import type { QueryDescriptor, SearchDescriptor, BatchOperation } from '../../query/types';
|
|
14
|
+
import type { DatabaseSchema, RawRecord } from '../../schema/types';
|
|
15
|
+
/**
|
|
16
|
+
* Minimal driver interface that wraps any SQLite library.
|
|
17
|
+
*
|
|
18
|
+
* Implementations:
|
|
19
|
+
* - For React Native: wrap react-native-quick-sqlite or op-sqlite
|
|
20
|
+
* - For Web: wrap sql.js
|
|
21
|
+
* - For Node tests: wrap better-sqlite3
|
|
22
|
+
*/
|
|
23
|
+
export interface SQLiteDriver {
|
|
24
|
+
open(name: string): Promise<void>;
|
|
25
|
+
execute(sql: string, bindings?: unknown[]): Promise<void>;
|
|
26
|
+
query(sql: string, bindings?: unknown[]): Promise<Record<string, unknown>[]>;
|
|
27
|
+
executeInTransaction(fn: () => Promise<void>): Promise<void>;
|
|
28
|
+
close(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export interface SQLiteAdapterConfig extends AdapterConfig {
|
|
31
|
+
/** The SQLite driver to use. If not provided, a default will be selected. */
|
|
32
|
+
driver?: SQLiteDriver;
|
|
33
|
+
/** Optional encryption config */
|
|
34
|
+
encryption?: EncryptionConfig;
|
|
35
|
+
}
|
|
36
|
+
export declare class SQLiteAdapter implements StorageAdapter {
|
|
37
|
+
private _driver;
|
|
38
|
+
private _databaseName;
|
|
39
|
+
private _encryption?;
|
|
40
|
+
private _initialized;
|
|
41
|
+
constructor(config: SQLiteAdapterConfig);
|
|
42
|
+
initialize(schema: DatabaseSchema): Promise<void>;
|
|
43
|
+
find(query: QueryDescriptor): Promise<RawRecord[]>;
|
|
44
|
+
count(query: QueryDescriptor): Promise<number>;
|
|
45
|
+
findById(table: string, id: string): Promise<RawRecord | null>;
|
|
46
|
+
insert(table: string, raw: RawRecord): Promise<void>;
|
|
47
|
+
update(table: string, raw: RawRecord): Promise<void>;
|
|
48
|
+
markAsDeleted(table: string, id: string): Promise<void>;
|
|
49
|
+
destroyPermanently(table: string, id: string): Promise<void>;
|
|
50
|
+
batch(operations: BatchOperation[]): Promise<void>;
|
|
51
|
+
search(descriptor: SearchDescriptor): Promise<{
|
|
52
|
+
records: RawRecord[];
|
|
53
|
+
total: number;
|
|
54
|
+
}>;
|
|
55
|
+
getLocalChanges(tables: string[]): Promise<Record<string, {
|
|
56
|
+
created: RawRecord[];
|
|
57
|
+
updated: RawRecord[];
|
|
58
|
+
deleted: string[];
|
|
59
|
+
}>>;
|
|
60
|
+
applyRemoteChanges(changes: Record<string, {
|
|
61
|
+
created: RawRecord[];
|
|
62
|
+
updated: RawRecord[];
|
|
63
|
+
deleted: string[];
|
|
64
|
+
}>): Promise<void>;
|
|
65
|
+
markAsSynced(table: string, ids: string[]): Promise<void>;
|
|
66
|
+
getSchemaVersion(): Promise<number>;
|
|
67
|
+
migrate(migrations: Migration[]): Promise<void>;
|
|
68
|
+
reset(): Promise<void>;
|
|
69
|
+
close(): Promise<void>;
|
|
70
|
+
}
|