UNPKG

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
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