@calljmp/cli
Version:
11 lines (9 loc) • 8.69 kB
JavaScript
;var B=Object.create;var N=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,z=Object.prototype.hasOwnProperty;var Q=(t,a)=>{for(var r in a)N(t,r,{get:a[r],enumerable:!0})},W=(t,a,r,s)=>{if(a&&typeof a=="object"||typeof a=="function")for(let g of H(a))!z.call(t,g)&&g!==r&&N(t,g,{get:()=>a[g],enumerable:!(s=G(a,g))||s.enumerable});return t};var w=(t,a,r)=>(r=t!=null?B(K(t)):{},W(a||!t||!t.__esModule?N(r,"default",{value:t,enumerable:!0}):r,t)),X=t=>W(N({},"__esModule",{value:!0}),t);var te={};Q(te,{default:()=>ee});module.exports=X(te);var q=require("commander"),C=w(require("../../config")),T=w(require("ora")),e=w(require("chalk")),F=w(require("crypto")),S=w(require("enquirer")),u=w(require("fs/promises")),A=w(require("path")),o=w(require("../../logger")),Y=w(require("../../server")),$=require("../../build"),D=w(require("../../sql")),I=require("../../sqlite/migration"),j=require("../../database"),L=require("./migration"),P=require("../../sqlite/utils");async function V(t){const a=[],r=(0,T.default)(e.default.yellow("Retrieving database schema...")).start();try{const s=await t.retrieveSchema();a.push(...s),r.succeed(e.default.green("Database schema retrieved."))}catch(s){r.fail(e.default.red("Failed to retrieve database schema!")),o.default.error(s),process.exit(1)}return a}function Z(t,a){const r=t.replace(/\s+/g," ").replace(/,\s*/g,", ").replace(/\(\s*/g,"(").replace(/\s*\)/g,")").replace(/\bSELECT\b/gi,"SELECT").replace(/\bFROM\b/gi,"FROM").replace(/\bWHERE\b/gi,"WHERE").replace(/\bINSERT\b/gi,"INSERT").replace(/\bINTO\b/gi,"INTO").replace(/\bUPDATE\b/gi,"UPDATE").replace(/\bSET\b/gi,"SET").replace(/\bDELETE\b/gi,"DELETE").replace(/\bCREATE\b/gi,"CREATE").replace(/\bTABLE\b/gi,"TABLE").replace(/\bALTER\b/gi,"ALTER").replace(/\bDROP\b/gi,"DROP").trim(),s=[],g=r.split(" ");let l="";for(const d of g){const E=l?`${l} ${d}`:d;[...E].length<=a?l=E:l?(s.push(l),l=d):s.push(d)}return l&&s.push(l),s.length?s:[""]}function v(t,a){o.default.info(e.default.bold(t)),o.default.info(e.default.dim("\u250C"+"\u2500".repeat(8)+"\u252C"+"\u2500".repeat(100)+"\u2510")),o.default.info(e.default.dim("\u2502 ")+e.default.bold("Step".padEnd(7))+e.default.dim("\u2502 ")+e.default.bold("SQL Statement".padEnd(98))+e.default.dim(" \u2502")),o.default.info(e.default.dim("\u251C"+"\u2500".repeat(8)+"\u253C"+"\u2500".repeat(100)+"\u2524")),a.forEach((l,d)=>{const E=l.statements.flatMap(n=>Z(n,98));(E.length?E:[""]).forEach((n,f)=>{const m=n.padEnd(98);o.default.info(e.default.dim("\u2502 ")+(f===0?e.default.cyan(String(d+1).padEnd(7)):" ".repeat(7))+e.default.dim("\u2502 ")+e.default.white(m)+e.default.dim(" \u2502"))}),d<a.length-1&&o.default.info(e.default.dim("\u251C"+"\u2500".repeat(8)+"\u253C"+"\u2500".repeat(100)+"\u2524"))}),o.default.info(e.default.dim("\u2514"+"\u2500".repeat(8)+"\u2534"+"\u2500".repeat(100)+"\u2518"))}const J=()=>new q.Command("schema").description("Manage database schema").addOption(C.ConfigOptions.ProjectDirectory).option("--migrations-table [table]","Migrations table name",L.MIGRATION_TABLE).option("--schema-name [name]","Name of the schema file","schema.sql").option("--migration-name [name]","Name of the migration file").option("--no-sync","Skip syncing the database").option("--no-confirm","Skip confirmation prompt").action(async t=>{const a=await(0,C.default)(t);(!a.accessToken||!a.projectId)&&(o.default.error(e.default.red("Project is not linked. Please run `setup` command first.")),process.exit(1));const r=new j.Database({baseUrl:a.baseUrl,accessToken:a.accessToken,projectId:a.projectId}),s=[],g=[],l=[],d=await(0,L.collectMigrations)(a);if(t.sync){const n=await V(r);if(s.push(...n),n.length){const m=t.schemaName,i=A.default.join(a.schema,m),y=await u.default.access(i,u.default.constants.F_OK).then(()=>!0).catch(()=>!1);let h=!0;if(y&&t.confirm){const{confirm:p}=await S.default.prompt({type:"confirm",name:"confirm",message:`Do you want to overwrite the existing schema file (${m})?`,initial:!0});h=p}h&&(await u.default.mkdir(a.schema,{recursive:!0}),await u.default.writeFile(i,n.join(`;
`),"utf-8"),o.default.info(e.default.green(`Schema file created: ${m}`)))}const f=(0,T.default)(e.default.yellow("Retrieving migrations...")).start();try{const m=await r.query(`SELECT * FROM ${t.migrationsTable}`),i=(0,L.dataToInsertStatements)(t.migrationsTable,m.rows);l.push(...i),f.succeed(e.default.green("Migration data retrieved."))}catch{f.info(e.default.dim("Skipping migrations table data."))}}const E=await u.default.readdir(a.schema).catch(()=>[]);for(const n of E)if(n.toLowerCase().endsWith(".sql")){const f=A.default.join(a.schema,n),m=await u.default.readFile(f,"utf-8");g.push(...(0,D.default)(m).map(P.normalizeSql).filter(i=>i.length>0))}await(async n=>{const f=await Y.create({script:await(0,$.build)({entryPoints:a.entry,debug:!0}),database:a.data});try{await f.ready;const m=await f.getD1Database("DATABASE");await n(m)}finally{await f.dispose()}})(async n=>{const f=async()=>(await n.prepare('SELECT sql FROM sqlite_master WHERE name NOT LIKE "sqlite_%" AND name NOT LIKE "_cf_%"').all()).results.map(i=>i.sql);if(s.length){const m=await f(),i=new I.SqliteMigration;await i.exec(m.join(";"));const y=await Promise.all(d.map(async({file:h})=>{const p=await u.default.readFile(h,"utf-8");return(0,D.default)(p).join(";")}));if(await i.prepare([...s,...y].join(";")),i.totalSteps){v("Migration steps (syncing remote schema to local)",i.steps);let h=!0;if(t.confirm){const{confirm:p}=await S.default.prompt({type:"confirm",name:"confirm",message:`Do you want to apply these ${i.totalSteps} step(s) to sync your local database with the remote schema?`,initial:!0});p||(o.default.info(e.default.yellow("Aborting schema synchronization.")),h=!1)}if(h){const p=(0,T.default)(e.default.yellow("Applying remote schema to local database...")).start();try{await n.batch(i.statements().map(c=>n.prepare(c))),p.succeed(e.default.green("Remote schema successfully synced to local database."))}catch(c){p.fail(e.default.red("Failed to sync remote schema to local database!")),o.default.error(c),process.exit(1)}if(l.length){const c=(0,T.default)(e.default.yellow("Applying migration data to local database...")).start();try{await n.batch(l.map(b=>n.prepare(b))),c.succeed(e.default.green("Migration data applied to local database."))}catch(b){c.fail(e.default.red("Failed to apply migration data to local database!")),o.default.error(b),process.exit(1)}}}}else o.default.info(e.default.green("No schema changes detected. Local database is already up to date with the remote schema."))}{const m=await f(),i=new I.SqliteMigration;if(await i.exec(m.join(";")),await i.prepare(g.join(";")),i.totalSteps){v("Migration steps",i.steps);let y=!0,h=!0,p=null;if(y&&t.confirm){const{confirm:c}=await S.default.prompt({type:"confirm",name:"confirm",message:`Do you want to generate a new migration file with these ${i.totalSteps} step(s)?`,initial:!0});c||(o.default.info(e.default.yellow("Aborting migration file generation.")),y=!1,h=!1)}if(y){const c=d.reduce((R,_)=>Math.max(R,_.version),0)+1,{name:b}=t.migrationName?{name:t.migrationName}:await S.default.prompt({type:"input",name:"name",message:"Enter a name for the migration file (e.g. add-users-table):",initial:"new-migration"}),M=i.sql(),U=await F.default.subtle.digest("SHA-256",Buffer.from(M,"utf-8")).then(R=>Buffer.from(R).toString("hex")),O=`${c.toString().padStart(4,"0")}-${b.replace(/[^a-zA-Z0-9-_]/g,"_")}.sql`,k=A.default.join(a.migrations,O);await u.default.mkdir(a.migrations,{recursive:!0}),await u.default.writeFile(k,M,"utf-8"),o.default.info(e.default.green(`Migration file created: ${O}`)),p={version:c,name:b,hash:U}}if(h&&t.confirm){const{confirm:c}=await S.default.prompt({type:"confirm",name:"confirm",message:"Do you want to apply this migration?",initial:!0});c||(o.default.info(e.default.yellow("Aborting migration application.")),h=!1)}if(h&&p){const c=(0,T.default)(e.default.yellow("Applying migration...")).start();try{await n.batch([`
CREATE TABLE IF NOT EXISTS ${t.migrationsTable} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
version INTEGER NOT NULL,
hash TEXT NOT NULL
)
`,...i.statements(),`INSERT INTO ${t.migrationsTable} (name, version, hash) VALUES ('${p.name}', ${p.version}, '${p.hash}')`].map(b=>n.prepare(b))),c.succeed(e.default.green("Migration applied."))}catch(b){c.fail(e.default.red("Failed to apply migration!")),o.default.error(b),process.exit(1)}}}}})});var ee=J;