Skip to content

Commit

Permalink
build: generate drivers meta (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
sandros94 authored Jan 24, 2025
1 parent 37d2d3c commit 5e555fb
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 45 deletions.
1 change: 1 addition & 0 deletions .github/workflows/autofix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
node-version: 20
cache: "pnpm"
- run: pnpm install
- run: pnpm run gen-connectors
- run: pnpm automd
- run: pnpm lint:fix
- uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
connectors
integrations
src/_connectors.ts
dist
node_modules
.output
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"integrations"
],
"scripts": {
"build": "unbuild",
"build": "pnpm gen-connectors && unbuild",
"gen-connectors": "jiti scripts/gen-connectors.ts",
"db0": "pnpm jiti src/cli",
"dev": "vitest",
"lint": "eslint . && prettier -c src test",
Expand All @@ -66,9 +67,11 @@
"eslint": "^9.18.0",
"eslint-config-unjs": "^0.4.2",
"jiti": "^2.4.2",
"mlly": "^1.7.4",
"mysql2": "^3.12.0",
"pg": "^8.13.1",
"prettier": "^3.4.2",
"scule": "^1.3.0",
"typescript": "^5.7.3",
"unbuild": "^3.3.1",
"vitest": "^3.0.4"
Expand Down
27 changes: 12 additions & 15 deletions pnpm-lock.yaml

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

111 changes: 111 additions & 0 deletions scripts/gen-connectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { readFile, readdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { findTypeExports } from "mlly";
import { camelCase, upperFirst } from "scule";

const connectorsDir = fileURLToPath(
new URL("../src/connectors", import.meta.url),
);

const connectorsMetaFile = fileURLToPath(
new URL("../src/_connectors.ts", import.meta.url),
);

const aliases = {
"better-sqlite3": ["sqlite"],
"bun-sqlite": ["bun"],
"libsql-node": ["libsql"],
} as const;

async function getConnectorFiles(dir: string): Promise<string[]> {
const files: string[] = [];
const entries = await readdir(dir, { withFileTypes: true });

for (const entry of entries) {
if (entry.isDirectory()) {
files.push(...(await getConnectorFiles(join(dir, entry.name))));
} else if (entry.isFile()) {
files.push(join(dir, entry.name));
}
}

return files;
}

const connectorFiles = await getConnectorFiles(connectorsDir);
const connectorEntries = connectorFiles.map((file) =>
file.replace(connectorsDir + "/", ""),
);

const connectors: {
name: string;
safeName: string;
names: string[];
subpath: string;
optionsTExport?: string;
optionsTName?: string;
}[] = [];

for (const entry of connectorEntries) {
const pathName = entry.replace(/\.ts$/, "");
const name = pathName.replace(/\/|\\/g, "-");
const subpath = `db0/connectors/${pathName}`;
const fullPath = join(connectorsDir, `${pathName}.ts`);

const contents = await readFile(fullPath, "utf8");
const optionsTExport = findTypeExports(contents).find((type) =>
type.name?.endsWith("Options"),
)?.name;

const safeName = camelCase(name).replace(/db/i, "DB").replace(/sql/i, "SQL");

const alternativeNames: string[] = aliases[name] || [];

const names = [...new Set([name, ...alternativeNames])];

const optionsTName = upperFirst(safeName) + "Options";

connectors.push({
name,
safeName,
names,
subpath,
optionsTExport,
optionsTName,
});
}

connectors.sort((a, b) => a.name.localeCompare(b.name));

const genCode = /* ts */ `// Auto-generated using scripts/gen-connectors.
// Do not manually edit!
${connectors
.filter((d) => d.optionsTExport)
.map(
(d) =>
/* ts */ `import type { ${d.optionsTExport} as ${d.optionsTName} } from "${d.subpath}";`,
)
.join("\n")}
export type BuiltinConnectorName = ${connectors.flatMap((d) => d.names.map((name) => `"${name}"`)).join(" | ")};
export type BuiltinConnectorOptions = {
${connectors
.filter((d) => d.optionsTExport)
.flatMap((d) =>
d.names.map(
(name, i) =>
`${i === 0 ? "" : `/** @deprecated Alias of ${d.name} */\n `}"${name}": ${d.optionsTName};`,
),
)
.join("\n ")}
};
export const builtinConnectors = Object.freeze({
${connectors.flatMap((d) => d.names.map((name, i) => `${i === 0 ? "" : `/** @deprecated Alias of ${d.name} */\n `}"${name}": "${d.subpath}"`)).join(",\n ")},
} as const);
`;

await writeFile(connectorsMetaFile, genCode, "utf8");
console.log("Generated connectors metadata file to", connectorsMetaFile);
55 changes: 55 additions & 0 deletions src/_connectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Auto-generated using scripts/gen-connectors.
// Do not manually edit!
import type { ConnectorOptions as BetterSQLite3Options } from "db0/connectors/better-sqlite3";
import type { ConnectorOptions as BunSQLiteOptions } from "db0/connectors/bun-sqlite";
import type { ConnectorOptions as CloudflareD1Options } from "db0/connectors/cloudflare-d1";
import type { ConnectorOptions as LibSQLCoreOptions } from "db0/connectors/libsql/core";
import type { ConnectorOptions as LibSQLHttpOptions } from "db0/connectors/libsql/http";
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 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" | "pglite" | "planetscale" | "postgresql";

export type BuiltinConnectorOptions = {
"better-sqlite3": BetterSQLite3Options;
/** @deprecated Alias of better-sqlite3 */
"sqlite": BetterSQLite3Options;
"bun-sqlite": BunSQLiteOptions;
/** @deprecated Alias of bun-sqlite */
"bun": BunSQLiteOptions;
"cloudflare-d1": CloudflareD1Options;
"libsql-core": LibSQLCoreOptions;
"libsql-http": LibSQLHttpOptions;
"libsql-node": LibSQLNodeOptions;
/** @deprecated Alias of libsql-node */
"libsql": LibSQLNodeOptions;
"libsql-web": LibSQLWebOptions;
"mysql2": MySQL2Options;
"pglite": PgliteOptions;
"planetscale": PlanetscaleOptions;
"postgresql": PostgreSQLOptions;
};

export const builtinConnectors = Object.freeze({
"better-sqlite3": "db0/connectors/better-sqlite3",
/** @deprecated Alias of better-sqlite3 */
"sqlite": "db0/connectors/better-sqlite3",
"bun-sqlite": "db0/connectors/bun-sqlite",
/** @deprecated Alias of bun-sqlite */
"bun": "db0/connectors/bun-sqlite",
"cloudflare-d1": "db0/connectors/cloudflare-d1",
"libsql-core": "db0/connectors/libsql/core",
"libsql-http": "db0/connectors/libsql/http",
"libsql-node": "db0/connectors/libsql/node",
/** @deprecated Alias of libsql-node */
"libsql": "db0/connectors/libsql/node",
"libsql-web": "db0/connectors/libsql/web",
"mysql2": "db0/connectors/mysql2",
"pglite": "db0/connectors/pglite",
"planetscale": "db0/connectors/planetscale",
"postgresql": "db0/connectors/postgresql",
} as const);
4 changes: 3 additions & 1 deletion src/connectors/mysql2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import mysql from "mysql2/promise";

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

export default function mysqlConnector(opts: mysql.ConnectionOptions) {
export type ConnectorOptions = mysql.ConnectionOptions

export default function mysqlConnector(opts: ConnectorOptions) {
let _connection: mysql.Connection | undefined;
const getConnection = async () => {
if (_connection) {
Expand Down
4 changes: 3 additions & 1 deletion src/connectors/planetscale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Client, type Config } from "@planetscale/database";

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

export default function planetscaleConnector(opts: Config) {
export type ConnectorOptions = Config

export default function planetscaleConnector(opts: ConnectorOptions) {
let _client: undefined | Client;
function getClient() {
if (_client) {
Expand Down
26 changes: 0 additions & 26 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,3 @@ export type {
SQLDialect,
Statement,
} from "./types";

/**
* A mapping of available database connector identifiers to their module paths.
* This constant facilitates the use of different database connectors by providing easy access to the
* by providing easy access to the connector's specific import paths.
*/
export const connectors = {
sqlite: "db0/connectors/better-sqlite3",
postgresql: "db0/connectors/postgresql",
pglite: "db0/connectors/pglite",
"cloudflare-d1": "db0/connectors/cloudflare-d1",
libsql: "db0/connectors/libsql/node",
"libsql-node": "db0/connectors/libsql/node",
"libsql-http": "db0/connectors/libsql/http",
"libsql-web": "db0/connectors/libsql/web",
bun: "db0/connectors/bun-sqlite",
"bun-sqlite": "db0/connectors/bun-sqlite",
planetscale: "db0/connectors/planetscale",
mysql: "db0/connectors/mysql2",
} as const;

/**
* Type alias for the keys of the {@link connectors} map.
* Represents the names of available database connectors.
*/
export type ConnectorName = keyof typeof connectors;
5 changes: 4 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"esModuleInterop": true
"esModuleInterop": true,
"paths": {
"db0/connectors/*": ["./src/connectors/*"]
}
},
"include": [
"src"
Expand Down

0 comments on commit 5e555fb

Please sign in to comment.