@izumisy/kyrage 1.2.3 → 1.3.1
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 +3 -7
- package/dist/main.js +6 -6
- package/package.json +5 -5
- package/dist/chunk-3M6BYRKC.js +0 -1
- package/dist/logger-SE7G5AMI.js +0 -1
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.ZodUnion<readonly [z.ZodObject<{
|
|
28
28
|
container: z.ZodObject<{
|
|
29
|
-
image: z.ZodString
|
|
29
|
+
image: z.ZodDefault<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 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`
|
|
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}))},Ge=async e=>{let{rows:t}=await ie`
|
|
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}))},Ye=async e=>{let{rows:t}=await ie`
|
|
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
|
|
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(`
|
|
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
|
+
`))},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);
|
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.1",
|
|
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",
|
package/dist/chunk-3M6BYRKC.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createConsola as r}from"consola";var s=r({stdout:process.stderr}),e={stdout:o=>console.log(o),reporter:{...s}},g={stdout:()=>{},reporter:{info:()=>{},warn:()=>{},success:()=>{},log:()=>{},error:()=>{}}};export{e as a,g as b};
|
package/dist/logger-SE7G5AMI.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a,b}from"./chunk-3M6BYRKC.js";import"./chunk-EY62Q3Z2.js";export{a as defaultConsolaLogger,b as nullLogger};
|