drizzle-setup
Version:
A powerful CLI tool to automatically scaffold and configure database setup using Drizzle ORM for PostgreSQL,SQLite,MySQL and More.
376 lines (366 loc) ⢠9.67 kB
JavaScript
import { confirm, select, spinner, text } from "@clack/prompts";
import fs from "fs-extra";
import { fileURLToPath } from "url";
import path from "path";
import { glob } from "glob";
import { execa } from "execa";
//#region src/configs/databases/sqlite.ts
const SQLiteDatabasesConfigs = [
{
name: "SQLite",
path: "sqlite",
template_path: "templates/sqlite/sqlite",
env_var: { DB_FILE_NAME: "file:local.db" },
packages: [
"drizzle-orm",
"@libsql/client",
"dotenv",
"drizzle-kit -D"
]
},
{
name: "Turso",
path: "turso",
template_path: "templates/sqlite/turso",
env_var: {
TURSO_DATABASE_URL: "",
TURSO_AUTH_TOKEN: ""
},
packages: [
"drizzle-orm",
"@libsql/client",
"dotenv",
"drizzle-kit -D"
]
},
{
name: "Bun SQLite",
path: "bun_sqlite",
template_path: "templates/sqlite/bun-sqlite",
env_var: { DB_FILE_NAME: "mydb.sqlite" },
packages: [
"drizzle-orm",
"@types/bun -D",
"dotenv",
"drizzle-kit -D"
]
}
];
function getSQLiteDatabasesConfigs() {
return SQLiteDatabasesConfigs.map((config) => {
return {
label: config.name,
value: config.path
};
});
}
var sqlite_default = SQLiteDatabasesConfigs;
//#endregion
//#region src/configs/databases/postgres_sql.ts
const PostgresqlDatabasesConfigs = [
{
name: "PostgreSQL",
path: "postgres_sql",
template_path: "templates/postgres/postgres",
env_var: { DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres" },
packages: [
"drizzle-orm",
"pg",
"dotenv",
"@types/pg -D",
"drizzle-kit -D"
]
},
{
name: "Neon",
path: "neon",
template_path: "templates/postgres/neon",
env_var: { DATABASE_URL: "" },
packages: [
"drizzle-orm",
"@neondatabase/serverless",
"dotenv",
"drizzle-kit -D"
]
},
{
name: "Vercel Postgres",
path: "vercel_postgres",
template_path: "templates/postgres/vercel-postgres",
env_var: { POSTGRES_URL: "" },
packages: [
"drizzle-orm",
"@vercel/postgres",
"dotenv",
"drizzle-kit -D"
]
}
];
function getPostgresqlDatabasesConfigs() {
return PostgresqlDatabasesConfigs.map((config) => {
return {
label: config.name,
value: config.path
};
});
}
var postgres_sql_default = PostgresqlDatabasesConfigs;
//#endregion
//#region src/utils/env-update.ts
async function updateAllEnvFiles(envVars) {
const cwd = process.cwd();
const envFiles = await glob(".env*", {
cwd,
dot: true
});
if (envFiles.length === 0) envFiles.push(".env");
for (const envFile of envFiles) {
const envFilePath = path.join(cwd, envFile);
let lines = [];
const envMap = /* @__PURE__ */ new Map();
const exists = await fs.pathExists(envFilePath);
if (exists) {
const content = await fs.readFile(envFilePath, "utf-8");
lines = content.split("\n");
}
for (const line of lines) {
const match = line.match(/^([^=]+)=(.*)$/);
if (match) envMap.set(match[1].trim(), match[2]);
}
const newVars = [];
for (const [key, value] of Object.entries(envVars)) if (!envMap.has(key)) newVars.push(`${key}=${value}`);
if (exists && lines.length > 0) {
const content = lines.join("\n") + (newVars.length > 0 ? `\n${newVars.join("\n")}` : "");
await fs.writeFile(envFilePath, content);
} else await fs.writeFile(envFilePath, newVars.join("\n"));
}
}
var env_update_default = updateAllEnvFiles;
//#endregion
//#region src/utils/drizzle-config-update.ts
async function createConfigFile(drizzle_configTargetPath$1, drizzle_configPath$1, dbPath$1) {
let content = await fs.readFile(drizzle_configPath$1, "utf-8");
content = content.replace(/{{path}}/g, dbPath$1.toString().replace(/\\/g, "\\\\"));
await fs.writeFile(drizzle_configTargetPath$1, content);
return true;
}
var drizzle_config_update_default = createConfigFile;
//#endregion
//#region src/utils/pkg-manger-run.ts
async function pkgMangerRun(pkg_manger$1, dbConfig$1) {
for (const rawPkg of dbConfig$1.packages) {
const parts = rawPkg.trim().split(" ");
const pkg = parts[0];
const isDev = parts.includes("-D");
const args = pkg_manger$1 === "bun" ? isDev ? [
"add",
"-D",
pkg
] : ["add", pkg] : pkg_manger$1 === "yarn" ? isDev ? [
"add",
"--dev",
pkg
] : ["add", pkg] : isDev ? [
"install",
pkg,
"--save-dev"
] : ["install", pkg];
await execa(pkg_manger$1.toString(), args, { stdio: "ignore" });
}
}
var pkg_manger_run_default = pkgMangerRun;
//#endregion
//#region src/configs/dblists.ts
const dbLists = [
{
label: "PostgreSQL",
value: "postgres_sql"
},
{
label: "SQLite",
value: "sqlite"
},
{
label: "MySQL",
value: "mysql"
}
];
function dbListsByValue(value) {
return dbLists.find((dbList) => dbList.value === value);
}
var dblists_default = dbLists;
//#endregion
//#region src/utils/update-scripts.ts
async function UpdateScripts(packageJsonPath) {
await fs.readFile(packageJsonPath, "utf8", async (readErr, data) => {
if (readErr) throw readErr;
const packageJson = JSON.parse(data);
if (!packageJson.scripts) packageJson.scripts = {};
const newScripts = {
"db-push": "drizzle-kit push",
"db-generate": "drizzle-kit generate",
"db-migrate": "drizzle-kit migrate"
};
Object.assign(packageJson.scripts, newScripts);
const updatedPackageJson = JSON.stringify(packageJson, null, 2);
await fs.writeFile(packageJsonPath, updatedPackageJson, "utf8");
});
}
var update_scripts_default = UpdateScripts;
//#endregion
//#region src/configs/databases/mysql.ts
const MySQLlDatabasesConfigs = [{
name: "MySQL",
path: "mysql",
template_path: "templates/mysql/mysql",
env_var: { DATABASE_URL: "jdbc:mysql://localhost:3306/your_database_name" },
packages: [
"drizzle-orm",
"mysql2",
"dotenv",
"drizzle-kit -D"
]
}, {
name: "PlanetScale",
path: "planetscale",
template_path: "templates/mysql/planetscale",
env_var: {
DATABASE_HOST: "",
DATABASE_USERNAME: "",
DATABASE_PASSWORD: "",
DATABASE_URL: ""
},
packages: [
"drizzle-orm",
"@planetscale/database",
"dotenv",
"drizzle-kit -D"
]
}];
function getMySQLlDatabasesConfigs() {
return MySQLlDatabasesConfigs.map((config) => {
return {
label: config.name,
value: config.path
};
});
}
var mysql_default = MySQLlDatabasesConfigs;
//#endregion
//#region src/index.ts
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const databaseConfigs = [
...postgres_sql_default,
...sqlite_default,
...mysql_default
];
const databaseGroups = {
PostgreSQL: getPostgresqlDatabasesConfigs(),
SQLite: getSQLiteDatabasesConfigs(),
MySQL: getMySQLlDatabasesConfigs()
};
const dbGroup = await select({
message: "Pick a database group",
options: dblists_default
});
if (dbGroup === void 0) {
console.log("Operation cancelled.");
process.exit(0);
}
const dbOption = await select({
message: `Pick a ${dbListsByValue(dbGroup.toString())?.label} database`,
options: databaseGroups[dbListsByValue(dbGroup.toString())?.label]
});
if (dbOption === void 0) {
console.log("Operation cancelled.");
process.exit(0);
}
const dbPath = await text({
message: "Database folder path",
initialValue: "./src/db"
});
if (dbPath === void 0) {
console.log("Operation cancelled.");
process.exit(0);
}
const dbConfig = databaseConfigs.find((config) => config.path === dbOption);
if (dbConfig === void 0) {
console.log("Operation cancelled.");
process.exit(0);
}
const templatePath = path.join(__dirname, `${dbConfig.template_path}/db`);
const drizzle_configPath = path.join(__dirname, `${dbConfig.template_path}/drizzle.config.ts`);
const envVar = dbConfig.env_var;
const targetPath = path.resolve(process.cwd(), dbPath.toString());
const drizzle_configTargetPath = path.resolve(process.cwd(), "drizzle.config.ts");
const scriptJsonPath = path.resolve(process.cwd(), "package.json");
try {
if (await fs.pathExists(targetPath)) {
console.log(`ā Folder already exists at ${targetPath}. Aborting.`);
process.exit(1);
}
await fs.copy(templatePath, targetPath);
} catch (error) {
console.error("šØ Error copying template:", error);
process.exit(1);
}
try {
await drizzle_config_update_default(drizzle_configTargetPath, drizzle_configPath, dbPath.toString());
} catch (error) {
console.error("šØ Error copying and modifying drizzle.config.ts:", error);
}
try {
await env_update_default(envVar);
} catch (error) {
console.error("šØ Error updating .env file:", error);
}
const updateScripts = await confirm({
message: "Update package.json scripts?",
initialValue: true
});
if (updateScripts === true) try {
await update_scripts_default(scriptJsonPath);
} catch (error) {
console.error("šØ Error updating package.json scripts:", error);
}
const pkg_manger = await select({
message: "Pick a package manager",
options: [
{
label: "pnpm",
value: "pnpm"
},
{
label: "bun",
value: "bun"
},
{
label: "npm",
value: "npm"
},
{
label: "yarn",
value: "yarn"
}
]
});
if (!pkg_manger) {
console.log("ā Operation cancelled.");
process.exit(0);
}
const s = spinner({});
s.start(`Installing ${dbConfig.packages.join(", ")} with ${pkg_manger.toString()}...`);
try {
await pkg_manger_run_default(pkg_manger, dbConfig);
s.stop?.("All packages installed successfully", 0);
console.log(`\nš Template copied to ${dbPath.toString()}
\nā .env file vars at on top updated!
\nš drizzle.config.ts added!
\nš package.json scripts updated!
\nā
Drizzle Setup completed!`);
} catch (_err) {
s.stop("šØ Failed to install packages");
console.error("š Installation failed. Please check your internet connection and \nverify that your package manager is installed and functioning correctly.");
process.exit(1);
}
//#endregion