tinybase 9.5.0 → 9.6.0-beta.1

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.
Files changed (148) hide show
  1. package/@types/omni/index.d.ts +4 -0
  2. package/@types/omni/with-schemas/index.d.ts +4 -0
  3. package/@types/persisters/index.d.ts +8 -1
  4. package/@types/persisters/persister-better-sqlite3/index.d.ts +178 -0
  5. package/@types/persisters/persister-better-sqlite3/with-schemas/index.d.ts +202 -0
  6. package/@types/persisters/persister-capacitor-sqlite/index.d.ts +181 -0
  7. package/@types/persisters/persister-capacitor-sqlite/with-schemas/index.d.ts +205 -0
  8. package/@types/persisters/persister-indexed-db/index.d.ts +17 -9
  9. package/@types/persisters/persister-indexed-db/with-schemas/index.d.ts +18 -10
  10. package/@types/persisters/persister-libsql/index.d.ts +27 -0
  11. package/@types/persisters/persister-libsql/with-schemas/index.d.ts +27 -0
  12. package/@types/persisters/persister-pg/index.d.ts +197 -0
  13. package/@types/persisters/persister-pg/with-schemas/index.d.ts +222 -0
  14. package/@types/persisters/persister-supabase/index.d.ts +201 -0
  15. package/@types/persisters/persister-supabase/with-schemas/index.d.ts +217 -0
  16. package/@types/persisters/with-schemas/index.d.ts +8 -1
  17. package/@types/ui-react-dom/index.d.ts +10 -10
  18. package/@types/ui-react-dom/with-schemas/index.d.ts +10 -10
  19. package/@types/ui-react-dom-charts/index.d.ts +7 -7
  20. package/@types/ui-react-dom-charts/with-schemas/index.d.ts +7 -7
  21. package/@types/ui-react-inspector/index.d.ts +1 -1
  22. package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
  23. package/@types/ui-solid-dom/index.d.ts +10 -10
  24. package/@types/ui-solid-dom/with-schemas/index.d.ts +10 -10
  25. package/@types/ui-solid-inspector/index.d.ts +1 -1
  26. package/@types/ui-solid-inspector/with-schemas/index.d.ts +1 -1
  27. package/@types/ui-svelte-dom/index.d.ts +10 -10
  28. package/@types/ui-svelte-dom/with-schemas/index.d.ts +10 -10
  29. package/@types/ui-svelte-inspector/index.d.ts +1 -1
  30. package/@types/ui-svelte-inspector/with-schemas/index.d.ts +1 -1
  31. package/agents.md +55 -2
  32. package/min/omni/index.js +1 -1
  33. package/min/omni/index.js.gz +0 -0
  34. package/min/omni/with-schemas/index.js +1 -1
  35. package/min/omni/with-schemas/index.js.gz +0 -0
  36. package/min/persisters/index.js +1 -1
  37. package/min/persisters/index.js.gz +0 -0
  38. package/min/persisters/persister-better-sqlite3/index.js +1 -0
  39. package/min/persisters/persister-better-sqlite3/index.js.gz +0 -0
  40. package/min/persisters/persister-better-sqlite3/with-schemas/index.js +1 -0
  41. package/min/persisters/persister-better-sqlite3/with-schemas/index.js.gz +0 -0
  42. package/min/persisters/persister-capacitor-sqlite/index.js +1 -0
  43. package/min/persisters/persister-capacitor-sqlite/index.js.gz +0 -0
  44. package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js +1 -0
  45. package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js.gz +0 -0
  46. package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
  47. package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
  48. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
  49. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
  50. package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
  51. package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
  52. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
  53. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
  54. package/min/persisters/persister-electric-sql/index.js +1 -1
  55. package/min/persisters/persister-electric-sql/index.js.gz +0 -0
  56. package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
  57. package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
  58. package/min/persisters/persister-expo-sqlite/index.js +1 -1
  59. package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
  60. package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
  61. package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
  62. package/min/persisters/persister-indexed-db/index.js +1 -1
  63. package/min/persisters/persister-indexed-db/index.js.gz +0 -0
  64. package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
  65. package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
  66. package/min/persisters/persister-libsql/index.js +1 -1
  67. package/min/persisters/persister-libsql/index.js.gz +0 -0
  68. package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
  69. package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
  70. package/min/persisters/persister-pg/index.js +1 -0
  71. package/min/persisters/persister-pg/index.js.gz +0 -0
  72. package/min/persisters/persister-pg/with-schemas/index.js +1 -0
  73. package/min/persisters/persister-pg/with-schemas/index.js.gz +0 -0
  74. package/min/persisters/persister-pglite/index.js +1 -1
  75. package/min/persisters/persister-pglite/index.js.gz +0 -0
  76. package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
  77. package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
  78. package/min/persisters/persister-postgres/index.js +1 -1
  79. package/min/persisters/persister-postgres/index.js.gz +0 -0
  80. package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
  81. package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
  82. package/min/persisters/persister-powersync/index.js +1 -1
  83. package/min/persisters/persister-powersync/index.js.gz +0 -0
  84. package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
  85. package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
  86. package/min/persisters/persister-react-native-sqlite/index.js +1 -1
  87. package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
  88. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
  89. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
  90. package/min/persisters/persister-sqlite-bun/index.js +1 -1
  91. package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
  92. package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
  93. package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
  94. package/min/persisters/persister-sqlite-wasm/index.js +1 -1
  95. package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
  96. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
  97. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
  98. package/min/persisters/persister-sqlite3/index.js +1 -1
  99. package/min/persisters/persister-sqlite3/index.js.gz +0 -0
  100. package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
  101. package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
  102. package/min/persisters/persister-supabase/index.js +1 -0
  103. package/min/persisters/persister-supabase/index.js.gz +0 -0
  104. package/min/persisters/persister-supabase/with-schemas/index.js +1 -0
  105. package/min/persisters/persister-supabase/with-schemas/index.js.gz +0 -0
  106. package/min/persisters/with-schemas/index.js +1 -1
  107. package/min/persisters/with-schemas/index.js.gz +0 -0
  108. package/omni/index.js +269 -34
  109. package/omni/with-schemas/index.js +269 -34
  110. package/package.json +164 -4
  111. package/persisters/index.js +23 -7
  112. package/persisters/persister-better-sqlite3/index.js +1767 -0
  113. package/persisters/persister-better-sqlite3/with-schemas/index.js +1767 -0
  114. package/persisters/persister-capacitor-sqlite/index.js +1769 -0
  115. package/persisters/persister-capacitor-sqlite/with-schemas/index.js +1769 -0
  116. package/persisters/persister-cr-sqlite-wasm/index.js +20 -6
  117. package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +20 -6
  118. package/persisters/persister-durable-object-sql-storage/index.js +20 -7
  119. package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +20 -7
  120. package/persisters/persister-electric-sql/index.js +20 -6
  121. package/persisters/persister-electric-sql/with-schemas/index.js +20 -6
  122. package/persisters/persister-expo-sqlite/index.js +20 -6
  123. package/persisters/persister-expo-sqlite/with-schemas/index.js +20 -6
  124. package/persisters/persister-indexed-db/index.js +48 -20
  125. package/persisters/persister-indexed-db/with-schemas/index.js +48 -20
  126. package/persisters/persister-libsql/index.js +20 -6
  127. package/persisters/persister-libsql/with-schemas/index.js +20 -6
  128. package/persisters/persister-pg/index.js +1905 -0
  129. package/persisters/persister-pg/with-schemas/index.js +1905 -0
  130. package/persisters/persister-pglite/index.js +20 -6
  131. package/persisters/persister-pglite/with-schemas/index.js +20 -6
  132. package/persisters/persister-postgres/index.js +20 -6
  133. package/persisters/persister-postgres/with-schemas/index.js +20 -6
  134. package/persisters/persister-powersync/index.js +27 -10
  135. package/persisters/persister-powersync/with-schemas/index.js +27 -10
  136. package/persisters/persister-react-native-sqlite/index.js +20 -6
  137. package/persisters/persister-react-native-sqlite/with-schemas/index.js +20 -6
  138. package/persisters/persister-sqlite-bun/index.js +20 -6
  139. package/persisters/persister-sqlite-bun/with-schemas/index.js +20 -6
  140. package/persisters/persister-sqlite-wasm/index.js +20 -6
  141. package/persisters/persister-sqlite-wasm/with-schemas/index.js +20 -6
  142. package/persisters/persister-sqlite3/index.js +20 -6
  143. package/persisters/persister-sqlite3/with-schemas/index.js +20 -6
  144. package/persisters/persister-supabase/index.js +883 -0
  145. package/persisters/persister-supabase/with-schemas/index.js +883 -0
  146. package/persisters/with-schemas/index.js +23 -7
  147. package/readme.md +14 -14
  148. package/releases.md +163 -66
@@ -0,0 +1,205 @@
1
+ /**
2
+ * The persister-capacitor-sqlite module of the TinyBase project lets you save
3
+ * and load Store data to and from a SQLite database in a Capacitor app, via the
4
+ * `@capacitor-community/sqlite` plugin.
5
+ * @see Database Persistence guide
6
+ * @packageDocumentation
7
+ * @module persister-capacitor-sqlite
8
+ * @since 9.6.0
9
+ */
10
+ import type {SQLiteDBConnection} from '@capacitor-community/sqlite';
11
+ import type {MergeableStore} from '../../../mergeable-store/with-schemas/index.d.ts';
12
+ import type {
13
+ OptionalSchemas,
14
+ Store,
15
+ } from '../../../store/with-schemas/index.d.ts';
16
+ import type {
17
+ DatabasePersisterConfig,
18
+ DpcJson,
19
+ Persister,
20
+ Persists,
21
+ } from '../../with-schemas/index.d.ts';
22
+
23
+ /**
24
+ * The CapacitorSqlitePersister interface represents a Persister that lets you
25
+ * save and load Store data to and from a SQLite database in a Capacitor app.
26
+ *
27
+ * You should use the createCapacitorSqlitePersister function to create a
28
+ * CapacitorSqlitePersister object.
29
+ *
30
+ * It is a minor extension to the Persister interface and simply provides an
31
+ * extra getDb method for accessing a reference to the database connection the
32
+ * Store is being persisted to.
33
+ * @category Persister
34
+ * @since 9.6.0
35
+ */
36
+ export interface CapacitorSqlitePersister<
37
+ Schemas extends OptionalSchemas,
38
+ > extends Persister<Schemas, Persists.StoreOrMergeableStore> {
39
+ /**
40
+ * The getDb method returns a reference to the database connection the Store
41
+ * is being persisted to.
42
+ * @returns A reference to the database connection.
43
+ * @example
44
+ * This example creates a Persister object against a newly-created Store and
45
+ * then gets the database connection back out again.
46
+ *
47
+ * ```js ignore
48
+ * import {
49
+ * CapacitorSQLite,
50
+ * SQLiteConnection,
51
+ * } from '@capacitor-community/sqlite';
52
+ * import {createStore} from 'tinybase';
53
+ * import {createCapacitorSqlitePersister} from 'tinybase/persisters/persister-capacitor-sqlite';
54
+ *
55
+ * const sqlite = new SQLiteConnection(CapacitorSQLite);
56
+ * const db = await sqlite.createConnection(
57
+ * 'my.db',
58
+ * false,
59
+ * 'no-encryption',
60
+ * 1,
61
+ * false,
62
+ * );
63
+ * await db.open();
64
+ *
65
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
66
+ * const persister = createCapacitorSqlitePersister(store, db, 'my_tinybase');
67
+ *
68
+ * console.log(persister.getDb() == db);
69
+ * // -> true
70
+ *
71
+ * await persister.destroy();
72
+ * ```
73
+ * @category Getter
74
+ * @since 9.6.0
75
+ */
76
+ getDb(): SQLiteDBConnection;
77
+ }
78
+
79
+ /**
80
+ * The createCapacitorSqlitePersister function creates a
81
+ * CapacitorSqlitePersister object that can persist a Store to a SQLite database
82
+ * in a Capacitor app.
83
+ *
84
+ * This has schema-based typing. The following is a simplified representation:
85
+ *
86
+ * ```ts override
87
+ * createCapacitorSqlitePersister<StoreType extends Store>(
88
+ * store: StoreType,
89
+ * db: SQLiteDBConnection,
90
+ * configOrStoreTableName?:
91
+ * | (NoInfer<StoreType> extends MergeableStore
92
+ * ? DpcJson
93
+ * : DatabasePersisterConfig)
94
+ * | string,
95
+ * onSqlCommand?: (sql: string, params?: any[]) => void,
96
+ * onIgnoredError?: (error: any) => void,
97
+ * ): CapacitorSqlitePersister;
98
+ * ```
99
+ *
100
+ * A CapacitorSqlitePersister supports regular Store objects, and can also be
101
+ * used to persist the metadata of a MergeableStore when using the JSON
102
+ * serialization mode, as described below.
103
+ *
104
+ * As well as providing a reference to the Store to persist, you must provide a
105
+ * `db` parameter which is an open SQLiteDBConnection, as returned from the
106
+ * plugin's `createConnection` method.
107
+ *
108
+ * A database Persister uses one of two modes: either a JSON serialization of
109
+ * the whole Store stored in a single row of a table (the default), or a tabular
110
+ * mapping of Table Ids to database table names and vice-versa).
111
+ *
112
+ * The third argument is a DatabasePersisterConfig object that configures which
113
+ * of those modes to use, and settings for each. If the third argument is simply
114
+ * a string, it is used as the `storeTableName` property of the JSON
115
+ * serialization.
116
+ *
117
+ * See the documentation for the DpcJson and DpcTabular types for more
118
+ * information on how both of those modes can be configured.
119
+ *
120
+ * The plugin does not signal when the database changes underneath the
121
+ * Persister, so if you enable automatic loading with the startAutoLoad method,
122
+ * it polls the database for changes in the same way that the LibSqlPersister
123
+ * does.
124
+ *
125
+ * Note: TinyBase's tests for this module run against a mocked plugin rather
126
+ * than a real device, since `@capacitor-community/sqlite` needs a native iOS or
127
+ * Android runtime (or its `jeep-sqlite` web component) that a Node test suite
128
+ * cannot provide. The SQL behavior itself is covered by the other SQLite
129
+ * Persisters, which share all of it, but the binding to the plugin is only
130
+ * verified against those mocks. Please report anything that behaves differently
131
+ * on a real device.
132
+ * @param store The Store or MergeableStore to persist.
133
+ * @param db The database connection that was returned from
134
+ * `createConnection(...)`.
135
+ * @param configOrStoreTableName A DatabasePersisterConfig to configure the
136
+ * persistence mode (or a string to set the `storeTableName` property of the
137
+ * JSON serialization).
138
+ * @param onSqlCommand An optional handler called every time the Persister
139
+ * executes a SQL command or query. This is suitable for logging persistence
140
+ * behavior in a development environment.
141
+ * @param onIgnoredError An optional handler for the errors that the Persister
142
+ * would otherwise ignore when trying to save or load data. This is suitable for
143
+ * debugging persistence issues in a development environment.
144
+ * @returns A reference to the new CapacitorSqlitePersister object.
145
+ * @example
146
+ * This example creates a CapacitorSqlitePersister object and persists the Store
147
+ * to a SQLite database as a JSON serialization into the `my_tinybase` table. It
148
+ * makes a change to the database directly and then reloads it back into the
149
+ * Store.
150
+ *
151
+ * ```js ignore
152
+ * import {
153
+ * CapacitorSQLite,
154
+ * SQLiteConnection,
155
+ * } from '@capacitor-community/sqlite';
156
+ * import {createStore} from 'tinybase';
157
+ * import {createCapacitorSqlitePersister} from 'tinybase/persisters/persister-capacitor-sqlite';
158
+ *
159
+ * const sqlite = new SQLiteConnection(CapacitorSQLite);
160
+ * const db = await sqlite.createConnection(
161
+ * 'my.db',
162
+ * false,
163
+ * 'no-encryption',
164
+ * 1,
165
+ * false,
166
+ * );
167
+ * await db.open();
168
+ *
169
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
170
+ * const persister = createCapacitorSqlitePersister(store, db, 'my_tinybase');
171
+ *
172
+ * await persister.save();
173
+ * // Store will be saved to the database.
174
+ *
175
+ * console.log((await db.query('SELECT * FROM my_tinybase;')).values);
176
+ * // -> [{_id: '_', store: '[{"pets":{"fido":{"species":"dog"}}},{}]'}]
177
+ *
178
+ * await db.run(
179
+ * 'UPDATE my_tinybase SET store = ? WHERE _id = ?;',
180
+ * ['[{"pets":{"felix":{"species":"cat"}}},{}]', '_'],
181
+ * false,
182
+ * );
183
+ * await persister.load();
184
+ * console.log(store.getTables());
185
+ * // -> {pets: {felix: {species: 'cat'}}}
186
+ *
187
+ * await persister.destroy();
188
+ * ```
189
+ * @category Creation
190
+ * @since 9.6.0
191
+ */
192
+ export function createCapacitorSqlitePersister<Schemas extends OptionalSchemas>(
193
+ store: MergeableStore<Schemas>,
194
+ db: SQLiteDBConnection,
195
+ configOrStoreTableName?: DpcJson | string,
196
+ onSqlCommand?: (sql: string, params?: any[]) => void,
197
+ onIgnoredError?: (error: any) => void,
198
+ ): CapacitorSqlitePersister<Schemas>;
199
+ export function createCapacitorSqlitePersister<Schemas extends OptionalSchemas>(
200
+ store: Store<Schemas> & {getMergeableContent?: never},
201
+ db: SQLiteDBConnection,
202
+ configOrStoreTableName?: DatabasePersisterConfig<Schemas> | string,
203
+ onSqlCommand?: (sql: string, params?: any[]) => void,
204
+ onIgnoredError?: (error: any) => void,
205
+ ): CapacitorSqlitePersister<Schemas>;
@@ -6,8 +6,9 @@
6
6
  * @module persister-indexed-db
7
7
  * @since v4.2.0
8
8
  */
9
+ import type {MergeableStore} from '../../mergeable-store/index.d.ts';
9
10
  import type {Store} from '../../store/index.d.ts';
10
- import type {Persister} from '../index.d.ts';
11
+ import type {Persister, Persists} from '../index.d.ts';
11
12
 
12
13
  /**
13
14
  * The IndexedDbPersister interface represents a Persister that lets you save
@@ -22,7 +23,7 @@ import type {Persister} from '../index.d.ts';
22
23
  * @category Persister
23
24
  * @since v4.3.14
24
25
  */
25
- export interface IndexedDbPersister extends Persister {
26
+ export interface IndexedDbPersister extends Persister<Persists.StoreOrMergeableStore> {
26
27
  /**
27
28
  * The getDbName method returns the unique key of the IndexedDB the Store is
28
29
  * being persisted to.
@@ -53,17 +54,24 @@ export interface IndexedDbPersister extends Persister {
53
54
  * The createIndexedDbPersister function creates an IndexedDbPersister object
54
55
  * that can persist a Store to the browser's IndexedDB storage.
55
56
  *
56
- * An IndexedDbPersister only supports regular Store objects, and cannot be used
57
- * to persist the metadata of a MergeableStore.
57
+ * An IndexedDbPersister supports regular Store objects, and, since v9.6, can
58
+ * also be used to persist the metadata of a MergeableStore.
58
59
  *
59
60
  * As well as providing a reference to the Store to persist, you must provide a
60
61
  * `dbName` parameter which is unique to your application. This is the key used
61
62
  * to identify which IndexedDB to use.
62
63
  *
63
- * Within that database, this Persister will create two object stores: one
64
- * called 't', and one called 'v'. These will contain the Store's tabular and
65
- * key-value data respectively, using 'k' and 'v' to store the key and value of
66
- * each entry, as shown in the example.
64
+ * Within that database, this Persister will create three object stores. A
65
+ * regular Store uses one called 't' and one called 'v', which contain its
66
+ * tabular and key-value data respectively, using 'k' and 'v' to store the key
67
+ * and value of each entry, as shown in the example. A MergeableStore instead
68
+ * uses one called 'm', which holds its two halves of mergeable content under
69
+ * the keys 't' and 'v'.
70
+ *
71
+ * Since the two live alongside each other, a database written by a regular
72
+ * Store can be read by another regular Store, and the same for MergeableStore
73
+ * objects, but the two do not share data. Databases created before v9.6 are
74
+ * upgraded in place, and their existing content is preserved.
67
75
  *
68
76
  * Note that it is not possible to reactively detect changes to a browser's
69
77
  * IndexedDB. If you do choose to enable automatic loading for the Persister
@@ -113,7 +121,7 @@ export interface IndexedDbPersister extends Persister {
113
121
  * @since v4.2.0
114
122
  */
115
123
  export function createIndexedDbPersister(
116
- store: Store,
124
+ store: Store | MergeableStore,
117
125
  dbName: string,
118
126
  autoLoadIntervalSeconds?: number,
119
127
  onIgnoredError?: (error: any) => void,
@@ -6,11 +6,12 @@
6
6
  * @module persister-indexed-db
7
7
  * @since v4.2.0
8
8
  */
9
+ import type {MergeableStore} from '../../../mergeable-store/with-schemas/index.d.ts';
9
10
  import type {
10
11
  OptionalSchemas,
11
12
  Store,
12
13
  } from '../../../store/with-schemas/index.d.ts';
13
- import type {Persister} from '../../with-schemas/index.d.ts';
14
+ import type {Persister, Persists} from '../../with-schemas/index.d.ts';
14
15
 
15
16
  /**
16
17
  * The IndexedDbPersister interface represents a Persister that lets you save
@@ -27,7 +28,7 @@ import type {Persister} from '../../with-schemas/index.d.ts';
27
28
  */
28
29
  export interface IndexedDbPersister<
29
30
  Schemas extends OptionalSchemas,
30
- > extends Persister<Schemas> {
31
+ > extends Persister<Schemas, Persists.StoreOrMergeableStore> {
31
32
  /**
32
33
  * The getDbName method returns the unique key of the IndexedDB the Store is
33
34
  * being persisted to.
@@ -62,24 +63,31 @@ export interface IndexedDbPersister<
62
63
  *
63
64
  * ```ts override
64
65
  * createIndexedDbPersister(
65
- * store: Store,
66
+ * store: Store | MergeableStore,
66
67
  * dbName: string,
67
68
  * autoLoadIntervalSeconds?: number,
68
69
  * onIgnoredError?: (error: any) => void,
69
70
  * ): IndexedDbPersister;
70
71
  * ```
71
72
  *
72
- * An IndexedDbPersister only supports regular Store objects, and cannot be used
73
- * to persist the metadata of a MergeableStore.
73
+ * An IndexedDbPersister supports regular Store objects, and, since v9.6, can
74
+ * also be used to persist the metadata of a MergeableStore.
74
75
  *
75
76
  * As well as providing a reference to the Store to persist, you must provide a
76
77
  * `dbName` parameter which is unique to your application. This is the key used
77
78
  * to identify which IndexedDB to use.
78
79
  *
79
- * Within that database, this Persister will create two object stores: one
80
- * called 't', and one called 'v'. These will contain the Store's tabular and
81
- * key-value data respectively, using 'k' and 'v' to store the key and value of
82
- * each entry, as shown in the example.
80
+ * Within that database, this Persister will create three object stores. A
81
+ * regular Store uses one called 't' and one called 'v', which contain its
82
+ * tabular and key-value data respectively, using 'k' and 'v' to store the key
83
+ * and value of each entry, as shown in the example. A MergeableStore instead
84
+ * uses one called 'm', which holds its two halves of mergeable content under
85
+ * the keys 't' and 'v'.
86
+ *
87
+ * Since the two live alongside each other, a database written by a regular
88
+ * Store can be read by another regular Store, and the same for MergeableStore
89
+ * objects, but the two do not share data. Databases created before v9.6 are
90
+ * upgraded in place, and their existing content is preserved.
83
91
  *
84
92
  * Note that it is not possible to reactively detect changes to a browser's
85
93
  * IndexedDB. If you do choose to enable automatic loading for the Persister
@@ -129,7 +137,7 @@ export interface IndexedDbPersister<
129
137
  * @since v4.2.0
130
138
  */
131
139
  export function createIndexedDbPersister<Schemas extends OptionalSchemas>(
132
- store: Store<Schemas>,
140
+ store: Store<Schemas> | MergeableStore<Schemas>,
133
141
  dbName: string,
134
142
  autoLoadIntervalSeconds?: number,
135
143
  onIgnoredError?: (error: any) => void,
@@ -2,6 +2,10 @@
2
2
  * The persister-libsql module of the TinyBase project lets you save and load
3
3
  * Store data to and from a local LibSQL database (in an appropriate
4
4
  * environment).
5
+ *
6
+ * This is also the module to use with hosted services built on LibSQL, such as
7
+ * Turso and Astro DB. See the createLibSqlPersister function for how to get at
8
+ * the underlying client in an Astro project.
5
9
  * @see Database Persistence guide
6
10
  * @packageDocumentation
7
11
  * @module persister-libsql
@@ -78,6 +82,29 @@ export interface LibSqlPersister extends Persister {
78
82
  * Note: When using tabular mode, SQL NULL values are loaded as TinyBase null
79
83
  * values, making tables dense (every Row has every Cell). See the Database
80
84
  * Persistence guide for details.
85
+ *
86
+ * In an Astro project, the `db` object exported from `astro:db` is a Drizzle
87
+ * wrapper around a LibSQL client, and its `$client` property is the client this
88
+ * Persister needs. That property is present at runtime but missing from the
89
+ * type that Astro exports, so TypeScript needs a cast to reach it:
90
+ *
91
+ * ```js ignore
92
+ * import type {Database} from '@astrojs/db/runtime';
93
+ * import type {Client} from '@libsql/client';
94
+ * import {db} from 'astro:db';
95
+ * import {createStore} from 'tinybase';
96
+ * import {createLibSqlPersister} from 'tinybase/persisters/persister-libsql';
97
+ *
98
+ * const client = (db as Database & {$client: Client}).$client;
99
+ * const persister = createLibSqlPersister(
100
+ * createStore(),
101
+ * client,
102
+ * 'my_tinybase',
103
+ * );
104
+ *
105
+ * await persister.load();
106
+ * await persister.destroy();
107
+ * ```
81
108
  * @param store The Store to persist.
82
109
  * @param client The database client that was returned from `createClient(...)`.
83
110
  * @param configOrStoreTableName A DatabasePersisterConfig to configure the
@@ -2,6 +2,10 @@
2
2
  * The persister-libsql module of the TinyBase project lets you save and load
3
3
  * Store data to and from a local LibSQL database (in an appropriate
4
4
  * environment).
5
+ *
6
+ * This is also the module to use with hosted services built on LibSQL, such as
7
+ * Turso and Astro DB. See the createLibSqlPersister function for how to get at
8
+ * the underlying client in an Astro project.
5
9
  * @see Database Persistence guide
6
10
  * @packageDocumentation
7
11
  * @module persister-libsql
@@ -98,6 +102,29 @@ export interface LibSqlPersister<
98
102
  * Note: When using tabular mode, SQL NULL values are loaded as TinyBase null
99
103
  * values, making tables dense (every Row has every Cell). See the Database
100
104
  * Persistence guide for details.
105
+ *
106
+ * In an Astro project, the `db` object exported from `astro:db` is a Drizzle
107
+ * wrapper around a LibSQL client, and its `$client` property is the client this
108
+ * Persister needs. That property is present at runtime but missing from the
109
+ * type that Astro exports, so TypeScript needs a cast to reach it:
110
+ *
111
+ * ```js ignore
112
+ * import type {Database} from '@astrojs/db/runtime';
113
+ * import type {Client} from '@libsql/client';
114
+ * import {db} from 'astro:db';
115
+ * import {createStore} from 'tinybase';
116
+ * import {createLibSqlPersister} from 'tinybase/persisters/persister-libsql';
117
+ *
118
+ * const client = (db as Database & {$client: Client}).$client;
119
+ * const persister = createLibSqlPersister(
120
+ * createStore(),
121
+ * client,
122
+ * 'my_tinybase',
123
+ * );
124
+ *
125
+ * await persister.load();
126
+ * await persister.destroy();
127
+ * ```
101
128
  * @param store The Store to persist.
102
129
  * @param client The database client that was returned from `createClient(...)`.
103
130
  * @param configOrStoreTableName A DatabasePersisterConfig to configure the
@@ -0,0 +1,197 @@
1
+ /**
2
+ * The persister-pg module of the TinyBase project lets you save and load Store
3
+ * data to and from a PostgreSQL database, via the `pg` module (in an
4
+ * appropriate environment).
5
+ *
6
+ * Since the `pg` module is the de facto standard PostgreSQL driver for Node.js,
7
+ * this module also works with the many hosted PostgreSQL services that provide
8
+ * a `pg`-compatible driver, such as Neon.
9
+ * @see Database Persistence guide
10
+ * @packageDocumentation
11
+ * @module persister-pg
12
+ * @since 9.6.0
13
+ */
14
+ import type {Client, Pool} from 'pg';
15
+ import type {MergeableStore} from '../../mergeable-store/index.d.ts';
16
+ import type {Store} from '../../store/index.d.ts';
17
+ import type {
18
+ DatabasePersisterConfig,
19
+ DpcJson,
20
+ Persister,
21
+ Persists,
22
+ } from '../index.d.ts';
23
+
24
+ /**
25
+ * The PgPersister interface represents a Persister that lets you save and load
26
+ * Store data to and from a PostgreSQL database, via the `pg` module.
27
+ *
28
+ * You should use the createPgPersister function to create a PgPersister object.
29
+ *
30
+ * It is a minor extension to the Persister interface and simply provides an
31
+ * extra getPg method for accessing a reference to the database connection the
32
+ * Store is being persisted to.
33
+ * @category Persister
34
+ * @since 9.6.0
35
+ */
36
+ export interface PgPersister extends Persister<Persists.StoreOrMergeableStore> {
37
+ /**
38
+ * The getPg method returns a reference to the database connection the Store
39
+ * is being persisted to.
40
+ * @returns A reference to the `pg` Pool or Client.
41
+ * @example
42
+ * This example creates a Persister object against a newly-created Store and
43
+ * then gets the database connection back out again.
44
+ *
45
+ * ```js
46
+ * import {Pool} from 'pg';
47
+ * import {createStore} from 'tinybase';
48
+ * import {createPgPersister} from 'tinybase/persisters/persister-pg';
49
+ *
50
+ * const pool = new Pool({
51
+ * connectionString: 'postgres://localhost:5432/tinybase',
52
+ * });
53
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
54
+ * const persister = await createPgPersister(store, pool, 'my_tinybase');
55
+ *
56
+ * console.log(persister.getPg() == pool);
57
+ * // -> true
58
+ *
59
+ * await persister.destroy();
60
+ * await pool.end();
61
+ * ```
62
+ * @category Getter
63
+ * @since 9.6.0
64
+ */
65
+ getPg(): Pool | Client;
66
+ }
67
+
68
+ /**
69
+ * The createPgPersister function creates a PgPersister object that can persist
70
+ * the Store to a PostgreSQL database via the `pg` module.
71
+ *
72
+ * A PgPersister supports regular Store objects, and can also be used to persist
73
+ * the metadata of a MergeableStore when using the JSON serialization mode, as
74
+ * described below.
75
+ *
76
+ * As well as providing a reference to the Store to persist, you must provide a
77
+ * `pg` parameter which is either a Pool or a Client. If you provide a Pool, one
78
+ * connection is checked out for the lifetime of the Persister (and a second
79
+ * while automatic loading is enabled), since the Persister needs to issue
80
+ * transactions on a stable connection. Make sure your pool is large enough to
81
+ * accommodate that.
82
+ *
83
+ * A database Persister uses one of two modes: either a JSON serialization of
84
+ * the whole Store stored in a single row of a table (the default), or a tabular
85
+ * mapping of Table Ids to database table names and vice-versa).
86
+ *
87
+ * The third argument is a DatabasePersisterConfig object that configures which
88
+ * of those modes to use, and settings for each. If the third argument is simply
89
+ * a string, it is used as the `storeTableName` property of the JSON
90
+ * serialization.
91
+ *
92
+ * See the documentation for the DpcJson and DpcTabular types for more
93
+ * information on how both of those modes can be configured.
94
+ *
95
+ * Note: When using tabular mode, SQL NULL values are loaded as TinyBase null
96
+ * values, making tables dense (every Row has every Cell). See the Database
97
+ * Persistence guide for details.
98
+ *
99
+ * This method is asynchronous because it will await the creation of a dedicated
100
+ * new connection to the database. You will need to `await` a call to this
101
+ * function or handle the return type natively as a Promise.
102
+ * @param store The Store or MergeableStore to persist.
103
+ * @param pg The `pg` Pool or Client that identifies the database connection.
104
+ * @param configOrStoreTableName A DatabasePersisterConfig to configure the
105
+ * persistence mode (or a string to set the `storeTableName` property of the
106
+ * JSON serialization).
107
+ * @param onSqlCommand An optional handler called every time the Persister
108
+ * executes a SQL command or query. This is suitable for logging persistence
109
+ * behavior in a development environment.
110
+ * @param onIgnoredError An optional handler for the errors that the Persister
111
+ * would otherwise ignore when trying to save or load data. This is suitable for
112
+ * debugging persistence issues in a development environment.
113
+ * @returns A reference to the new PgPersister object.
114
+ * @example
115
+ * This example creates a PgPersister object and persists the Store to a local
116
+ * PostgreSQL database as a JSON serialization into the `my_tinybase` table. It
117
+ * makes a change to the database directly and then reloads it back into the
118
+ * Store.
119
+ *
120
+ * ```js
121
+ * import {Pool} from 'pg';
122
+ * import {createStore} from 'tinybase';
123
+ * import {createPgPersister} from 'tinybase/persisters/persister-pg';
124
+ *
125
+ * const pool = new Pool({
126
+ * connectionString: 'postgres://localhost:5432/tinybase',
127
+ * });
128
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
129
+ * const persister = await createPgPersister(store, pool, 'my_tinybase');
130
+ *
131
+ * await persister.save();
132
+ * // Store will be saved to the database.
133
+ *
134
+ * console.log((await pool.query('SELECT * FROM my_tinybase;')).rows);
135
+ * // -> [{_id: '_', store: '[{"pets":{"fido":{"species":"dog"}}},{}]'}]
136
+ *
137
+ * const json = '[{"pets":{"felix":{"species":"cat"}}},{}]';
138
+ * await pool.query('UPDATE my_tinybase SET store = $1 WHERE _id = $2;', [
139
+ * json,
140
+ * '_',
141
+ * ]);
142
+ *
143
+ * await persister.load();
144
+ * console.log(store.getTables());
145
+ * // -> {pets: {felix: {species: 'cat'}}}
146
+ *
147
+ * await persister.destroy();
148
+ * await pool.end();
149
+ * ```
150
+ * @example
151
+ * This example creates a PgPersister object and persists the Store to a local
152
+ * PostgreSQL database with tabular mapping.
153
+ *
154
+ * ```js
155
+ * import {Pool} from 'pg';
156
+ * import {createStore} from 'tinybase';
157
+ * import {createPgPersister} from 'tinybase/persisters/persister-pg';
158
+ *
159
+ * const pool = new Pool({
160
+ * connectionString: 'postgres://localhost:5432/tinybase',
161
+ * });
162
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
163
+ * const persister = await createPgPersister(store, pool, {
164
+ * mode: 'tabular',
165
+ * tables: {load: {pets: 'pets'}, save: {pets: 'pets'}},
166
+ * });
167
+ *
168
+ * await persister.save();
169
+ * console.log((await pool.query('SELECT * FROM pets;')).rows);
170
+ * // -> [{_id: 'fido', species: '"dog"'}]
171
+ * // Note that Cells and Values are JSON-encoded in PostgreSQL databases.
172
+ *
173
+ * await pool.query(
174
+ * `INSERT INTO pets (_id, species) VALUES ('felix', '"cat"')`,
175
+ * );
176
+ * await persister.load();
177
+ * console.log(store.getTables());
178
+ * // -> {pets: {fido: {species: 'dog'}, felix: {species: 'cat'}}}
179
+ *
180
+ * await persister.destroy();
181
+ * await pool.query('DROP TABLE IF EXISTS pets');
182
+ * await pool.end();
183
+ * ```
184
+ * @category Creation
185
+ * @since 9.6.0
186
+ */
187
+ export function createPgPersister<StoreType extends Store>(
188
+ store: StoreType,
189
+ pg: Pool | Client,
190
+ configOrStoreTableName?:
191
+ | (NoInfer<StoreType> extends MergeableStore
192
+ ? DpcJson
193
+ : DatabasePersisterConfig)
194
+ | string,
195
+ onSqlCommand?: (sql: string, params?: any[]) => void,
196
+ onIgnoredError?: (error: any) => void,
197
+ ): Promise<PgPersister>;