@izumisy/kyrage 1.3.1 → 1.4.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.
Files changed (2) hide show
  1. package/dist/main.js +6 -6
  2. package/package.json +4 -4
package/dist/main.js CHANGED
@@ -1,4 +1,4 @@
1
- import{a as S,b as E}from"./chunk-EY62Q3Z2.js";import{defineCommand as on,runMain as sn}from"citty";var he="1.3.1";import{defineCommand as Kt}from"citty";import g from"zod";import{loadConfig as Me}from"c12";import m from"zod";var $=m.object({type:m.string()}).catchall(m.any()),v=m.object({table:m.string(),name:m.string()}),X=m.object({table:m.string(),column:m.string()}),Z=m.object({...v.shape,columns:m.array(m.string()).readonly()}),ee=m.object({...v.shape,columns:m.array(m.string()).readonly()}),De=m.enum(["cascade","set null","set default","restrict","no action"]),te=m.object({...v.shape,columns:m.array(m.string()).readonly(),referencedTable:m.string(),referencedColumns:m.array(m.string()).readonly(),onDelete:De.optional(),onUpdate:De.optional()}),xe=m.discriminatedUnion("type",[m.object({type:m.literal("create_table"),table:m.string(),columns:m.record(m.string(),$)}),m.object({type:m.literal("drop_table"),table:m.string()}),m.object({...X.shape,type:m.literal("add_column"),attributes:$}),m.object({...X.shape,type:m.literal("drop_column"),attributes:$}),m.object({...X.shape,type:m.literal("alter_column"),before:$,after:$}),m.object({...v.shape,type:m.literal("create_index"),columns:m.array(m.string()).readonly(),unique:m.boolean()}),m.object({...v.shape,type:m.literal("drop_index")}),m.object({...Z.shape,type:m.literal("create_primary_key_constraint")}),m.object({...v.shape,type:m.literal("drop_primary_key_constraint")}),m.object({...ee.shape,type:m.literal("create_unique_constraint")}),m.object({...v.shape,type:m.literal("drop_unique_constraint")}),m.object({...te.shape,type:m.literal("create_foreign_key_constraint")}),m.object({...v.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"})};import{getContainerRuntimeClient as re}from"testcontainers";import F from"zod";var P=e=>F.object({container:F.object({image:F.string().default(e.defaultImage),name:F.string().optional()})}),R=class{constructor(t,n){this.dialect=t;this.containerFactory=n}async setup(t,n){return new ae({dialect:this.dialect,manageType:n,containerName:t.container.name,containerFactory:()=>this.containerFactory(t.container.image)})}async hasExisting(t){return t==="dev-start"?M(this.dialect):!1}async cleanup(){await ve()}},ne="kyrage.dialect",oe="kyrage.managed",_e="kyrage.managed-by",ae=class{constructor(t){this.options=t;this.startedContainer=null;this.container=this.setupContainer()}setupContainer(){let t=this.options.containerFactory();return t.withLabels({[ne]:this.options.dialect,[oe]:"true",[_e]:this.options.manageType}),this.options.manageType==="dev-start"&&t.withReuse(),this.options.containerName&&t.withName(this.options.containerName),t}async start(){this.startedContainer=await this.container.start()}async stop(){this.startedContainer&&(await this.startedContainer.stop(),this.startedContainer=null)}async remove(){await ve(),this.startedContainer=null}getConnectionString(){if(!this.startedContainer)throw new Error("Container is not started");return this.startedContainer.getConnectionUri()}async getStatus(){let n=await(await re()).container.fetchByLabel(ne,this.options.dialect,{status:["running"]});if(n){let a=await n.inspect();return{type:"container",imageName:a.Config.Image,containerID:a.Id}}return{type:"unavailable"}}async isAvailable(){return(await this.getStatus()).type==="container"}},M=async e=>(await(await re()).container.list()).some(a=>a.Labels[oe]==="true"&&a.Labels[_e]==="dev-start"&&a.Labels[ne]===e&&a.State==="running"),ve=async()=>{let e=await re(),n=(await e.container.list()).filter(a=>a.Labels[oe]==="true").map(a=>a.Id);await Promise.allSettled(n.map(async a=>e.container.getById(a).remove({force:!0})))};var Ue=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()}),Le=g.object({tableName:g.string(),columns:g.record(g.string(),Ue)}),je=g.object({...v.shape,columns:g.array(g.string()).readonly(),unique:g.boolean().default(!1)}),Fe=g.enum(["postgres","cockroachdb"]),Be=g.object({dialect:Fe,connectionString:g.string()}),He=g.union([P({defaultImage:""})]),Qe=g.object({database:Be,dev:He.optional(),tables:g.array(Le).readonly(),indexes:g.array(je).readonly(),primaryKeyConstraints:g.array(Z).readonly(),uniqueConstraints:g.array(ee).readonly(),foreignKeyConstraints:g.array(te).readonly()}),Ne=async()=>{let e=await Me({name:"kyrage"});return Qe.parse(e.config)};import{Kysely as rt}from"kysely";import{PostgresDialect as ze,sql as ie}from"kysely";import{Pool as Ve}from"pg";import{PostgreSqlContainer as We}from"@testcontainers/postgresql";import*as N from"ramda";var Se=(e,t)=>{let n=u=>r=>N.any(N.whereEq({name:r.name,table:r.table}),u),[a,o]=N.partition(n(e.uniqueConstraints),t.constraints.unique),[l,i]=N.partition(n(e.indexes),t.indexes),c=N.reject(n(l),o),s=N.reject(n(a),i);return{indexes:[...l,...s],uniqueConstraints:[...a,...c]}};var B=class{getName(){return"postgres"}createKyselyDialect(t){return new ze({pool:new Ve({connectionString:t})})}createIntrospectionDriver(t){return{convertTypeName:ce,introspect:se(t)}}createDevDatabaseProvider(){return new R(this.getName(),t=>new We(t))}parseDevDatabaseConfig(t){return P({defaultImage:"postgres:16"}).parse(t)}async hasReusableDevDatabase(){return M(this.getName())}},se=e=>async t=>{var s=[];try{let n=S(s,e.getDB(),!0);let[a,o,l]=await Promise.all([Je(n),Ge(n),Ye(n)]);let{indexes:i,uniqueConstraints:c}=Se(t.config,{indexes:o,constraints:l});return{tables:a,indexes:i,constraints:{...l,unique:c}}}catch(u){var r=u,p=!0}finally{var d=E(s,r,p);d&&await d}},ce=e=>({bool:"boolean",int2:"smallint",int4:"integer",int8:"bigint"})[e]??e,Je=async e=>{let{rows:t}=await ie`
1
+ import{a as N,b as w}from"./chunk-EY62Q3Z2.js";import{defineCommand as Un,runMain as Ln}from"citty";var Ke="1.4.0";import{defineCommand as un}from"citty";import f from"zod";import{loadConfig as wt}from"c12";import g from"zod";var v=g.object({type:g.string()}).catchall(g.any()),b=g.object({table:g.string(),name:g.string()}),q=g.object({table:g.string(),column:g.string()}),Q=g.object({...b.shape,columns:g.array(g.string()).readonly()}),W=g.object({...b.shape,columns:g.array(g.string()).readonly()}),Pe=g.enum(["cascade","set null","set default","restrict","no action"]),J=g.object({...b.shape,columns:g.array(g.string()).readonly(),referencedTable:g.string(),referencedColumns:g.array(g.string()).readonly(),onDelete:Pe.optional(),onUpdate:Pe.optional()});import{getContainerRuntimeClient as ce}from"testcontainers";import G from"zod";var k=e=>G.object({container:G.object({image:G.string().default(e.defaultImage),name:G.string().optional()})}),I=class{constructor(t,n){this.dialect=t;this.containerFactory=n}async setup(t,n){return new se({dialect:this.dialect,manageType:n,containerName:t.container.name,containerFactory:()=>this.containerFactory(t.container.image)})}async hasExisting(t){return t==="dev-start"?L(this.dialect):!1}async cleanup(){await Ie()}},ie="kyrage.dialect",le="kyrage.managed",qe="kyrage.managed-by",se=class{constructor(t){this.options=t;this.startedContainer=null;this.container=this.setupContainer()}setupContainer(){let t=this.options.containerFactory();return t.withLabels({[ie]:this.options.dialect,[le]:"true",[qe]:this.options.manageType}),this.options.manageType==="dev-start"&&t.withReuse(),this.options.containerName&&t.withName(this.options.containerName),t}async start(){this.startedContainer=await this.container.start()}async stop(){this.startedContainer&&(await this.startedContainer.stop(),this.startedContainer=null)}async remove(){await Ie(),this.startedContainer=null}getConnectionString(){if(!this.startedContainer)throw new Error("Container is not started");return this.startedContainer.getConnectionUri()}async getStatus(){let n=await(await ce()).container.fetchByLabel(ie,this.options.dialect,{status:["running"]});if(n){let a=await n.inspect();return{type:"container",imageName:a.Config.Image,containerID:a.Id}}return{type:"unavailable"}}async isAvailable(){return(await this.getStatus()).type==="container"}},L=async e=>(await(await ce()).container.list()).some(a=>a.Labels[le]==="true"&&a.Labels[qe]==="dev-start"&&a.Labels[ie]===e&&a.State==="running"),Ie=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})))};var At=f.object({type:f.string(),primaryKey:f.boolean().optional().default(!1),notNull:f.boolean().optional().default(!1),unique:f.boolean().optional().default(!1),defaultSql:f.string().optional()}),Et=f.object({tableName:f.string(),columns:f.record(f.string(),At)}),Rt=f.object({...b.shape,columns:f.array(f.string()).readonly(),unique:f.boolean().default(!1)}),Kt=f.enum(["postgres","cockroachdb"]),Pt=f.object({dialect:Kt,connectionString:f.string()}),qt=f.union([k({defaultImage:""})]),It=f.object({database:Pt,dev:qt.optional(),tables:f.array(Et).readonly(),indexes:f.array(Rt).readonly(),primaryKeyConstraints:f.array(Q).readonly(),uniqueConstraints:f.array(W).readonly(),foreignKeyConstraints:f.array(J).readonly()}),ke=async()=>{let e=await wt({name:"kyrage"});return It.parse(e.config)};import{Kysely as Wt}from"kysely";import{PostgresDialect as kt,sql as me}from"kysely";import{Pool as $t}from"pg";import{PostgreSqlContainer as Mt}from"@testcontainers/postgresql";import*as T from"ramda";var $e=(e,t)=>{let n=m=>r=>T.any(T.whereEq({name:r.name,table:r.table}),m),[a,o]=T.partition(n(e.uniqueConstraints),t.constraints.unique),[l,i]=T.partition(n(e.indexes),t.indexes),c=T.reject(n(l),o),s=T.reject(n(a),i);return{indexes:[...l,...s],uniqueConstraints:[...a,...c]}};var Y=class{getName(){return"postgres"}createKyselyDialect(t){return new kt({pool:new $t({connectionString:t})})}createIntrospectionDriver(t){return{convertTypeName:ue,introspect:pe(t)}}createDevDatabaseProvider(){return new I(this.getName(),t=>new Mt(t))}parseDevDatabaseConfig(t){return k({defaultImage:"postgres:16"}).parse(t)}async hasReusableDevDatabase(){return L(this.getName())}},pe=e=>async t=>{var s=[];try{let n=N(s,e.getDB(),!0);let[a,o,l]=await Promise.all([jt(n),Ut(n),Lt(n)]);let{indexes:i,uniqueConstraints:c}=$e(t.config,{indexes:o,constraints:l});return{tables:a,indexes:i,constraints:{...l,unique:c}}}catch(m){var r=m,p=!0}finally{var u=w(s,r,p);u&&await u}},ue=e=>({bool:"boolean",int2:"smallint",int4:"integer",int8:"bigint"})[e]??e,jt=async e=>{let{rows:t}=await me`
2
2
  SELECT
3
3
  n.nspname AS table_schema,
4
4
  c.relname AS table_name,
@@ -18,7 +18,7 @@ import{a as S,b as E}from"./chunk-EY62Q3Z2.js";import{defineCommand as on,runMai
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}))},Ge=async e=>{let{rows:t}=await ie`
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}))},Ut=async e=>{let{rows:t}=await me`
22
22
  SELECT
23
23
  t.relname AS table_name,
24
24
  c.relname AS index_name,
@@ -33,7 +33,7 @@ import{a as S,b as E}from"./chunk-EY62Q3Z2.js";import{defineCommand as on,runMai
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}))},Ye=async e=>{let{rows:t}=await ie`
36
+ `.$castTo().execute(e);return t.map(n=>({table:n.table_name,name:n.index_name,columns:n.column_names,unique:n.is_unique}))},Lt=async e=>{let{rows:t}=await me`
37
37
  SELECT
38
38
  n.nspname AS schema,
39
39
  t.relname AS table,
@@ -89,8 +89,8 @@ import{a as S,b as E}from"./chunk-EY62Q3Z2.js";import{defineCommand as on,runMai
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:i,...c}=n;return{...c,referencedTable:a,referencedColumns:o,onDelete:l,onUpdate:i}})}};import{CockroachDbContainer as Xe}from"@testcontainers/cockroachdb";import{Pool as Ze}from"pg";import{PostgresAdapter as et,PostgresDialect as tt}from"kysely";var H=class{getName(){return"cockroachdb"}createKyselyDialect(t){return new me({pool:new Ze({connectionString:t})})}createIntrospectionDriver(t){let n=["rowid"];return{convertTypeName:ce,introspect:async a=>{let o=await se(t)(a);return{tables:o.tables.filter(i=>!n.includes(i.name)),indexes:o.indexes,constraints:o.constraints}}}}createDevDatabaseProvider(){return new R(this.getName(),t=>new Xe(t))}parseDevDatabaseConfig(t){return P({defaultImage:"cockroachdb/cockroach:latest-v24.3"}).parse(t)}async hasReusableDevDatabase(){return M(this.getName())}},le=class extends et{async acquireMigrationLock(t,n){await t.selectFrom(n.lockTable).selectAll().forUpdate().execute()}},me=class extends tt{createAdapter(){return new le}};var nt={postgres:new B,cockroachdb:new H},w=e=>{let t=nt[e];if(!t)throw new Error(`Unsupported dialect: ${e}`);return t};import{DummyDriver as at}from"kysely";var Q=class extends at{constructor(n){super();this.queries=n}async acquireConnection(){return new ue(this.queries)}},ue=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 z=e=>new pe({databaseProps:e.database,options:e.options}),pe=class{constructor(t){this.constructorProps=t}getDB(t){let n=w(this.constructorProps.databaseProps.dialect).createKyselyDialect(this.constructorProps.databaseProps.connectionString);return new de({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}},de=class extends rt{constructor(n,a){let o=[];super({dialect:{...n.dialect,createDriver:()=>a.isPlan?new Q(o):n.dialect.createDriver()}});this.plannedQueries=[];this.plannedQueries=o}getPlannedQueries(){return this.plannedQueries}};import{createConsola as ot}from"consola";var it=ot({stdout:process.stderr}),x={stdout:e=>console.log(e),reporter:{...it}},ye={stdout:()=>{},reporter:{info:()=>{},warn:()=>{},success:()=>{},log:()=>{},error:()=>{}}};async function T(){let e=await Ne();return{client:z({database:e.database}),logger:x,config:e}}import{Migrator as Rt}from"kysely";import{DEFAULT_MIGRATION_TABLE as Ee,isColumnDataType as st,sql as Te}from"kysely";import{readdir as ct,readFile as lt}from"fs/promises";import{join as mt}from"path";import U from"zod";import*as Ae from"ramda";var I="migrations",ut=U.object({operations:U.array(xe).readonly()}),pt=U.object({id:U.string(),version:U.string(),diff:ut}),ge=async()=>{try{let t=(await ct(I)).filter(n=>n.endsWith(".json")).map(async n=>pt.parse(JSON.parse(await lt(mt(I,n),"utf-8"))));return await Promise.all(t)}catch(e){if(e instanceof Object&&"code"in e&&e.code==="ENOENT")return[];throw e}},A=async e=>{var l=[];try{let t=S(l,e.getDB(),!0);let n=await ge();let a=(await t.introspection.getTables({withInternalKyselyTables:!0})).map(r=>r.name);if(!a.includes(Ee))return n;let o=await t.selectFrom(Ee).select(["name","timestamp"]).$narrowType().execute();return n.filter(r=>!o.some(p=>p.name===r.id))}catch(i){var c=i,s=!0}finally{var u=E(l,c,s);u&&await u}},Oe=e=>({getMigrations:async()=>{let t=await e.migrationsResolver(),n={};return t.forEach(a=>{n[a.id]={up:async o=>{await dt(o,a.diff)}}}),n}});async function dt(e,t){let n=Ae.pipe(Tt,At,Ot);for(let a of n(t.operations))await yt(e,a)}async function yt(e,t){switch(t.type){case"create_table":return gt(e,t);case"drop_table":return ft(e,t);case"add_column":return bt(e,t);case"drop_column":return Ct(e,t);case"alter_column":return ht(e,t);case"create_index":return Dt(e,t);case"drop_index":return xt(e,t);case"create_primary_key_constraint":return _t(e,t);case"drop_primary_key_constraint":return vt(e,t);case"create_unique_constraint":return Nt(e,t);case"drop_unique_constraint":return St(e,t);case"create_foreign_key_constraint":return Et(e,t);case"drop_foreign_key_constraint":return wt(e,t);default:throw new Error(`Unknown operation type: ${t.type}`)}}async function gt(e,t){let n=e.schema.createTable(t.table);for(let[a,o]of Object.entries(t.columns)){let l=o.type;fe(l),n=n.addColumn(a,l,i=>{let c=i;return o.notNull&&(c=c.notNull()),typeof o.defaultSql=="string"&&(c=c.defaultTo(Te.raw(o.defaultSql))),c})}await n.execute()}async function ft(e,t){await e.schema.dropTable(t.table).execute()}async function bt(e,t){let n=t.attributes.type;fe(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(Te.raw(t.attributes.defaultSql))),o}).execute()}async function Ct(e,t){await e.schema.alterTable(t.table).dropColumn(t.column).execute()}async function ht(e,t){let{table:n,column:a,before:o,after:l}=t;if(o.type!==l.type){let i=l.type;fe(i),await e.schema.alterTable(n).alterColumn(a,c=>c.setDataType(i)).execute()}l.notNull!==o.notNull&&(l.notNull?await e.schema.alterTable(n).alterColumn(a,i=>i.setNotNull()).execute():await e.schema.alterTable(n).alterColumn(a,i=>i.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 xt(e,t){await e.schema.dropIndex(t.name).execute()}async function _t(e,t){await e.schema.alterTable(t.table).addPrimaryKeyConstraint(t.name,t.columns).execute()}async function vt(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function Nt(e,t){await e.schema.alterTable(t.table).addUniqueConstraint(t.name,t.columns).execute()}async function St(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function Et(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 wt(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}var fe=e=>{if(!st(e))throw new Error(`Unsupported data type: ${e}`)},we={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},Tt=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))},At=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})},Ot=e=>e.slice().sort((t,n)=>{let a=we[t.type],o=we[n.type];return a!==o?a-o:t.table.localeCompare(n.table)});import{format as Pt}from"sql-formatter";async function L(e,t){var p=[];try{let{client:n,logger:a}=e;let{reporter:o}=a;let l=S(p,n.getDB({plan:t.plan}),!0);let i=Oe({migrationsResolver:async()=>t.plan?await A(n):await ge(),options:{plan:t.plan}});let c=new Rt({db:l,provider:i});let{results:s,error:u}=await c.migrateToLatest();let r=l.getPlannedQueries();if(r.length>0){r.forEach(D=>{a.stdout(t.pretty?Pt(D.sql):D.sql)});return}s&&s.length>0?s.forEach(D=>{D.status==="Error"?o.error(`Migration failed: ${D.migrationName}`):D.status==="Success"&&o.success(`Migration applied: ${D.migrationName}`)}):o.info("No migrations to run");if(u)throw u instanceof Error?u:new Error(`Migration error: ${u}`)}catch(d){var C=d,b=!0}finally{var h=E(p,C,b);h&&await h}}var Ke=Kt({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 T();await L(t,{plan:e.args.plan,pretty:e.args.pretty})}catch(t){x.reporter.error(t),process.exit(1)}}});import{defineCommand as Ft}from"citty";import{mkdir as Bt,writeFile as Ht,unlink as Qt}from"fs/promises";import{join as zt}from"path";import*as y from"ramda";var q=()=>({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)}),V=y.prop("name"),It=y.eqBy(e=>[e.type,e.notNull??!1,e.primaryKey??!1,e.unique??!1]);function qt(e,t){let n=[],a=q(),o=e.columns,l=t.columns,i=Object.keys(o),c=Object.keys(l);return a.added(i,c,s=>({column:s,attributes:l[s]})).forEach(s=>{n.push(f.addColumn({table:e.name,column:s.column},s.attributes))}),a.removed(i,c,s=>({column:s,attributes:o[s]})).forEach(s=>{n.push(f.dropColumn({table:e.name,column:s.column},s.attributes))}),a.changed(i,c,s=>!It(o[s],l[s]),s=>({column:s,before:o[s],after:l[s]})).forEach(s=>{n.push(f.alterColumn({table:e.name,column:s.column},s.before,s.after))}),n}function kt(e){let{current:t,ideal:n}=e,a=[],o=q(),l=y.map(V,t),i=y.map(V,n);return o.added(l,i,c=>n.find(u=>u.name===c)).forEach(c=>{a.push(f.createTable(c.name,c.columns))}),o.removed(l,i,y.identity).forEach(c=>{a.push(f.dropTable(c))}),y.filter(c=>n.some(s=>s.name===c.name))(t).forEach(c=>{let s=n.find(u=>u.name===c.name);a.push(...qt(c,s))}),a}function $t(e){let{current:t,ideal:n}=e,a=[],o=q(),l=r=>`${r.table}:${r.name}`,i=new Map(t.map(r=>[l(r),r])),c=new Map(n.map(r=>[l(r),r])),s=Array.from(i.keys()),u=Array.from(c.keys());return o.added(s,u,r=>c.get(r)).forEach(r=>{a.push(f.createIndex(r))}),o.removed(s,u,r=>{let p=i.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropIndex(r))}),o.changed(s,u,r=>{let p=i.get(r),d=c.get(r);return!y.equals(p.columns,d.columns)||p.unique!==d.unique},r=>{let p=i.get(r),d=c.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropIndex(r)),a.push(f.createIndex(p))}),a}function Mt(e){let{current:t,ideal:n}=e,a=[],o=q(),l=r=>`${r.table}:${r.name}`,i=new Map(t.map(r=>[l(r),r])),c=new Map(n.map(r=>[l(r),r])),s=Array.from(i.keys()),u=Array.from(c.keys());return o.added(s,u,r=>c.get(r)).forEach(r=>{a.push(f.createPrimaryKeyConstraint(r))}),o.removed(s,u,r=>{let p=i.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropPrimaryKeyConstraint(r))}),o.changed(s,u,r=>{let p=i.get(r),d=c.get(r);return!y.equals(p.columns,d.columns)},r=>{let p=i.get(r),d=c.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropPrimaryKeyConstraint(r)),a.push(f.createPrimaryKeyConstraint(p))}),a}function Ut(e){let{current:t,ideal:n}=e,a=[],o=q(),l=r=>`${r.table}:${r.name}`,i=new Map(t.map(r=>[l(r),r])),c=new Map(n.map(r=>[l(r),r])),s=Array.from(i.keys()),u=Array.from(c.keys());return o.added(s,u,r=>c.get(r)).forEach(r=>{a.push(f.createUniqueConstraint(r))}),o.removed(s,u,r=>{let p=i.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropUniqueConstraint(r))}),o.changed(s,u,r=>{let p=i.get(r),d=c.get(r);return!y.equals(p.columns,d.columns)},r=>{let p=i.get(r),d=c.get(r);return{current:p,ideal:d}}).forEach(({current:r,ideal:p})=>{a.push(f.dropUniqueConstraint(r)),a.push(f.createUniqueConstraint(p))}),a}function Lt(e){let t=[],n=q(),a=e.current.map(V),o=e.ideal.map(V);t.push(...n.added(a,o,i=>{let c=e.ideal.find(p=>p.name===i),{table:s,name:u,...r}=c;return f.createForeignKeyConstraint({table:s,name:u},r)})),t.push(...n.removed(a,o,i=>{let c=e.current.find(s=>s.name===i);return f.dropForeignKeyConstraint(c)}));let l=i=>{let c=e.current.find(u=>u.name===i),s=e.ideal.find(u=>u.name===i);return!c||!s?!1:!(y.equals(c.columns,s.columns)&&c.referencedTable===s.referencedTable&&y.equals(c.referencedColumns,s.referencedColumns)&&c.onDelete===s.onDelete&&c.onUpdate===s.onUpdate)};return t.push(...n.changed(a,o,l,i=>{let c=e.current.find(d=>d.name===i),s=e.ideal.find(d=>d.name===i),{table:u,name:r,...p}=s;return[f.dropForeignKeyConstraint(c),f.createForeignKeyConstraint({table:u,name:r},p)]}).flat()),t}function Re(e){let t=kt({current:e.current.tables,ideal:e.ideal.tables}),n=$t({current:e.current.indexes,ideal:e.ideal.indexes}),a=Mt({current:e.current.primaryKeyConstraints,ideal:e.ideal.primaryKeyConstraints}),o=Ut({current:e.current.uniqueConstraints,ideal:e.ideal.uniqueConstraints}),l=Lt({current:e.current.foreignKeyConstraints,ideal:e.ideal.foreignKeyConstraints});return{operations:[...t,...n,...a,...o,...l]}}var Pe=e=>{let n=w(e.getDialect()).createIntrospectionDriver(e);return{introspect:async o=>{var b=[];try{let l=S(b,e.getDB(),!0);let i=await l.introspection.getTables();let{tables:c,indexes:s,constraints:u}=await n.introspect({config:o});let r=()=>i.map(_=>{let K={};for(let k of _.columns){let Y=c.find(Ce=>Ce.table===_.name&&Ce.name===k.name);Y&&(K[k.name]={schema:_.schema,table:_.name,name:k.name,dataType:n.convertTypeName(k.dataType),default:Y.default??null,characterMaximumLength:Y.characterMaximumLength??null,notNull:!k.isNullable})}return{schema:_.schema,name:_.name,columns:K}});let p=_=>!_.table.startsWith("kysely_");let d=()=>s.filter(p);let C=()=>({primaryKey:u.primaryKey.filter(p),unique:u.unique.filter(p),foreignKey:u.foreignKey.filter(p)});return{tables:r(),indexes:d(),constraints:C()}}catch(h){var D=h,O=!0}finally{var G=E(b,D,O);G&&await G}}}};var W=async(e,t,n)=>{let a=w(t),o=await a.createDevDatabaseProvider().setup(a.parseDevDatabaseConfig(e),n);return{manageType:n,instance:o}};async function jt(e,t){let{config:n}=e,a=w(n.database.dialect);switch(t.mode){case"dev-start":{let{instance:o,manageType:l}=await W(n.dev,n.database.dialect,"dev-start");return{manageType:l,manager:o,result:{reused:await o.isAvailable()}}}case"generate-dev":{let o=await a.hasReusableDevDatabase(),{instance:l,manageType:i}=await W(n.dev,n.database.dialect,o?"dev-start":"one-off");return{manageType:i,manager:l,result:{reused:o}}}}}async function J(e,t){let{config:n}=e,a=t.logger||ye,{reporter:o}=a;if(!n.dev)throw new Error("Dev database configuration is required");let{manageType:l,manager:i,result:c}=await jt(e,t);c.reused?o.info("\u{1F504} Reusing existing dev database..."):o.info("\u{1F680} Starting dev database..."),await i.start(),o.success(`Dev database started: ${n.database.dialect}`);let s=z({database:{dialect:n.database.dialect,connectionString:i.getConnectionString()}}),u=await A(s);return u.length>0?(o.info(`\u{1F504} Applying ${u.length} pending migrations...`),await L({client:s,logger:ye,config:n},{plan:!1,pretty:!1}),o.success(`Applied ${u.length} migrations`)):o.info("No pending migrations found"),{client:s,manager:i,cleanup:async()=>{switch(t.mode){case"dev-start":o.success("Persistent dev database ready: "+n.database.dialect);break;case"generate-dev":l==="dev-start"?o.info("Dev start container remains running"):(await i.stop(),o.success("Temporary dev database stopped"));break}}}}async function Vt(e,t){let{logger:n,config:a}=e,{reporter:o}=n;t.squash&&await Wt(e);let{client:l,cleanup:i}=t.dev?await J(e,{mode:"generate-dev",logger:n}):{client:e.client,cleanup:async()=>{}};try{if(!t.ignorePending){let r=await A(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 c=await Jt({client:l,config:a});if(!c){o.info("No changes detected, no migration needed.");return}Gt(n,c.diff);let s=`${I}/${c.id}.json`;await Bt(I,{recursive:!0}),await Ht(s,JSON.stringify(c,null,2));let u=t.squash?`Generated squashed migration: ${s}`:`Migration file generated: ${s}`;o.success(u),t.dev&&await L({...e,client:l},{plan:!1,pretty:!1})}finally{await i()}}var Wt=async e=>{let{client:t,logger:n}=e,{reporter:a}=n,o=await A(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(i=>{a.info(` - ${i.id}.json`)});let l=o.map(i=>zt(I,`${i.id}.json`));try{await Promise.all(l.map(i=>Qt(i))),a.success(`\u{1F5D1}\uFE0F Removed ${l.length} pending migration files`)}catch(i){throw new Error(`Failed to remove pending migration files: ${i}`)}},Jt=async e=>{let{client:t,config:n}=e,a=Pe(t),{tables:o,indexes:l,constraints:i}=await a.introspect(n),c=(d,C)=>b=>b.some(h=>h.table===d&&h.columns.length===1&&h.columns[0]===C),s=o.map(d=>({name:d.name,columns:Object.fromEntries(Object.entries(d.columns).map(([C,b])=>{let h=c(d.name,C),D=h(i.primaryKey),O=h(i.unique),_=i.primaryKey.some(K=>K.table===d.name&&K.columns.length>1&&K.columns.includes(C))?!0:b.notNull;return[C,{type:b.dataType,notNull:_,defaultSql:b.default??void 0,primaryKey:D,unique:O}]}))})),u=n.tables.map(d=>({name:d.tableName,columns:Object.fromEntries(Object.entries(d.columns).map(([C,b])=>{let h=(n.primaryKeyConstraints??[]).some(O=>O.table===d.tableName&&O.columns.includes(C)),D=b.primaryKey||b.notNull||h;return[C,{...b,notNull:D}]}))})),r=Re({current:{tables:s,indexes:l,uniqueConstraints:i.unique,primaryKeyConstraints:i.primaryKey,foreignKeyConstraints:i.foreignKey},ideal:{...n,tables:u}});return r.operations.length===0?null:{version:"1",id:Date.now()+"",diff:r}},Gt=(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(`
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:i,...c}=n;return{...c,referencedTable:a,referencedColumns:o,onDelete:l,onUpdate:i}})}};import{CockroachDbContainer as Bt}from"@testcontainers/cockroachdb";import{Pool as zt}from"pg";import{PostgresAdapter as Ft,PostgresDialect as Ht}from"kysely";var Z=class{getName(){return"cockroachdb"}createKyselyDialect(t){return new ye({pool:new zt({connectionString:t})})}createIntrospectionDriver(t){let n=["rowid"];return{convertTypeName:ue,introspect:async a=>{let o=await pe(t)(a);return{tables:o.tables.filter(i=>!n.includes(i.name)),indexes:o.indexes,constraints:o.constraints}}}}createDevDatabaseProvider(){return new I(this.getName(),t=>new Bt(t))}parseDevDatabaseConfig(t){return k({defaultImage:"cockroachdb/cockroach:latest-v24.3"}).parse(t)}async hasReusableDevDatabase(){return L(this.getName())}},de=class extends Ft{async acquireMigrationLock(t,n){await t.selectFrom(n.lockTable).selectAll().forUpdate().execute()}},ye=class extends Ht{createAdapter(){return new de}};var Vt={postgres:new Y,cockroachdb:new Z},A=e=>{let t=Vt[e];if(!t)throw new Error(`Unsupported dialect: ${e}`);return t};import{DummyDriver as Qt}from"kysely";var X=class extends Qt{constructor(n){super();this.queries=n}async acquireConnection(){return new fe(this.queries)}},fe=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 ee=e=>new ge({databaseProps:e.database,options:e.options}),ge=class{constructor(t){this.constructorProps=t}getDB(t){let n=A(this.constructorProps.databaseProps.dialect).createKyselyDialect(this.constructorProps.databaseProps.connectionString);return new be({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}},be=class extends Wt{constructor(n,a){let o=[];super({dialect:{...n.dialect,createDriver:()=>a.isPlan?new X(o):n.dialect.createDriver()}});this.plannedQueries=[];this.plannedQueries=o}getPlannedQueries(){return this.plannedQueries}};import{createConsola as Jt}from"consola";var Gt=Jt({stdout:process.stderr}),S={stdout:e=>console.log(e),reporter:{...Gt}},he={stdout:()=>{},reporter:{info:()=>{},warn:()=>{},success:()=>{},log:()=>{},error:()=>{}}};async function E(){let e=await ke();return{client:ee({database:e.database}),logger:S,config:e}}import{Migrator as dn}from"kysely";import{DEFAULT_MIGRATION_TABLE as Ct}from"kysely";import{readdir as sn,readFile as cn}from"fs/promises";import{join as ln}from"path";import F from"zod";import en from"zod";import h from"zod";import B from"zod";import{sql as Zt}from"kysely";import{isColumnDataType as Yt}from"kysely";var $=e=>{if(!Yt(e))throw new Error(`Unsupported data type: ${e}`)};var y=e=>e;var Me=y({typeName:"create_table",schema:B.object({type:B.literal("create_table"),table:B.string(),columns:B.record(B.string(),v)}),execute:async(e,t)=>{let n=e.schema.createTable(t.table);n=Ce(n,t.columns),await n.execute()}}),je=(e,t)=>({type:"create_table",table:e,columns:t});function Ce(e,t){let n=e;for(let[a,o]of Object.entries(t)){let l=o.type;$(l),n=n.addColumn(a,l,i=>{let c=i;return o.notNull&&(c=c.notNull()),typeof o.defaultSql=="string"&&(c=c.defaultTo(Zt.raw(o.defaultSql))),c})}return n}var Ue=y({typeName:"create_table_with_constraints",schema:h.object({type:h.literal("create_table_with_constraints"),table:h.string(),columns:h.record(h.string(),v),constraints:h.object({primaryKey:h.object({name:h.string(),columns:h.array(h.string()).readonly()}).optional(),unique:h.array(h.object({name:h.string(),columns:h.array(h.string()).readonly()})).readonly().optional()}).optional()}),execute:async(e,t)=>{let n=e.schema.createTable(t.table);if(n=Ce(n,t.columns),t.constraints){let{primaryKey:a,unique:o}=t.constraints;if(a&&(n=n.addPrimaryKeyConstraint(a.name,a.columns)),o)for(let l of o)n=n.addUniqueConstraint(l.name,l.columns)}await n.execute()}});import xe from"zod";var Le=y({typeName:"drop_table",schema:xe.object({type:xe.literal("drop_table"),table:xe.string()}),execute:async(e,t)=>{await e.schema.dropTable(t.table).execute()}}),Be=e=>({type:"drop_table",table:e});import ze from"zod";import{sql as Xt}from"kysely";var Fe=y({typeName:"add_column",schema:ze.object({...q.shape,type:ze.literal("add_column"),attributes:v}),execute:async(e,t)=>{let n=t.attributes.type;$(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(Xt.raw(t.attributes.defaultSql))),o}).execute()}}),He=(e,t)=>({...e,type:"add_column",attributes:t});import Ve from"zod";var Qe=y({typeName:"drop_column",schema:Ve.object({...q.shape,type:Ve.literal("drop_column"),attributes:v}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropColumn(t.column).execute()}}),We=(e,t)=>({...e,type:"drop_column",attributes:t});import Je from"zod";var Ge=y({typeName:"alter_column",schema:Je.object({...q.shape,type:Je.literal("alter_column"),before:v,after:v}),execute:async(e,t)=>{let{table:n,column:a,before:o,after:l}=t;if(o.type!==l.type){let i=l.type;$(i),await e.schema.alterTable(n).alterColumn(a,c=>c.setDataType(i)).execute()}l.notNull!==o.notNull&&(l.notNull?await e.schema.alterTable(n).alterColumn(a,i=>i.setNotNull()).execute():await e.schema.alterTable(n).alterColumn(a,i=>i.dropNotNull()).execute())}}),Ye=(e,t,n)=>({...e,type:"alter_column",before:t,after:n});import z from"zod";var Ze=y({typeName:"create_index",schema:z.object({...b.shape,type:z.literal("create_index"),columns:z.array(z.string()).readonly(),unique:z.boolean()}),execute:async(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()}}),De=e=>({...e,type:"create_index"});import Xe from"zod";var et=y({typeName:"drop_index",schema:Xe.object({...b.shape,type:Xe.literal("drop_index")}),execute:async(e,t)=>{await e.schema.dropIndex(t.name).execute()}}),_e=e=>({...e,type:"drop_index"});import tt from"zod";var nt=y({typeName:"create_primary_key_constraint",schema:tt.object({...Q.shape,type:tt.literal("create_primary_key_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).addPrimaryKeyConstraint(t.name,t.columns).execute()}}),ve=e=>({...e,type:"create_primary_key_constraint"});import at from"zod";var rt=y({typeName:"drop_primary_key_constraint",schema:at.object({...b.shape,type:at.literal("drop_primary_key_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),Se=e=>({...e,type:"drop_primary_key_constraint"});import ot from"zod";var it=y({typeName:"create_unique_constraint",schema:ot.object({...W.shape,type:ot.literal("create_unique_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).addUniqueConstraint(t.name,t.columns).execute()}}),Oe=e=>({...e,type:"create_unique_constraint"});import st from"zod";var ct=y({typeName:"drop_unique_constraint",schema:st.object({...b.shape,type:st.literal("drop_unique_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),Te=e=>({...e,type:"drop_unique_constraint"});import lt from"zod";var mt=y({typeName:"create_foreign_key_constraint",schema:lt.object({...J.shape,type:lt.literal("create_foreign_key_constraint")}),execute:async(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()}}),Ne=(e,t)=>({...e,...t,type:"create_foreign_key_constraint"});import pt from"zod";var ut=y({typeName:"drop_foreign_key_constraint",schema:pt.object({...b.shape,type:pt.literal("drop_foreign_key_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),we=e=>({...e,type:"drop_foreign_key_constraint"});var dt=[Ue,Me,Le,Fe,Qe,Ge,Ze,et,nt,rt,it,ct,mt,ut],yt=en.union(dt.map(e=>e.schema));async function ft(e,t){return await tn(t.type)(e,t)}function tn(e){let t=dt.find(n=>n.typeName===e);if(!t)throw new Error(`Unknown operation type: ${e}`);return t.execute}import*as bt from"ramda";var nn=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))},an=e=>{let t=new Set;if(e.forEach(i=>{i.type==="create_table"&&t.add(i.table)}),t.size===0)return e;let n=new Map,a=new Map,o=[];e.forEach(i=>{if(i.type==="create_table")n.set(i.table,i);else if((i.type==="create_primary_key_constraint"||i.type==="create_unique_constraint")&&t.has(i.table)){let c=a.get(i.table)||[];a.set(i.table,[...c,i])}else o.push(i)});let l=[];return n.forEach((i,c)=>{let s=a.get(c)||[];if(s.length===0)l.push(i);else{let m={};s.forEach(r=>{r.type==="create_primary_key_constraint"?m.primaryKey={name:r.name,columns:r.columns}:r.type==="create_unique_constraint"&&(m.unique||(m.unique=[]),m.unique.push({name:r.name,columns:r.columns}))}),l.push({type:"create_table_with_constraints",table:i.table,columns:i.columns,constraints:m})}}),[...l,...o]},rn=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})},on=e=>e.slice().sort((t,n)=>{let a=gt[t.type],o=gt[n.type];return a!==o?a-o:t.table.localeCompare(n.table)}),gt={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_with_constraints:6,create_table:7,add_column:8,alter_column:9,create_index:10,create_primary_key_constraint:11,create_unique_constraint:12,create_foreign_key_constraint:13},ht=bt.pipe(nn,an,rn,on);var xt=e=>({getMigrations:async()=>{let t=await e.migrationsResolver(),n={};return t.forEach(a=>{n[a.id]={up:async o=>{for(let l of ht(a.diff.operations))await ft(o,l)}}}),n}}),mn=F.object({operations:F.array(yt).readonly()}),pn=F.object({id:F.string(),version:F.string(),diff:mn}),M="migrations",Ae=async()=>{try{let t=(await sn(M)).filter(n=>n.endsWith(".json")).map(async n=>pn.parse(JSON.parse(await cn(ln(M,n),"utf-8"))));return await Promise.all(t)}catch(e){if(e instanceof Object&&"code"in e&&e.code==="ENOENT")return[];throw e}},R=async e=>{var l=[];try{let t=N(l,e.getDB(),!0);let n=await Ae();let a=(await t.introspection.getTables({withInternalKyselyTables:!0})).map(r=>r.name);if(!a.includes(Ct))return n;let o=await t.selectFrom(Ct).select(["name","timestamp"]).$narrowType().execute();return n.filter(r=>!o.some(p=>p.name===r.id))}catch(i){var c=i,s=!0}finally{var m=w(l,c,s);m&&await m}};import{format as yn}from"sql-formatter";async function H(e,t){var p=[];try{let{client:n,logger:a}=e;let{reporter:o}=a;let l=N(p,n.getDB({plan:t.plan}),!0);let i=xt({migrationsResolver:async()=>t.plan?await R(n):await Ae(),options:{plan:t.plan}});let c=new dn({db:l,provider:i});let{results:s,error:m}=await c.migrateToLatest();let r=l.getPlannedQueries();if(r.length>0){r.forEach(_=>{a.stdout(t.pretty?yn(_.sql):_.sql)});return}s&&s.length>0?s.forEach(_=>{_.status==="Error"?o.error(`Migration failed: ${_.migrationName}`):_.status==="Success"&&o.success(`Migration applied: ${_.migrationName}`)}):o.info("No migrations to run");if(m)throw m instanceof Error?m:new Error(`Migration error: ${m}`)}catch(u){var x=u,C=!0}finally{var D=w(p,x,C);D&&await D}}var Dt=un({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 E();await H(t,{plan:e.args.plan,pretty:e.args.pretty})}catch(t){S.reporter.error(t),process.exit(1)}}});import{defineCommand as vn}from"citty";import{mkdir as Sn,writeFile as On,unlink as Tn}from"fs/promises";import{join as Nn}from"path";import*as d from"ramda";var j=()=>({added:(e,t,n)=>d.pipe(d.difference(t),d.map(n))(e),removed:(e,t,n)=>d.pipe(d.difference(e),d.map(n))(t),changed:(e,t,n,a)=>d.pipe(d.intersection(e),d.filter(n),d.map(a))(t)}),te=d.prop("name"),fn=d.eqBy(e=>[e.type,e.notNull??!1,e.primaryKey??!1,e.unique??!1]);function gn(e,t){let n=[],a=j(),o=e.columns,l=t.columns,i=Object.keys(o),c=Object.keys(l);return a.added(i,c,s=>({column:s,attributes:l[s]})).forEach(s=>{n.push(He({table:e.name,column:s.column},s.attributes))}),a.removed(i,c,s=>({column:s,attributes:o[s]})).forEach(s=>{n.push(We({table:e.name,column:s.column},s.attributes))}),a.changed(i,c,s=>!fn(o[s],l[s]),s=>({column:s,before:o[s],after:l[s]})).forEach(s=>{n.push(Ye({table:e.name,column:s.column},s.before,s.after))}),n}function bn(e){let{current:t,ideal:n}=e,a=[],o=j(),l=d.map(te,t),i=d.map(te,n);return o.added(l,i,c=>n.find(m=>m.name===c)).forEach(c=>{a.push(je(c.name,c.columns))}),o.removed(l,i,d.identity).forEach(c=>{a.push(Be(c))}),d.filter(c=>n.some(s=>s.name===c.name))(t).forEach(c=>{let s=n.find(m=>m.name===c.name);a.push(...gn(c,s))}),a}function hn(e){let{current:t,ideal:n}=e,a=[],o=j(),l=r=>`${r.table}:${r.name}`,i=new Map(t.map(r=>[l(r),r])),c=new Map(n.map(r=>[l(r),r])),s=Array.from(i.keys()),m=Array.from(c.keys());return o.added(s,m,r=>c.get(r)).forEach(r=>{a.push(De(r))}),o.removed(s,m,r=>{let p=i.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(_e(r))}),o.changed(s,m,r=>{let p=i.get(r),u=c.get(r);return!d.equals(p.columns,u.columns)||p.unique!==u.unique},r=>{let p=i.get(r),u=c.get(r);return{current:p,ideal:u}}).forEach(({current:r,ideal:p})=>{a.push(_e(r)),a.push(De(p))}),a}function Cn(e){let{current:t,ideal:n}=e,a=[],o=j(),l=r=>`${r.table}:${r.name}`,i=new Map(t.map(r=>[l(r),r])),c=new Map(n.map(r=>[l(r),r])),s=Array.from(i.keys()),m=Array.from(c.keys());return o.added(s,m,r=>c.get(r)).forEach(r=>{a.push(ve(r))}),o.removed(s,m,r=>{let p=i.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(Se(r))}),o.changed(s,m,r=>{let p=i.get(r),u=c.get(r);return!d.equals(p.columns,u.columns)},r=>{let p=i.get(r),u=c.get(r);return{current:p,ideal:u}}).forEach(({current:r,ideal:p})=>{a.push(Se(r)),a.push(ve(p))}),a}function xn(e){let{current:t,ideal:n}=e,a=[],o=j(),l=r=>`${r.table}:${r.name}`,i=new Map(t.map(r=>[l(r),r])),c=new Map(n.map(r=>[l(r),r])),s=Array.from(i.keys()),m=Array.from(c.keys());return o.added(s,m,r=>c.get(r)).forEach(r=>{a.push(Oe(r))}),o.removed(s,m,r=>{let p=i.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(Te(r))}),o.changed(s,m,r=>{let p=i.get(r),u=c.get(r);return!d.equals(p.columns,u.columns)},r=>{let p=i.get(r),u=c.get(r);return{current:p,ideal:u}}).forEach(({current:r,ideal:p})=>{a.push(Te(r)),a.push(Oe(p))}),a}function Dn(e){let t=[],n=j(),a=e.current.map(te),o=e.ideal.map(te);t.push(...n.added(a,o,i=>{let c=e.ideal.find(p=>p.name===i),{table:s,name:m,...r}=c;return Ne({table:s,name:m},r)})),t.push(...n.removed(a,o,i=>{let c=e.current.find(s=>s.name===i);return we(c)}));let l=i=>{let c=e.current.find(m=>m.name===i),s=e.ideal.find(m=>m.name===i);return!c||!s?!1:!(d.equals(c.columns,s.columns)&&c.referencedTable===s.referencedTable&&d.equals(c.referencedColumns,s.referencedColumns)&&c.onDelete===s.onDelete&&c.onUpdate===s.onUpdate)};return t.push(...n.changed(a,o,l,i=>{let c=e.current.find(u=>u.name===i),s=e.ideal.find(u=>u.name===i),{table:m,name:r,...p}=s;return[we(c),Ne({table:m,name:r},p)]}).flat()),t}function _t(e){let t=bn({current:e.current.tables,ideal:e.ideal.tables}),n=hn({current:e.current.indexes,ideal:e.ideal.indexes}),a=Cn({current:e.current.primaryKeyConstraints,ideal:e.ideal.primaryKeyConstraints}),o=xn({current:e.current.uniqueConstraints,ideal:e.ideal.uniqueConstraints}),l=Dn({current:e.current.foreignKeyConstraints,ideal:e.ideal.foreignKeyConstraints});return{operations:[...t,...n,...a,...o,...l]}}var vt=e=>{let n=A(e.getDialect()).createIntrospectionDriver(e);return{introspect:async o=>{var C=[];try{let l=N(C,e.getDB(),!0);let i=await l.introspection.getTables();let{tables:c,indexes:s,constraints:m}=await n.introspect({config:o});let r=()=>i.map(O=>{let P={};for(let U of O.columns){let oe=c.find(Re=>Re.table===O.name&&Re.name===U.name);oe&&(P[U.name]={schema:O.schema,table:O.name,name:U.name,dataType:n.convertTypeName(U.dataType),default:oe.default??null,characterMaximumLength:oe.characterMaximumLength??null,notNull:!U.isNullable})}return{schema:O.schema,name:O.name,columns:P}});let p=O=>!O.table.startsWith("kysely_");let u=()=>s.filter(p);let x=()=>({primaryKey:m.primaryKey.filter(p),unique:m.unique.filter(p),foreignKey:m.foreignKey.filter(p)});return{tables:r(),indexes:u(),constraints:x()}}catch(D){var _=D,K=!0}finally{var re=w(C,_,K);re&&await re}}}};var ne=async(e,t,n)=>{let a=A(t),o=await a.createDevDatabaseProvider().setup(a.parseDevDatabaseConfig(e),n);return{manageType:n,instance:o}};async function _n(e,t){let{config:n}=e,a=A(n.database.dialect);switch(t.mode){case"dev-start":{let{instance:o,manageType:l}=await ne(n.dev,n.database.dialect,"dev-start");return{manageType:l,manager:o,result:{reused:await o.isAvailable()}}}case"generate-dev":{let o=await a.hasReusableDevDatabase(),{instance:l,manageType:i}=await ne(n.dev,n.database.dialect,o?"dev-start":"one-off");return{manageType:i,manager:l,result:{reused:o}}}}}async function ae(e,t){let{config:n}=e,a=t.logger||he,{reporter:o}=a;if(!n.dev)throw new Error("Dev database configuration is required");let{manageType:l,manager:i,result:c}=await _n(e,t);c.reused?o.info("\u{1F504} Reusing existing dev database..."):o.info("\u{1F680} Starting dev database..."),await i.start(),o.success(`Dev database started: ${n.database.dialect}`);let s=ee({database:{dialect:n.database.dialect,connectionString:i.getConnectionString()}}),m=await R(s);return m.length>0?(o.info(`\u{1F504} Applying ${m.length} pending migrations...`),await H({client:s,logger:he,config:n},{plan:!1,pretty:!1}),o.success(`Applied ${m.length} migrations`)):o.info("No pending migrations found"),{client:s,manager:i,cleanup:async()=>{switch(t.mode){case"dev-start":o.success("Persistent dev database ready: "+n.database.dialect);break;case"generate-dev":l==="dev-start"?o.info("Dev start container remains running"):(await i.stop(),o.success("Temporary dev database stopped"));break}}}}async function wn(e,t){let{logger:n,config:a}=e,{reporter:o}=n;t.squash&&await An(e);let{client:l,cleanup:i}=t.dev?await ae(e,{mode:"generate-dev",logger:n}):{client:e.client,cleanup:async()=>{}};try{if(!t.ignorePending){let r=await R(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 c=await En({client:l,config:a});if(!c){o.info("No changes detected, no migration needed.");return}Rn(n,c.diff);let s=`${M}/${c.id}.json`;await Sn(M,{recursive:!0}),await On(s,JSON.stringify(c,null,2));let m=t.squash?`Generated squashed migration: ${s}`:`Migration file generated: ${s}`;o.success(m),t.dev&&await H({...e,client:l},{plan:!1,pretty:!1})}finally{await i()}}var An=async e=>{let{client:t,logger:n}=e,{reporter:a}=n,o=await R(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(i=>{a.info(` - ${i.id}.json`)});let l=o.map(i=>Nn(M,`${i.id}.json`));try{await Promise.all(l.map(i=>Tn(i))),a.success(`\u{1F5D1}\uFE0F Removed ${l.length} pending migration files`)}catch(i){throw new Error(`Failed to remove pending migration files: ${i}`)}},En=async e=>{let{client:t,config:n}=e,a=vt(t),{tables:o,indexes:l,constraints:i}=await a.introspect(n),c=(u,x)=>C=>C.some(D=>D.table===u&&D.columns.length===1&&D.columns[0]===x),s=o.map(u=>({name:u.name,columns:Object.fromEntries(Object.entries(u.columns).map(([x,C])=>{let D=c(u.name,x),_=D(i.primaryKey),K=D(i.unique),O=i.primaryKey.some(P=>P.table===u.name&&P.columns.length>1&&P.columns.includes(x))?!0:C.notNull;return[x,{type:C.dataType,notNull:O,defaultSql:C.default??void 0,primaryKey:_,unique:K}]}))})),m=n.tables.map(u=>({name:u.tableName,columns:Object.fromEntries(Object.entries(u.columns).map(([x,C])=>{let D=(n.primaryKeyConstraints??[]).some(K=>K.table===u.tableName&&K.columns.includes(x)),_=C.primaryKey||C.notNull||D;return[x,{...C,notNull:_}]}))})),r=_t({current:{tables:s,indexes:l,uniqueConstraints:i.unique,primaryKeyConstraints:i.primaryKey,foreignKeyConstraints:i.foreignKey},ideal:{...n,tables:m}});return r.operations.length===0?null:{version:"1",id:Date.now()+"",diff:r}},Rn=(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
- `))},Ie=Ft({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 T();await Vt(t,{ignorePending:e.args["ignore-pending"],dev:e.args.dev,squash:e.args.squash})}catch(t){x.reporter.error(t),process.exit(1)}}});import{defineCommand as j}from"citty";async function Yt(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 Xt(e){let{manager:t,logger:n}=e;if(!await t.isAvailable()){n.reporter.info("No running dev containers found");return}await t.start(),console.log(t.getConnectionString())}async function Zt(e){let{manager:t,logger:n}=e;if(!await t.isAvailable()){n.reporter.info("No dev containers found");return}await t.remove(),n.reporter.success("Cleaned up dev containers")}async function en(e){let{logger:t}=e,{reporter:n}=t,{manager:a}=await J(e,{mode:"dev-start",logger:t});n.success(`\u2728 Dev database ready: ${a.getConnectionString()}`)}async function be(){let e=await T();if(!e.config.dev)throw new Error("No dev database configuration found");let{instance:t}=await W(e.config.dev,e.config.database.dialect,"dev-start");return{...e,manager:t}}var tn=j({meta:{name:"start",description:"Start development database with migrations applied"},run:async()=>{try{let e=await T();await en(e)}catch(e){x.reporter.error(e),process.exit(1)}}}),nn=j({meta:{name:"status",description:"Show status of kyrage dev container"},run:async()=>{try{let e=await be();await Yt(e)}catch(e){x.reporter.error(e),process.exit(1)}}}),an=j({meta:{name:"get-url",description:"Print connection URL for running dev container"},run:async()=>{try{let e=await be();await Xt(e)}catch(e){x.reporter.error(e),process.exit(1)}}}),rn=j({meta:{name:"clean",description:"Remove all kyrage dev containers"},run:async()=>{try{let e=await be();await Zt(e)}catch(e){x.reporter.error(e),process.exit(1)}}}),qe=j({meta:{name:"dev",description:"Manage development database containers"},subCommands:{start:tn,status:nn,"get-url":an,clean:rn}});var cn=on({meta:{name:"kyrage",version:he,description:"Kysely migration CLI with declarative schema"},subCommands:{apply:Ke,generate:Ie,dev:qe}});sn(cn);
96
+ `))},St=vn({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 E();await wn(t,{ignorePending:e.args["ignore-pending"],dev:e.args.dev,squash:e.args.squash})}catch(t){S.reporter.error(t),process.exit(1)}}});import{defineCommand as V}from"citty";async function Kn(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 Pn(e){let{manager:t,logger:n}=e;if(!await t.isAvailable()){n.reporter.info("No running dev containers found");return}await t.start(),console.log(t.getConnectionString())}async function qn(e){let{manager:t,logger:n}=e;if(!await t.isAvailable()){n.reporter.info("No dev containers found");return}await t.remove(),n.reporter.success("Cleaned up dev containers")}async function In(e){let{logger:t}=e,{reporter:n}=t,{manager:a}=await ae(e,{mode:"dev-start",logger:t});n.success(`\u2728 Dev database ready: ${a.getConnectionString()}`)}async function Ee(){let e=await E();if(!e.config.dev)throw new Error("No dev database configuration found");let{instance:t}=await ne(e.config.dev,e.config.database.dialect,"dev-start");return{...e,manager:t}}var kn=V({meta:{name:"start",description:"Start development database with migrations applied"},run:async()=>{try{let e=await E();await In(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),$n=V({meta:{name:"status",description:"Show status of kyrage dev container"},run:async()=>{try{let e=await Ee();await Kn(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),Mn=V({meta:{name:"get-url",description:"Print connection URL for running dev container"},run:async()=>{try{let e=await Ee();await Pn(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),jn=V({meta:{name:"clean",description:"Remove all kyrage dev containers"},run:async()=>{try{let e=await Ee();await qn(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),Ot=V({meta:{name:"dev",description:"Manage development database containers"},subCommands:{start:kn,status:$n,"get-url":Mn,clean:jn}});var Bn=Un({meta:{name:"kyrage",version:Ke,description:"Kysely migration CLI with declarative schema"},subCommands:{apply:Dt,generate:St,dev:Ot}});Ln(Bn);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@izumisy/kyrage",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "1.3.1",
5
+ "version": "1.4.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",
@@ -33,16 +33,16 @@
33
33
  "@testcontainers/cockroachdb": "^11.5.1",
34
34
  "@testcontainers/postgresql": "^11.5.1",
35
35
  "better-sqlite3": "^12.2.0",
36
- "c12": "^3.2.0",
36
+ "c12": "^3.3.0",
37
37
  "citty": "^0.1.6",
38
38
  "consola": "^3.4.2",
39
39
  "kysely": "^0.28.7",
40
- "mysql2": "^3.14.4",
40
+ "mysql2": "^3.15.0",
41
41
  "pg": "^8.16.3",
42
42
  "ramda": "^0.31.3",
43
43
  "sql-formatter": "^15.6.9",
44
44
  "testcontainers": "^11.5.1",
45
- "zod": "^4.1.5"
45
+ "zod": "^4.1.11"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@swc/core": "^1.13.5",