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,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection — manages all records for a single table/model.
|
|
3
|
+
*
|
|
4
|
+
* Collections provide CRUD operations, query building, record caching,
|
|
5
|
+
* and change notification. Each Collection is associated with one Model class.
|
|
6
|
+
*/
|
|
7
|
+
import type { ModelSchema, RawRecord } from '../schema/types';
|
|
8
|
+
import type { ModelStatic, ModelCollectionRef, ModelDatabaseRef, Model } from '../model/Model';
|
|
9
|
+
import { QueryBuilder } from '../query/QueryBuilder';
|
|
10
|
+
import type { QueryDescriptor } from '../query/types';
|
|
11
|
+
import type { Observable } from '../observable/Subject';
|
|
12
|
+
import type { StorageAdapter } from '../adapters/types';
|
|
13
|
+
export type CollectionChangeType = 'created' | 'updated' | 'deleted';
|
|
14
|
+
export interface CollectionChange {
|
|
15
|
+
readonly type: CollectionChangeType;
|
|
16
|
+
readonly record: Model;
|
|
17
|
+
}
|
|
18
|
+
export declare class Collection<M extends Model = Model> implements ModelCollectionRef {
|
|
19
|
+
readonly table: string;
|
|
20
|
+
private _modelClass;
|
|
21
|
+
private _schema;
|
|
22
|
+
private _database;
|
|
23
|
+
/** In-memory cache of instantiated records by ID */
|
|
24
|
+
private _cache;
|
|
25
|
+
/** Emits whenever the collection changes */
|
|
26
|
+
private _changes$;
|
|
27
|
+
constructor(database: ModelDatabaseRef & {
|
|
28
|
+
_adapter: StorageAdapter;
|
|
29
|
+
}, modelClass: ModelStatic);
|
|
30
|
+
get schema(): ModelSchema;
|
|
31
|
+
/**
|
|
32
|
+
* Create a new record.
|
|
33
|
+
* Must be called inside `db.write()`.
|
|
34
|
+
*/
|
|
35
|
+
create(patch: Record<string, unknown>): Promise<M>;
|
|
36
|
+
/**
|
|
37
|
+
* Find a record by ID.
|
|
38
|
+
* Returns the cached instance if available.
|
|
39
|
+
*/
|
|
40
|
+
findById(id: string): Promise<M | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Find a record by ID or throw.
|
|
43
|
+
*/
|
|
44
|
+
findByIdOrFail(id: string): Promise<M>;
|
|
45
|
+
/**
|
|
46
|
+
* Query records using the fluent QueryBuilder.
|
|
47
|
+
*/
|
|
48
|
+
query(): QueryBuilder;
|
|
49
|
+
query(fn: (qb: QueryBuilder) => void): QueryBuilder;
|
|
50
|
+
/**
|
|
51
|
+
* Execute a query and return model instances.
|
|
52
|
+
*/
|
|
53
|
+
fetch(queryOrBuilder: QueryDescriptor | QueryBuilder): Promise<M[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Count records matching a query.
|
|
56
|
+
*/
|
|
57
|
+
count(queryOrBuilder?: QueryDescriptor | QueryBuilder): Promise<number>;
|
|
58
|
+
/**
|
|
59
|
+
* Full-text search.
|
|
60
|
+
*/
|
|
61
|
+
search(opts: {
|
|
62
|
+
term: string;
|
|
63
|
+
fields: string[];
|
|
64
|
+
limit?: number;
|
|
65
|
+
offset?: number;
|
|
66
|
+
extend?: (qb: QueryBuilder) => void;
|
|
67
|
+
orderBy?: Record<string, 'asc' | 'desc'>;
|
|
68
|
+
}): Promise<{
|
|
69
|
+
records: M[];
|
|
70
|
+
total: number;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Observe all changes to this collection.
|
|
74
|
+
*/
|
|
75
|
+
get changes$(): Observable<CollectionChange>;
|
|
76
|
+
/**
|
|
77
|
+
* Create a live query that re-runs whenever the collection changes.
|
|
78
|
+
* Returns an observable of record arrays.
|
|
79
|
+
*/
|
|
80
|
+
observeQuery(queryOrBuilder: QueryDescriptor | QueryBuilder): Observable<M[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Observe a single record by ID.
|
|
83
|
+
*/
|
|
84
|
+
observeById(id: string): Observable<M | null>;
|
|
85
|
+
/**
|
|
86
|
+
* Observe a count matching a query.
|
|
87
|
+
*/
|
|
88
|
+
observeCount(queryOrBuilder?: QueryDescriptor | QueryBuilder): Observable<number>;
|
|
89
|
+
_update(id: string, rawUpdates: Partial<RawRecord>): Promise<void>;
|
|
90
|
+
_delete(id: string): Promise<void>;
|
|
91
|
+
_destroyPermanently(id: string): Promise<void>;
|
|
92
|
+
_getDatabase(): ModelDatabaseRef;
|
|
93
|
+
/** Create a Model instance from a raw record */
|
|
94
|
+
private _instantiate;
|
|
95
|
+
/** Get-or-create a Model instance from a raw record (cache-aware) */
|
|
96
|
+
private _materialize;
|
|
97
|
+
/** Clear the cache — used during reset or sync */
|
|
98
|
+
_clearCache(): void;
|
|
99
|
+
/** Directly add a raw record to cache (used during sync) */
|
|
100
|
+
_cacheRaw(raw: RawRecord): M;
|
|
101
|
+
/** Notify external change (used by sync/batch) */
|
|
102
|
+
_notifyChange(type: CollectionChangeType, record: Model): void;
|
|
103
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Collection — manages all records for a single table/model.
|
|
4
|
+
*
|
|
5
|
+
* Collections provide CRUD operations, query building, record caching,
|
|
6
|
+
* and change notification. Each Collection is associated with one Model class.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.Collection = void 0;
|
|
10
|
+
const Model_1 = require("../model/Model");
|
|
11
|
+
const QueryBuilder_1 = require("../query/QueryBuilder");
|
|
12
|
+
const Subject_1 = require("../observable/Subject");
|
|
13
|
+
const Subject_2 = require("../observable/Subject");
|
|
14
|
+
// ─── Collection class ──────────────────────────────────────────────────────
|
|
15
|
+
class Collection {
|
|
16
|
+
table;
|
|
17
|
+
_modelClass;
|
|
18
|
+
_schema;
|
|
19
|
+
_database;
|
|
20
|
+
/** In-memory cache of instantiated records by ID */
|
|
21
|
+
_cache = new Map();
|
|
22
|
+
/** Emits whenever the collection changes */
|
|
23
|
+
_changes$ = new Subject_1.Subject();
|
|
24
|
+
constructor(database, modelClass) {
|
|
25
|
+
this._database = database;
|
|
26
|
+
this._modelClass = modelClass;
|
|
27
|
+
this._schema = modelClass.schema;
|
|
28
|
+
this.table = this._schema.table;
|
|
29
|
+
}
|
|
30
|
+
// ─── Schema access ──────────────────────────────────────────────────
|
|
31
|
+
get schema() {
|
|
32
|
+
return this._schema;
|
|
33
|
+
}
|
|
34
|
+
// ─── CRUD ──────────────────────────────────────────────────────────
|
|
35
|
+
/**
|
|
36
|
+
* Create a new record.
|
|
37
|
+
* Must be called inside `db.write()`.
|
|
38
|
+
*/
|
|
39
|
+
async create(patch) {
|
|
40
|
+
this._database._ensureInWriter('Collection.create()');
|
|
41
|
+
const raw = (0, Model_1.createRawRecord)(this._schema, patch);
|
|
42
|
+
await this._database._adapter.insert(this.table, raw);
|
|
43
|
+
const record = this._instantiate(raw);
|
|
44
|
+
this._cache.set(record.id, record);
|
|
45
|
+
this._changes$.next({ type: 'created', record });
|
|
46
|
+
return record;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Find a record by ID.
|
|
50
|
+
* Returns the cached instance if available.
|
|
51
|
+
*/
|
|
52
|
+
async findById(id) {
|
|
53
|
+
const cached = this._cache.get(id);
|
|
54
|
+
if (cached)
|
|
55
|
+
return cached;
|
|
56
|
+
const raw = await this._database._adapter.findById(this.table, id);
|
|
57
|
+
if (!raw)
|
|
58
|
+
return null;
|
|
59
|
+
const record = this._instantiate(raw);
|
|
60
|
+
this._cache.set(id, record);
|
|
61
|
+
return record;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Find a record by ID or throw.
|
|
65
|
+
*/
|
|
66
|
+
async findByIdOrFail(id) {
|
|
67
|
+
const record = await this.findById(id);
|
|
68
|
+
if (!record) {
|
|
69
|
+
throw new Error(`Record not found: ${this.table}/${id}`);
|
|
70
|
+
}
|
|
71
|
+
return record;
|
|
72
|
+
}
|
|
73
|
+
query(fn) {
|
|
74
|
+
const qb = new QueryBuilder_1.QueryBuilder(this.table);
|
|
75
|
+
// Automatically exclude soft-deleted records
|
|
76
|
+
qb.where('_status', 'neq', 'deleted');
|
|
77
|
+
if (fn)
|
|
78
|
+
fn(qb);
|
|
79
|
+
return qb;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Execute a query and return model instances.
|
|
83
|
+
*/
|
|
84
|
+
async fetch(queryOrBuilder) {
|
|
85
|
+
const descriptor = queryOrBuilder instanceof QueryBuilder_1.QueryBuilder ? queryOrBuilder.build() : queryOrBuilder;
|
|
86
|
+
const raws = await this._database._adapter.find(descriptor);
|
|
87
|
+
return raws.map((raw) => this._materialize(raw));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Count records matching a query.
|
|
91
|
+
*/
|
|
92
|
+
async count(queryOrBuilder) {
|
|
93
|
+
const descriptor = queryOrBuilder
|
|
94
|
+
? (queryOrBuilder instanceof QueryBuilder_1.QueryBuilder
|
|
95
|
+
? queryOrBuilder.build()
|
|
96
|
+
: queryOrBuilder)
|
|
97
|
+
: this.query().build();
|
|
98
|
+
return this._database._adapter.count(descriptor);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Full-text search.
|
|
102
|
+
*/
|
|
103
|
+
async search(opts) {
|
|
104
|
+
const qb = this.query();
|
|
105
|
+
if (opts.extend)
|
|
106
|
+
opts.extend(qb);
|
|
107
|
+
const orderByEntries = opts.orderBy
|
|
108
|
+
? Object.entries(opts.orderBy).map(([column, order]) => ({ column, order }))
|
|
109
|
+
: [];
|
|
110
|
+
const descriptor = {
|
|
111
|
+
table: this.table,
|
|
112
|
+
term: opts.term,
|
|
113
|
+
fields: opts.fields,
|
|
114
|
+
conditions: qb.build().conditions,
|
|
115
|
+
orderBy: orderByEntries,
|
|
116
|
+
limit: opts.limit ?? 50,
|
|
117
|
+
offset: opts.offset ?? 0,
|
|
118
|
+
};
|
|
119
|
+
const result = await this._database._adapter.search(descriptor);
|
|
120
|
+
const records = result.records.map((raw) => this._materialize(raw));
|
|
121
|
+
return { records, total: result.total };
|
|
122
|
+
}
|
|
123
|
+
// ─── Observe ──────────────────────────────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* Observe all changes to this collection.
|
|
126
|
+
*/
|
|
127
|
+
get changes$() {
|
|
128
|
+
return this._changes$;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create a live query that re-runs whenever the collection changes.
|
|
132
|
+
* Returns an observable of record arrays.
|
|
133
|
+
*/
|
|
134
|
+
observeQuery(queryOrBuilder) {
|
|
135
|
+
const descriptor = queryOrBuilder instanceof QueryBuilder_1.QueryBuilder ? queryOrBuilder.build() : queryOrBuilder;
|
|
136
|
+
return new Subject_2.SharedObservable((emit) => {
|
|
137
|
+
// Initial fetch
|
|
138
|
+
this._database._adapter.find(descriptor).then((raws) => {
|
|
139
|
+
emit(raws.map((raw) => this._materialize(raw)));
|
|
140
|
+
});
|
|
141
|
+
// Re-fetch on any collection change
|
|
142
|
+
const unsub = this._changes$.subscribe(async () => {
|
|
143
|
+
const raws = await this._database._adapter.find(descriptor);
|
|
144
|
+
emit(raws.map((raw) => this._materialize(raw)));
|
|
145
|
+
});
|
|
146
|
+
return unsub;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Observe a single record by ID.
|
|
151
|
+
*/
|
|
152
|
+
observeById(id) {
|
|
153
|
+
return new Subject_2.SharedObservable((emit) => {
|
|
154
|
+
// Initial fetch
|
|
155
|
+
this.findById(id).then(emit);
|
|
156
|
+
// Re-check on changes
|
|
157
|
+
const unsub = this._changes$.subscribe(async (change) => {
|
|
158
|
+
if (change.record.id === id) {
|
|
159
|
+
if (change.type === 'deleted') {
|
|
160
|
+
emit(null);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
emit(await this.findById(id));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return unsub;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Observe a count matching a query.
|
|
172
|
+
*/
|
|
173
|
+
observeCount(queryOrBuilder) {
|
|
174
|
+
const descriptor = queryOrBuilder
|
|
175
|
+
? (queryOrBuilder instanceof QueryBuilder_1.QueryBuilder
|
|
176
|
+
? queryOrBuilder.build()
|
|
177
|
+
: queryOrBuilder)
|
|
178
|
+
: this.query().build();
|
|
179
|
+
return new Subject_2.SharedObservable((emit) => {
|
|
180
|
+
this._database._adapter.count(descriptor).then(emit);
|
|
181
|
+
const unsub = this._changes$.subscribe(async () => {
|
|
182
|
+
emit(await this._database._adapter.count(descriptor));
|
|
183
|
+
});
|
|
184
|
+
return unsub;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// ─── Internal (called by Model) ────────────────────────────────────
|
|
188
|
+
async _update(id, rawUpdates) {
|
|
189
|
+
const existing = this._cache.get(id);
|
|
190
|
+
if (!existing)
|
|
191
|
+
throw new Error(`Cannot update: record ${id} not in cache`);
|
|
192
|
+
const merged = { ...existing._rawRecord, ...rawUpdates };
|
|
193
|
+
await this._database._adapter.update(this.table, merged);
|
|
194
|
+
this._changes$.next({ type: 'updated', record: existing });
|
|
195
|
+
}
|
|
196
|
+
async _delete(id) {
|
|
197
|
+
await this._database._adapter.markAsDeleted(this.table, id);
|
|
198
|
+
const record = this._cache.get(id);
|
|
199
|
+
if (record) {
|
|
200
|
+
this._changes$.next({ type: 'deleted', record });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async _destroyPermanently(id) {
|
|
204
|
+
await this._database._adapter.destroyPermanently(this.table, id);
|
|
205
|
+
const record = this._cache.get(id);
|
|
206
|
+
this._cache.delete(id);
|
|
207
|
+
if (record) {
|
|
208
|
+
this._changes$.next({ type: 'deleted', record });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
_getDatabase() {
|
|
212
|
+
return this._database;
|
|
213
|
+
}
|
|
214
|
+
// ─── Internal helpers ──────────────────────────────────────────────
|
|
215
|
+
/** Create a Model instance from a raw record */
|
|
216
|
+
_instantiate(raw) {
|
|
217
|
+
return new this._modelClass(this, raw);
|
|
218
|
+
}
|
|
219
|
+
/** Get-or-create a Model instance from a raw record (cache-aware) */
|
|
220
|
+
_materialize(raw) {
|
|
221
|
+
const existing = this._cache.get(raw.id);
|
|
222
|
+
if (existing) {
|
|
223
|
+
// Refresh the raw data
|
|
224
|
+
existing._setRaw(raw);
|
|
225
|
+
return existing;
|
|
226
|
+
}
|
|
227
|
+
const record = this._instantiate(raw);
|
|
228
|
+
this._cache.set(raw.id, record);
|
|
229
|
+
return record;
|
|
230
|
+
}
|
|
231
|
+
/** Clear the cache — used during reset or sync */
|
|
232
|
+
_clearCache() {
|
|
233
|
+
this._cache.clear();
|
|
234
|
+
}
|
|
235
|
+
/** Directly add a raw record to cache (used during sync) */
|
|
236
|
+
_cacheRaw(raw) {
|
|
237
|
+
return this._materialize(raw);
|
|
238
|
+
}
|
|
239
|
+
/** Notify external change (used by sync/batch) */
|
|
240
|
+
_notifyChange(type, record) {
|
|
241
|
+
this._changes$.next({ type, record });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
exports.Collection = Collection;
|
|
245
|
+
//# sourceMappingURL=Collection.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Collection = void 0;
|
|
4
|
+
var Collection_1 = require("./Collection");
|
|
5
|
+
Object.defineProperty(exports, "Collection", { enumerable: true, get: function () { return Collection_1.Collection; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database — the top-level entry point.
|
|
3
|
+
*
|
|
4
|
+
* The Database owns the adapter, manages collections, and provides
|
|
5
|
+
* the `write()` transactional boundary.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const db = new Database({
|
|
9
|
+
* adapter: new SQLiteAdapter({ databaseName: 'app.db' }),
|
|
10
|
+
* models: [Post, User, Comment],
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* await db.write(async () => {
|
|
14
|
+
* await db.get(Post).create({ title: 'Hello' });
|
|
15
|
+
* });
|
|
16
|
+
*/
|
|
17
|
+
import type { StorageAdapter } from '../adapters/types';
|
|
18
|
+
import type { EncryptionConfig } from '../adapters/types';
|
|
19
|
+
import type { ModelSchema, RawRecord } from '../schema/types';
|
|
20
|
+
import { Collection } from '../collection/Collection';
|
|
21
|
+
import type { Model } from '../model/Model';
|
|
22
|
+
import type { ModelStatic, ModelDatabaseRef } from '../model/Model';
|
|
23
|
+
import type { BatchOperation } from '../query/types';
|
|
24
|
+
import type { Observable } from '../observable/Subject';
|
|
25
|
+
export interface DatabaseConfig {
|
|
26
|
+
readonly adapter: StorageAdapter;
|
|
27
|
+
readonly models: ModelStatic[];
|
|
28
|
+
readonly schemaVersion?: number;
|
|
29
|
+
readonly encryption?: EncryptionConfig;
|
|
30
|
+
}
|
|
31
|
+
export type DatabaseEvent = {
|
|
32
|
+
type: 'initialized';
|
|
33
|
+
} | {
|
|
34
|
+
type: 'write_started';
|
|
35
|
+
} | {
|
|
36
|
+
type: 'write_completed';
|
|
37
|
+
} | {
|
|
38
|
+
type: 'sync_started';
|
|
39
|
+
} | {
|
|
40
|
+
type: 'sync_completed';
|
|
41
|
+
} | {
|
|
42
|
+
type: 'reset';
|
|
43
|
+
};
|
|
44
|
+
export declare class Database implements ModelDatabaseRef {
|
|
45
|
+
private config;
|
|
46
|
+
readonly _adapter: StorageAdapter;
|
|
47
|
+
private _collections;
|
|
48
|
+
private _modelMap;
|
|
49
|
+
private _initialized;
|
|
50
|
+
private _isInWriter;
|
|
51
|
+
private _writeQueue;
|
|
52
|
+
private _isProcessingQueue;
|
|
53
|
+
private _events$;
|
|
54
|
+
private _schemaVersion;
|
|
55
|
+
constructor(config: DatabaseConfig);
|
|
56
|
+
/**
|
|
57
|
+
* Initialize the database. Must be called before any operations.
|
|
58
|
+
* Creates tables if they don't exist.
|
|
59
|
+
*/
|
|
60
|
+
initialize(): Promise<void>;
|
|
61
|
+
private _buildDatabaseSchema;
|
|
62
|
+
/**
|
|
63
|
+
* Get the collection for a model class.
|
|
64
|
+
*/
|
|
65
|
+
get<M extends Model>(modelClass: ModelStatic<ModelSchema>): Collection<M>;
|
|
66
|
+
/**
|
|
67
|
+
* Get a collection by table name.
|
|
68
|
+
*/
|
|
69
|
+
collection(table: string): Collection;
|
|
70
|
+
/**
|
|
71
|
+
* All registered collections.
|
|
72
|
+
*/
|
|
73
|
+
get collections(): Collection[];
|
|
74
|
+
/**
|
|
75
|
+
* Execute a write transaction.
|
|
76
|
+
*
|
|
77
|
+
* All mutations (create, update, delete) must happen inside a write() call.
|
|
78
|
+
* Write calls are serialized — only one runs at a time.
|
|
79
|
+
*/
|
|
80
|
+
write<T>(fn: () => Promise<T>): Promise<T>;
|
|
81
|
+
private _processWriteQueue;
|
|
82
|
+
/**
|
|
83
|
+
* @internal Throw if not inside a writer.
|
|
84
|
+
*/
|
|
85
|
+
_ensureInWriter(action: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Execute a batch of operations atomically.
|
|
88
|
+
* Must be called inside `db.write()`.
|
|
89
|
+
*/
|
|
90
|
+
batch(operations: BatchOperation[]): Promise<void>;
|
|
91
|
+
/** @internal used by Model */
|
|
92
|
+
_batch(operations: BatchOperation[]): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Run a sync cycle.
|
|
95
|
+
* See sync/index.ts for the full implementation.
|
|
96
|
+
*/
|
|
97
|
+
sync(opts: {
|
|
98
|
+
pullChanges: (params: {
|
|
99
|
+
lastPulledAt: number | null;
|
|
100
|
+
}) => Promise<{
|
|
101
|
+
changes: Record<string, {
|
|
102
|
+
created: RawRecord[];
|
|
103
|
+
updated: RawRecord[];
|
|
104
|
+
deleted: string[];
|
|
105
|
+
}>;
|
|
106
|
+
timestamp: number;
|
|
107
|
+
}>;
|
|
108
|
+
pushChanges: (params: {
|
|
109
|
+
changes: Record<string, {
|
|
110
|
+
created: RawRecord[];
|
|
111
|
+
updated: RawRecord[];
|
|
112
|
+
deleted: string[];
|
|
113
|
+
}>;
|
|
114
|
+
lastPulledAt: number;
|
|
115
|
+
}) => Promise<void>;
|
|
116
|
+
}): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Completely reset the database — drops all data.
|
|
119
|
+
*/
|
|
120
|
+
reset(): Promise<void>;
|
|
121
|
+
get events$(): Observable<DatabaseEvent>;
|
|
122
|
+
close(): Promise<void>;
|
|
123
|
+
private _ensureInitialized;
|
|
124
|
+
/**
|
|
125
|
+
* The tables this database manages.
|
|
126
|
+
*/
|
|
127
|
+
get tables(): string[];
|
|
128
|
+
}
|