@gonvex/expo-sqlite 0.5.2-staging.1 → 0.5.2-staging.11
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/dist/index.d.ts +2 -0
- package/dist/index.js +12 -0
- package/package.json +2 -2
- package/dist/src/index.d.ts +0 -24
- package/dist/src/index.js +0 -135
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export declare class ExpoSQLiteLocalReplicaStorage implements LocalReplicaStorag
|
|
|
18
18
|
private initialize;
|
|
19
19
|
private migrateSchema;
|
|
20
20
|
load(scope?: ReplicaScope): Promise<ReplicaSnapshot | undefined>;
|
|
21
|
+
loadSession(scope: string): Promise<import("@gonvex/client").LocalReplicaSession | undefined>;
|
|
22
|
+
saveSession(scope: string, session: import("@gonvex/client").LocalReplicaSession | undefined): Promise<void>;
|
|
21
23
|
applyTransaction(transaction: ReplicaTransaction, _snapshot: ReplicaSnapshot, scope?: ReplicaScope): Promise<void>;
|
|
22
24
|
advanceWatermark(windows: readonly ReplicaWindow[], cursor: ReplicaSnapshot["cursor"], scope?: ReplicaScope): Promise<void>;
|
|
23
25
|
replaceSnapshot(snapshot: ReplicaSnapshot, scope?: ReplicaScope): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -93,6 +93,18 @@ export class ExpoSQLiteLocalReplicaStorage {
|
|
|
93
93
|
return undefined;
|
|
94
94
|
return { cursor: cursor ? JSON.parse(cursor.value) : undefined, entities, liveQueries };
|
|
95
95
|
}
|
|
96
|
+
async loadSession(scope) {
|
|
97
|
+
await this.initialize();
|
|
98
|
+
const row = await this.database.getFirstAsync(`SELECT scope, key, value FROM _gonvex_replica_meta WHERE scope = ? AND key = 'session'`, scope);
|
|
99
|
+
return row ? JSON.parse(row.value) : undefined;
|
|
100
|
+
}
|
|
101
|
+
async saveSession(scope, session) {
|
|
102
|
+
await this.initialize();
|
|
103
|
+
if (session)
|
|
104
|
+
await this.database.runAsync(`INSERT OR REPLACE INTO _gonvex_replica_meta (scope,key,value) VALUES (?, 'session', ?)`, scope, JSON.stringify(session));
|
|
105
|
+
else
|
|
106
|
+
await this.database.runAsync(`DELETE FROM _gonvex_replica_meta WHERE scope = ? AND key = 'session'`, scope);
|
|
107
|
+
}
|
|
96
108
|
async applyTransaction(transaction, _snapshot, scope = defaultReplicaScope) {
|
|
97
109
|
await this.initialize();
|
|
98
110
|
await this.database.withTransactionAsync(async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gonvex/expo-sqlite",
|
|
3
|
-
"version": "0.5.2-staging.
|
|
3
|
+
"version": "0.5.2-staging.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@gonvex/client": "0.5.2-staging.
|
|
21
|
+
"@gonvex/client": "0.5.2-staging.11"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"typescript": "^6.0.3",
|
package/dist/src/index.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { LocalReplicaStorage, ReplicaScope, ReplicaSnapshot, ReplicaTransaction } from "@gonvex/client";
|
|
2
|
-
export interface ExpoSQLiteDatabase {
|
|
3
|
-
execAsync(sql: string): Promise<void>;
|
|
4
|
-
runAsync(sql: string, ...params: unknown[]): Promise<unknown>;
|
|
5
|
-
getFirstAsync<T>(sql: string, ...params: unknown[]): Promise<T | null>;
|
|
6
|
-
getAllAsync<T>(sql: string, ...params: unknown[]): Promise<T[]>;
|
|
7
|
-
withTransactionAsync(task: () => Promise<void>): Promise<void>;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Transactional, normalized SQLite persistence for Expo. Every server
|
|
11
|
-
* transaction updates entities, Live Query memberships, and the replica
|
|
12
|
-
* cursor inside one SQLite transaction.
|
|
13
|
-
*/
|
|
14
|
-
export declare class ExpoSQLiteLocalReplicaStorage implements LocalReplicaStorage {
|
|
15
|
-
private readonly database;
|
|
16
|
-
private initialized?;
|
|
17
|
-
constructor(database: ExpoSQLiteDatabase);
|
|
18
|
-
private initialize;
|
|
19
|
-
private migrateSchema;
|
|
20
|
-
load(scope?: ReplicaScope): Promise<ReplicaSnapshot | undefined>;
|
|
21
|
-
applyTransaction(transaction: ReplicaTransaction, _snapshot: ReplicaSnapshot, scope?: ReplicaScope): Promise<void>;
|
|
22
|
-
replaceSnapshot(snapshot: ReplicaSnapshot, scope?: ReplicaScope): Promise<void>;
|
|
23
|
-
}
|
|
24
|
-
export declare function expoSQLite(database: ExpoSQLiteDatabase): LocalReplicaStorage;
|
package/dist/src/index.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
const defaultReplicaScope = "default";
|
|
2
|
-
const replicaSchemaVersion = 2;
|
|
3
|
-
/**
|
|
4
|
-
* Transactional, normalized SQLite persistence for Expo. Every server
|
|
5
|
-
* transaction updates entities, Live Query memberships, and the replica
|
|
6
|
-
* cursor inside one SQLite transaction.
|
|
7
|
-
*/
|
|
8
|
-
export class ExpoSQLiteLocalReplicaStorage {
|
|
9
|
-
database;
|
|
10
|
-
initialized;
|
|
11
|
-
constructor(database) {
|
|
12
|
-
this.database = database;
|
|
13
|
-
}
|
|
14
|
-
initialize() {
|
|
15
|
-
return this.initialized ??= this.migrateSchema();
|
|
16
|
-
}
|
|
17
|
-
async migrateSchema() {
|
|
18
|
-
const [entities, queries, meta] = await Promise.all([
|
|
19
|
-
this.database.getAllAsync(`PRAGMA table_info(_gonvex_replica_entities)`),
|
|
20
|
-
this.database.getAllAsync(`PRAGMA table_info(_gonvex_replica_queries)`),
|
|
21
|
-
this.database.getAllAsync(`PRAGMA table_info(_gonvex_replica_meta)`),
|
|
22
|
-
]);
|
|
23
|
-
const legacyEntities = entities.length > 0 && !entities.some((column) => column.name === "scope");
|
|
24
|
-
const legacyQueries = queries.length > 0 && !queries.some((column) => column.name === "scope");
|
|
25
|
-
const legacyMeta = meta.length > 0 && !meta.some((column) => column.name === "scope");
|
|
26
|
-
const createTables = `
|
|
27
|
-
CREATE TABLE IF NOT EXISTS _gonvex_replica_entities (
|
|
28
|
-
scope TEXT NOT NULL, entity TEXT NOT NULL, id TEXT NOT NULL, value TEXT NOT NULL,
|
|
29
|
-
PRIMARY KEY (scope, entity, id)
|
|
30
|
-
);
|
|
31
|
-
CREATE TABLE IF NOT EXISTS _gonvex_replica_queries (
|
|
32
|
-
scope TEXT NOT NULL, signature TEXT NOT NULL, value TEXT NOT NULL,
|
|
33
|
-
PRIMARY KEY (scope, signature)
|
|
34
|
-
);
|
|
35
|
-
CREATE TABLE IF NOT EXISTS _gonvex_replica_meta (
|
|
36
|
-
scope TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL,
|
|
37
|
-
PRIMARY KEY (scope, key)
|
|
38
|
-
);
|
|
39
|
-
`;
|
|
40
|
-
if (!legacyEntities && !legacyQueries && !legacyMeta) {
|
|
41
|
-
await this.database.execAsync(`PRAGMA user_version = ${replicaSchemaVersion};${createTables}`);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
// The v1 tables had no namespace at all. Keep their contents available to
|
|
45
|
-
// direct/default LocalReplica users, but never leave those rows in the
|
|
46
|
-
// canonical tables where an authenticated scope could read them.
|
|
47
|
-
await this.database.withTransactionAsync(async () => {
|
|
48
|
-
if (legacyEntities)
|
|
49
|
-
await this.database.execAsync(`ALTER TABLE _gonvex_replica_entities RENAME TO _gonvex_replica_entities_legacy_v1`);
|
|
50
|
-
if (legacyQueries)
|
|
51
|
-
await this.database.execAsync(`ALTER TABLE _gonvex_replica_queries RENAME TO _gonvex_replica_queries_legacy_v1`);
|
|
52
|
-
if (legacyMeta)
|
|
53
|
-
await this.database.execAsync(`ALTER TABLE _gonvex_replica_meta RENAME TO _gonvex_replica_meta_legacy_v1`);
|
|
54
|
-
await this.database.execAsync(createTables);
|
|
55
|
-
if (legacyEntities) {
|
|
56
|
-
await this.database.execAsync(`INSERT INTO _gonvex_replica_entities (scope, entity, id, value)
|
|
57
|
-
SELECT '${defaultReplicaScope}', entity, id, value FROM _gonvex_replica_entities_legacy_v1`);
|
|
58
|
-
}
|
|
59
|
-
if (legacyQueries) {
|
|
60
|
-
await this.database.execAsync(`INSERT INTO _gonvex_replica_queries (scope, signature, value)
|
|
61
|
-
SELECT '${defaultReplicaScope}', signature, value FROM _gonvex_replica_queries_legacy_v1`);
|
|
62
|
-
}
|
|
63
|
-
if (legacyMeta) {
|
|
64
|
-
await this.database.execAsync(`INSERT INTO _gonvex_replica_meta (scope, key, value)
|
|
65
|
-
SELECT '${defaultReplicaScope}', key, value FROM _gonvex_replica_meta_legacy_v1`);
|
|
66
|
-
}
|
|
67
|
-
await this.database.execAsync(`PRAGMA user_version = ${replicaSchemaVersion}`);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
async load(scope = defaultReplicaScope) {
|
|
71
|
-
await this.initialize();
|
|
72
|
-
const cursor = await this.database.getFirstAsync(`SELECT scope, key, value FROM _gonvex_replica_meta WHERE scope = ? AND key = 'cursor'`, scope);
|
|
73
|
-
const entities = {};
|
|
74
|
-
const entityRecords = await this.database.getAllAsync(`SELECT scope, entity, id, value FROM _gonvex_replica_entities WHERE scope = ? ORDER BY entity, id`, scope);
|
|
75
|
-
for (const row of entityRecords) {
|
|
76
|
-
(entities[row.entity] ??= {})[row.id] = JSON.parse(row.value);
|
|
77
|
-
}
|
|
78
|
-
const liveQueries = {};
|
|
79
|
-
const queryRecords = await this.database.getAllAsync(`SELECT scope, signature, value FROM _gonvex_replica_queries WHERE scope = ? ORDER BY signature`, scope);
|
|
80
|
-
for (const row of queryRecords) {
|
|
81
|
-
liveQueries[row.signature] = JSON.parse(row.value);
|
|
82
|
-
}
|
|
83
|
-
if (!cursor && entityRecords.length === 0 && queryRecords.length === 0)
|
|
84
|
-
return undefined;
|
|
85
|
-
return { cursor: cursor ? JSON.parse(cursor.value) : undefined, entities, liveQueries };
|
|
86
|
-
}
|
|
87
|
-
async applyTransaction(transaction, _snapshot, scope = defaultReplicaScope) {
|
|
88
|
-
await this.initialize();
|
|
89
|
-
await this.database.withTransactionAsync(async () => {
|
|
90
|
-
const previous = await this.database.getFirstAsync(`SELECT scope, key, value FROM _gonvex_replica_meta WHERE scope = ? AND key = 'cursor'`, scope);
|
|
91
|
-
if (previous && JSON.parse(previous.value).epoch !== transaction.cursor.epoch) {
|
|
92
|
-
await this.database.runAsync(`DELETE FROM _gonvex_replica_entities WHERE scope = ?`, scope);
|
|
93
|
-
await this.database.runAsync(`DELETE FROM _gonvex_replica_queries WHERE scope = ?`, scope);
|
|
94
|
-
}
|
|
95
|
-
for (const change of transaction.changes) {
|
|
96
|
-
if (change.operation === "delete") {
|
|
97
|
-
await this.database.runAsync(`DELETE FROM _gonvex_replica_entities WHERE scope = ? AND entity = ? AND id = ?`, scope, change.entity, change.id);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
await this.database.runAsync(`INSERT INTO _gonvex_replica_entities (scope, entity, id, value) VALUES (?, ?, ?, ?)
|
|
101
|
-
ON CONFLICT(scope, entity, id) DO UPDATE SET value = excluded.value`, scope, change.entity, change.id, JSON.stringify(change.newValue));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
for (const membership of transaction.memberships ?? []) {
|
|
105
|
-
await this.database.runAsync(`INSERT INTO _gonvex_replica_queries (scope, signature, value) VALUES (?, ?, ?)
|
|
106
|
-
ON CONFLICT(scope, signature) DO UPDATE SET value = excluded.value`, scope, membership.signature, JSON.stringify(membership));
|
|
107
|
-
}
|
|
108
|
-
await this.database.runAsync(`INSERT INTO _gonvex_replica_meta (scope, key, value) VALUES (?, 'cursor', ?)
|
|
109
|
-
ON CONFLICT(scope, key) DO UPDATE SET value = excluded.value`, scope, JSON.stringify(transaction.cursor));
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
async replaceSnapshot(snapshot, scope = defaultReplicaScope) {
|
|
113
|
-
await this.initialize();
|
|
114
|
-
await this.database.withTransactionAsync(async () => {
|
|
115
|
-
await this.database.runAsync(`DELETE FROM _gonvex_replica_entities WHERE scope = ?`, scope);
|
|
116
|
-
await this.database.runAsync(`DELETE FROM _gonvex_replica_queries WHERE scope = ?`, scope);
|
|
117
|
-
await this.database.runAsync(`DELETE FROM _gonvex_replica_meta WHERE scope = ? AND key = 'cursor'`, scope);
|
|
118
|
-
for (const [entity, rows] of Object.entries(snapshot.entities)) {
|
|
119
|
-
for (const [id, value] of Object.entries(rows)) {
|
|
120
|
-
await this.database.runAsync(`INSERT INTO _gonvex_replica_entities (scope, entity, id, value) VALUES (?, ?, ?, ?)`, scope, entity, id, JSON.stringify(value));
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
for (const [signature, membership] of Object.entries(snapshot.liveQueries)) {
|
|
124
|
-
await this.database.runAsync(`INSERT INTO _gonvex_replica_queries (scope, signature, value) VALUES (?, ?, ?)`, scope, signature, JSON.stringify(membership));
|
|
125
|
-
}
|
|
126
|
-
if (snapshot.cursor) {
|
|
127
|
-
await this.database.runAsync(`INSERT INTO _gonvex_replica_meta (scope, key, value) VALUES (?, 'cursor', ?)
|
|
128
|
-
ON CONFLICT(scope, key) DO UPDATE SET value = excluded.value`, scope, JSON.stringify(snapshot.cursor));
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
export function expoSQLite(database) {
|
|
134
|
-
return new ExpoSQLiteLocalReplicaStorage(database);
|
|
135
|
-
}
|