@lunora/cli
Version:
The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands
6 lines (5 loc) • 3.65 kB
JavaScript
import{quoteIdentifier as l,sqlAffinityForKind as h,frameworkColumnDdl as $,MAX_D1_TABLE_COLUMNS as u,columnRef as y,physicalIndexName as d}from"@lunora/d1/dialect";import{LunoraError as T}from"@lunora/errors";const R=e=>h(e),m=(e,n)=>{const o=[l(e),n.sqlType];return n.nullable||o.push("NOT NULL"),o.join(" ")},L=e=>{const n=Object.entries(e.columns).map(([t,i])=>` ${m(t,i)}`),o=$(),r=o.length+n.length;if(r>u)throw new T("VALIDATION_ERROR",`table "${e.name}" needs ${String(r)} columns, over D1's ${String(u)}-column limit — split the table, or move the extra fields into one object field`);const s=[...o.map(t=>` ${t}`),...n].join(`,
`);return`CREATE TABLE IF NOT EXISTS ${l(e.name)} (
${s}
);`},b=e=>`DROP TABLE IF EXISTS ${l(e)};`,E=(e,n,o)=>`ALTER TABLE ${l(e)} ADD COLUMN ${m(n,o)};`,c=(e,n)=>{const o=n.fields.map(r=>y(r)).join(", ");return`CREATE ${n.unique?"UNIQUE ":""}INDEX IF NOT EXISTS ${d(e,n.name)} ON ${l(e)} (${o});`},O=(e,n)=>`DROP INDEX IF EXISTS ${d(e,n)};`,N=(e,n,o,r,s)=>{o.sqlType!==r.sqlType&&s.push({kind:"columnTypeChange",summary:`column type change on ${e}.${n}: ${o.sqlType} → ${r.sqlType} (write SQL manually)`}),o.nullable!==r.nullable&&s.push({kind:"columnTypeChange",summary:`nullability change on ${e}.${n}: ${o.nullable?"NULL":"NOT NULL"} → ${r.nullable?"NULL":"NOT NULL"} (write SQL manually)`})},g=(e,n,o,r,s)=>{for(const[t,i]of Object.entries(o)){const a=n[t];if(a===void 0){r.push({kind:"addColumn",sql:E(e,t,i),summary:`ADD COLUMN ${e}.${t}`});continue}N(e,t,a,i,s)}for(const t of Object.keys(n))o[t]===void 0&&s.push({kind:"dropColumn",summary:`DROP COLUMN ${e}.${t} (SQLite drop-column requires careful migration — write SQL manually)`})},I=(e,n,o,r,s)=>{for(const[t,i]of Object.entries(o)){const a=n[t];if(a===void 0){r.push({kind:"createIndex",sql:c(e,i),summary:`CREATE INDEX ${t} ON ${e}`});continue}(!(a.fields.length===i.fields.length&&a.fields.every((p,f)=>p===i.fields[f]))||a.unique!==i.unique)&&s.push({kind:"indexRename",summary:`index ${t} changed on ${e} — drop+create manually if intentional`})}for(const t of Object.keys(n))o[t]===void 0&&r.push({kind:"dropIndex",sql:O(e,t),summary:`DROP INDEX ${t}`})},D=(e,n,o)=>{o.push({kind:"createTable",sql:L(n),summary:`CREATE TABLE ${e}`});for(const r of Object.values(n.indexes))o.push({kind:"createIndex",sql:c(e,r),summary:`CREATE INDEX ${r.name} ON ${e}`})},S=(e,n)=>{const o=e?.tables??{},r=[],s=[];for(const[t,i]of Object.entries(n.tables)){const a=o[t];if(a===void 0){D(t,i,r);continue}g(t,a.columns,i.columns,r,s),I(t,a.indexes,i.indexes,r,s)}for(const t of Object.keys(o))n.tables[t]===void 0&&r.push({kind:"dropTable",sql:b(t),summary:`DROP TABLE ${t}`});return{empty:r.length===0&&s.length===0,entries:r,unsupported:s}},C=(e,n,o)=>{const r=[`-- Lunora migration: ${e}`,`-- Generated at ${o}`,"-- This file was produced by `lunora migrate generate`. Review carefully before applying.",""];for(const s of n.entries)r.push(`-- ${s.summary}`,s.sql,"");if(n.unsupported.length>0){r.push("-- ---------------------------------------------------------------","-- The following deltas are NOT auto-generated in v0.1.","-- Write the appropriate SQL below by hand:","--");for(const s of n.unsupported)r.push(`-- * ${s.summary}`);r.push("-- ---------------------------------------------------------------","")}return n.empty&&r.push("-- No changes detected. Re-running `lunora migrate generate` will overwrite this file.",""),r.join(`
`)};export{S as diffSnapshots,E as renderAddColumn,c as renderCreateIndex,L as renderCreateTable,O as renderDropIndex,b as renderDropTable,C as renderMigrationFile,R as validatorKindToSqlType};