Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: neon connector #117

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions docs/2.connectors/neon.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,33 @@ icon: cbi:neon

> Connect DB0 to Neon Serverless Postgres.

:read-more{to="https://neon.tech/"}
:read-more{to="https://neon.tech"}

::read-more{to="https://github.com/unjs/db0/issues/32"}
This connector is planned to be supported. Follow up via [unjs/db0#32](https://github.com/unjs/db0/issues/32).
::
## Usage

For this connector, you need to install [`@neondatabase/serverless`](https://www.npmjs.com/package/@neondatabase/serverless) dependency:

:pm-install{name="@neondatabase/serverless"}

Use `neon` connector:

```js
import { createDatabase } from "db0";
import neonConnector from "db0/connectors/neon";

const db = createDatabase(
neonConnector({
/* options */
}),
);
```

## Options

### `url`

The URL of the Neon Serverless Postgres instance.

**Type:** `string`

:read-more{to="https://neon.tech/docs/serverless/serverless-driver#neon-function-configuration-options"}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@libsql/client": "^0.14.0",
"@planetscale/database": "^1.19.0",
"@types/better-sqlite3": "^7.6.12",
"@neondatabase/serverless": "^0.10.1",
"@types/bun": "^1.2.0",
"@types/pg": "^8.11.11",
"@types/sqlite3": "^3.1.11",
Expand All @@ -80,6 +81,7 @@
"peerDependencies": {
"@electric-sql/pglite": "*",
"@libsql/client": "*",
"@neondatabase/serverless": "*",
"better-sqlite3": "*",
"drizzle-orm": "*",
"mysql2": "*",
Expand All @@ -89,6 +91,9 @@
"@libsql/client": {
"optional": true
},
"@neondatabase/serverless": {
"optional": true
},
"better-sqlite3": {
"optional": true
},
Expand Down
42 changes: 31 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion src/_connectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
import type { ConnectorOptions as LibSQLNodeOptions } from "db0/connectors/libsql/node";
import type { ConnectorOptions as LibSQLWebOptions } from "db0/connectors/libsql/web";
import type { ConnectorOptions as MySQL2Options } from "db0/connectors/mysql2";
import type { ConnectorOptions as NeonOptions } from "db0/connectors/neon";
import type { ConnectorOptions as NodeSQLite3Options } from "db0/connectors/node-sqlite3";
import type { ConnectorOptions as PgliteOptions } from "db0/connectors/pglite";
import type { ConnectorOptions as PlanetscaleOptions } from "db0/connectors/planetscale";
import type { ConnectorOptions as PostgreSQLOptions } from "db0/connectors/postgresql";

export type BuiltinConnectorName = "better-sqlite3" | "sqlite" | "bun-sqlite" | "bun" | "cloudflare-d1" | "libsql-core" | "libsql-http" | "libsql-node" | "libsql" | "libsql-web" | "mysql2" | "node-sqlite3" | "pglite" | "planetscale" | "postgresql";
export type BuiltinConnectorName = "better-sqlite3" | "sqlite" | "bun-sqlite" | "bun" | "cloudflare-d1" | "libsql-core" | "libsql-http" | "libsql-node" | "libsql" | "libsql-web" | "mysql2" | "neon" | "node-sqlite3" | "pglite" | "planetscale" | "postgresql";

export type BuiltinConnectorOptions = {
"better-sqlite3": BetterSQLite3Options;
Expand All @@ -30,6 +31,7 @@
"libsql": LibSQLNodeOptions;
"libsql-web": LibSQLWebOptions;
"mysql2": MySQL2Options;
"neon": NeonOptions;
"node-sqlite3": NodeSQLite3Options;
"pglite": PgliteOptions;
"planetscale": PlanetscaleOptions;
Expand All @@ -51,6 +53,7 @@
"libsql": "db0/connectors/libsql/node",
"libsql-web": "db0/connectors/libsql/web",
"mysql2": "db0/connectors/mysql2",
"neon": "db0/connectors/neon",

Check warning on line 56 in src/_connectors.ts

View check run for this annotation

Codecov / codecov/patch

src/_connectors.ts#L56

Added line #L56 was not covered by tests
"node-sqlite3": "db0/connectors/node-sqlite3",
"pglite": "db0/connectors/pglite",
"planetscale": "db0/connectors/planetscale",
Expand Down
59 changes: 59 additions & 0 deletions src/connectors/neon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { neon, HTTPTransactionOptions, NeonQueryFunction } from '@neondatabase/serverless';

import type { Connector, Statement } from "../types";

export interface ConnectorOptions extends HTTPTransactionOptions<undefined, undefined> {
/**
* The URL of the Neon Serverless Postgres instance.
*
* @required
*/
url: string;
}

export default function neonConnector(opts: ConnectorOptions) {
let _connection: NeonQueryFunction<undefined, undefined>;
const getConnection = async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems can be non async right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true!

if (_connection) {
return _connection;
}

Check warning on line 19 in src/connectors/neon.ts

View check run for this annotation

Codecov / codecov/patch

src/connectors/neon.ts#L17-L19

Added lines #L17 - L19 were not covered by tests

const { url, ...transactionOptions } = opts;

Check warning on line 21 in src/connectors/neon.ts

View check run for this annotation

Codecov / codecov/patch

src/connectors/neon.ts#L21

Added line #L21 was not covered by tests

_connection = neon(url, {
...transactionOptions,
})

Check warning on line 25 in src/connectors/neon.ts

View check run for this annotation

Codecov / codecov/patch

src/connectors/neon.ts#L23-L25

Added lines #L23 - L25 were not covered by tests

return _connection;
};

Check warning on line 28 in src/connectors/neon.ts

View check run for this annotation

Codecov / codecov/patch

src/connectors/neon.ts#L27-L28

Added lines #L27 - L28 were not covered by tests

return <Connector>{
name: "neon",
dialect: "postgresql",
exec(sql: string) {
return getConnection().then((c) => c(sql));
},

Check warning on line 35 in src/connectors/neon.ts

View check run for this annotation

Codecov / codecov/patch

src/connectors/neon.ts#L34-L35

Added lines #L34 - L35 were not covered by tests
prepare(sql: string) {
const stmt = <Statement>{
_sql: sql,
_params: [],
bind(...params) {
if (params.length > 0) {
this._params = params;
}
return stmt;
},
all(...params) {
return getConnection().then((c) => c(this._sql, params || this._params));
},
run(...params) {
return getConnection().then((c) => c(this._sql, params || this._params));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run is supposed to only return success right? currently we are returning whatever we get back, so I should change that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you confirm what is production behavior of neon currently? Ideally if it returns additional info, it seems to be correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm so sorry, I've missed your comments πŸ₯² sure that sounds good

},
get(...params) {
return getConnection().then((c) => c(this._sql, params || this._params)).then((res) => res[0]);
},
};
return stmt;
},

Check warning on line 57 in src/connectors/neon.ts

View check run for this annotation

Codecov / codecov/patch

src/connectors/neon.ts#L37-L57

Added lines #L37 - L57 were not covered by tests
};
}
15 changes: 15 additions & 0 deletions test/connectors/neon.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { describe } from "vitest";
import connector from "../../src/connectors/neon";
import { testConnector } from "./_tests";

describe.runIf(process.env.POSTGRESQL_URL)(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish we could somehow mock @neondatabase/serverless (not sure if in their SDK they have it already). We could use something like pglite to emulate their interface in order to allow automated tests.

"connectors: neon.test",
() => {
testConnector({
dialect: "postgresql",
connector: connector({
url: process.env.POSTGRESQL_URL!,
}),
});
},
);
Loading