Skip to content

Commit 85d1061

Browse files
committed
[sqlite] ExpoSqlite Persister
1 parent fad4a91 commit 85d1061

File tree

8 files changed

+181
-18
lines changed

8 files changed

+181
-18
lines changed

site/build.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ const addApi = (docs: Docs): Docs =>
135135
.addApiFile('lib/types/persisters/persister-sqlite3.d.ts')
136136
.addApiFile('lib/types/persisters/persister-sqlite-wasm.d.ts')
137137
.addApiFile('lib/types/persisters/persister-cr-sqlite-wasm.d.ts')
138+
.addApiFile('lib/types/persisters/persister-expo-sqlite.d.ts')
138139
.addApiFile('lib/types/tools.d.ts')
139140
.addApiFile('lib/types/ui-react.d.ts');
140141

site/guides/3_schemas_and_persistence/4_persisting_data.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@ which returns a new Persister object that can load and save a Store. Between
1616
them, these allow you to store your TinyBase data locally, remotely, to SQLite
1717
databases, and across synchronization boundaries with CRDT frameworks.
1818

19-
| Module | Function | Storage |
20-
| ------------------------ | --------------------------- | ---------------------------------------------------------------------------------- |
21-
| persister-browser | createSessionPersister | Browser session storage |
22-
| persister-browser | createLocalPersister | Browser local storage |
23-
| persister-remote | createRemotePersister | Remote server |
24-
| persister-file | createFilePersister | Local file (where possible) |
25-
| persister-sqlite3 | createSqlite3Persister | SQLite in Node, via [sqlite3](https://github.com/TryGhost/node-sqlite3) |
26-
| persister-sqlite-wasm | createSqliteWasmPersister | SQLite in a browser, via [sqlite-wasm](https://github.com/tomayac/sqlite-wasm) |
27-
| persister-cr-sqlite-wasm | createCrSqliteWasmPersister | SQLite CRDTs, via [cr-sqlite-wasm](https://github.com/vlcn-io/cr-sqlite) |
28-
| persister-yjs | createYjsPersister | Yjs CRDTs, via [yjs](https://github.com/yjs/yjs) |
29-
| persister-automerge | createSqliteWasmPersister | Automerge CRDTs, via [automerge-repo](https://github.com/automerge/automerge-repo) |
19+
| Module | Function | Storage |
20+
| ------------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------ |
21+
| persister-browser | createSessionPersister | Browser session storage |
22+
| persister-browser | createLocalPersister | Browser local storage |
23+
| persister-remote | createRemotePersister | Remote server |
24+
| persister-file | createFilePersister | Local file (where possible) |
25+
| persister-sqlite3 | createSqlite3Persister | SQLite in Node, via [sqlite3](https://github.com/TryGhost/node-sqlite3) |
26+
| persister-sqlite-wasm | createSqliteWasmPersister | SQLite in a browser, via [sqlite-wasm](https://github.com/tomayac/sqlite-wasm) |
27+
| persister-cr-sqlite-wasm | createCrSqliteWasmPersister | SQLite CRDTs, via [cr-sqlite-wasm](https://github.com/vlcn-io/cr-sqlite) |
28+
| persister-expo-sqlite | createExpoSqlitePersister | SQLite in React Native, via [expo-sqlite](https://github.com/expo/expo/tree/main/packages/expo-sqlite) |
29+
| persister-yjs | createYjsPersister | Yjs CRDTs, via [yjs](https://github.com/yjs/yjs) |
30+
| persister-automerge | createSqliteWasmPersister | Automerge CRDTs, via [automerge-repo](https://github.com/automerge/automerge-repo) |
3031

3132
See the Database Persistence guide for details on how to work with SQLite
3233
databases, and the Synchronizing Data guide for more complex synchronization

site/guides/3_schemas_and_persistence/6_database_persistence.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
Since v4.0, there are various options for persisting Store data to and from
44
SQLite databases, via a range of third-party modules.
55

6-
There are currently three SQLite-based persistence options:
7-
8-
| Module | Function | Storage |
9-
| ------------------------ | --------------------------- | ------------------------------------------------------------------------------ |
10-
| persister-sqlite3 | createSqlite3Persister | SQLite in Node, via [sqlite3](https://github.com/TryGhost/node-sqlite3) |
11-
| persister-sqlite-wasm | createSqliteWasmPersister | SQLite in a browser, via [sqlite-wasm](https://github.com/tomayac/sqlite-wasm) |
12-
| persister-cr-sqlite-wasm | createCrSqliteWasmPersister | SQLite CRDTs, via [cr-sqlite-wasm](https://github.com/vlcn-io/cr-sqlite) |
6+
There are currently four SQLite-based persistence options:
7+
8+
| Module | Function | Storage |
9+
| ------------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------ |
10+
| persister-sqlite3 | createSqlite3Persister | SQLite in Node, via [sqlite3](https://github.com/TryGhost/node-sqlite3) |
11+
| persister-sqlite-wasm | createSqliteWasmPersister | SQLite in a browser, via [sqlite-wasm](https://github.com/tomayac/sqlite-wasm) |
12+
| persister-cr-sqlite-wasm | createCrSqliteWasmPersister | SQLite CRDTs, via [cr-sqlite-wasm](https://github.com/vlcn-io/cr-sqlite) |
13+
| persister-expo-sqlite | createExpoSqlitePersister | SQLite in React Native, via [expo-sqlite](https://github.com/expo/expo/tree/main/packages/expo-sqlite) |
1314

1415
(Take a look at the
1516
[vite-tinybase-ts-react-crsqlite](https://github.com/tinyplex/vite-tinybase-ts-react-crsqlite)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {DatabasePersisterConfig, Persister} from '../types/persisters';
2+
import {ResultSet, SQLiteDatabase} from 'expo-sqlite';
3+
import {UpdateListener, createSqlitePersister} from './sqlite/create';
4+
import {IdObj} from '../common/obj';
5+
import {Store} from '../types/store';
6+
import {createExpoSqlitePersister as createExpoSqlitePersisterDecl} from '../types/persisters/persister-expo-sqlite';
7+
8+
type Subscription = {remove: () => void};
9+
10+
export const createExpoSqlitePersister = ((
11+
store: Store,
12+
db: SQLiteDatabase,
13+
configOrStoreTableName?: DatabasePersisterConfig | string,
14+
logSql?: (sql: string, args?: any[]) => void,
15+
): Persister =>
16+
createSqlitePersister(
17+
store,
18+
configOrStoreTableName,
19+
async (sql: string, args: any[] = []): Promise<IdObj<any>[]> =>
20+
((await db.execAsync([{sql, args}], false))[0] as ResultSet).rows,
21+
(listener: UpdateListener): Subscription =>
22+
db.onDatabaseChange(({tableName}) => listener(tableName)),
23+
(subscription: Subscription) => subscription.remove(),
24+
logSql,
25+
)) as typeof createExpoSqlitePersisterDecl;

src/types/docs/persisters.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* |persister-sqlite3|createSqlite3Persister|SQLite in Node, via [sqlite3](https://github.com/TryGhost/node-sqlite3)|
1919
* |persister-sqlite-wasm|createSqliteWasmPersister|SQLite in a browser, via [sqlite-wasm](https://github.com/tomayac/sqlite-wasm)|
2020
* |persister-cr-sqlite-wasm|createCrSqliteWasmPersister|SQLite CRDTs, via [cr-sqlite-wasm](https://github.com/vlcn-io/cr-sqlite)|
21+
* |persister-expo-sqlite|createExpoSqlitePersister|SQLite in React Native, via [expo-sqlite](https://github.com/expo/expo/tree/main/packages/expo-sqlite)|
2122
* |persister-yjs|createYjsPersister|Yjs CRDTs, via [yjs](https://github.com/yjs/yjs)|
2223
* |persister-automerge|createSqliteWasmPersister|Automerge CRDTs, via [automerge-repo](https://github.com/automerge/automerge-repo)|
2324
*
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* The persister-expo-sqlite module of the TinyBase project lets you save and
3+
* load Store data to and from a local Expo-SQLite database (in an appropriate
4+
* React Native environment).
5+
*
6+
* Note that this Persister is currently experimental as Expo themselves iterate
7+
* on the underlying database library API.
8+
* @see Persisting Data guide
9+
* @packageDocumentation
10+
* @module persister-expo-sqlite
11+
*/
12+
/// persister-expo-sqlite
13+
/**
14+
* The createExpoSqlitePersister function creates a Persister object that can
15+
* persist the Store to a local Expo-SQLite database (in an appropriate React
16+
* Native environment).
17+
*
18+
* Note that this Persister is currently experimental as Expo themselves iterate
19+
* on the underlying database library API.
20+
*
21+
* As well as providing a reference to the Store to persist, you must provide a
22+
* `db` parameter which identifies the database instance.
23+
*
24+
* A database Persister uses one of two modes: either a JSON serialization of
25+
* the whole Store stored in a single row of a table (the default), or a tabular
26+
* mapping of Table Ids to database table names and vice-versa).
27+
*
28+
* The third argument is a DatabasePersisterConfig object that configures which
29+
* of those modes to use, and settings for each. If the third argument is simply
30+
* a string, it is used as the `storeTableName` property of the JSON
31+
* serialization.
32+
*
33+
* See the documentation for the DpcJson and DpcTabular types for more
34+
* information on how both of those modes can be configured.
35+
* @param store The Store to persist.
36+
* @param db The database instance that was returned from
37+
* `SQLite.openDatabase(...)`.
38+
* @param configOrStoreTableName A DatabasePersisterConfig to configure the
39+
* persistence mode (or a string to set the `storeTableName` property of the
40+
* JSON serialization).
41+
* @returns A reference to the new Persister object.
42+
* @example
43+
* This example creates a Persister object and persists the Store to a local
44+
* SQLite database as a JSON serialization into the `my_tinybase` table. It
45+
* makes a change to the database directly and then reloads it back into the
46+
* Store.
47+
*
48+
* ```js yolo
49+
* const db = SQLite.openDatabase('my.db');
50+
* const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
51+
* const persister = createExpoSqlitePersister(store, db, 'my_tinybase');
52+
*
53+
* await persister.save();
54+
* // Store will be saved to the database.
55+
*
56+
* console.log(
57+
* await new Promise((resolve) =>
58+
* db.all('SELECT * FROM my_tinybase;', (_, rows) => resolve(rows)),
59+
* ),
60+
* );
61+
* // -> [{_id: '_', store: '[{"pets":{"fido":{"species":"dog"}}},{}]'}]
62+
*
63+
* await new Promise((resolve) =>
64+
* db.all(
65+
* 'UPDATE my_tinybase SET store = ' +
66+
* `'[{"pets":{"felix":{"species":"cat"}}},{}]' WHERE _id = '_';`,
67+
* resolve,
68+
* ),
69+
* );
70+
* await persister.load();
71+
* console.log(store.getTables());
72+
* // -> {pets: {felix: {species: 'cat'}}}
73+
*
74+
* persister.destroy();
75+
* ```
76+
* @example
77+
* This example creates a Persister object and persists the Store to a local
78+
* SQLite database with tabular mapping.
79+
*
80+
* ```js yolo
81+
* const db = SQLite.openDatabase('my.db');
82+
* const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
83+
* const persister = createExpoSqlitePersister(store, db, {
84+
* mode: 'tabular',
85+
* tables: {load: {pets: 'pets'}, save: {pets: 'pets'}},
86+
* });
87+
*
88+
* await persister.save();
89+
* console.log(
90+
* await new Promise((resolve) =>
91+
* db.all('SELECT * FROM pets;', (_, rows) => resolve(rows)),
92+
* ),
93+
* );
94+
* // -> [{_id: 'fido', species: 'dog'}]
95+
*
96+
* await new Promise((resolve) =>
97+
* db.all(
98+
* `INSERT INTO pets (_id, species) VALUES ('felix', 'cat')`,
99+
* resolve,
100+
* ),
101+
* );
102+
* await persister.load();
103+
* console.log(store.getTables());
104+
* // -> {pets: {fido: {species: 'dog'}, felix: {species: 'cat'}}}
105+
*
106+
* persister.destroy();
107+
* ```
108+
* @category Creation
109+
*/
110+
/// createExpoSqlitePersister
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// persister-expo-sqlite
2+
3+
import {DatabasePersisterConfig, Persister} from '../persisters';
4+
import {SQLiteDatabase} from 'expo-sqlite';
5+
import {Store} from '../store';
6+
7+
/// createExpoSqlitePersister
8+
export function createExpoSqlitePersister(
9+
store: Store,
10+
db: SQLiteDatabase,
11+
configOrStoreTableName?: DatabasePersisterConfig | string,
12+
): Persister;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// persister-expo-sqlite
2+
3+
import {DatabasePersisterConfig, Persister} from '../persisters';
4+
import {OptionalSchemas, Store} from '../store';
5+
import {SQLiteDatabase} from 'expo-sqlite';
6+
7+
/// createExpoSqlitePersister
8+
export function createExpoSqlitePersister<Schemas extends OptionalSchemas>(
9+
store: Store<Schemas>,
10+
db: SQLiteDatabase,
11+
configOrStoreTableName?: DatabasePersisterConfig<Schemas> | string,
12+
): Persister<Schemas>;

0 commit comments

Comments
 (0)