@izumisy/kyrage 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -6
- package/dist/main.js +6 -6
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -24,14 +24,12 @@ declare const databaseSchema: z.ZodObject<{
|
|
|
24
24
|
connectionString: z.ZodString;
|
|
25
25
|
}, z.core.$strip>;
|
|
26
26
|
type DatabaseValue = z.infer<typeof databaseSchema>;
|
|
27
|
-
declare const devDatabaseSchema: z.
|
|
27
|
+
declare const devDatabaseSchema: z.ZodObject<{
|
|
28
28
|
container: z.ZodObject<{
|
|
29
29
|
image: z.ZodString;
|
|
30
30
|
name: z.ZodOptional<z.ZodString>;
|
|
31
31
|
}, z.core.$strip>;
|
|
32
|
-
}, z.core.$strip
|
|
33
|
-
connectionString: z.ZodString;
|
|
34
|
-
}, z.core.$strip>]>>;
|
|
32
|
+
}, z.core.$strip>;
|
|
35
33
|
type DevDatabaseValue = z.infer<typeof devDatabaseSchema>;
|
|
36
34
|
|
|
37
35
|
declare const primaryKeyConstraintSchema: z.ZodObject<{
|
|
@@ -165,8 +163,6 @@ declare const defineConfig: (config: DefineConfigProp) => {
|
|
|
165
163
|
image: string;
|
|
166
164
|
name?: string | undefined;
|
|
167
165
|
};
|
|
168
|
-
} | {
|
|
169
|
-
connectionString: string;
|
|
170
166
|
} | undefined;
|
|
171
167
|
readonly indexes: {
|
|
172
168
|
columns: readonly string[];
|
package/dist/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as de,b as Q}from"./chunk-3M6BYRKC.js";import{a as S,b as E}from"./chunk-EY62Q3Z2.js";import{defineCommand as en,runMain as tn}from"citty";var ye="1.3.0";import{defineCommand as St}from"citty";import g from"zod";import{loadConfig as Re}from"c12";import m from"zod";var P=m.object({type:m.string()}).catchall(m.any()),_=m.object({table:m.string(),name:m.string()}),V=m.object({table:m.string(),column:m.string()}),z=m.object({..._.shape,columns:m.array(m.string()).readonly()}),W=m.object({..._.shape,columns:m.array(m.string()).readonly()}),ge=m.enum(["cascade","set null","set default","restrict","no action"]),J=m.object({..._.shape,columns:m.array(m.string()).readonly(),referencedTable:m.string(),referencedColumns:m.array(m.string()).readonly(),onDelete:ge.optional(),onUpdate:ge.optional()}),fe=m.discriminatedUnion("type",[m.object({type:m.literal("create_table"),table:m.string(),columns:m.record(m.string(),P)}),m.object({type:m.literal("drop_table"),table:m.string()}),m.object({...V.shape,type:m.literal("add_column"),attributes:P}),m.object({...V.shape,type:m.literal("drop_column"),attributes:P}),m.object({...V.shape,type:m.literal("alter_column"),before:P,after:P}),m.object({..._.shape,type:m.literal("create_index"),columns:m.array(m.string()).readonly(),unique:m.boolean()}),m.object({..._.shape,type:m.literal("drop_index")}),m.object({...z.shape,type:m.literal("create_primary_key_constraint")}),m.object({..._.shape,type:m.literal("drop_primary_key_constraint")}),m.object({...W.shape,type:m.literal("create_unique_constraint")}),m.object({..._.shape,type:m.literal("drop_unique_constraint")}),m.object({...J.shape,type:m.literal("create_foreign_key_constraint")}),m.object({..._.shape,type:m.literal("drop_foreign_key_constraint")})]),f={createTable:(e,t)=>({type:"create_table",table:e,columns:t}),dropTable:e=>({type:"drop_table",table:e}),addColumn:(e,t)=>({...e,type:"add_column",attributes:t}),dropColumn:(e,t)=>({...e,type:"drop_column",attributes:t}),alterColumn:(e,t,n)=>({...e,type:"alter_column",before:t,after:n}),createIndex:e=>({...e,type:"create_index"}),dropIndex:e=>({...e,type:"drop_index"}),createPrimaryKeyConstraint:e=>({...e,type:"create_primary_key_constraint"}),dropPrimaryKeyConstraint:e=>({...e,type:"drop_primary_key_constraint"}),createUniqueConstraint:e=>({...e,type:"create_unique_constraint"}),dropUniqueConstraint:e=>({...e,type:"drop_unique_constraint"}),createForeignKeyConstraint:(e,t)=>({...e,...t,type:"create_foreign_key_constraint"}),dropForeignKeyConstraint:e=>({...e,type:"drop_foreign_key_constraint"})};var Pe=g.object({type:g.string(),primaryKey:g.boolean().optional().default(!1),notNull:g.boolean().optional().default(!1),unique:g.boolean().optional().default(!1),defaultSql:g.string().optional()}),qe=g.object({tableName:g.string(),columns:g.record(g.string(),Pe)}),Ie=g.object({..._.shape,columns:g.array(g.string()).readonly(),unique:g.boolean().default(!1)}),ke=g.enum(["postgres","cockroachdb"]),$e=g.object({dialect:ke,connectionString:g.string()}),Me=g.object({container:g.object({image:g.string(),name:g.string().optional()})}),Ue=g.object({database:$e,dev:Me.optional(),tables:g.array(qe).readonly(),indexes:g.array(Ie).readonly(),primaryKeyConstraints:g.array(z).readonly(),uniqueConstraints:g.array(W).readonly(),foreignKeyConstraints:g.array(J).readonly()}),be=async()=>{let e=await Re({name:"kyrage"});return Ue.parse(e.config)};import{Kysely as Ze}from"kysely";import{PostgresDialect as je,sql as Y}from"kysely";import{Pool as Le}from"pg";import{PostgreSqlContainer as Fe}from"@testcontainers/postgresql";import*as D from"ramda";var M=class{getName(){return"postgres"}getDevDatabaseImageName(){return"postgres:16"}createKyselyDialect(t){return new je({pool:new Le({connectionString:t})})}createIntrospectionDriver(t){return{convertTypeName:X,introspect:G(t)}}createDevDatabaseContainer(t){return new Fe(t)}},G=e=>async t=>{var i=[];try{let n=S(i,e.getDB(),!0);let[a,o,l]=await Promise.all([He(n),Qe(n),Ve(n)]);let{indexes:c,uniqueConstraints:s}=Be(t.config,{indexes:o,constraints:l});return{tables:a,indexes:c,constraints:{...l,unique:s}}}catch(u){var r=u,p=!0}finally{var d=E(i,r,p);d&&await d}},Be=(e,t)=>{let n=u=>r=>D.any(D.whereEq({name:r.name,table:r.table}),u),[a,o]=D.partition(n(e.uniqueConstraints),t.constraints.unique),[l,c]=D.partition(n(e.indexes),t.indexes),s=D.reject(n(l),o),i=D.reject(n(a),c);return{indexes:[...l,...i],uniqueConstraints:[...a,...s]}},X=e=>({bool:"boolean",int2:"smallint",int4:"integer",int8:"bigint"})[e]??e,He=async e=>{let{rows:t}=await Y`
|
|
2
2
|
SELECT
|
|
3
3
|
n.nspname AS table_schema,
|
|
4
4
|
c.relname AS table_name,
|
|
@@ -18,7 +18,7 @@ import{a as ye,b as Q}from"./chunk-3M6BYRKC.js";import{a as N,b as E}from"./chun
|
|
|
18
18
|
AND a.attnum > 0
|
|
19
19
|
AND NOT a.attisdropped
|
|
20
20
|
ORDER BY c.relname, a.attnum;
|
|
21
|
-
`.$castTo().execute(e);return t.map(n=>({schema:n.table_schema,table:n.table_name,name:n.column_name,default:n.column_default,characterMaximumLength:n.character_maximum_length?Number(n.character_maximum_length):null}))},
|
|
21
|
+
`.$castTo().execute(e);return t.map(n=>({schema:n.table_schema,table:n.table_name,name:n.column_name,default:n.column_default,characterMaximumLength:n.character_maximum_length?Number(n.character_maximum_length):null}))},Qe=async e=>{let{rows:t}=await Y`
|
|
22
22
|
SELECT
|
|
23
23
|
t.relname AS table_name,
|
|
24
24
|
c.relname AS index_name,
|
|
@@ -33,7 +33,7 @@ import{a as ye,b as Q}from"./chunk-3M6BYRKC.js";import{a as N,b as E}from"./chun
|
|
|
33
33
|
AND n.nspname = 'public'
|
|
34
34
|
AND NOT i.indisprimary
|
|
35
35
|
GROUP BY t.relname, c.relname, i.indisunique, i.indisprimary, c.oid;
|
|
36
|
-
`.$castTo().execute(e);return t.map(n=>({table:n.table_name,name:n.index_name,columns:n.column_names,unique:n.is_unique}))},
|
|
36
|
+
`.$castTo().execute(e);return t.map(n=>({table:n.table_name,name:n.index_name,columns:n.column_names,unique:n.is_unique}))},Ve=async e=>{let{rows:t}=await Y`
|
|
37
37
|
SELECT
|
|
38
38
|
n.nspname AS schema,
|
|
39
39
|
t.relname AS table,
|
|
@@ -89,8 +89,8 @@ import{a as ye,b as Q}from"./chunk-3M6BYRKC.js";import{a as N,b as E}from"./chun
|
|
|
89
89
|
GROUP BY n.nspname, t.relname, c.conname, c.contype, c.oid, c.conkey, t.oid,
|
|
90
90
|
rt.relname, c.confkey, c.confdeltype, c.confupdtype
|
|
91
91
|
ORDER BY t.relname, c.conname;
|
|
92
|
-
`.$castTo().execute(e);return{primaryKey:t.filter(n=>n.type==="PRIMARY KEY"),unique:t.filter(n=>n.type==="UNIQUE"),foreignKey:t.filter(n=>n.type==="FOREIGN KEY").map(n=>{let{referenced_table:a,referenced_columns:o,on_delete:l,on_update:c,...s}=n;return{...s,referencedTable:a,referencedColumns:o,onDelete:l,onUpdate:c}})}};import{CockroachDbContainer as We}from"@testcontainers/cockroachdb";import{Pool as Je}from"pg";import{PostgresAdapter as Ye,PostgresDialect as Ge}from"kysely";var U=class{getName(){return"cockroachdb"}getDevDatabaseImageName(){return"cockroachdb/cockroach:latest-v24.3"}createKyselyDialect(t){return new ee({pool:new Je({connectionString:t})})}createIntrospectionDriver(t){return{convertTypeName:X,introspect:G(t)}}createDevDatabaseContainer(t){return new We(t)}},Z=class extends Ye{async acquireMigrationLock(t,n){await t.selectFrom(n.lockTable).selectAll().forUpdate().execute()}},ee=class extends Ge{createAdapter(){return new Z}};var Xe={postgres:new M,cockroachdb:new U},A=e=>{let t=Xe[e];if(!t)throw new Error(`Unsupported dialect: ${e}`);return t};import{DummyDriver as Ze}from"kysely";var j=class extends Ze{constructor(n){super();this.queries=n}async acquireConnection(){return new te(this.queries)}},te=class{constructor(t){this.queries=t}async executeQuery(t){let n=t.query.kind;if(n==="CreateTableNode"||n==="DropTableNode"||n==="AlterTableNode"){if(t.query.table.table.identifier.name.startsWith("kysely_"))return{rows:[]};this.queries.push(t)}else(n==="CreateIndexNode"||n==="DropIndexNode")&&this.queries.push(t);return{rows:[]}}async*streamQuery(){}};var L=e=>new ne({databaseProps:e.database,options:e.options}),ne=class{constructor(t){this.constructorProps=t}getDB(t){let n=A(this.constructorProps.databaseProps.dialect).createKyselyDialect(this.constructorProps.databaseProps.connectionString);return new ae({dialect:{createAdapter:()=>n.createAdapter(),createDriver:()=>n.createDriver(),createIntrospector:a=>n.createIntrospector(a),createQueryCompiler:()=>n.createQueryCompiler()}},{isPlan:t?.plan===!0})}getDialect(){return this.constructorProps.databaseProps.dialect}},ae=class extends et{constructor(n,a){let o=[];super({dialect:{...n.dialect,createDriver:()=>a.isPlan?new j(o):n.dialect.createDriver()}});this.plannedQueries=[];this.plannedQueries=o}getPlannedQueries(){return this.plannedQueries}};async function v(){let e=await Ce();return{client:L({database:e.database}),logger:ye,config:e}}import{Migrator as vt}from"kysely";import{DEFAULT_MIGRATION_TABLE as he,isColumnDataType as tt,sql as _e}from"kysely";import{readdir as nt,readFile as at}from"fs/promises";import{join as rt}from"path";import q from"zod";import*as De from"ramda";var O="migrations",ot=q.object({operations:q.array(be).readonly()}),it=q.object({id:q.string(),version:q.string(),diff:ot}),re=async()=>{try{let t=(await nt(O)).filter(n=>n.endsWith(".json")).map(async n=>it.parse(JSON.parse(await at(rt(O,n),"utf-8"))));return await Promise.all(t)}catch(e){if(e instanceof Object&&"code"in e&&e.code==="ENOENT")return[];throw e}},w=async e=>{var l=[];try{let t=N(l,e.getDB(),!0);let n=await re();let a=(await t.introspection.getTables({withInternalKyselyTables:!0})).map(r=>r.name);if(!a.includes(he))return n;let o=await t.selectFrom(he).select(["name","timestamp"]).$narrowType().execute();return n.filter(r=>!o.some(p=>p.name===r.id))}catch(c){var s=c,i=!0}finally{var u=E(l,s,i);u&&await u}},Se=e=>({getMigrations:async()=>{let t=await e.migrationsResolver(),n={};return t.forEach(a=>{n[a.id]={up:async()=>{await st(e.db,a.diff)}}}),n}});async function st(e,t){let n=De.pipe(Dt,St,Nt);for(let a of n(t.operations))await ct(e,a)}async function ct(e,t){switch(t.type){case"create_table":return lt(e,t);case"drop_table":return mt(e,t);case"add_column":return ut(e,t);case"drop_column":return pt(e,t);case"alter_column":return dt(e,t);case"create_index":return yt(e,t);case"drop_index":return gt(e,t);case"create_primary_key_constraint":return ft(e,t);case"drop_primary_key_constraint":return bt(e,t);case"create_unique_constraint":return Ct(e,t);case"drop_unique_constraint":return ht(e,t);case"create_foreign_key_constraint":return xt(e,t);case"drop_foreign_key_constraint":return _t(e,t);default:throw new Error(`Unknown operation type: ${t.type}`)}}async function lt(e,t){let n=e.schema.createTable(t.table);for(let[a,o]of Object.entries(t.columns)){let l=o.type;oe(l),n=n.addColumn(a,l,c=>{let s=c;return o.notNull&&(s=s.notNull()),typeof o.defaultSql=="string"&&(s=s.defaultTo(_e.raw(o.defaultSql))),s})}await n.execute()}async function mt(e,t){await e.schema.dropTable(t.table).execute()}async function ut(e,t){let n=t.attributes.type;oe(n),await e.schema.alterTable(t.table).addColumn(t.column,n,a=>{let o=a;return t.attributes.notNull&&(o=o.notNull()),typeof t.attributes.defaultSql=="string"&&(o=o.defaultTo(_e.raw(t.attributes.defaultSql))),o}).execute()}async function pt(e,t){await e.schema.alterTable(t.table).dropColumn(t.column).execute()}async function dt(e,t){let{table:n,column:a,before:o,after:l}=t;if(o.type!==l.type){let c=l.type;oe(c),await e.schema.alterTable(n).alterColumn(a,s=>s.setDataType(c)).execute()}l.notNull!==o.notNull&&(l.notNull?await e.schema.alterTable(n).alterColumn(a,c=>c.setNotNull()).execute():await e.schema.alterTable(n).alterColumn(a,c=>c.dropNotNull()).execute())}async function yt(e,t){let n=e.schema.createIndex(t.name).on(t.table);for(let a of t.columns)n=n.column(a);t.unique&&(n=n.unique()),await n.execute()}async function gt(e,t){await e.schema.dropIndex(t.name).execute()}async function ft(e,t){await e.schema.alterTable(t.table).addPrimaryKeyConstraint(t.name,t.columns).execute()}async function bt(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function Ct(e,t){await e.schema.alterTable(t.table).addUniqueConstraint(t.name,t.columns).execute()}async function ht(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function xt(e,t){let n=e.schema.alterTable(t.table).addForeignKeyConstraint(t.name,t.columns,t.referencedTable,t.referencedColumns);t.onDelete&&(n=n.onDelete(t.onDelete)),t.onUpdate&&(n=n.onUpdate(t.onUpdate)),await n.execute()}async function _t(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}var oe=e=>{if(!tt(e))throw new Error(`Unsupported data type: ${e}`)},xe={drop_foreign_key_constraint:0,drop_unique_constraint:1,drop_primary_key_constraint:2,drop_index:3,drop_column:4,drop_table:5,create_table:6,add_column:7,alter_column:8,create_index:9,create_primary_key_constraint:10,create_unique_constraint:11,create_foreign_key_constraint:12},Dt=e=>{let t=new Set;return e.forEach(n=>{n.type==="drop_table"&&t.add(n.table)}),t.size===0?e:e.filter(n=>n.type==="drop_table"?!0:!t.has(n.table))},St=e=>{let t=new Set;return e.forEach(n=>{(n.type==="drop_unique_constraint"||n.type==="drop_primary_key_constraint")&&t.add(`${n.table}.${n.name}`)}),e.filter(n=>{if(n.type==="drop_index"){let a=`${n.table}.${n.name}`;if(t.has(a))return!1}return!0})},Nt=e=>e.slice().sort((t,n)=>{let a=xe[t.type],o=xe[n.type];return a!==o?a-o:t.table.localeCompare(n.table)});import{format as wt}from"sql-formatter";async function I(e,t){var r=[];try{let{client:n,logger:a}=e;let{reporter:o}=a;let l=N(r,n.getDB({plan:t.plan}),!0);let c=new vt({db:l,provider:Se({db:l,migrationsResolver:async()=>t.plan?await w(n):await re(),options:{plan:t.plan}})});let{results:s,error:i}=await c.migrateToLatest();let u=l.getPlannedQueries();if(u.length>0){u.forEach(b=>{a.stdout(t.pretty?wt(b.sql):b.sql)});return}s&&s.length>0?s.forEach(b=>{b.status==="Error"?o.error(`Migration failed: ${b.migrationName}`):b.status==="Success"&&o.success(`Migration applied: ${b.migrationName}`)}):o.info("No migrations to run");if(i)throw i instanceof Error?i:new Error(`Migration error: ${i}`)}catch(p){var d=p,h=!0}finally{var C=E(r,d,h);C&&await C}}var Ne=Et({meta:{name:"apply",description:"Run migrations to sync database schema"},args:{plan:{type:"boolean",description:"Plan the migration without applying it",default:!1},pretty:{type:"boolean",description:"Pretty print the migration SQL (only for --plan)",default:!1}},run:async e=>{try{let t=await v();await I(t,{plan:e.args.plan,pretty:e.args.pretty})}catch(t){let{defaultConsolaLogger:n}=await import("./logger-SE7G5AMI.js");n.reporter.error(t),process.exit(1)}}});import{defineCommand as Mt}from"citty";import{mkdir as Ut,writeFile as jt,unlink as Lt}from"fs/promises";import{join as Ft}from"path";import*as g from"ramda";var K=()=>({added:(e,t,n)=>g.pipe(g.difference(t),g.map(n))(e),removed:(e,t,n)=>g.pipe(g.difference(e),g.map(n))(t),changed:(e,t,n,a)=>g.pipe(g.intersection(e),g.filter(n),g.map(a))(t)}),F=g.prop("name"),Tt=g.eqBy(e=>[e.type,e.notNull??!1,e.primaryKey??!1,e.unique??!1]);function At(e,t){let n=[],a=K(),o=e.columns,l=t.columns,c=Object.keys(o),s=Object.keys(l);return a.added(c,s,i=>({column:i,attributes:l[i]})).forEach(i=>{n.push(f.addColumn({table:e.name,column:i.column},i.attributes))}),a.removed(c,s,i=>({column:i,attributes:o[i]})).forEach(i=>{n.push(f.dropColumn({table:e.name,column:i.column},i.attributes))}),a.changed(c,s,i=>!Tt(o[i],l[i]),i=>({column:i,before:o[i],after:l[i]})).forEach(i=>{n.push(f.alterColumn({table:e.name,column:i.column},i.before,i.after))}),n}function Ot(e){let{current:t,ideal:n}=e,a=[],o=K(),l=g.map(F,t),c=g.map(F,n);return o.added(l,c,s=>n.find(u=>u.name===s)).forEach(s=>{a.push(f.createTable(s.name,s.columns))}),o.removed(l,c,g.identity).forEach(s=>{a.push(f.dropTable(s))}),g.filter(s=>n.some(i=>i.name===s.name))(t).forEach(s=>{let i=n.find(u=>u.name===s.name);a.push(...At(s,i))}),a}function Kt(e){let{current:t,ideal:n}=e,a=[],o=K(),l=r=>`${r.table}:${r.name}`,c=new Map(t.map(r=>[l(r),r])),s=new Map(n.map(r=>[l(r),r])),i=Array.from(c.keys()),u=Array.from(s.keys());return o.added(i,u,r=>s.get(r)).forEach(r=>{a.push(f.createIndex(r))}),o.removed(i,u,r=>{let p=c.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropIndex(r))}),o.changed(i,u,r=>{let p=c.get(r),d=s.get(r);return!g.equals(p.columns,d.columns)||p.unique!==d.unique},r=>{let p=c.get(r),d=s.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropIndex(r)),a.push(f.createIndex(p))}),a}function Rt(e){let{current:t,ideal:n}=e,a=[],o=K(),l=r=>`${r.table}:${r.name}`,c=new Map(t.map(r=>[l(r),r])),s=new Map(n.map(r=>[l(r),r])),i=Array.from(c.keys()),u=Array.from(s.keys());return o.added(i,u,r=>s.get(r)).forEach(r=>{a.push(f.createPrimaryKeyConstraint(r))}),o.removed(i,u,r=>{let p=c.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropPrimaryKeyConstraint(r))}),o.changed(i,u,r=>{let p=c.get(r),d=s.get(r);return!g.equals(p.columns,d.columns)},r=>{let p=c.get(r),d=s.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropPrimaryKeyConstraint(r)),a.push(f.createPrimaryKeyConstraint(p))}),a}function Pt(e){let{current:t,ideal:n}=e,a=[],o=K(),l=r=>`${r.table}:${r.name}`,c=new Map(t.map(r=>[l(r),r])),s=new Map(n.map(r=>[l(r),r])),i=Array.from(c.keys()),u=Array.from(s.keys());return o.added(i,u,r=>s.get(r)).forEach(r=>{a.push(f.createUniqueConstraint(r))}),o.removed(i,u,r=>{let p=c.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropUniqueConstraint(r))}),o.changed(i,u,r=>{let p=c.get(r),d=s.get(r);return!g.equals(p.columns,d.columns)},r=>{let p=c.get(r),d=s.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropUniqueConstraint(r)),a.push(f.createUniqueConstraint(p))}),a}function qt(e){let t=[],n=K(),a=e.current.map(F),o=e.ideal.map(F);t.push(...n.added(a,o,c=>{let s=e.ideal.find(p=>p.name===c),{table:i,name:u,...r}=s;return f.createForeignKeyConstraint({table:i,name:u},r)})),t.push(...n.removed(a,o,c=>{let s=e.current.find(i=>i.name===c);return f.dropForeignKeyConstraint(s)}));let l=c=>{let s=e.current.find(u=>u.name===c),i=e.ideal.find(u=>u.name===c);return!s||!i?!1:!(g.equals(s.columns,i.columns)&&s.referencedTable===i.referencedTable&&g.equals(s.referencedColumns,i.referencedColumns)&&s.onDelete===i.onDelete&&s.onUpdate===i.onUpdate)};return t.push(...n.changed(a,o,l,c=>{let s=e.current.find(d=>d.name===c),i=e.ideal.find(d=>d.name===c),{table:u,name:r,...p}=i;return[f.dropForeignKeyConstraint(s),f.createForeignKeyConstraint({table:u,name:r},p)]}).flat()),t}function Ee(e){let t=Ot({current:e.current.tables,ideal:e.ideal.tables}),n=Kt({current:e.current.indexes,ideal:e.ideal.indexes}),a=Rt({current:e.current.primaryKeyConstraints,ideal:e.ideal.primaryKeyConstraints}),o=Pt({current:e.current.uniqueConstraints,ideal:e.ideal.uniqueConstraints}),l=qt({current:e.current.foreignKeyConstraints,ideal:e.ideal.foreignKeyConstraints});return{operations:[...t,...n,...a,...o,...l]}}var ve=e=>{let n=A(e.getDialect()).createIntrospectionDriver(e);return{introspect:async o=>{var C=[];try{let l=N(C,e.getDB(),!0);let c=await l.introspection.getTables();let{tables:s,indexes:i,constraints:u}=await n.introspect({config:o});let r=()=>c.map(x=>({schema:x.schema,name:x.name,columns:Object.fromEntries(x.columns.map(S=>{let pe=s.filter(de=>de.table===x.name&&de.name===S.name)[0]||{};return[S.name,{schema:x.schema,table:x.name,name:S.name,dataType:n.convertTypeName(S.dataType),default:pe.default??null,characterMaximumLength:pe.characterMaximumLength??null,notNull:!S.isNullable}]}))}));let p=x=>!x.table.startsWith("kysely_");let d=()=>i.filter(p);let h=()=>({primaryKey:u.primaryKey.filter(p),unique:u.unique.filter(p),foreignKey:u.foreignKey.filter(p)});return{tables:r(),indexes:d(),constraints:h()}}catch(b){var R=b,T=!0}finally{var H=E(C,R,T);H&&await H}}}};import{getContainerRuntimeClient as le}from"testcontainers";var ie="kyrage.dialect",me="kyrage.managed",we="kyrage.managed-by",Te=async e=>(await(await le()).container.list()).some(a=>a.Labels[me]==="true"&&a.Labels[we]==="dev-start"&&a.Labels[ie]===e&&a.State==="running"),It=async()=>{let e=await le(),n=(await e.container.list()).filter(a=>a.Labels[me]==="true").map(a=>a.Id);await Promise.allSettled(n.map(async a=>e.container.getById(a).remove({force:!0})))},kt=new Error("Dev database is not started or unavailable"),se=class{constructor(t,n){this.options=t;this.startedContainer=null;let a=n(),o=this.options.manageType||"one-off";a.withLabels({[ie]:this.options.dialect,[me]:"true",[we]:o}),o==="dev-start"&&a.withReuse(),this.options.containerName&&a.withName(this.options.containerName),this.container=a}async findRunningContainer(){return(await le()).container.fetchByLabel(ie,this.options.dialect,{status:["running"]})}async exists(){return!!await this.findRunningContainer()}async start(){this.startedContainer=await this.container.start()}getConnectionString(){if(!this.startedContainer)throw kt;return this.startedContainer.getConnectionUri()}async stop(){this.startedContainer&&(await this.startedContainer.stop(),this.startedContainer=null)}async remove(){await It(),this.startedContainer=null}async getStatus(){let t=await this.findRunningContainer();if(!t)return null;let n=await t.inspect();return{type:"container",imageName:n.Config.Image,containerID:n.Id}}},ce=class{constructor(t){this.connectionString=t}async start(){}async stop(){}async remove(){}async exists(){return!0}getConnectionString(){return this.connectionString}async getStatus(){return{type:"connectionString"}}},k=(e,t,n)=>{if("connectionString"in e)return new ce(e.connectionString);if("container"in e)return new se({dialect:t,containerName:n==="dev-start"?e.container.name:void 0,manageType:n},()=>A(t).createDevDatabaseContainer(e.container.image));throw new Error("Invalid dev database configuration")};async function $t(e,t){let{config:n}=e,a=n.database.dialect;switch(t.mode){case"dev-start":{let o="dev-start",l=k(n.dev,a,o);return{manager:l,containerType:o,result:{reused:await l.exists()}}}case"generate-dev":{let o=await Te(a),l=o?"dev-start":"one-off";return{manager:k(n.dev,a,l),containerType:l,result:{reused:o}}}}}async function B(e,t){let{config:n}=e,a=t.logger||Q,{reporter:o}=a;if(!n.dev)throw new Error("Dev database configuration is required");let{manager:l,containerType:c,result:s}=await $t(e,t);s.reused?o.info("\u{1F504} Reusing existing dev database..."):o.info("\u{1F680} Starting dev database..."),await l.start(),o.success(`Dev database started: ${n.database.dialect}`);let i=L({database:{dialect:n.database.dialect,connectionString:l.getConnectionString()}}),u=await w(i);return u.length>0?(o.info(`\u{1F504} Applying ${u.length} pending migrations...`),await I({client:i,logger:Q,config:n},{plan:!1,pretty:!1}),o.success(`Applied ${u.length} migrations`)):o.info("No pending migrations found"),{client:i,manager:l,cleanup:async()=>{switch(t.mode){case"dev-start":o.success("Persistent dev database ready: "+n.database.dialect);break;case"generate-dev":c==="dev-start"?o.info("Dev start container remains running"):(await l.stop(),o.success("Temporary dev database stopped"));break}}}}async function Bt(e,t){let{logger:n,config:a}=e,{reporter:o}=n;t.squash&&await Ht(e);let{client:l,cleanup:c}=t.dev?await B(e,{mode:"generate-dev",logger:n}):{client:e.client,cleanup:async()=>{}};try{if(!t.ignorePending){let r=await w(l);if(r.length>0)if(t.dev)o.info(`Dev database has ${r.length} pending migrations. These will be applied automatically as baseline.`);else{o.warn([`There are pending migrations: ${r.map(p=>p.id).join(", ")}`,"Please apply them first before generating a new migration.","Otherwise, use --ignore-pending to skip this check."].join(`
|
|
93
|
-
`));return}}let s=await
|
|
92
|
+
`.$castTo().execute(e);return{primaryKey:t.filter(n=>n.type==="PRIMARY KEY"),unique:t.filter(n=>n.type==="UNIQUE"),foreignKey:t.filter(n=>n.type==="FOREIGN KEY").map(n=>{let{referenced_table:a,referenced_columns:o,on_delete:l,on_update:c,...s}=n;return{...s,referencedTable:a,referencedColumns:o,onDelete:l,onUpdate:c}})}};import{CockroachDbContainer as ze}from"@testcontainers/cockroachdb";import{Pool as We}from"pg";import{PostgresAdapter as Je,PostgresDialect as Ye}from"kysely";var U=class{getName(){return"cockroachdb"}getDevDatabaseImageName(){return"cockroachdb/cockroach:latest-v24.3"}createKyselyDialect(t){return new ee({pool:new We({connectionString:t})})}createIntrospectionDriver(t){return{convertTypeName:X,introspect:G(t)}}createDevDatabaseContainer(t){return new ze(t)}},Z=class extends Je{async acquireMigrationLock(t,n){await t.selectFrom(n.lockTable).selectAll().forUpdate().execute()}},ee=class extends Ye{createAdapter(){return new Z}};var Ge={postgres:new M,cockroachdb:new U},A=e=>{let t=Ge[e];if(!t)throw new Error(`Unsupported dialect: ${e}`);return t};import{DummyDriver as Xe}from"kysely";var j=class extends Xe{constructor(n){super();this.queries=n}async acquireConnection(){return new te(this.queries)}},te=class{constructor(t){this.queries=t}async executeQuery(t){let n=t.query.kind;if(n==="CreateTableNode"||n==="DropTableNode"||n==="AlterTableNode"){if(t.query.table.table.identifier.name.startsWith("kysely_"))return{rows:[]};this.queries.push(t)}else(n==="CreateIndexNode"||n==="DropIndexNode")&&this.queries.push(t);return{rows:[]}}async*streamQuery(){}};var L=e=>new ne({databaseProps:e.database,options:e.options}),ne=class{constructor(t){this.constructorProps=t}getDB(t){let n=A(this.constructorProps.databaseProps.dialect).createKyselyDialect(this.constructorProps.databaseProps.connectionString);return new ae({dialect:{createAdapter:()=>n.createAdapter(),createDriver:()=>n.createDriver(),createIntrospector:a=>n.createIntrospector(a),createQueryCompiler:()=>n.createQueryCompiler()}},{isPlan:t?.plan===!0})}getDialect(){return this.constructorProps.databaseProps.dialect}},ae=class extends Ze{constructor(n,a){let o=[];super({dialect:{...n.dialect,createDriver:()=>a.isPlan?new j(o):n.dialect.createDriver()}});this.plannedQueries=[];this.plannedQueries=o}getPlannedQueries(){return this.plannedQueries}};async function v(){let e=await be();return{client:L({database:e.database}),logger:de,config:e}}import{Migrator as Et}from"kysely";import{DEFAULT_MIGRATION_TABLE as Ce,isColumnDataType as et,sql as xe}from"kysely";import{readdir as tt,readFile as nt}from"fs/promises";import{join as at}from"path";import q from"zod";import*as _e from"ramda";var O="migrations",rt=q.object({operations:q.array(fe).readonly()}),ot=q.object({id:q.string(),version:q.string(),diff:rt}),re=async()=>{try{let t=(await tt(O)).filter(n=>n.endsWith(".json")).map(async n=>ot.parse(JSON.parse(await nt(at(O,n),"utf-8"))));return await Promise.all(t)}catch(e){if(e instanceof Object&&"code"in e&&e.code==="ENOENT")return[];throw e}},w=async e=>{var l=[];try{let t=S(l,e.getDB(),!0);let n=await re();let a=(await t.introspection.getTables({withInternalKyselyTables:!0})).map(r=>r.name);if(!a.includes(Ce))return n;let o=await t.selectFrom(Ce).select(["name","timestamp"]).$narrowType().execute();return n.filter(r=>!o.some(p=>p.name===r.id))}catch(c){var s=c,i=!0}finally{var u=E(l,s,i);u&&await u}},De=e=>({getMigrations:async()=>{let t=await e.migrationsResolver(),n={};return t.forEach(a=>{n[a.id]={up:async()=>{await it(e.db,a.diff)}}}),n}});async function it(e,t){let n=_e.pipe(_t,Dt,Nt);for(let a of n(t.operations))await st(e,a)}async function st(e,t){switch(t.type){case"create_table":return ct(e,t);case"drop_table":return lt(e,t);case"add_column":return mt(e,t);case"drop_column":return ut(e,t);case"alter_column":return pt(e,t);case"create_index":return dt(e,t);case"drop_index":return yt(e,t);case"create_primary_key_constraint":return gt(e,t);case"drop_primary_key_constraint":return ft(e,t);case"create_unique_constraint":return bt(e,t);case"drop_unique_constraint":return Ct(e,t);case"create_foreign_key_constraint":return ht(e,t);case"drop_foreign_key_constraint":return xt(e,t);default:throw new Error(`Unknown operation type: ${t.type}`)}}async function ct(e,t){let n=e.schema.createTable(t.table);for(let[a,o]of Object.entries(t.columns)){let l=o.type;oe(l),n=n.addColumn(a,l,c=>{let s=c;return o.notNull&&(s=s.notNull()),typeof o.defaultSql=="string"&&(s=s.defaultTo(xe.raw(o.defaultSql))),s})}await n.execute()}async function lt(e,t){await e.schema.dropTable(t.table).execute()}async function mt(e,t){let n=t.attributes.type;oe(n),await e.schema.alterTable(t.table).addColumn(t.column,n,a=>{let o=a;return t.attributes.notNull&&(o=o.notNull()),typeof t.attributes.defaultSql=="string"&&(o=o.defaultTo(xe.raw(t.attributes.defaultSql))),o}).execute()}async function ut(e,t){await e.schema.alterTable(t.table).dropColumn(t.column).execute()}async function pt(e,t){let{table:n,column:a,before:o,after:l}=t;if(o.type!==l.type){let c=l.type;oe(c),await e.schema.alterTable(n).alterColumn(a,s=>s.setDataType(c)).execute()}l.notNull!==o.notNull&&(l.notNull?await e.schema.alterTable(n).alterColumn(a,c=>c.setNotNull()).execute():await e.schema.alterTable(n).alterColumn(a,c=>c.dropNotNull()).execute())}async function dt(e,t){let n=e.schema.createIndex(t.name).on(t.table);for(let a of t.columns)n=n.column(a);t.unique&&(n=n.unique()),await n.execute()}async function yt(e,t){await e.schema.dropIndex(t.name).execute()}async function gt(e,t){await e.schema.alterTable(t.table).addPrimaryKeyConstraint(t.name,t.columns).execute()}async function ft(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function bt(e,t){await e.schema.alterTable(t.table).addUniqueConstraint(t.name,t.columns).execute()}async function Ct(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function ht(e,t){let n=e.schema.alterTable(t.table).addForeignKeyConstraint(t.name,t.columns,t.referencedTable,t.referencedColumns);t.onDelete&&(n=n.onDelete(t.onDelete)),t.onUpdate&&(n=n.onUpdate(t.onUpdate)),await n.execute()}async function xt(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}var oe=e=>{if(!et(e))throw new Error(`Unsupported data type: ${e}`)},he={drop_foreign_key_constraint:0,drop_unique_constraint:1,drop_primary_key_constraint:2,drop_index:3,drop_column:4,drop_table:5,create_table:6,add_column:7,alter_column:8,create_index:9,create_primary_key_constraint:10,create_unique_constraint:11,create_foreign_key_constraint:12},_t=e=>{let t=new Set;return e.forEach(n=>{n.type==="drop_table"&&t.add(n.table)}),t.size===0?e:e.filter(n=>n.type==="drop_table"?!0:!t.has(n.table))},Dt=e=>{let t=new Set;return e.forEach(n=>{(n.type==="drop_unique_constraint"||n.type==="drop_primary_key_constraint")&&t.add(`${n.table}.${n.name}`)}),e.filter(n=>{if(n.type==="drop_index"){let a=`${n.table}.${n.name}`;if(t.has(a))return!1}return!0})},Nt=e=>e.slice().sort((t,n)=>{let a=he[t.type],o=he[n.type];return a!==o?a-o:t.table.localeCompare(n.table)});import{format as vt}from"sql-formatter";async function I(e,t){var r=[];try{let{client:n,logger:a}=e;let{reporter:o}=a;let l=S(r,n.getDB({plan:t.plan}),!0);let c=new Et({db:l,provider:De({db:l,migrationsResolver:async()=>t.plan?await w(n):await re(),options:{plan:t.plan}})});let{results:s,error:i}=await c.migrateToLatest();let u=l.getPlannedQueries();if(u.length>0){u.forEach(b=>{a.stdout(t.pretty?vt(b.sql):b.sql)});return}s&&s.length>0?s.forEach(b=>{b.status==="Error"?o.error(`Migration failed: ${b.migrationName}`):b.status==="Success"&&o.success(`Migration applied: ${b.migrationName}`)}):o.info("No migrations to run");if(i)throw i instanceof Error?i:new Error(`Migration error: ${i}`)}catch(p){var d=p,h=!0}finally{var C=E(r,d,h);C&&await C}}var Ne=St({meta:{name:"apply",description:"Run migrations to sync database schema"},args:{plan:{type:"boolean",description:"Plan the migration without applying it",default:!1},pretty:{type:"boolean",description:"Pretty print the migration SQL (only for --plan)",default:!1}},run:async e=>{try{let t=await v();await I(t,{plan:e.args.plan,pretty:e.args.pretty})}catch(t){let{defaultConsolaLogger:n}=await import("./logger-SE7G5AMI.js");n.reporter.error(t),process.exit(1)}}});import{defineCommand as $t}from"citty";import{mkdir as Mt,writeFile as Ut,unlink as jt}from"fs/promises";import{join as Lt}from"path";import*as y from"ramda";var K=()=>({added:(e,t,n)=>y.pipe(y.difference(t),y.map(n))(e),removed:(e,t,n)=>y.pipe(y.difference(e),y.map(n))(t),changed:(e,t,n,a)=>y.pipe(y.intersection(e),y.filter(n),y.map(a))(t)}),F=y.prop("name"),wt=y.eqBy(e=>[e.type,e.notNull??!1,e.primaryKey??!1,e.unique??!1]);function Tt(e,t){let n=[],a=K(),o=e.columns,l=t.columns,c=Object.keys(o),s=Object.keys(l);return a.added(c,s,i=>({column:i,attributes:l[i]})).forEach(i=>{n.push(f.addColumn({table:e.name,column:i.column},i.attributes))}),a.removed(c,s,i=>({column:i,attributes:o[i]})).forEach(i=>{n.push(f.dropColumn({table:e.name,column:i.column},i.attributes))}),a.changed(c,s,i=>!wt(o[i],l[i]),i=>({column:i,before:o[i],after:l[i]})).forEach(i=>{n.push(f.alterColumn({table:e.name,column:i.column},i.before,i.after))}),n}function At(e){let{current:t,ideal:n}=e,a=[],o=K(),l=y.map(F,t),c=y.map(F,n);return o.added(l,c,s=>n.find(u=>u.name===s)).forEach(s=>{a.push(f.createTable(s.name,s.columns))}),o.removed(l,c,y.identity).forEach(s=>{a.push(f.dropTable(s))}),y.filter(s=>n.some(i=>i.name===s.name))(t).forEach(s=>{let i=n.find(u=>u.name===s.name);a.push(...Tt(s,i))}),a}function Ot(e){let{current:t,ideal:n}=e,a=[],o=K(),l=r=>`${r.table}:${r.name}`,c=new Map(t.map(r=>[l(r),r])),s=new Map(n.map(r=>[l(r),r])),i=Array.from(c.keys()),u=Array.from(s.keys());return o.added(i,u,r=>s.get(r)).forEach(r=>{a.push(f.createIndex(r))}),o.removed(i,u,r=>{let p=c.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropIndex(r))}),o.changed(i,u,r=>{let p=c.get(r),d=s.get(r);return!y.equals(p.columns,d.columns)||p.unique!==d.unique},r=>{let p=c.get(r),d=s.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropIndex(r)),a.push(f.createIndex(p))}),a}function Kt(e){let{current:t,ideal:n}=e,a=[],o=K(),l=r=>`${r.table}:${r.name}`,c=new Map(t.map(r=>[l(r),r])),s=new Map(n.map(r=>[l(r),r])),i=Array.from(c.keys()),u=Array.from(s.keys());return o.added(i,u,r=>s.get(r)).forEach(r=>{a.push(f.createPrimaryKeyConstraint(r))}),o.removed(i,u,r=>{let p=c.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropPrimaryKeyConstraint(r))}),o.changed(i,u,r=>{let p=c.get(r),d=s.get(r);return!y.equals(p.columns,d.columns)},r=>{let p=c.get(r),d=s.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropPrimaryKeyConstraint(r)),a.push(f.createPrimaryKeyConstraint(p))}),a}function Rt(e){let{current:t,ideal:n}=e,a=[],o=K(),l=r=>`${r.table}:${r.name}`,c=new Map(t.map(r=>[l(r),r])),s=new Map(n.map(r=>[l(r),r])),i=Array.from(c.keys()),u=Array.from(s.keys());return o.added(i,u,r=>s.get(r)).forEach(r=>{a.push(f.createUniqueConstraint(r))}),o.removed(i,u,r=>{let p=c.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropUniqueConstraint(r))}),o.changed(i,u,r=>{let p=c.get(r),d=s.get(r);return!y.equals(p.columns,d.columns)},r=>{let p=c.get(r),d=s.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropUniqueConstraint(r)),a.push(f.createUniqueConstraint(p))}),a}function Pt(e){let t=[],n=K(),a=e.current.map(F),o=e.ideal.map(F);t.push(...n.added(a,o,c=>{let s=e.ideal.find(p=>p.name===c),{table:i,name:u,...r}=s;return f.createForeignKeyConstraint({table:i,name:u},r)})),t.push(...n.removed(a,o,c=>{let s=e.current.find(i=>i.name===c);return f.dropForeignKeyConstraint(s)}));let l=c=>{let s=e.current.find(u=>u.name===c),i=e.ideal.find(u=>u.name===c);return!s||!i?!1:!(y.equals(s.columns,i.columns)&&s.referencedTable===i.referencedTable&&y.equals(s.referencedColumns,i.referencedColumns)&&s.onDelete===i.onDelete&&s.onUpdate===i.onUpdate)};return t.push(...n.changed(a,o,l,c=>{let s=e.current.find(d=>d.name===c),i=e.ideal.find(d=>d.name===c),{table:u,name:r,...p}=i;return[f.dropForeignKeyConstraint(s),f.createForeignKeyConstraint({table:u,name:r},p)]}).flat()),t}function Se(e){let t=At({current:e.current.tables,ideal:e.ideal.tables}),n=Ot({current:e.current.indexes,ideal:e.ideal.indexes}),a=Kt({current:e.current.primaryKeyConstraints,ideal:e.ideal.primaryKeyConstraints}),o=Rt({current:e.current.uniqueConstraints,ideal:e.ideal.uniqueConstraints}),l=Pt({current:e.current.foreignKeyConstraints,ideal:e.ideal.foreignKeyConstraints});return{operations:[...t,...n,...a,...o,...l]}}var Ee=e=>{let n=A(e.getDialect()).createIntrospectionDriver(e);return{introspect:async o=>{var C=[];try{let l=S(C,e.getDB(),!0);let c=await l.introspection.getTables();let{tables:s,indexes:i,constraints:u}=await n.introspect({config:o});let r=()=>c.map(x=>({schema:x.schema,name:x.name,columns:Object.fromEntries(x.columns.map(N=>{let ue=s.filter(pe=>pe.table===x.name&&pe.name===N.name)[0]||{};return[N.name,{schema:x.schema,table:x.name,name:N.name,dataType:n.convertTypeName(N.dataType),default:ue.default??null,characterMaximumLength:ue.characterMaximumLength??null,notNull:!N.isNullable}]}))}));let p=x=>!x.table.startsWith("kysely_");let d=()=>i.filter(p);let h=()=>({primaryKey:u.primaryKey.filter(p),unique:u.unique.filter(p),foreignKey:u.foreignKey.filter(p)});return{tables:r(),indexes:d(),constraints:h()}}catch(b){var R=b,T=!0}finally{var H=E(C,R,T);H&&await H}}}};import{getContainerRuntimeClient as ce}from"testcontainers";var ie="kyrage.dialect",le="kyrage.managed",ve="kyrage.managed-by",we=async e=>(await(await ce()).container.list()).some(a=>a.Labels[le]==="true"&&a.Labels[ve]==="dev-start"&&a.Labels[ie]===e&&a.State==="running"),qt=async()=>{let e=await ce(),n=(await e.container.list()).filter(a=>a.Labels[le]==="true").map(a=>a.Id);await Promise.allSettled(n.map(async a=>e.container.getById(a).remove({force:!0})))},It=new Error("Dev database is not started or unavailable"),se=class{constructor(t,n){this.options=t;this.startedContainer=null;let a=n(),o=this.options.manageType||"one-off";a.withLabels({[ie]:this.options.dialect,[le]:"true",[ve]:o}),o==="dev-start"&&a.withReuse(),this.options.containerName&&a.withName(this.options.containerName),this.container=a}async findRunningContainer(){return(await ce()).container.fetchByLabel(ie,this.options.dialect,{status:["running"]})}async exists(){return!!await this.findRunningContainer()}async start(){this.startedContainer=await this.container.start()}getConnectionString(){if(!this.startedContainer)throw It;return this.startedContainer.getConnectionUri()}async stop(){this.startedContainer&&(await this.startedContainer.stop(),this.startedContainer=null)}async remove(){await qt(),this.startedContainer=null}async getStatus(){let t=await this.findRunningContainer();if(!t)return null;let n=await t.inspect();return{type:"container",imageName:n.Config.Image,containerID:n.Id}}},k=(e,t,n)=>{if("container"in e)return new se({dialect:t,containerName:n==="dev-start"?e.container.name:void 0,manageType:n},()=>A(t).createDevDatabaseContainer(e.container.image));throw new Error("Invalid dev database configuration")};async function kt(e,t){let{config:n}=e,a=n.database.dialect;switch(t.mode){case"dev-start":{let o="dev-start",l=k(n.dev,a,o);return{manager:l,containerType:o,result:{reused:await l.exists()}}}case"generate-dev":{let o=await we(a),l=o?"dev-start":"one-off";return{manager:k(n.dev,a,l),containerType:l,result:{reused:o}}}}}async function B(e,t){let{config:n}=e,a=t.logger||Q,{reporter:o}=a;if(!n.dev)throw new Error("Dev database configuration is required");let{manager:l,containerType:c,result:s}=await kt(e,t);s.reused?o.info("\u{1F504} Reusing existing dev database..."):o.info("\u{1F680} Starting dev database..."),await l.start(),o.success(`Dev database started: ${n.database.dialect}`);let i=L({database:{dialect:n.database.dialect,connectionString:l.getConnectionString()}}),u=await w(i);return u.length>0?(o.info(`\u{1F504} Applying ${u.length} pending migrations...`),await I({client:i,logger:Q,config:n},{plan:!1,pretty:!1}),o.success(`Applied ${u.length} migrations`)):o.info("No pending migrations found"),{client:i,manager:l,cleanup:async()=>{switch(t.mode){case"dev-start":o.success("Persistent dev database ready: "+n.database.dialect);break;case"generate-dev":c==="dev-start"?o.info("Dev start container remains running"):(await l.stop(),o.success("Temporary dev database stopped"));break}}}}async function Ft(e,t){let{logger:n,config:a}=e,{reporter:o}=n;t.squash&&await Bt(e);let{client:l,cleanup:c}=t.dev?await B(e,{mode:"generate-dev",logger:n}):{client:e.client,cleanup:async()=>{}};try{if(!t.ignorePending){let r=await w(l);if(r.length>0)if(t.dev)o.info(`Dev database has ${r.length} pending migrations. These will be applied automatically as baseline.`);else{o.warn([`There are pending migrations: ${r.map(p=>p.id).join(", ")}`,"Please apply them first before generating a new migration.","Otherwise, use --ignore-pending to skip this check."].join(`
|
|
93
|
+
`));return}}let s=await Ht({client:l,config:a});if(!s){o.info("No changes detected, no migration needed.");return}Qt(n,s.diff);let i=`${O}/${s.id}.json`;await Mt(O,{recursive:!0}),await Ut(i,JSON.stringify(s,null,2));let u=t.squash?`Generated squashed migration: ${i}`:`Migration file generated: ${i}`;o.success(u),t.dev&&await I({...e,client:l},{plan:!1,pretty:!1})}finally{await c()}}var Bt=async e=>{let{client:t,logger:n}=e,{reporter:a}=n,o=await w(t);if(o.length===0){a.info("No pending migrations found, nothing to squash.");return}a.info(`Found ${o.length} pending migrations to squash:`),o.forEach(c=>{a.info(` - ${c.id}.json`)});let l=o.map(c=>Lt(O,`${c.id}.json`));try{await Promise.all(l.map(c=>jt(c))),a.success(`\u{1F5D1}\uFE0F Removed ${l.length} pending migration files`)}catch(c){throw new Error(`Failed to remove pending migration files: ${c}`)}},Ht=async e=>{let{client:t,config:n}=e,a=Ee(t),{tables:o,indexes:l,constraints:c}=await a.introspect(n),s=(d,h)=>C=>C.some(b=>b.table===d&&b.columns.length===1&&b.columns[0]===h),i=o.map(d=>({name:d.name,columns:Object.fromEntries(Object.entries(d.columns).map(([h,C])=>{let b=s(d.name,h),R=b(c.primaryKey),T=b(c.unique),x=c.primaryKey.some(N=>N.table===d.name&&N.columns.length>1&&N.columns.includes(h))?!0:C.notNull;return[h,{type:C.dataType,notNull:x,defaultSql:C.default??void 0,primaryKey:R,unique:T}]}))})),u=n.tables.map(d=>({name:d.tableName,columns:Object.fromEntries(Object.entries(d.columns).map(([h,C])=>{let b=(n.primaryKeyConstraints??[]).some(T=>T.table===d.tableName&&T.columns.includes(h)),R=C.primaryKey||C.notNull||b;return[h,{...C,notNull:R}]}))})),r=Se({current:{tables:i,indexes:l,uniqueConstraints:c.unique,primaryKeyConstraints:c.primaryKey,foreignKeyConstraints:c.foreignKey},ideal:{...n,tables:u}});return r.operations.length===0?null:{version:"1",id:Date.now()+"",diff:r}},Qt=(e,t)=>{let n=[];t.operations.forEach(a=>{switch(a.type){case"create_table":n.push(`-- create_table: ${a.table}`),Object.entries(a.columns).forEach(([o,l])=>{n.push(` -> column: ${o} (${JSON.stringify(l)})`)});break;case"drop_table":n.push(`-- remove_table: ${a.table}`);break;case"add_column":n.push([`-- add_column: ${a.table}.${a.column}`,` -> to: ${JSON.stringify(a.attributes)}`].join(`
|
|
94
94
|
`));break;case"drop_column":n.push(`-- remove_column: ${a.table}.${a.column}`);break;case"alter_column":n.push([`-- change_column: ${a.table}.${a.column}`,` -> from: ${JSON.stringify(a.before)}`,` -> to: ${JSON.stringify(a.after)}`].join(`
|
|
95
95
|
`));break;case"create_index":n.push(`-- create_index: ${a.table}.${a.name} (${a.columns.join(", ")})${a.unique?" [unique]":""}`);break;case"drop_index":n.push(`-- drop_index: ${a.table}.${a.name}`);break;case"create_primary_key_constraint":n.push(`-- create_primary_key_constraint: ${a.table}.${a.name} (${a.columns.join(", ")})`);break;case"drop_primary_key_constraint":n.push(`-- drop_primary_key_constraint: ${a.table}.${a.name}`);break;case"create_unique_constraint":n.push(`-- create_unique_constraint: ${a.table}.${a.name} (${a.columns.join(", ")})`);break;case"drop_unique_constraint":n.push(`-- drop_unique_constraint: ${a.table}.${a.name}`);break;case"create_foreign_key_constraint":n.push(`-- create_foreign_key_constraint: ${a.table}.${a.name} (${a.columns.join(", ")}) -> ${a.referencedTable} (${a.referencedColumns.join(", ")})${a.onDelete?` ON DELETE ${a.onDelete.toUpperCase()}`:""}${a.onUpdate?` ON UPDATE ${a.onUpdate.toUpperCase()}`:""}`);break;case"drop_foreign_key_constraint":n.push(`-- drop_foreign_key_constraint: ${a.table}.${a.name}`);break;default:break}}),e.reporter.log(n.join(`
|
|
96
|
-
`))},
|
|
96
|
+
`))},Te=$t({meta:{name:"generate",description:"Generate migration files based on the current schema"},args:{"ignore-pending":{type:"boolean",description:"Ignore pending migrations and generate a new one",default:!1},dev:{type:"boolean",description:"Use dev database for safe migration generation",default:!1},squash:{type:"boolean",description:"Consolidate pending migrations into a single migration file",default:!1}},run:async e=>{try{let t=await v();await Ft(t,{ignorePending:e.args["ignore-pending"],dev:e.args.dev,squash:e.args.squash})}catch(t){let{defaultConsolaLogger:n}=await import("./logger-SE7G5AMI.js");n.reporter.error(t),process.exit(1)}}});import{defineCommand as $}from"citty";async function Vt(e){let{manager:t,logger:n}=e,a=await t.getStatus();if(!a||a.type!=="container"){n.reporter.info("No running dev containers found");return}n.reporter.info(`Running: ${a.containerID} (${a.imageName})`)}async function zt(e){let{manager:t,logger:n}=e;if(!await t.exists()){n.reporter.info("No running dev containers found");return}await t.start(),console.log(t.getConnectionString())}async function Wt(e){let{manager:t,logger:n}=e;if(!await t.exists()){n.reporter.info("No dev containers found");return}await t.remove(),n.reporter.success("Cleaned up dev containers")}async function Jt(e){let{logger:t}=e,{reporter:n}=t,{manager:a}=await B(e,{mode:"dev-start",logger:t});n.success(`\u2728 Dev database ready: ${a.getConnectionString()}`)}async function me(){let e=await v();if(!e.config.dev||!("container"in e.config.dev))throw new Error("No dev database container configuration found");let t=k(e.config.dev,e.config.database.dialect,"dev-start");return{...e,manager:t}}var Yt=$({meta:{name:"start",description:"Start development database with migrations applied"},run:async()=>{try{let e=await v();await Jt(e)}catch(e){let{defaultConsolaLogger:t}=await import("./logger-SE7G5AMI.js");t.reporter.error(e),process.exit(1)}}}),Gt=$({meta:{name:"status",description:"Show status of kyrage dev container"},run:async()=>{try{let e=await me();await Vt(e)}catch(e){let{defaultConsolaLogger:t}=await import("./logger-SE7G5AMI.js");t.reporter.error(e),process.exit(1)}}}),Xt=$({meta:{name:"get-url",description:"Print connection URL for running dev container"},run:async()=>{try{let e=await me();await zt(e)}catch(e){let{defaultConsolaLogger:t}=await import("./logger-SE7G5AMI.js");t.reporter.error(e),process.exit(1)}}}),Zt=$({meta:{name:"clean",description:"Remove all kyrage dev containers"},run:async()=>{try{let e=await me();await Wt(e)}catch(e){let{defaultConsolaLogger:t}=await import("./logger-SE7G5AMI.js");t.reporter.error(e),process.exit(1)}}}),Ae=$({meta:{name:"dev",description:"Manage development database containers"},subCommands:{start:Yt,status:Gt,"get-url":Xt,clean:Zt}});var nn=en({meta:{name:"kyrage",version:ye,description:"Kysely migration CLI with declarative schema"},subCommands:{apply:Ne,generate:Te,dev:Ae}});tn(nn);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@izumisy/kyrage",
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.3.0",
|
|
6
6
|
"description": "A minimal, schema-based declarative migration tool for Node.js ecosystem",
|
|
7
7
|
"author": "Seiya Izumi (https://github.com/IzumiSy)",
|
|
8
8
|
"license": "MIT",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"c12": "^3.2.0",
|
|
37
37
|
"citty": "^0.1.6",
|
|
38
38
|
"consola": "^3.4.2",
|
|
39
|
-
"kysely": "^0.28.
|
|
39
|
+
"kysely": "^0.28.7",
|
|
40
40
|
"mysql2": "^3.14.4",
|
|
41
41
|
"pg": "^8.16.3",
|
|
42
42
|
"ramda": "^0.31.3",
|
|
43
|
-
"sql-formatter": "^15.6.
|
|
43
|
+
"sql-formatter": "^15.6.9",
|
|
44
44
|
"testcontainers": "^11.5.1",
|
|
45
45
|
"zod": "^4.1.5"
|
|
46
46
|
},
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"@types/better-sqlite3": "^7.6.13",
|
|
50
50
|
"@types/node": "^24",
|
|
51
51
|
"@types/pg": "^8.15.5",
|
|
52
|
-
"@types/ramda": "^0.31.
|
|
53
|
-
"memfs": "^4.
|
|
52
|
+
"@types/ramda": "^0.31.1",
|
|
53
|
+
"memfs": "^4.39.0",
|
|
54
54
|
"prettier": "^3",
|
|
55
55
|
"tsup": "^8.5.0",
|
|
56
56
|
"typescript": "^5",
|