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);
107 changes: 107 additions & 0 deletions src/connectors/mysql2-pool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import mysql from "mysql2/promise";
import { createDatabase } from "../database.ts";
import type { Connector, Primitive } from "db0";
import { BoundableStatement } from "./_internal/statement.ts";

export type ConnectorOptions = mysql.PoolOptions;

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

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

const query: InternalQuery = async (sql, params) => {
const pool = getPool();
try {
const result = await pool.query(sql, params);
return result[0];
} finally {
}
};

return {
name: "mysql-pool",
dialect: "mysql",
getInstance: () => getConnection(),
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