tanstack-db-pglite 1.0.4 → 1.0.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/dist/drizzle.js +18 -3
- package/dist/sql.d.ts +20 -0
- package/dist/sql.js +135 -0
- package/package.json +17 -9
package/dist/drizzle.js
CHANGED
|
@@ -6,15 +6,30 @@ export function drizzleCollectionOptions({ startSync = true, ...config }) {
|
|
|
6
6
|
// eslint-disable-next-line ts/no-explicit-any
|
|
7
7
|
async function onDrizzleInsert(data, tx) {
|
|
8
8
|
// @ts-expect-error drizzle types
|
|
9
|
-
await (tx || config.db).insert(config.table).values(data)
|
|
9
|
+
await (tx || config.db).insert(config.table).values(data).catch((e) => {
|
|
10
|
+
if (e instanceof Error && e.cause) {
|
|
11
|
+
throw e.cause;
|
|
12
|
+
}
|
|
13
|
+
throw e;
|
|
14
|
+
});
|
|
10
15
|
}
|
|
11
16
|
// eslint-disable-next-line ts/no-explicit-any
|
|
12
17
|
async function onDrizzleUpdate(id, changes, tx) {
|
|
13
|
-
await (tx || config.db).update(config.table).set(changes).where(eq(config.primaryColumn, id))
|
|
18
|
+
await (tx || config.db).update(config.table).set(changes).where(eq(config.primaryColumn, id)).catch((e) => {
|
|
19
|
+
if (e instanceof Error && e.cause) {
|
|
20
|
+
throw e.cause;
|
|
21
|
+
}
|
|
22
|
+
throw e;
|
|
23
|
+
});
|
|
14
24
|
}
|
|
15
25
|
// eslint-disable-next-line ts/no-explicit-any
|
|
16
26
|
async function onDrizzleDelete(ids, tx) {
|
|
17
|
-
await (tx || config.db).delete(config.table).where(inArray(config.primaryColumn, ids))
|
|
27
|
+
await (tx || config.db).delete(config.table).where(inArray(config.primaryColumn, ids)).catch((e) => {
|
|
28
|
+
if (e instanceof Error && e.cause) {
|
|
29
|
+
throw e.cause;
|
|
30
|
+
}
|
|
31
|
+
throw e;
|
|
32
|
+
});
|
|
18
33
|
}
|
|
19
34
|
const getSyncParams = async () => {
|
|
20
35
|
const params = await syncParams;
|
package/dist/sql.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PGlite } from '@electric-sql/pglite';
|
|
2
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
+
import type { CollectionConfig, DeleteMutationFnParams, InsertMutationFnParams, SyncConfig, UpdateMutationFnParams } from '@tanstack/db';
|
|
4
|
+
export declare function sqlCollectionOptions<ItemType extends Record<string, unknown>, Schema extends StandardSchemaV1<ItemType, ItemType> = StandardSchemaV1<ItemType, ItemType>, SyncParams extends Parameters<SyncConfig<ItemType, string>['sync']>[0] = Parameters<SyncConfig<ItemType, string>['sync']>[0]>({ startSync, ...config }: {
|
|
5
|
+
db: PGlite;
|
|
6
|
+
tableName: string;
|
|
7
|
+
primaryKeyColumn: string;
|
|
8
|
+
schema: Schema;
|
|
9
|
+
getKey?: (row: ItemType) => string;
|
|
10
|
+
onInsert?: (params: InsertMutationFnParams<ItemType, string>) => Promise<void>;
|
|
11
|
+
onUpdate?: (params: UpdateMutationFnParams<ItemType, string>) => Promise<void>;
|
|
12
|
+
onDelete?: (params: DeleteMutationFnParams<ItemType, string>) => Promise<void>;
|
|
13
|
+
startSync?: boolean;
|
|
14
|
+
prepare?: () => Promise<unknown> | unknown;
|
|
15
|
+
sync?: (params: Pick<SyncParams, 'write' | 'collection'>) => Promise<void>;
|
|
16
|
+
}): CollectionConfig<ItemType, string> & {
|
|
17
|
+
utils: {
|
|
18
|
+
runSync: () => Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
};
|
package/dist/sql.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
function quoteId(name) {
|
|
2
|
+
return `"${String(name).replace(/"/g, '""')}"`;
|
|
3
|
+
}
|
|
4
|
+
export function sqlCollectionOptions({ startSync = true, ...config }) {
|
|
5
|
+
const table = quoteId(config.tableName);
|
|
6
|
+
const primaryKey = quoteId(config.primaryKeyColumn);
|
|
7
|
+
const getKey = config.getKey ?? ((row) => String(row[config.primaryKeyColumn]));
|
|
8
|
+
const { promise: syncParams, resolve: resolveSyncParams } = Promise.withResolvers();
|
|
9
|
+
async function runSelect(conn) {
|
|
10
|
+
const result = await conn.query(`SELECT * FROM ${table}`);
|
|
11
|
+
return (result.rows ?? []);
|
|
12
|
+
}
|
|
13
|
+
async function runInsert(conn, rows) {
|
|
14
|
+
for (const row of rows) {
|
|
15
|
+
const cols = Object.keys(row).filter(k => row[k] !== undefined);
|
|
16
|
+
if (cols.length === 0)
|
|
17
|
+
continue;
|
|
18
|
+
const columns = cols.map(quoteId).join(', ');
|
|
19
|
+
const placeholders = cols.map((_, i) => `$${i + 1}`).join(', ');
|
|
20
|
+
const values = cols.map(c => row[c]);
|
|
21
|
+
await conn.query(`INSERT INTO ${table} (${columns}) VALUES (${placeholders})`, values);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function runUpdate(conn, id, changes) {
|
|
25
|
+
const entries = Object.entries(changes).filter(([, v]) => v !== undefined);
|
|
26
|
+
if (entries.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
const setClause = entries.map(([k], i) => `${quoteId(k)} = $${i + 1}`).join(', ');
|
|
29
|
+
const params = [...entries.map(([, v]) => v), id];
|
|
30
|
+
await conn.query(`UPDATE ${table} SET ${setClause} WHERE ${primaryKey} = $${params.length}`, params);
|
|
31
|
+
}
|
|
32
|
+
async function runDelete(conn, ids) {
|
|
33
|
+
if (ids.length === 0)
|
|
34
|
+
return;
|
|
35
|
+
await conn.query(`DELETE FROM ${table} WHERE ${primaryKey} = ANY($1)`, [ids]);
|
|
36
|
+
}
|
|
37
|
+
const getSyncParams = async () => {
|
|
38
|
+
const params = await syncParams;
|
|
39
|
+
return {
|
|
40
|
+
write: async (p) => {
|
|
41
|
+
params.begin();
|
|
42
|
+
try {
|
|
43
|
+
if (p.type === 'insert') {
|
|
44
|
+
await runInsert(config.db, [p.value]);
|
|
45
|
+
}
|
|
46
|
+
else if (p.type === 'update') {
|
|
47
|
+
await runUpdate(config.db, params.collection.getKeyFromItem(p.value), p.value);
|
|
48
|
+
}
|
|
49
|
+
else if (p.type === 'delete') {
|
|
50
|
+
await runDelete(config.db, [params.collection.getKeyFromItem(p.value)]);
|
|
51
|
+
}
|
|
52
|
+
params.write(p);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
params.commit();
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
collection: params.collection,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
async function runMutations(mutations) {
|
|
62
|
+
const { begin, write, commit } = await syncParams;
|
|
63
|
+
begin();
|
|
64
|
+
mutations.forEach((m) => {
|
|
65
|
+
write({ type: m.type, value: m.modified });
|
|
66
|
+
});
|
|
67
|
+
commit();
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
startSync: true,
|
|
71
|
+
sync: {
|
|
72
|
+
sync: (params) => {
|
|
73
|
+
resolveSyncParams(params);
|
|
74
|
+
(async () => {
|
|
75
|
+
try {
|
|
76
|
+
await config.prepare?.();
|
|
77
|
+
params.begin();
|
|
78
|
+
const rows = await runSelect(config.db);
|
|
79
|
+
rows.forEach((row) => {
|
|
80
|
+
params.write({ type: 'insert', value: row });
|
|
81
|
+
});
|
|
82
|
+
params.commit();
|
|
83
|
+
if (config.sync && startSync) {
|
|
84
|
+
await config.sync(await getSyncParams());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
params.markReady();
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
gcTime: 0,
|
|
94
|
+
// @ts-expect-error CollectionConfig schema type does not include StandardSchemaV1
|
|
95
|
+
schema: config.schema,
|
|
96
|
+
getKey,
|
|
97
|
+
onInsert: async (params) => {
|
|
98
|
+
await config.db.transaction(async (tx) => {
|
|
99
|
+
await runInsert(tx, params.transaction.mutations.map(m => m.modified));
|
|
100
|
+
if (config.onInsert) {
|
|
101
|
+
await config.onInsert(params);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
await runMutations(params.transaction.mutations);
|
|
105
|
+
},
|
|
106
|
+
onUpdate: async (params) => {
|
|
107
|
+
await config.db.transaction(async (tx) => {
|
|
108
|
+
await Promise.all(params.transaction.mutations.map(m => runUpdate(tx, m.key, m.changes)));
|
|
109
|
+
if (config.onUpdate) {
|
|
110
|
+
await config.onUpdate(params);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
await runMutations(params.transaction.mutations);
|
|
114
|
+
},
|
|
115
|
+
onDelete: async (params) => {
|
|
116
|
+
await config.db.transaction(async (tx) => {
|
|
117
|
+
await runDelete(tx, params.transaction.mutations.map(m => m.key));
|
|
118
|
+
if (config.onDelete) {
|
|
119
|
+
await config.onDelete(params);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
await runMutations(params.transaction.mutations);
|
|
123
|
+
},
|
|
124
|
+
utils: {
|
|
125
|
+
runSync: async () => {
|
|
126
|
+
if (!config.sync) {
|
|
127
|
+
throw new Error('Sync is not defined');
|
|
128
|
+
}
|
|
129
|
+
const params = await getSyncParams();
|
|
130
|
+
await params.collection.stateWhenReady();
|
|
131
|
+
await config.sync(params);
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tanstack-db-pglite",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"packageManager": "pnpm@10.
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"packageManager": "pnpm@10.30.3",
|
|
5
5
|
"description": "",
|
|
6
6
|
"author": "Valerii Strilets",
|
|
7
7
|
"license": "MIT",
|
|
@@ -25,19 +25,27 @@
|
|
|
25
25
|
"prepublishOnly": "pnpm build",
|
|
26
26
|
"build": "tsc",
|
|
27
27
|
"lint": "eslint .",
|
|
28
|
-
"lint:fix": "eslint . --fix"
|
|
28
|
+
"lint:fix": "eslint . --fix",
|
|
29
|
+
"update": "taze -r -I major"
|
|
29
30
|
},
|
|
30
31
|
"peerDependencies": {
|
|
31
|
-
"@
|
|
32
|
-
"
|
|
32
|
+
"@electric-sql/pglite": ">=0.3.0",
|
|
33
|
+
"@tanstack/db": ">=0.5.0",
|
|
34
|
+
"drizzle-orm": ">=0.45.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"drizzle-orm": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
33
40
|
},
|
|
34
41
|
"dependencies": {
|
|
35
42
|
"drizzle-zod": "^0.8.3"
|
|
36
43
|
},
|
|
37
44
|
"devDependencies": {
|
|
38
|
-
"@antfu/eslint-config": "^
|
|
39
|
-
"eslint": "^
|
|
40
|
-
"jiti": "^2.
|
|
41
|
-
"
|
|
45
|
+
"@antfu/eslint-config": "^7.6.1",
|
|
46
|
+
"eslint": "^10.0.2",
|
|
47
|
+
"jiti": "^2.6.1",
|
|
48
|
+
"taze": "^19.9.2",
|
|
49
|
+
"typescript": "^5.9.3"
|
|
42
50
|
}
|
|
43
51
|
}
|