Skip to content

Commit 3e4ec15

Browse files
committed
start Neon Client work 🐘
1 parent 2f65eb7 commit 3e4ec15

File tree

5 files changed

+143
-7
lines changed

5 files changed

+143
-7
lines changed

β€Žpackage.jsonβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"@cloudflare/workers-types": "^4.20251014.0",
4646
"@electric-sql/pglite": "^0.3.11",
4747
"@libsql/client": "^0.15.15",
48+
"@neondatabase/serverless": "^1.0.2",
4849
"@planetscale/database": "^1.19.0",
4950
"@types/better-sqlite3": "^7.6.13",
5051
"@types/bun": "^1.3.1",

β€Žpnpm-lock.yamlβ€Ž

Lines changed: 28 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žsrc/connectors/neon.tsβ€Ž

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import {
2+
Client as NeonClient,
3+
type QueryResult,
4+
type WebSocketConstructor,
5+
} from "@neondatabase/serverless";
6+
import type { Connector, Primitive } from "db0";
7+
8+
import { BoundableStatement } from "./_internal/statement.ts";
9+
10+
export type ConnectorOptions = {
11+
connectionString: string;
12+
pooler?: boolean;
13+
webSocketConstructor?: WebSocketConstructor;
14+
};
15+
16+
type InternalQuery = (
17+
sql: string,
18+
params?: Primitive[],
19+
) => Promise<QueryResult>;
20+
21+
export default function postgresqlConnector(
22+
connectionString?: ConnectorOptions,
23+
webSocketConstructor?: WebSocketConstructor,
24+
): Connector<NeonClient> {
25+
let _client: undefined | NeonClient | Promise<NeonClient>;
26+
function getClient() {
27+
if (_client) {
28+
return _client;
29+
}
30+
31+
const client = new NeonClient(connectionString);
32+
_client = client.connect().then(() => {
33+
/**
34+
* @description Allow to override the WebSocket constructor or provide one when platform does not support it.
35+
* @see https://github.com/neondatabase/serverless?tab=readme-ov-file#pool-and-client
36+
*/
37+
if (webSocketConstructor) {
38+
client.neonConfig.webSocketConstructor = webSocketConstructor;
39+
}
40+
41+
_client = client;
42+
return _client;
43+
});
44+
45+
return _client;
46+
}
47+
48+
const query: InternalQuery = async (sql, params) => {
49+
const client = getClient();
50+
51+
return (await client).query(normalizeParams(sql), params);
52+
};
53+
54+
return {
55+
name: "neon",
56+
dialect: "postgresql",
57+
getInstance: () => getClient(),
58+
exec: (sql) => query(sql),
59+
prepare: (sql) => new StatementWrapper(sql, query),
60+
dispose: async () => {
61+
await (await _client)?.end?.();
62+
_client = undefined;
63+
},
64+
};
65+
}
66+
67+
// // https://www.postgresql.org/docs/9.3/sql-prepare.html
68+
function normalizeParams(sql: string) {
69+
let i = 0;
70+
return sql.replace(/\?/g, () => `$${++i}`);
71+
}
72+
73+
class StatementWrapper extends BoundableStatement<void> {
74+
#query: InternalQuery;
75+
#sql: string;
76+
77+
constructor(sql: string, query: InternalQuery) {
78+
super();
79+
this.#sql = sql;
80+
this.#query = query;
81+
}
82+
83+
async all(...params: Primitive[]) {
84+
const res = await this.#query(this.#sql, params);
85+
return res.rows;
86+
}
87+
88+
async run(...params: Primitive[]) {
89+
const res = await this.#query(this.#sql, params);
90+
return {
91+
success: true,
92+
...res,
93+
};
94+
}
95+
96+
async get(...params: Primitive[]) {
97+
const res = await this.#query(this.#sql, params);
98+
return res.rows[0];
99+
}
100+
}

β€Žtest/connectors/neon.test.tsβ€Ž

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { describe } from "vitest";
2+
import connector from "../../src/connectors/neon";
3+
import { testConnector } from "./_tests";
4+
5+
describe.runIf(process.env.NEON_URL)("connectors: neon.test", () => {
6+
testConnector({
7+
dialect: "postgresql",
8+
connector: connector({
9+
connectionString: process.env.NEON_URL!,
10+
}),
11+
});
12+
});

β€Žtest/test-db.sqlβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)
2+

0 commit comments

Comments
Β (0)