tanstack-db-pglite 1.3.5 → 1.3.6
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/README.md +137 -24
- package/dist/drizzle.d.ts +1 -1
- package/dist/drizzle.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
# tanstack-db-pglite
|
|
2
2
|
|
|
3
|
-
A seamless integration between [TanStack DB](https://tanstack.com/db) and [PGLite](https://github.com/electric-sql/pglite) with [Drizzle ORM](https://orm.drizzle.team/) for browser-based database management.
|
|
3
|
+
A seamless integration between [TanStack DB](https://tanstack.com/db) and [PGLite](https://github.com/electric-sql/pglite) with optional [Drizzle ORM](https://orm.drizzle.team/) support for browser-based database management.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install tanstack-db-pglite @tanstack/db
|
|
8
|
+
npm install tanstack-db-pglite @tanstack/db @electric-sql/pglite
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
> **Note:** `@tanstack/db` and `drizzle-orm`
|
|
11
|
+
> **Note:** `@tanstack/db` and `@electric-sql/pglite` are peer dependencies. `drizzle-orm` is an optional peer dependency required only when using `drizzleCollectionOptions`.
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## APIs
|
|
14
|
+
|
|
15
|
+
This package exports two collection option creators:
|
|
16
|
+
|
|
17
|
+
- `drizzleCollectionOptions` — uses Drizzle ORM on top of PGlite
|
|
18
|
+
- `sqlCollectionOptions` — uses raw SQL queries directly on PGlite
|
|
19
|
+
|
|
20
|
+
Both follow the TanStack DB [collection options creator](https://tanstack.com/db/latest/docs/guides/collection-options-creator) pattern.
|
|
21
|
+
|
|
22
|
+
## Quick Start (Drizzle)
|
|
14
23
|
|
|
15
24
|
```typescript
|
|
16
|
-
import {
|
|
25
|
+
import { PGlite } from '@electric-sql/pglite'
|
|
17
26
|
import { createCollection } from '@tanstack/react-db'
|
|
18
27
|
import { drizzle } from 'drizzle-orm/pglite'
|
|
19
28
|
import { drizzleCollectionOptions } from 'tanstack-db-pglite'
|
|
20
29
|
import { chats } from '~/drizzle'
|
|
21
30
|
|
|
22
|
-
const pglite = new
|
|
31
|
+
const pglite = new PGlite()
|
|
23
32
|
const db = drizzle(pglite)
|
|
24
33
|
|
|
25
34
|
export const chatsCollection = createCollection(drizzleCollectionOptions({
|
|
@@ -27,26 +36,23 @@ export const chatsCollection = createCollection(drizzleCollectionOptions({
|
|
|
27
36
|
table: chats,
|
|
28
37
|
primaryColumn: chats.id,
|
|
29
38
|
prepare: async () => {
|
|
30
|
-
// Prepare your database before starting the collection (e.g., run migrations)
|
|
31
39
|
await waitForMigrations()
|
|
32
40
|
},
|
|
33
|
-
sync: async ({
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
})
|
|
41
|
+
sync: async ({ begin, commit, write, markReady }) => {
|
|
42
|
+
const eventSource = new EventSource('/api/chats/sync')
|
|
43
|
+
|
|
44
|
+
eventSource.onmessage = (event) => {
|
|
45
|
+
const item = JSON.parse(event.data)
|
|
46
|
+
begin()
|
|
47
|
+
write(item)
|
|
48
|
+
commit()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
eventSource.addEventListener('ready', () => markReady())
|
|
52
|
+
|
|
53
|
+
return () => {
|
|
54
|
+
eventSource.close()
|
|
55
|
+
}
|
|
50
56
|
},
|
|
51
57
|
onInsert: async (params) => {
|
|
52
58
|
await saveInCloud(params)
|
|
@@ -59,3 +65,110 @@ export const chatsCollection = createCollection(drizzleCollectionOptions({
|
|
|
59
65
|
},
|
|
60
66
|
}))
|
|
61
67
|
```
|
|
68
|
+
|
|
69
|
+
## Quick Start (Raw SQL)
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { PGlite } from '@electric-sql/pglite'
|
|
73
|
+
import { createCollection } from '@tanstack/react-db'
|
|
74
|
+
import { sqlCollectionOptions } from 'tanstack-db-pglite'
|
|
75
|
+
import { z } from 'zod'
|
|
76
|
+
|
|
77
|
+
const pglite = new PGlite()
|
|
78
|
+
|
|
79
|
+
const chatSchema = z.object({
|
|
80
|
+
id: z.string(),
|
|
81
|
+
name: z.string(),
|
|
82
|
+
updatedAt: z.string(),
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
export const chatsCollection = createCollection(sqlCollectionOptions({
|
|
86
|
+
db: pglite,
|
|
87
|
+
tableName: 'chats',
|
|
88
|
+
primaryKeyColumn: 'id',
|
|
89
|
+
schema: chatSchema,
|
|
90
|
+
prepare: async () => {
|
|
91
|
+
await pglite.query(`
|
|
92
|
+
CREATE TABLE IF NOT EXISTS chats (
|
|
93
|
+
id TEXT PRIMARY KEY,
|
|
94
|
+
name TEXT NOT NULL,
|
|
95
|
+
"updatedAt" TEXT NOT NULL
|
|
96
|
+
)
|
|
97
|
+
`)
|
|
98
|
+
},
|
|
99
|
+
sync: async ({ begin, commit, write, markReady }) => {
|
|
100
|
+
const eventSource = new EventSource('/api/chats/sync')
|
|
101
|
+
|
|
102
|
+
eventSource.onmessage = (event) => {
|
|
103
|
+
const item = JSON.parse(event.data)
|
|
104
|
+
begin()
|
|
105
|
+
write(item)
|
|
106
|
+
commit()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
eventSource.addEventListener('ready', () => markReady())
|
|
110
|
+
|
|
111
|
+
return () => {
|
|
112
|
+
eventSource.close()
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
}))
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Options
|
|
119
|
+
|
|
120
|
+
### Common Options
|
|
121
|
+
|
|
122
|
+
| Option | Type | Description |
|
|
123
|
+
|--------|------|-------------|
|
|
124
|
+
| `startSync` | `boolean` | Whether to run the `sync` callback automatically on startup. Defaults to `true`. When `false`, use `collection.utils.runSync()` to trigger manually. |
|
|
125
|
+
| `prepare` | `() => Promise<unknown> \| unknown` | Runs before the initial data load (e.g., run migrations). |
|
|
126
|
+
| `sync` | `(params) => Promise<(() => void) \| void>` | Sync callback receiving `write`, `markReady`, `collection`, and `metadata`. Return a cleanup function to close subscriptions. |
|
|
127
|
+
| `rowUpdateMode` | `'partial' \| 'full'` | Whether sync updates contain partial changes or full row replacements. |
|
|
128
|
+
| `onInsert` | `(params) => Promise<void>` | Called when a row is inserted optimistically. Persist to your backend here. |
|
|
129
|
+
| `onUpdate` | `(params) => Promise<void>` | Called when a row is updated optimistically. Persist to your backend here. |
|
|
130
|
+
| `onDelete` | `(params) => Promise<void>` | Called when a row is deleted optimistically. Persist to your backend here. |
|
|
131
|
+
|
|
132
|
+
### `drizzleCollectionOptions` Specific
|
|
133
|
+
|
|
134
|
+
| Option | Type | Description |
|
|
135
|
+
|--------|------|-------------|
|
|
136
|
+
| `db` | `PgliteDatabase` | Drizzle PGlite database instance. |
|
|
137
|
+
| `table` | `PgTable` | Drizzle table definition. |
|
|
138
|
+
| `primaryColumn` | `IndexColumn` | The primary key column from the table. |
|
|
139
|
+
|
|
140
|
+
### `sqlCollectionOptions` Specific
|
|
141
|
+
|
|
142
|
+
| Option | Type | Description |
|
|
143
|
+
|--------|------|-------------|
|
|
144
|
+
| `db` | `PGlite \| PGliteWorker` | PGlite instance (or worker). |
|
|
145
|
+
| `tableName` | `string` | SQL table name. |
|
|
146
|
+
| `primaryKeyColumn` | `string` | Name of the primary key column. |
|
|
147
|
+
| `schema` | `StandardSchemaV1` | A Standard Schema (e.g., Zod) for the row type. |
|
|
148
|
+
| `getKey` | `(row) => string` | Custom key extractor. Defaults to `row[primaryKeyColumn]`. |
|
|
149
|
+
|
|
150
|
+
## Utilities
|
|
151
|
+
|
|
152
|
+
Both adapters expose a `utils` object on the collection:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Manually trigger sync (cleans up any previous sync, then re-syncs)
|
|
156
|
+
await chatsCollection.utils.runSync()
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
This is useful when `startSync: false` and you want to control when sync starts (e.g., after authentication).
|
|
160
|
+
|
|
161
|
+
## Sync Callback
|
|
162
|
+
|
|
163
|
+
The `sync` callback receives:
|
|
164
|
+
|
|
165
|
+
- **`write(message)`** — writes a change to both PGlite and the TanStack DB collection. Accepts `{ type: 'insert', value }`, `{ type: 'update', value }`, or `{ type: 'delete', key }`.
|
|
166
|
+
- **`markReady()`** — signals that the initial data is loaded and the collection is ready for queries. Must be called once.
|
|
167
|
+
- **`collection`** — reference to the collection instance.
|
|
168
|
+
- **`metadata`** — persisted sync metadata API for storing resume tokens, cursors, etc.
|
|
169
|
+
|
|
170
|
+
Return a cleanup function to close long-lived connections (WebSocket, EventSource, etc.) when the collection is destroyed or `runSync()` is called again.
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/dist/drizzle.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare function drizzleCollectionOptions<Table extends PgTable>({ startS
|
|
|
19
19
|
table: Table;
|
|
20
20
|
primaryColumn: IndexColumn;
|
|
21
21
|
rowUpdateMode?: 'partial' | 'full';
|
|
22
|
-
sync?: (params:
|
|
22
|
+
sync?: (params: SyncParams<Table>) => Promise<(() => void) | void>;
|
|
23
23
|
prepare?: () => Promise<unknown> | unknown;
|
|
24
24
|
onInsert?: (params: InsertMutationFnParams<Table['$inferSelect'], string>) => Promise<void>;
|
|
25
25
|
onUpdate?: (params: UpdateMutationFnParams<Table['$inferSelect'], string>) => Promise<void>;
|
package/dist/drizzle.js
CHANGED
|
@@ -89,12 +89,13 @@ export function drizzleCollectionOptions({ startSync = true, ...config }) {
|
|
|
89
89
|
const key = 'key' in message ? message.key : params.collection.getKeyFromItem(message.value);
|
|
90
90
|
await onDrizzleDelete([key]);
|
|
91
91
|
}
|
|
92
|
-
params.begin();
|
|
93
92
|
params.write(message);
|
|
94
|
-
params.commit();
|
|
95
93
|
},
|
|
96
94
|
collection: params.collection,
|
|
97
95
|
markReady: params.markReady,
|
|
96
|
+
begin: params.begin,
|
|
97
|
+
commit: params.commit,
|
|
98
|
+
truncate: params.truncate,
|
|
98
99
|
...(params.metadata && { metadata: params.metadata }),
|
|
99
100
|
});
|
|
100
101
|
};
|