Skip to content

Commit 306ee30

Browse files
committed
Add DoSqliteDriver, typegres/core + do-sqlite entries, codegen fixes
1 parent 2f33ae7 commit 306ee30

20 files changed

Lines changed: 345 additions & 234 deletions

package.json

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@
2828
"./exoeval": {
2929
"import": "./dist/exoeval/index.mjs",
3030
"types": "./dist/exoeval/index.d.mts"
31+
},
32+
"./capnweb": {
33+
"import": "./dist/capnweb/shim.mjs",
34+
"types": "./dist/capnweb/shim.d.mts"
35+
},
36+
"./drivers/do": {
37+
"import": "./dist/drivers/do.mjs",
38+
"types": "./dist/drivers/do.d.mts"
39+
},
40+
"./drivers/pg": {
41+
"import": "./dist/drivers/pg.mjs",
42+
"types": "./dist/drivers/pg.d.mts"
43+
},
44+
"./drivers/pglite": {
45+
"import": "./dist/drivers/pglite.mjs",
46+
"types": "./dist/drivers/pglite.d.mts"
47+
},
48+
"./drivers/sqlite": {
49+
"import": "./dist/drivers/sqlite.mjs",
50+
"types": "./dist/drivers/sqlite.d.mts"
3151
}
3252
},
3353
"bin": {
@@ -38,14 +58,18 @@
3858
],
3959
"peerDependencies": {
4060
"@electric-sql/pglite": "^0.4.4",
41-
"pg": "^8.20.0"
61+
"pg": "^8.20.0",
62+
"better-sqlite3": "^12.11.1"
4263
},
4364
"peerDependenciesMeta": {
4465
"@electric-sql/pglite": {
4566
"optional": true
4667
},
4768
"pg": {
4869
"optional": true
70+
},
71+
"better-sqlite3": {
72+
"optional": true
4973
}
5074
},
5175
"engines": {
@@ -54,7 +78,7 @@
5478
"scripts": {
5579
"build": "tsdown",
5680
"codegen": "node --experimental-strip-types src/types/postgres/emit.ts && node --experimental-strip-types src/types/sqlite/emit.ts",
57-
"codegen:check": "tmp=$(mktemp -d) && node --experimental-strip-types src/types/postgres/emit.ts --out-dir \"$tmp/pg\" && { diff -r \"$tmp/pg\" src/types/postgres/generated || { echo 'src/types/postgres/generated is stale \u2014 run `npm run codegen` and commit.' >&2; rm -rf \"$tmp\"; exit 1; }; } && node --experimental-strip-types src/types/sqlite/emit.ts --out-dir \"$tmp/sqlite\" && { diff -r \"$tmp/sqlite/generated\" src/types/sqlite/generated || { echo 'src/types/sqlite/generated is stale \u2014 run `npm run codegen` and commit.' >&2; rm -rf \"$tmp\"; exit 1; }; } && rm -rf \"$tmp\"",
81+
"codegen:check": "tmp=$(mktemp -d) && node --experimental-strip-types src/types/postgres/emit.ts --out-dir \"$tmp/pg\" && { diff -r \"$tmp/pg\" src/types/postgres/generated || { echo 'src/types/postgres/generated is stale run `npm run codegen` and commit.' >&2; rm -rf \"$tmp\"; exit 1; }; } && node --experimental-strip-types src/types/sqlite/emit.ts --out-dir \"$tmp/sqlite\" && { diff -r \"$tmp/sqlite/generated\" src/types/sqlite/generated || { echo 'src/types/sqlite/generated is stale run `npm run codegen` and commit.' >&2; rm -rf \"$tmp\"; exit 1; }; } && rm -rf \"$tmp\"",
5882
"lint": "eslint src",
5983
"typecheck": "tsgo --noEmit",
6084
"format": "prettier --write src",

site/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ public/demo.ts.static
1010
public/events-*.js
1111
public/chunk-*.js
1212
public/lib-*.js
13+
public/rolldown-runtime-*.js
14+
# playground driver code-split chunks from dynamic import() in typegres()
15+
public/pg-*.js
16+
public/pglite-*.js
17+
public/sqlite-*.js

src/database.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { test, expect, beforeAll, afterAll } from "vitest";
22
import { Int8, Text } from "./types/postgres";
33
import { sql } from "./builder/sql";
44
import { setupDb, db, conn } from "./test-helpers";
5-
import { PgDriver } from "./driver";
6-
import type { Driver } from "./driver";
5+
import { PgDriver } from "./drivers/pg";
6+
import type { Driver } from "./drivers/types";
77
import { requireDatabaseUrl } from "./pg";
88
import type { Connection } from "./database";
99
import { Database } from "./database";

src/database.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ExecuteFn, Driver, QueryResult } from "./driver";
1+
import type { ExecuteFn, Driver, QueryResult } from "./drivers/types";
22
import type { Fromable, RowType, RowTypeToTsType } from "./builder/query";
33
import { QueryBuilder, hydrateRows } from "./builder/query";
44
import { deserializeRows } from "./util";

src/driver.ts

Lines changed: 0 additions & 204 deletions
This file was deleted.

src/drivers/do.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { CompiledSql } from "../builder/sql";
2+
import type { Driver, ExecuteFn, QueryResult } from "./types";
3+
import { normalizeRow, stripMatchedOuterParens } from "./shared-sqlite";
4+
5+
// Duck-typed Cloudflare SqlStorage — no @cloudflare/workers-types dependency.
6+
export interface SqlStorageLike {
7+
exec(query: string, ...bindings: unknown[]): { toArray(): { [key: string]: unknown }[] };
8+
}
9+
10+
// typegres Driver over a Durable Object's SQLite (Cloudflare SqlStorage).
11+
// No node-only peer imports — safe to bundle into workerd.
12+
//
13+
// Contract notes:
14+
// - numbers bind as REAL (integer affinity from the dialect CAST);
15+
// - SqlStorage REJECTS BigInt (unlike better-sqlite3) — we do not coerce;
16+
// callers / the dialect must not emit bigint bindings for this backend;
17+
// - results are native JS values, normalized to strings for deserialize;
18+
// - blobs come back as ArrayBuffer (better-sqlite3 gives Uint8Array/Buffer).
19+
export class DoSqliteDriver implements Driver {
20+
readonly dialect = "sqlite" as const;
21+
22+
constructor(private readonly sql: SqlStorageLike) {}
23+
24+
execute: ExecuteFn = ({ text, values }: CompiledSql): Promise<QueryResult> => {
25+
const query = stripMatchedOuterParens(text);
26+
const rows = this.sql.exec(query, ...values).toArray().map(normalizeRow);
27+
return Promise.resolve({ rows });
28+
};
29+
30+
runInSingleConnection = <T>(cb: (execute: ExecuteFn) => Promise<T>): Promise<T> =>
31+
cb(this.execute);
32+
33+
close = (): Promise<void> => Promise.resolve();
34+
}

src/drivers/pg.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { CompiledSql } from "../builder/sql";
2+
import type { DialectName } from "../builder/sql";
3+
import type pg from "pg";
4+
import type { Driver, ExecuteFn, QueryResult } from "./types";
5+
6+
// pg adapter — returns raw text strings (no driver-side deserialization).
7+
// `pg` is an *optional* peer dep (see package.json#peerDependenciesMeta).
8+
// Dynamic import keeps bundlers from pulling pg into browser builds and
9+
// lets a missing peer fail late with a real module-not-found error.
10+
export class PgDriver implements Driver {
11+
readonly dialect: DialectName = "postgres";
12+
13+
static async create(
14+
connectionString: string,
15+
poolOptions: pg.PoolConfig = {},
16+
): Promise<PgDriver> {
17+
// eslint-disable-next-line no-restricted-syntax -- optional peer, see class comment
18+
const pgMod = (await import(/* webpackIgnore: true */ "pg")).default;
19+
const pool = new pgMod.Pool({
20+
connectionString,
21+
...poolOptions,
22+
types: { getTypeParser: () => (v: string) => v },
23+
});
24+
return new PgDriver(pool);
25+
}
26+
27+
private constructor(private pool: pg.Pool) {}
28+
29+
async execute({ text, values }: CompiledSql): Promise<QueryResult> {
30+
return this.pool.query(text, values as unknown[]);
31+
}
32+
33+
async runInSingleConnection<T>(cb: (execute: ExecuteFn) => Promise<T>): Promise<T> {
34+
const client = await this.pool.connect();
35+
try {
36+
return await cb(({ text, values }) => client.query(text, values as unknown[]));
37+
} finally {
38+
client.release();
39+
}
40+
}
41+
42+
async close(): Promise<void> {
43+
await this.pool.end();
44+
}
45+
}

0 commit comments

Comments
 (0)