Skip to content
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
73 changes: 73 additions & 0 deletions docs/2.connectors/mysql-pool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
icon: simple-icons:mysql
---
# MySQL (Pool)

> Connect DB0 to Mysql Database using mysql2 pool connection

## Usage

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

:pm-install{name="mysql2"}

Use `mysql2-pool` connector:

```js
import { createDatabase } from "db0";
import mysqlPool from "db0/connectors/mysql2-pool";

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

### Pool Query

```js
const {rows} = db.sql`SELECT * FROM tbl`;
```

### Transactions

For pool connections, do not use transactions with the **pool.query** method.

:read-more{title="node-postgres transactions" to="https://pg.nodejs.cn/features/transactions"}



To use transactions, get an instance first and dispose after finished.

```js
const c = await db.getInstance();
await c.sql`BEGIN`;
await c.sql`insert into test (name) values ('TEST1')`;
await c.sql`COMMIT`;
await c.sql`BEGIN`;
await c.sql`insert into test (name) values ('TEST2')`;
await c.sql`ROLLBACK`;
c.dispose();
```

The pid can test by:

```js
// Pool query: different pids
new Array(10).fill(1).forEach(async () => {
const {rows} = await db.sql`SELECT pg_backend_pid()`;
console.log(rows[0]);
});

// PoolConnection query: the same pid
const c = await db.getInstance();
new Array(10).fill(1).forEach(async () => {
const {rows} = await c.sql`SELECT pg_backend_pid()`;
console.log(rows[0]);
});
```

Options

:read-more{to="https://github.com/sidorares/node-mysql2/blob/master/typings/mysql/lib/Connection.d.ts#L82-L329"}
75 changes: 75 additions & 0 deletions docs/2.connectors/postgresql-pool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
icon: simple-icons:postgresql
---
# PostgreSQL (Pool)

> Connect DB0 to PostgreSQL

:read-more{to="https://www.postgresql.org"}

## Usage

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

:pm-install{name="pg @types/pg"}

Use `postgresql-pool` connector:

```js
import { createDatabase } from "db0";
import postgresqlPool from "db0/connectors/postgresql-pool";

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

### Pool Query

```js
const {rows} = db.sql`SELECT * FROM tbl`;
```

### Transactions

For pool connections, do not use transactions with the **pool.query** method.

:read-more{title="node-postgres transactions" to="https://pg.nodejs.cn/features/transactions"}



To use transactions, get an instance first and dispose after finished.

```js
const c = await db.getInstance();
await c.sql`BEGIN`;
await c.sql`insert into test (name) values ('TEST1')`;
await c.sql`COMMIT`;
await c.sql`BEGIN`;
await c.sql`insert into test (name) values ('TEST2')`;
await c.sql`ROLLBACK`;
c.dispose();
```

The pid can test by:

```js
// Pool query: different pids
new Array(10).fill(1).forEach(async () => {
const {rows} = await db.sql`SELECT pg_backend_pid()`;
console.log(rows[0]);
});

// PoolConnection query: the same pid
const c = await db.getInstance();
new Array(10).fill(1).forEach(async () => {
const {rows} = await c.sql`SELECT pg_backend_pid()`;
console.log(rows[0]);
});
```

## Options

:read-more{title="node-postgres client options" to="https://node-postgres.com/apis/client#new-client"}
6 changes: 6 additions & 0 deletions src/_connectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import type { ConnectorOptions as LibSQLHttpOptions } from "db0/connectors/libsq
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 MySQL2PoolOptions } from "db0/connectors/mysql2-pool";
import type { ConnectorOptions as NodeSQLiteOptions } from "db0/connectors/node-sqlite";
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";
import type { ConnectorOptions as PostgrePoolSQLOptions } from "db0/connectors/postgresql-pool";
import type { ConnectorOptions as SQLite3Options } from "db0/connectors/sqlite3";

export type ConnectorName = "better-sqlite3" | "bun-sqlite" | "bun" | "cloudflare-d1" | "cloudflare-hyperdrive-mysql" | "cloudflare-hyperdrive-postgresql" | "libsql-core" | "libsql-http" | "libsql-node" | "libsql" | "libsql-web" | "mysql2" | "node-sqlite" | "sqlite" | "pglite" | "planetscale" | "postgresql" | "sqlite3";
Expand All @@ -33,12 +35,14 @@ export type ConnectorOptions = {
"libsql": LibSQLNodeOptions;
"libsql-web": LibSQLWebOptions;
"mysql2": MySQL2Options;
"mysql2-pool": MySQL2PoolOptions;
"node-sqlite": NodeSQLiteOptions;
/** alias of node-sqlite */
"sqlite": NodeSQLiteOptions;
"pglite": PgliteOptions;
"planetscale": PlanetscaleOptions;
"postgresql": PostgreSQLOptions;
"postgresql-pool": PostgrePoolSQLOptions;
"sqlite3": SQLite3Options;
};

Expand All @@ -57,11 +61,13 @@ export const connectors: Record<ConnectorName, string> = Object.freeze({
"libsql": "db0/connectors/libsql/node",
"libsql-web": "db0/connectors/libsql/web",
"mysql2": "db0/connectors/mysql2",
"mysql2-pool": "db0/connectors/mysql2-pool",
"node-sqlite": "db0/connectors/node-sqlite",
/** alias of node-sqlite */
"sqlite": "db0/connectors/node-sqlite",
"pglite": "db0/connectors/pglite",
"planetscale": "db0/connectors/planetscale",
"postgresql": "db0/connectors/postgresql",
"postgresql-pool": "db0/connectors/postgresql-pool",
"sqlite3": "db0/connectors/sqlite3",
} as const);
106 changes: 106 additions & 0 deletions src/connectors/mysql2-pool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import mysql from "mysql2/promise";
import { createDatabase } from "../database.ts";
import type { Connector, Database, Primitive } from "db0";
import { BoundableStatement } from "./_internal/statement.ts";

export type ConnectorOptions = mysql.PoolOptions;
type Pool = mysql.Pool & {
getClient?: () => Promise<Database<Connector<mysql.PoolConnection>>>;
};

type InternalQuery = (
sql: string,
params?: Primitive[],
) => Promise<mysql.QueryResult>;

export default function postgresqlPoolConnector(
opts: ConnectorOptions,
): Connector<Pool> {
let _pool: Pool | undefined;
const getPool = () => {
if (!_pool) _pool = mysql.createPool(opts);
_pool.getClient = getClient;
return _pool;
};
const getClient = async () => {
let _client: mysql.PoolConnection | undefined;
let _clientPromise: Promise<mysql.PoolConnection> | undefined;
const _getClient = async () => {
if (!_client) {
if (!_clientPromise) {
_clientPromise = getPool()
.getConnection()
.then((client) => {
_client = client;
_clientPromise = undefined;
return client;
});
}
return _clientPromise;
}
return _client;
};
const _query: InternalQuery = (sql, params) =>
_getClient()
.then((c) => c.query(sql, params))
.then((res) => res[0]);
return createDatabase({
name: "postgresql-pool-client",
dialect: "postgresql",
getInstance: () => _getClient(),
exec: (sql) => _query(sql),
prepare: (sql) => new StatementWrapper(sql, _query),
dispose: async () => {
_client?.release?.();
_client = undefined;
},
});
};

const query: InternalQuery = (sql, params) =>
getClient()
.then((c) => c.getInstance())
.then((c) => c.query(sql, params))
.then((res) => res[0]);

return {
name: "postgresql-pool",
dialect: "postgresql",
getInstance: () => getPool(),
exec: (sql) => query(sql),
prepare: (sql) => new StatementWrapper(sql, query),
dispose: async () => {
await _pool?.end?.();
_pool = undefined;
},
};
}

class StatementWrapper extends BoundableStatement<void> {
#query: InternalQuery;
#sql: string;

constructor(sql: string, query: InternalQuery) {
super();
this.#sql = sql;
this.#query = query;
}

async all(...params: Primitive[]) {
const res = (await this.#query(this.#sql, params)) as mysql.RowDataPacket[];
return res;
}

async run(...params: Primitive[]) {
const res = (await this.#query(this.#sql, params)) as mysql.RowDataPacket[];
return {
success: true,
...res,
};
}

async get(...params: Primitive[]) {
const res = (await this.#query(this.#sql, params)) as mysql.RowDataPacket[];
return res[0];
}
}
Loading