@izumisy/kyrage 1.5.2 → 1.5.5

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.
@@ -0,0 +1,202 @@
1
+ import z from "zod";
2
+ import { ColumnDataType } from "kysely";
3
+
4
+ //#region src/config/loader.d.ts
5
+ declare const columnSchema: z.ZodObject<{
6
+ type: z.ZodString;
7
+ primaryKey: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
+ notNull: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
9
+ unique: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
10
+ defaultSql: z.ZodOptional<z.ZodString>;
11
+ }, z.core.$strip>;
12
+ type ColumnValue = z.infer<typeof columnSchema>;
13
+ declare const indexSchema: z.ZodObject<{
14
+ columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
15
+ unique: z.ZodDefault<z.ZodBoolean>;
16
+ table: z.ZodString;
17
+ name: z.ZodString;
18
+ }, z.core.$strip>;
19
+ type IndexSchema = z.infer<typeof indexSchema>;
20
+ declare const databaseSchema: z.ZodObject<{
21
+ dialect: z.ZodEnum<{
22
+ postgres: "postgres";
23
+ cockroachdb: "cockroachdb";
24
+ }>;
25
+ connectionString: z.ZodString;
26
+ }, z.core.$strip>;
27
+ type DatabaseValue = z.infer<typeof databaseSchema>;
28
+ declare const devDatabaseSchema: z.ZodUnion<readonly [z.ZodObject<{
29
+ container: z.ZodObject<{
30
+ image: z.ZodDefault<z.ZodString>;
31
+ name: z.ZodOptional<z.ZodString>;
32
+ }, z.core.$strip>;
33
+ }, z.core.$strip>]>;
34
+ type DevDatabaseValue = z.infer<typeof devDatabaseSchema>;
35
+ //#endregion
36
+ //#region src/operations/shared/types.d.ts
37
+ declare const primaryKeyConstraintSchema: z.ZodObject<{
38
+ columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
39
+ table: z.ZodString;
40
+ name: z.ZodString;
41
+ }, z.core.$strip>;
42
+ type PrimaryKeyConstraintSchema = z.infer<typeof primaryKeyConstraintSchema>;
43
+ declare const uniqueConstraintSchema: z.ZodObject<{
44
+ columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
45
+ table: z.ZodString;
46
+ name: z.ZodString;
47
+ }, z.core.$strip>;
48
+ type UniqueConstraintSchema = z.infer<typeof uniqueConstraintSchema>;
49
+ declare const referentialActionsSchema: z.ZodEnum<{
50
+ cascade: "cascade";
51
+ "set null": "set null";
52
+ "set default": "set default";
53
+ restrict: "restrict";
54
+ "no action": "no action";
55
+ }>;
56
+ type ReferentialActions = z.infer<typeof referentialActionsSchema>;
57
+ //#endregion
58
+ //#region src/config/builder.d.ts
59
+ /**
60
+ * Defines a column in a table.
61
+ */
62
+ declare const column: (type: ColumnDataType, options?: Partial<Omit<ColumnValue, "type">>) => {
63
+ type: ColumnDataType;
64
+ notNull: boolean | undefined;
65
+ primaryKey: boolean | undefined;
66
+ unique: boolean | undefined;
67
+ defaultSql: string | undefined;
68
+ };
69
+ type DefinedValue<T, K extends string> = Omit<T, "table"> & {
70
+ kind: K;
71
+ };
72
+ type DefinedColumn = ReturnType<typeof column>;
73
+ type DefinedIndex = DefinedValue<IndexSchema, "index">;
74
+ type DefinedPrimaryKeyConstraint = DefinedValue<PrimaryKeyConstraintSchema, "primaryKey">;
75
+ type DefinedUniqueConstraint = DefinedValue<UniqueConstraintSchema, "unique">;
76
+ type DefinedForeignKeyConstraint = {
77
+ kind: "foreignKey";
78
+ name: string;
79
+ columns: ReadonlyArray<string>;
80
+ referencedTable: string;
81
+ referencedColumns: ReadonlyArray<string>;
82
+ onDelete?: ReferentialActions;
83
+ onUpdate?: ReferentialActions;
84
+ inline?: boolean;
85
+ };
86
+ type ExpressionBuilders<T extends Record<string, DefinedColumn>> = {
87
+ /**
88
+ * Creates an index on the specified columns.
89
+ *
90
+ * The default is non-unique, and name is autogenerated by joining the column names and table name.
91
+ */
92
+ index: (columns: ReadonlyArray<string & keyof T>, options?: {
93
+ name?: string;
94
+ unique?: boolean;
95
+ }) => DefinedIndex;
96
+ /**
97
+ * Creates a primary key constraint on the specified columns.
98
+ *
99
+ * The default name is autogenerated by joining the column names and table name.
100
+ */
101
+ primaryKey: (columns: ReadonlyArray<string & keyof T>, options?: {
102
+ name?: string;
103
+ }) => DefinedPrimaryKeyConstraint;
104
+ /**
105
+ * Creates a unique constraint on the specified columns.
106
+ *
107
+ * The default name is autogenerated by joining the column names and table name.
108
+ */
109
+ unique: (columns: ReadonlyArray<string & keyof T>, options?: {
110
+ name?: string;
111
+ }) => DefinedUniqueConstraint;
112
+ /**
113
+ * Creates a foreign key constraint on the specified columns.
114
+ *
115
+ * The default name is autogenerated by joining the column names and table name.
116
+ */
117
+ reference: <R extends Record<string, DefinedColumn>>(columns: ReadonlyArray<string & keyof T> | (string & keyof T), referencedTable: {
118
+ tableName: string;
119
+ columns: R;
120
+ }, referencedColumns: ReadonlyArray<string & keyof R> | (string & keyof R), options?: {
121
+ name?: string;
122
+ onDelete?: ReferentialActions;
123
+ onUpdate?: ReferentialActions;
124
+ inline?: boolean;
125
+ }) => DefinedForeignKeyConstraint;
126
+ };
127
+ /**
128
+ * Defines a table with its columns and optional expression builders.
129
+ */
130
+ declare const defineTable: <T extends Record<string, DefinedColumn>>(
131
+ /**
132
+ * The name of the table.
133
+ */
134
+ name: string,
135
+ /**
136
+ * The columns in the table.
137
+ */
138
+ columns: T,
139
+ /**
140
+ * The expression builders for the table.
141
+ *
142
+ * This is where you can define additional indexes, constraints, or other
143
+ * database-specific features for the table.
144
+ */
145
+ tableExpBuilder?: (builder: ExpressionBuilders<T>) => ReadonlyArray<ReturnType<ExpressionBuilders<T>["index"]> | ReturnType<ExpressionBuilders<T>["primaryKey"]> | ReturnType<ExpressionBuilders<T>["unique"]> | ReturnType<ExpressionBuilders<T>["reference"]>>) => {
146
+ tableName: string;
147
+ columns: T;
148
+ indexes: DefinedIndex[];
149
+ primaryKeys: DefinedPrimaryKeyConstraint[];
150
+ uniques: DefinedUniqueConstraint[];
151
+ foreignKeys: DefinedForeignKeyConstraint[];
152
+ };
153
+ type DefinedTable = ReturnType<typeof defineTable> & {
154
+ indexes: ReadonlyArray<DefinedIndex>;
155
+ primaryKeys: ReadonlyArray<DefinedPrimaryKeyConstraint>;
156
+ uniques: ReadonlyArray<DefinedUniqueConstraint>;
157
+ foreignKeys: ReadonlyArray<DefinedForeignKeyConstraint>;
158
+ };
159
+ type DefinedTables = ReadonlyArray<DefinedTable>;
160
+ type DefineConfigProp = {
161
+ database: DatabaseValue;
162
+ dev?: DevDatabaseValue;
163
+ tables: DefinedTables;
164
+ };
165
+ declare const defineConfig: (config: DefineConfigProp) => {
166
+ readonly dev: {
167
+ container: {
168
+ image: string;
169
+ name?: string | undefined;
170
+ };
171
+ } | undefined;
172
+ readonly indexes: {
173
+ columns: readonly string[];
174
+ unique: boolean;
175
+ table: string;
176
+ name: string;
177
+ }[];
178
+ readonly primaryKeyConstraints: {
179
+ columns: readonly string[];
180
+ table: string;
181
+ name: string;
182
+ }[];
183
+ readonly uniqueConstraints: {
184
+ columns: readonly string[];
185
+ table: string;
186
+ name: string;
187
+ }[];
188
+ readonly foreignKeyConstraints: {
189
+ columns: readonly string[];
190
+ referencedTable: string;
191
+ referencedColumns: readonly string[];
192
+ table: string;
193
+ name: string;
194
+ onDelete?: "cascade" | "set null" | "set default" | "restrict" | "no action" | undefined;
195
+ onUpdate?: "cascade" | "set null" | "set default" | "restrict" | "no action" | undefined;
196
+ inline?: boolean | undefined;
197
+ }[];
198
+ readonly database: DatabaseValue;
199
+ readonly tables: DefinedTables;
200
+ };
201
+ //#endregion
202
+ export { DefineConfigProp, DefinedTable, DefinedTables, column, defineConfig, defineTable };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ const e={primaryKey:(e,t)=>t.length===1?`${e}_${t[0]}_primary_key`:`pk_${e}_${t.join(`_`)}`,unique:(e,t)=>t.length===1?`${e}_${t[0]}_unique`:`uq_${e}_${t.join(`_`)}`,index:(e,t)=>`idx_${e}_${t.join(`_`)}`,foreignKey:(e,t)=>`fk_${e}_${t.join(`_`)}`},t=(e,t)=>({type:e,notNull:t?.notNull,primaryKey:t?.primaryKey,unique:t?.unique,defaultSql:t?.defaultSql}),n=(t,n,r)=>{let i=e=>{if(e.length===0)throw Error(`At least one column must be specified.`)},a=(e,n)=>`${e}_${t}_${n.join(`_`)}`,o=r?r({index:(e,t)=>(i(e),{kind:`index`,name:t?.name??a(`idx`,e),columns:e,unique:t?.unique??!1}),primaryKey:(e,t)=>(i(e),{kind:`primaryKey`,name:t?.name??a(`pk`,e),columns:e}),unique:(e,t)=>(i(e),{kind:`unique`,name:t?.name??a(`uq`,e),columns:e}),reference:(n,r,a,o)=>{let s=Array.isArray(n)?n:[n],c=Array.isArray(a)?a:[a];return i(s),i(c),{kind:`foreignKey`,name:o?.name??e.foreignKey(t,s),columns:s,referencedTable:r.tableName,referencedColumns:c,onDelete:o?.onDelete,onUpdate:o?.onUpdate,inline:o?.inline??!0}}}):[];return{tableName:t,columns:n,indexes:o.filter(e=>e.kind===`index`),primaryKeys:o.filter(e=>e.kind===`primaryKey`),uniques:o.filter(e=>e.kind===`unique`),foreignKeys:o.filter(e=>e.kind===`foreignKey`)}},r=t=>{let n=new Map,r=new Map,i=new Map,a=new Map;for(let o of t.tables){let t=o.tableName;for(let e of o.indexes??[])n.set(`${t}:${e.name}`,{table:t,name:e.name,columns:e.columns,unique:e.unique});for(let e of o.primaryKeys??[])r.set(`${t}:${e.name}`,{table:t,name:e.name,columns:e.columns});for(let e of o.uniques??[])i.set(`${t}:${e.name}`,{table:t,name:e.name,columns:e.columns});for(let e of o.foreignKeys??[])a.set(`${t}:${e.name}`,{table:t,name:e.name,columns:e.columns,referencedTable:e.referencedTable,referencedColumns:e.referencedColumns,onDelete:e.onDelete,onUpdate:e.onUpdate,inline:e.inline});for(let[n,a]of Object.entries(o.columns)){if(a.primaryKey){let i=e.primaryKey(t,[n]),a=`${t}:${i}`;r.has(a)||r.set(a,{table:t,name:i,columns:[n]})}if(a.unique){let r=e.unique(t,[n]),a=`${t}:${r}`;i.has(a)||i.set(a,{table:t,name:r,columns:[n]})}}}return{...t,dev:t.dev,indexes:Array.from(n.values()),primaryKeyConstraints:Array.from(r.values()),uniqueConstraints:Array.from(i.values()),foreignKeyConstraints:Array.from(a.values())}};export{t as column,r as defineConfig,n as defineTable};
@@ -0,0 +1 @@
1
+ export { };
package/dist/main.mjs ADDED
@@ -0,0 +1,96 @@
1
+ import{defineCommand as e,runMain as t}from"citty";import n from"zod";import{loadConfig as r}from"c12";import{getContainerRuntimeClient as i}from"testcontainers";import{DEFAULT_MIGRATION_TABLE as a,DummyDriver as o,Kysely as s,Migrator as c,PostgresAdapter as l,PostgresDialect as u,isColumnDataType as ee,sql as d}from"kysely";import{Pool as f}from"pg";import{PostgreSqlContainer as te}from"@testcontainers/postgresql";import*as p from"ramda";import{CockroachDbContainer as ne}from"@testcontainers/cockroachdb";import{createConsola as re}from"consola";import*as ie from"fs/promises";import{join as m}from"path";import{CycleError as ae,Graph as oe,topologicalSort as se}from"graph-data-structure";import{format as ce}from"sql-formatter";var le=`1.5.5`;const h=n.object({type:n.string()}).catchall(n.any()),g=n.object({table:n.string(),name:n.string()}),_=n.object({table:n.string(),column:n.string()}),ue=n.object({...g.shape,columns:n.array(n.string()).readonly()}),de=n.object({...g.shape,columns:n.array(n.string()).readonly()}),v=n.enum([`cascade`,`set null`,`set default`,`restrict`,`no action`]),fe=n.object({...g.shape,columns:n.array(n.string()).readonly(),referencedTable:n.string(),referencedColumns:n.array(n.string()).readonly(),onDelete:v.optional(),onUpdate:v.optional(),inline:n.boolean().optional()}),y=e=>n.object({container:n.object({image:n.string().default(e.defaultImage),name:n.string().optional()})});var b=class{constructor(e,t){this.dialect=e,this.containerFactory=t}async setup(e,t){return new pe({dialect:this.dialect,manageType:t,containerName:e.container.name,containerFactory:()=>this.containerFactory(e.container.image)})}async hasExisting(e){return e===`dev-start`?w(this.dialect):!1}async cleanup(){await T()}};const x=`kyrage.dialect`,S=`kyrage.managed`,C=`kyrage.managed-by`;var pe=class{constructor(e){this.options=e,this.startedContainer=null,this.container=this.setupContainer()}setupContainer(){let e=this.options.containerFactory();return e.withLabels({[x]:this.options.dialect,[S]:`true`,[C]:this.options.manageType}),this.options.manageType===`dev-start`&&e.withReuse(),this.options.containerName&&e.withName(this.options.containerName),e}async start(){this.startedContainer=await this.container.start()}async stop(){this.startedContainer&&=(await this.startedContainer.stop(),null)}async remove(){await T(),this.startedContainer=null}getConnectionString(){if(!this.startedContainer)throw Error(`Container is not started`);return this.startedContainer.getConnectionUri()}async getStatus(){let e=await(await i()).container.fetchByLabel(x,this.options.dialect,{status:[`running`]});if(e){let t=await e.inspect();return{type:`container`,imageName:t.Config.Image,containerID:t.Id}}return{type:`unavailable`}}async isAvailable(){return(await this.getStatus()).type===`container`}};const w=async e=>(await(await i()).container.list()).some(t=>t.Labels[S]===`true`&&t.Labels[C]===`dev-start`&&t.Labels[x]===e&&t.State===`running`),T=async()=>{let e=await i(),t=(await e.container.list()).filter(e=>e.Labels[S]===`true`).map(e=>e.Id);await Promise.allSettled(t.map(async t=>e.container.getById(t).remove({force:!0})))},me=n.object({type:n.string(),primaryKey:n.boolean().optional().default(!1),notNull:n.boolean().optional().default(!1),unique:n.boolean().optional().default(!1),defaultSql:n.string().optional()}),he=n.object({tableName:n.string(),columns:n.record(n.string(),me)}),ge=n.object({...g.shape,columns:n.array(n.string()).readonly(),unique:n.boolean().default(!1)}),_e=n.enum([`postgres`,`cockroachdb`]),ve=n.object({dialect:_e,connectionString:n.string()}),ye=n.union([y({defaultImage:``})]),be=n.object({database:ve,dev:ye.optional(),tables:n.array(he).readonly(),indexes:n.array(ge).readonly(),primaryKeyConstraints:n.array(ue).readonly(),uniqueConstraints:n.array(de).readonly(),foreignKeyConstraints:n.array(fe).readonly()}),xe=async()=>{let e=await r({name:`kyrage`});return be.parse(e.config)},Se=(e,t)=>{let n=e=>t=>p.any(p.whereEq({name:t.name,table:t.table}),e),[r,i]=p.partition(n(e.uniqueConstraints),t.constraints.unique),[a,o]=p.partition(n(e.indexes),t.indexes),s=p.reject(n(a),i),c=p.reject(n(r),o);return{indexes:[...a,...c],uniqueConstraints:[...r,...s]}};var Ce=class{getName(){return`postgres`}createKyselyDialect(e){return new u({pool:new f({connectionString:e})})}createIntrospectionDriver(e){return{convertTypeName:D,introspect:E(e)}}createDevDatabaseProvider(){return new b(this.getName(),e=>new te(e))}parseDevDatabaseConfig(e){return y({defaultImage:`postgres:16`}).parse(e)}async hasReusableDevDatabase(){return w(this.getName())}};const E=e=>async t=>{await using n=e.getDB();let[r,i,a]=await Promise.all([we(n),Te(n),Ee(n)]),{indexes:o,uniqueConstraints:s}=Se(t.config,{indexes:i,constraints:a});return{tables:r,indexes:o,constraints:{...a,unique:s}}},D=e=>({bool:`boolean`,int2:`smallint`,int4:`integer`,int8:`bigint`})[e]??e,we=async e=>{let{rows:t}=await d`
2
+ SELECT
3
+ n.nspname AS table_schema,
4
+ c.relname AS table_name,
5
+ a.attname AS column_name,
6
+ pg_get_expr(d.adbin, d.adrelid) AS column_default,
7
+ CASE
8
+ WHEN t.typname = 'varchar' OR t.typname = 'char' THEN a.atttypmod - 4
9
+ ELSE NULL
10
+ END AS character_maximum_length
11
+ FROM pg_class c
12
+ JOIN pg_namespace n ON n.oid = c.relnamespace
13
+ JOIN pg_attribute a ON a.attrelid = c.oid
14
+ LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = a.attnum
15
+ JOIN pg_type t ON t.oid = a.atttypid
16
+ WHERE c.relkind = 'r'
17
+ AND n.nspname = 'public'
18
+ AND a.attnum > 0
19
+ AND NOT a.attisdropped
20
+ ORDER BY c.relname, a.attnum;
21
+ `.$castTo().execute(e);return t.map(e=>({schema:e.table_schema,table:e.table_name,name:e.column_name,default:e.column_default,characterMaximumLength:e.character_maximum_length?Number(e.character_maximum_length):null}))},Te=async e=>{let{rows:t}=await d`
22
+ SELECT
23
+ t.relname AS table_name,
24
+ c.relname AS index_name,
25
+ i.indisunique AS is_unique,
26
+ jsonb_agg(a.attname ORDER BY array_position(i.indkey, a.attnum)) AS column_names
27
+ FROM pg_class t
28
+ JOIN pg_namespace n ON n.oid = t.relnamespace
29
+ JOIN pg_index i ON i.indrelid = t.oid
30
+ JOIN pg_class c ON c.oid = i.indexrelid
31
+ JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY (i.indkey)
32
+ WHERE t.relkind = 'r'
33
+ AND n.nspname = 'public'
34
+ AND NOT i.indisprimary
35
+ GROUP BY t.relname, c.relname, i.indisunique, i.indisprimary, c.oid;
36
+ `.$castTo().execute(e);return t.map(e=>({table:e.table_name,name:e.index_name,columns:e.column_names,unique:e.is_unique}))},Ee=async e=>{let{rows:t}=await d`
37
+ SELECT
38
+ n.nspname AS schema,
39
+ t.relname AS table,
40
+ c.conname AS name,
41
+ CASE c.contype
42
+ WHEN 'p' THEN 'PRIMARY KEY'
43
+ WHEN 'u' THEN 'UNIQUE'
44
+ WHEN 'f' THEN 'FOREIGN KEY'
45
+ END AS type,
46
+ jsonb_agg(a.attname ORDER BY array_position(c.conkey, a.attnum)) AS columns,
47
+ -- Foreign Key専用の情報
48
+ CASE
49
+ WHEN c.contype = 'f' THEN rt.relname
50
+ ELSE NULL
51
+ END AS referenced_table,
52
+ CASE
53
+ WHEN c.contype = 'f' THEN jsonb_agg(ra.attname ORDER BY array_position(c.confkey, ra.attnum))
54
+ ELSE NULL
55
+ END AS referenced_columns,
56
+ CASE
57
+ WHEN c.contype = 'f' THEN
58
+ CASE c.confdeltype
59
+ WHEN 'c' THEN 'cascade'
60
+ WHEN 'n' THEN 'set null'
61
+ WHEN 'd' THEN 'set default'
62
+ WHEN 'r' THEN 'restrict'
63
+ WHEN 'a' THEN 'no action'
64
+ END
65
+ ELSE NULL
66
+ END AS on_delete,
67
+ CASE
68
+ WHEN c.contype = 'f' THEN
69
+ CASE c.confupdtype
70
+ WHEN 'c' THEN 'cascade'
71
+ WHEN 'n' THEN 'set null'
72
+ WHEN 'd' THEN 'set default'
73
+ WHEN 'r' THEN 'restrict'
74
+ WHEN 'a' THEN 'no action'
75
+ END
76
+ ELSE NULL
77
+ END AS on_update
78
+ FROM pg_constraint c
79
+ JOIN pg_class t ON c.conrelid = t.oid
80
+ JOIN pg_namespace n ON t.relnamespace = n.oid
81
+ JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey)
82
+ -- Foreign Key用のJOIN
83
+ LEFT JOIN pg_class rt ON c.confrelid = rt.oid
84
+ LEFT JOIN pg_attribute ra ON ra.attrelid = c.confrelid AND ra.attnum = ANY(c.confkey)
85
+ WHERE c.contype IN ('p', 'u', 'f') -- primary key, unique, foreign key constraints
86
+ AND n.nspname = 'public'
87
+ AND NOT a.attisdropped
88
+ AND (c.contype != 'f' OR NOT ra.attisdropped) -- Foreign Key用の条件
89
+ GROUP BY n.nspname, t.relname, c.conname, c.contype, c.oid, c.conkey, t.oid,
90
+ rt.relname, c.confkey, c.confdeltype, c.confupdtype
91
+ ORDER BY t.relname, c.conname;
92
+ `.$castTo().execute(e);return{primaryKey:t.filter(e=>e.type===`PRIMARY KEY`),unique:t.filter(e=>e.type===`UNIQUE`),foreignKey:t.filter(e=>e.type===`FOREIGN KEY`).map(e=>{let{referenced_table:t,referenced_columns:n,on_delete:r,on_update:i,...a}=e;return{...a,referencedTable:t,referencedColumns:n,onDelete:r,onUpdate:i}})}};var De=class{getName(){return`cockroachdb`}createKyselyDialect(e){return new ke({pool:new f({connectionString:e})})}createIntrospectionDriver(e){let t=[`rowid`];return{convertTypeName:D,introspect:async n=>{let r=await E(e)(n);return{tables:r.tables.filter(e=>!t.includes(e.name)),indexes:r.indexes,constraints:r.constraints}}}}createDevDatabaseProvider(){return new b(this.getName(),e=>new ne(e))}parseDevDatabaseConfig(e){return y({defaultImage:`cockroachdb/cockroach:latest-v24.3`}).parse(e)}async hasReusableDevDatabase(){return w(this.getName())}},Oe=class extends l{async acquireMigrationLock(e,t){await e.selectFrom(t.lockTable).selectAll().forUpdate().execute()}},ke=class extends u{createAdapter(){return new Oe}};const Ae={postgres:new Ce,cockroachdb:new De},O=e=>{let t=Ae[e];if(!t)throw Error(`Unsupported dialect: ${e}`);return t};var je=class extends o{constructor(e){super(),this.queries=e}async acquireConnection(){return new Me(this.queries)}},Me=class{constructor(e){this.queries=e}async executeQuery(e){let t=e.query.kind;if(t===`CreateTableNode`||t===`DropTableNode`||t===`AlterTableNode`){if(e.query.table.table.identifier.name.startsWith(`kysely_`))return{rows:[]};this.queries.push(e)}else (t===`CreateIndexNode`||t===`DropIndexNode`)&&this.queries.push(e);return{rows:[]}}async*streamQuery(){}};const k=e=>new Ne({databaseProps:e.database,options:e.options});var Ne=class{constructor(e){this.constructorProps=e}getDB(e){let t=O(this.constructorProps.databaseProps.dialect).createKyselyDialect(this.constructorProps.databaseProps.connectionString);return new Pe({dialect:{createAdapter:()=>t.createAdapter(),createDriver:()=>t.createDriver(),createIntrospector:e=>t.createIntrospector(e),createQueryCompiler:()=>t.createQueryCompiler()}},{isPlan:e?.plan===!0})}getDialect(){return this.constructorProps.databaseProps.dialect}},Pe=class extends s{constructor(e,t){let n=[];super({dialect:{...e.dialect,createDriver:()=>t.isPlan?new je(n):e.dialect.createDriver()}}),this.plannedQueries=[],this.plannedQueries=n}getPlannedQueries(){return this.plannedQueries}};const A={stdout:e=>console.log(e),reporter:{...re({stdout:process.stderr})}},j={stdout:()=>void 0,reporter:{info:()=>void 0,warn:()=>void 0,success:()=>void 0,log:()=>void 0,error:()=>void 0}};async function M(){let e=await xe();return{client:k({database:e.database}),logger:A,fs:ie,config:e}}const N=e=>{if(!ee(e))throw Error(`Unsupported data type: ${e}`)},P=e=>e,Fe=P({typeName:`create_table`,schema:n.object({type:n.literal(`create_table`),table:n.string(),columns:n.record(n.string(),h)}),execute:async(e,t)=>{let n=e.schema.createTable(t.table);n=F(n,t.columns),await n.execute()}}),Ie=(e,t)=>({type:`create_table`,table:e,columns:t});function F(e,t){let n=e;for(let[e,r]of Object.entries(t)){let t=r.type;N(t),n=n.addColumn(e,t,e=>{let t=e;return r.notNull&&(t=t.notNull()),typeof r.defaultSql==`string`&&(t=t.defaultTo(d.raw(r.defaultSql))),t})}return n}const Le=P({typeName:`create_table_with_constraints`,schema:n.object({type:n.literal(`create_table_with_constraints`),table:n.string(),columns:n.record(n.string(),h),constraints:n.object({primaryKey:n.object({name:n.string(),columns:n.array(n.string()).readonly()}).optional(),unique:n.array(n.object({name:n.string(),columns:n.array(n.string()).readonly()})).readonly().optional(),foreignKeys:n.array(n.object({name:n.string(),columns:n.array(n.string()).readonly(),referencedTable:n.string(),referencedColumns:n.array(n.string()).readonly(),onDelete:v.optional(),onUpdate:v.optional(),inline:n.boolean().optional()})).readonly().optional()}).optional()}),execute:async(e,t)=>{let n=e.schema.createTable(t.table);if(n=F(n,t.columns),t.constraints){let{primaryKey:e,unique:r,foreignKeys:i}=t.constraints;if(e&&(n=n.addPrimaryKeyConstraint(e.name,e.columns)),r)for(let e of r)n=n.addUniqueConstraint(e.name,e.columns);if(i)for(let e of i)n=n.addForeignKeyConstraint(e.name,e.columns,e.referencedTable,e.referencedColumns,t=>{let n=t;return e.onDelete&&(n=n.onDelete(e.onDelete)),e.onUpdate&&(n=n.onUpdate(e.onUpdate)),n})}await n.execute()}}),Re=(e,t,n)=>({type:`create_table_with_constraints`,table:e,columns:t,constraints:{primaryKey:n?.primaryKey,unique:n?.unique??[],foreignKeys:n?.foreignKeys??[]}}),ze=P({typeName:`drop_table`,schema:n.object({type:n.literal(`drop_table`),table:n.string()}),execute:async(e,t)=>{await e.schema.dropTable(t.table).execute()}}),Be=e=>({type:`drop_table`,table:e}),Ve=P({typeName:`add_column`,schema:n.object({..._.shape,type:n.literal(`add_column`),attributes:h}),execute:async(e,t)=>{let n=t.attributes.type;N(n),await e.schema.alterTable(t.table).addColumn(t.column,n,e=>{let n=e;return t.attributes.notNull&&(n=n.notNull()),typeof t.attributes.defaultSql==`string`&&(n=n.defaultTo(d.raw(t.attributes.defaultSql))),n}).execute()}}),He=(e,t)=>({...e,type:`add_column`,attributes:t}),Ue=P({typeName:`drop_column`,schema:n.object({..._.shape,type:n.literal(`drop_column`),attributes:h}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropColumn(t.column).execute()}}),We=(e,t)=>({...e,type:`drop_column`,attributes:t}),Ge=P({typeName:`alter_column`,schema:n.object({..._.shape,type:n.literal(`alter_column`),before:h,after:h}),execute:async(e,t)=>{let{table:n,column:r,before:i,after:a}=t;if(i.type!==a.type){let t=a.type;N(t),await e.schema.alterTable(n).alterColumn(r,e=>e.setDataType(t)).execute()}a.notNull!==i.notNull&&(a.notNull?await e.schema.alterTable(n).alterColumn(r,e=>e.setNotNull()).execute():await e.schema.alterTable(n).alterColumn(r,e=>e.dropNotNull()).execute())}}),Ke=(e,t,n)=>({...e,type:`alter_column`,before:t,after:n}),qe=P({typeName:`create_index`,schema:n.object({...g.shape,type:n.literal(`create_index`),columns:n.array(n.string()).readonly(),unique:n.boolean()}),execute:async(e,t)=>{let n=e.schema.createIndex(t.name).on(t.table);for(let e of t.columns)n=n.column(e);t.unique&&(n=n.unique()),await n.execute()}}),I=e=>({...e,type:`create_index`}),Je=P({typeName:`drop_index`,schema:n.object({...g.shape,type:n.literal(`drop_index`)}),execute:async(e,t)=>{await e.schema.dropIndex(t.name).execute()}}),L=e=>({...e,type:`drop_index`}),Ye=P({typeName:`create_primary_key_constraint`,schema:n.object({...ue.shape,type:n.literal(`create_primary_key_constraint`)}),execute:async(e,t)=>{await e.schema.alterTable(t.table).addPrimaryKeyConstraint(t.name,t.columns).execute()}}),R=e=>({...e,type:`create_primary_key_constraint`}),Xe=P({typeName:`drop_primary_key_constraint`,schema:n.object({...g.shape,type:n.literal(`drop_primary_key_constraint`)}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),z=e=>({...e,type:`drop_primary_key_constraint`}),Ze=P({typeName:`create_unique_constraint`,schema:n.object({...de.shape,type:n.literal(`create_unique_constraint`)}),execute:async(e,t)=>{await e.schema.alterTable(t.table).addUniqueConstraint(t.name,t.columns).execute()}}),B=e=>({...e,type:`create_unique_constraint`}),Qe=P({typeName:`drop_unique_constraint`,schema:n.object({...g.shape,type:n.literal(`drop_unique_constraint`)}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),V=e=>({...e,type:`drop_unique_constraint`}),$e=P({typeName:`create_foreign_key_constraint`,schema:n.object({...fe.shape,type:n.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()}}),H=(e,t)=>({...e,...t,type:`create_foreign_key_constraint`}),et=P({typeName:`drop_foreign_key_constraint`,schema:n.object({...g.shape,type:n.literal(`drop_foreign_key_constraint`)}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),U=e=>({...e,type:`drop_foreign_key_constraint`}),W=[Le,Fe,ze,Ve,Ue,Ge,qe,Je,Ye,Xe,Ze,Qe,$e,et],tt=n.union(W.map(e=>e.schema));async function nt(e,t){return await rt(t.type)(e,t)}function rt(e){let t=W.find(t=>t.typeName===e);if(!t)throw Error(`Unknown operation type: ${e}`);return t.execute}const it=e=>{let t=new Set;return e.forEach(e=>{e.type===`drop_table`&&t.add(e.table)}),t.size===0?e:e.filter(e=>e.type===`drop_table`?!0:!t.has(e.table))},at=e=>{let t=new Set;if(e.forEach(e=>{e.type===`create_table`&&t.add(e.table)}),t.size===0)return e;let n=new Map,r=new Map,i=[];e.forEach(e=>{e.type===`create_table`&&n.set(e.table,e)}),e.forEach(e=>{switch(e.type){case`create_table`:return;case`create_primary_key_constraint`:case`create_unique_constraint`:if(t.has(e.table)){let t=r.get(e.table)||[];r.set(e.table,[...t,e])}else i.push(e);break;case`create_foreign_key_constraint`:if(t.has(e.table)&&e.inline!==!1){let t=n.get(e.table),i=e.columns.filter(e=>!(e in t.columns));if(i.length>0)throw Error(`Foreign key constraint "${e.name}" references non-existent columns: ${i.join(`, `)}`);let a=r.get(e.table)||[];r.set(e.table,[...a,e])}else i.push(e);break;default:i.push(e);break}});let a=[];return n.forEach((e,t)=>{let n=r.get(t)||[];if(n.length===0){a.push(e);return}let i={unique:[],foreignKeys:[]};n.forEach(e=>{switch(e.type){case`create_primary_key_constraint`:i.primaryKey=e;break;case`create_unique_constraint`:i.unique.push(e);break;case`create_foreign_key_constraint`:i.foreignKeys.push(e);break}}),a.push(Re(e.table,e.columns,i))}),[...a,...i]},ot=e=>{let t=new Set;return e.forEach(e=>{(e.type===`drop_unique_constraint`||e.type===`drop_primary_key_constraint`)&&t.add(`${e.table}.${e.name}`)}),e.filter(e=>{if(e.type===`drop_index`){let n=`${e.table}.${e.name}`;if(t.has(n))return!1}return!0})},G=e=>`table`in e?e.table:null,st=e=>{let t=new Set;return e.forEach(e=>{let n=G(e);n&&t.add(n)}),t},ct=e=>{switch(e.type){case`create_foreign_key_constraint`:return[{table:e.table,referencedTable:e.referencedTable}];case`create_table_with_constraints`:return(e.constraints?.foreignKeys||[]).map(t=>({table:e.table,referencedTable:t.referencedTable}));default:return[]}},lt=e=>{let t=new oe;return e.forEach(e=>ct(e).forEach(n=>{n.table!==n.referencedTable&&(e.type!==`create_foreign_key_constraint`||e.inline!==!1)&&t.addEdge(n.referencedTable,n.table)})),t},ut=(e,t)=>{try{let n=se(lt(t)),r=new Set(n);return[...Array.from(e).filter(e=>!r.has(e)).sort(),...n]}catch(e){throw e instanceof ae?Error(`Circular dependency detected in foreign key constraints. Please resolve this by setting 'inline: false' for one of the foreign key constraints in each circular relationship.`):e}},dt=e=>new Map(e.map((e,t)=>[e,t])),ft=e=>(t,n)=>{let r=K[t.type],i=K[n.type];if(r!==i)return r-i;let a=G(t),o=G(n);if(a&&o){let t=e.get(a)??2**53-1,n=e.get(o)??2**53-1;if(t!==n)return t-n}return(a||``).localeCompare(o||``)},K={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},pt=p.pipe(it,at,ot,e=>p.sort(ft(p.pipe(st,t=>ut(t,e),dt)(e)),e)),mt=e=>({getMigrations:async()=>{let t=await e.migrationsResolver(),n={};return t.forEach(e=>{n[e.id]={up:async t=>{for(let n of pt(e.diff.operations))await nt(t,n)}}}),n}}),ht=n.object({operations:n.array(tt).readonly()}),gt=n.object({id:n.string(),version:n.string(),diff:ht}),q=`migrations`,_t=async e=>{let{fs:t}=e;try{let e=(await t.readdir(q)).filter(e=>e.endsWith(`.json`)).map(async e=>gt.parse(JSON.parse(await t.readFile(m(q,e),`utf-8`))));return await Promise.all(e)}catch(e){if(e instanceof Object&&`code`in e&&e.code===`ENOENT`)return[];throw e}},J=async e=>{let{client:t,fs:n}=e;await using r=t.getDB();let i=await _t({fs:n});if(!(await r.introspection.getTables({withInternalKyselyTables:!0})).map(e=>e.name).includes(a))return i;let o=await r.selectFrom(a).select([`name`,`timestamp`]).$narrowType().execute();return i.filter(e=>!o.some(t=>t.name===e.id))};async function Y(e,t){let{client:n,logger:r}=e,{reporter:i}=r;await using a=n.getDB({plan:t.plan});let{results:o,error:s}=await new c({db:a,provider:mt({migrationsResolver:async()=>t.plan?await J(e):await _t(e),options:{plan:t.plan}})}).migrateToLatest(),l=a.getPlannedQueries();if(l.length>0){l.forEach(e=>{r.stdout(t.pretty?ce(e.sql):e.sql)});return}if(o&&o.length>0?o.forEach(e=>{e.status===`Error`?i.error(`Migration failed: ${e.migrationName}`):e.status===`Success`&&i.success(`Migration applied: ${e.migrationName}`)}):i.info(`No migrations to run`),s)throw s instanceof Error?s:Error(`Migration error: ${s}`)}const vt=e({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{await Y(await M(),{plan:e.args.plan,pretty:e.args.pretty})}catch(e){A.reporter.error(e),process.exit(1)}}}),X=()=>({added:(e,t,n)=>p.pipe(p.difference(t),p.map(n))(e),removed:(e,t,n)=>p.pipe(p.difference(e),p.map(n))(t),changed:(e,t,n,r)=>p.pipe(p.intersection(e),p.filter(n),p.map(r))(t)}),Z=p.prop(`name`),yt=p.eqBy(e=>[e.type,e.notNull??!1,e.primaryKey??!1,e.unique??!1]);function bt(e,t){let n=[],r=X(),i=e.columns,a=t.columns,o=Object.keys(i),s=Object.keys(a);return r.added(o,s,e=>({column:e,attributes:a[e]})).forEach(t=>{n.push(He({table:e.name,column:t.column},t.attributes))}),r.removed(o,s,e=>({column:e,attributes:i[e]})).forEach(t=>{n.push(We({table:e.name,column:t.column},t.attributes))}),r.changed(o,s,e=>!yt(i[e],a[e]),e=>({column:e,before:i[e],after:a[e]})).forEach(t=>{n.push(Ke({table:e.name,column:t.column},t.before,t.after))}),n}function xt(e){let{current:t,ideal:n}=e,r=[],i=X(),a=p.map(Z,t),o=p.map(Z,n);return i.added(a,o,e=>n.find(t=>t.name===e)).forEach(e=>{r.push(Ie(e.name,e.columns))}),i.removed(a,o,p.identity).forEach(e=>{r.push(Be(e))}),p.filter(e=>n.some(t=>t.name===e.name))(t).forEach(e=>{let t=n.find(t=>t.name===e.name);r.push(...bt(e,t))}),r}function St(e){let{current:t,ideal:n}=e,r=[],i=X(),a=e=>`${e.table}:${e.name}`,o=new Map(t.map(e=>[a(e),e])),s=new Map(n.map(e=>[a(e),e])),c=Array.from(o.keys()),l=Array.from(s.keys());return i.added(c,l,e=>s.get(e)).forEach(e=>{r.push(I(e))}),i.removed(c,l,e=>{let t=o.get(e);return{table:t.table,name:t.name}}).forEach(e=>{r.push(L(e))}),i.changed(c,l,e=>{let t=o.get(e),n=s.get(e);return!p.equals(t.columns,n.columns)||t.unique!==n.unique},e=>({current:o.get(e),ideal:s.get(e)})).forEach(({current:e,ideal:t})=>{r.push(L(e)),r.push(I(t))}),r}function Ct(e){let{current:t,ideal:n}=e,r=[],i=X(),a=e=>`${e.table}:${e.name}`,o=new Map(t.map(e=>[a(e),e])),s=new Map(n.map(e=>[a(e),e])),c=Array.from(o.keys()),l=Array.from(s.keys());return i.added(c,l,e=>s.get(e)).forEach(e=>{r.push(R(e))}),i.removed(c,l,e=>{let t=o.get(e);return{table:t.table,name:t.name}}).forEach(e=>{r.push(z(e))}),i.changed(c,l,e=>{let t=o.get(e),n=s.get(e);return!p.equals(t.columns,n.columns)},e=>({current:o.get(e),ideal:s.get(e)})).forEach(({current:e,ideal:t})=>{r.push(z(e)),r.push(R(t))}),r}function wt(e){let{current:t,ideal:n}=e,r=[],i=X(),a=e=>`${e.table}:${e.name}`,o=new Map(t.map(e=>[a(e),e])),s=new Map(n.map(e=>[a(e),e])),c=Array.from(o.keys()),l=Array.from(s.keys());return i.added(c,l,e=>s.get(e)).forEach(e=>{r.push(B(e))}),i.removed(c,l,e=>{let t=o.get(e);return{table:t.table,name:t.name}}).forEach(e=>{r.push(V(e))}),i.changed(c,l,e=>{let t=o.get(e),n=s.get(e);return!p.equals(t.columns,n.columns)},e=>({current:o.get(e),ideal:s.get(e)})).forEach(({current:e,ideal:t})=>{r.push(V(e)),r.push(B(t))}),r}function Tt(e){let t=[],n=X(),r=e.current.map(Z),i=e.ideal.map(Z);return t.push(...n.added(r,i,t=>{let{table:n,name:r,...i}=e.ideal.find(e=>e.name===t);return H({table:n,name:r},i)})),t.push(...n.removed(r,i,t=>U(e.current.find(e=>e.name===t)))),t.push(...n.changed(r,i,t=>{let n=e.current.find(e=>e.name===t),r=e.ideal.find(e=>e.name===t);return!n||!r?!1:!(p.equals(n.columns,r.columns)&&n.referencedTable===r.referencedTable&&p.equals(n.referencedColumns,r.referencedColumns)&&n.onDelete===r.onDelete&&n.onUpdate===r.onUpdate)},t=>{let n=e.current.find(e=>e.name===t),{table:r,name:i,...a}=e.ideal.find(e=>e.name===t);return[U(n),H({table:r,name:i},a)]}).flat()),t}function Et(e){let t=xt({current:e.current.tables,ideal:e.ideal.tables}),n=St({current:e.current.indexes,ideal:e.ideal.indexes}),r=Ct({current:e.current.primaryKeyConstraints,ideal:e.ideal.primaryKeyConstraints}),i=wt({current:e.current.uniqueConstraints,ideal:e.ideal.uniqueConstraints}),a=Tt({current:e.current.foreignKeyConstraints,ideal:e.ideal.foreignKeyConstraints});return{operations:[...t,...n,...r,...i,...a]}}const Dt=e=>{let t=O(e.getDialect()).createIntrospectionDriver(e);return{introspect:async n=>{await using r=e.getDB();let i=await r.introspection.getTables(),{tables:a,indexes:o,constraints:s}=await t.introspect({config:n}),c=()=>i.map(e=>{let n={};for(let r of e.columns){let i=a.find(t=>t.table===e.name&&t.name===r.name);i&&(n[r.name]={schema:e.schema,table:e.name,name:r.name,dataType:t.convertTypeName(r.dataType),default:i.default??null,characterMaximumLength:i.characterMaximumLength??null,notNull:!r.isNullable})}return{schema:e.schema,name:e.name,columns:n}}),l=e=>!e.table.startsWith(`kysely_`);return{tables:c(),indexes:(()=>o.filter(l))(),constraints:(()=>({primaryKey:s.primaryKey.filter(l),unique:s.unique.filter(l),foreignKey:s.foreignKey.filter(l)}))()}}}},Q=async(e,t,n)=>{let r=O(t);return{manageType:n,instance:await r.createDevDatabaseProvider().setup(r.parseDevDatabaseConfig(e),n)}};async function Ot(e,t){let{config:n}=e,r=O(n.database.dialect);switch(t.mode){case`dev-start`:{let{instance:e,manageType:t}=await Q(n.dev,n.database.dialect,`dev-start`);return{manageType:t,manager:e,result:{reused:await e.isAvailable()}}}case`generate-dev`:{let e=await r.hasReusableDevDatabase(),{instance:t,manageType:i}=await Q(n.dev,n.database.dialect,e?`dev-start`:`one-off`);return{manageType:i,manager:t,result:{reused:e}}}}}async function kt(e,t){let{config:n}=e,{reporter:r}=t.logger||j;if(!n.dev)throw Error(`Dev database configuration is required`);let{manageType:i,manager:a,result:o}=await Ot(e,t);o.reused?r.info(`🔄 Reusing existing dev database...`):r.info(`🚀 Starting dev database...`),await a.start(),r.success(`Dev database started: ${n.database.dialect}`);let s=k({database:{dialect:n.database.dialect,connectionString:a.getConnectionString()}}),c=await J(e);return c.length>0?(r.info(`🔄 Applying ${c.length} pending migrations...`),await Y({client:s,logger:j,fs:e.fs,config:n},{plan:!1,pretty:!1}),r.success(`Applied ${c.length} migrations`)):r.info(`No pending migrations found`),{client:s,manager:a,cleanup:async()=>{switch(t.mode){case`dev-start`:r.success(`Persistent dev database ready: `+n.database.dialect);break;case`generate-dev`:i===`dev-start`?r.info(`Dev start container remains running`):(await a.stop(),r.success(`Temporary dev database stopped`));break}}}}async function At(e,t){let{logger:n,config:r,fs:i}=e,{reporter:a}=n;t.squash&&await jt(e);let{client:o,cleanup:s}=t.dev?await kt(e,{mode:`generate-dev`,logger:n}):{client:e.client,cleanup:async()=>void 0};try{if(!t.ignorePending){let n=await J(e);if(n.length>0)if(t.dev)a.info(`Dev database has ${n.length} pending migrations. These will be applied automatically as baseline.`);else{a.warn([`There are pending migrations: ${n.map(e=>e.id).join(`, `)}`,`Please apply them first before generating a new migration.`,`Otherwise, use --ignore-pending to skip this check.`].join(`
93
+ `));return}}let s=await Mt({client:o,config:r});if(!s){a.info(`No changes detected, no migration needed.`);return}Nt(n,s.diff);let c=`${q}/${s.id}.json`;await i.mkdir(q,{recursive:!0}),await i.writeFile(c,JSON.stringify(s,null,2));let l=t.squash?`Generated squashed migration: ${c}`:`Migration file generated: ${c}`;a.success(l),t.dev&&await Y({...e,client:o},{plan:!1,pretty:!1})}finally{await s()}}const jt=async e=>{let{logger:t,fs:n}=e,{reporter:r}=t,i=await J(e);if(i.length===0){r.info(`No pending migrations found, nothing to squash.`);return}r.info(`Found ${i.length} pending migrations to squash:`),i.forEach(e=>{r.info(` - ${e.id}.json`)});let a=i.map(e=>m(q,`${e.id}.json`));try{await Promise.all(a.map(e=>n.unlink(e))),r.success(`🗑️ Removed ${a.length} pending migration files`)}catch(e){throw Error(`Failed to remove pending migration files: ${e}`)}},Mt=async e=>{let{client:t,config:n}=e,{tables:r,indexes:i,constraints:a}=await Dt(t).introspect(n),o=(e,t)=>n=>n.some(n=>n.table===e&&n.columns.length===1&&n.columns[0]===t),s=r.map(e=>({name:e.name,columns:Object.fromEntries(Object.entries(e.columns).map(([t,n])=>{let r=o(e.name,t),i=r(a.primaryKey),s=r(a.unique),c=a.primaryKey.some(n=>n.table===e.name&&n.columns.length>1&&n.columns.includes(t))?!0:n.notNull;return[t,{type:n.dataType,notNull:c,defaultSql:n.default??void 0,primaryKey:i,unique:s}]}))})),c=n.tables.map(e=>({name:e.tableName,columns:Object.fromEntries(Object.entries(e.columns).map(([t,r])=>{let i=(n.primaryKeyConstraints??[]).some(n=>n.table===e.tableName&&n.columns.includes(t)),a=r.primaryKey||r.notNull||i;return[t,{...r,notNull:a}]}))})),l=Et({current:{tables:s,indexes:i,uniqueConstraints:a.unique,primaryKeyConstraints:a.primaryKey,foreignKeyConstraints:a.foreignKey},ideal:{...n,tables:c}});return l.operations.length===0?null:{version:`1`,id:Date.now()+``,diff:l}},Nt=(e,t)=>{let n=[];t.operations.forEach(e=>{switch(e.type){case`create_table`:n.push(`-- create_table: ${e.table}`),Object.entries(e.columns).forEach(([e,t])=>{n.push(` -> column: ${e} (${JSON.stringify(t)})`)});break;case`drop_table`:n.push(`-- remove_table: ${e.table}`);break;case`add_column`:n.push([`-- add_column: ${e.table}.${e.column}`,` -> to: ${JSON.stringify(e.attributes)}`].join(`
94
+ `));break;case`drop_column`:n.push(`-- remove_column: ${e.table}.${e.column}`);break;case`alter_column`:n.push([`-- change_column: ${e.table}.${e.column}`,` -> from: ${JSON.stringify(e.before)}`,` -> to: ${JSON.stringify(e.after)}`].join(`
95
+ `));break;case`create_index`:n.push(`-- create_index: ${e.table}.${e.name} (${e.columns.join(`, `)})${e.unique?` [unique]`:``}`);break;case`drop_index`:n.push(`-- drop_index: ${e.table}.${e.name}`);break;case`create_primary_key_constraint`:n.push(`-- create_primary_key_constraint: ${e.table}.${e.name} (${e.columns.join(`, `)})`);break;case`drop_primary_key_constraint`:n.push(`-- drop_primary_key_constraint: ${e.table}.${e.name}`);break;case`create_unique_constraint`:n.push(`-- create_unique_constraint: ${e.table}.${e.name} (${e.columns.join(`, `)})`);break;case`drop_unique_constraint`:n.push(`-- drop_unique_constraint: ${e.table}.${e.name}`);break;case`create_foreign_key_constraint`:n.push(`-- create_foreign_key_constraint: ${e.table}.${e.name} (${e.columns.join(`, `)}) -> ${e.referencedTable} (${e.referencedColumns.join(`, `)})${e.onDelete?` ON DELETE ${e.onDelete.toUpperCase()}`:``}${e.onUpdate?` ON UPDATE ${e.onUpdate.toUpperCase()}`:``}`);break;case`drop_foreign_key_constraint`:n.push(`-- drop_foreign_key_constraint: ${e.table}.${e.name}`);break;default:break}}),e.reporter.log(n.join(`
96
+ `))},Pt=e({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{await At(await M(),{ignorePending:e.args[`ignore-pending`],dev:e.args.dev,squash:e.args.squash})}catch(e){A.reporter.error(e),process.exit(1)}}});async function Ft(e){let{manager:t,logger:n}=e,r=await t.getStatus();if(!r||r.type!==`container`){n.reporter.info(`No running dev containers found`);return}n.reporter.info(`Running: ${r.containerID} (${r.imageName})`)}async function It(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 Lt(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 Rt(e){let{logger:t}=e,{reporter:n}=t,{manager:r}=await kt(e,{mode:`dev-start`,logger:t});n.success(`✨ Dev database ready: ${r.getConnectionString()}`)}async function $(){let e=await M();if(!e.config.dev)throw Error(`No dev database configuration found`);let{instance:t}=await Q(e.config.dev,e.config.database.dialect,`dev-start`);return{...e,manager:t}}const zt=e({meta:{name:`start`,description:`Start development database with migrations applied`},run:async()=>{try{await Rt(await M())}catch(e){A.reporter.error(e),process.exit(1)}}}),Bt=e({meta:{name:`status`,description:`Show status of kyrage dev container`},run:async()=>{try{await Ft(await $())}catch(e){A.reporter.error(e),process.exit(1)}}}),Vt=e({meta:{name:`get-url`,description:`Print connection URL for running dev container`},run:async()=>{try{await It(await $())}catch(e){A.reporter.error(e),process.exit(1)}}}),Ht=e({meta:{name:`clean`,description:`Remove all kyrage dev containers`},run:async()=>{try{await Lt(await $())}catch(e){A.reporter.error(e),process.exit(1)}}}),Ut=e({meta:{name:`dev`,description:`Manage development database containers`},subCommands:{start:zt,status:Bt,"get-url":Vt,clean:Ht}});t(e({meta:{name:`kyrage`,version:le,description:`Kysely migration CLI with declarative schema`},subCommands:{apply:vt,generate:Pt,dev:Ut}}));export{};
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.2",
5
+ "version": "1.5.5",
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",
@@ -22,45 +22,45 @@
22
22
  ],
23
23
  "exports": {
24
24
  ".": {
25
- "types": "./dist/index.d.ts",
26
- "default": "./dist/index.js"
25
+ "types": "./dist/index.d.mts",
26
+ "default": "./dist/index.mjs"
27
27
  }
28
28
  },
29
29
  "bin": {
30
- "kyrage": "./dist/main.js"
30
+ "kyrage": "./dist/main.mjs"
31
31
  },
32
32
  "dependencies": {
33
- "@testcontainers/cockroachdb": "^11.7.1",
34
- "@testcontainers/postgresql": "^11.7.1",
33
+ "@testcontainers/cockroachdb": "^11.11.0",
34
+ "@testcontainers/postgresql": "^11.11.0",
35
35
  "better-sqlite3": "^12.4.1",
36
- "c12": "^3.3.0",
36
+ "c12": "^3.3.3",
37
37
  "citty": "^0.1.6",
38
38
  "consola": "^3.4.2",
39
39
  "graph-data-structure": "^4.5.0",
40
40
  "kysely": "^0.28.8",
41
- "mysql2": "^3.15.2",
41
+ "mysql2": "^3.16.0",
42
42
  "pg": "^8.16.3",
43
- "ramda": "^0.31.3",
43
+ "ramda": "^0.32.0",
44
44
  "sql-formatter": "^15.6.10",
45
- "testcontainers": "^11.7.1",
45
+ "testcontainers": "^11.11.0",
46
46
  "zod": "^4.1.12"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@swc/core": "^1.13.5",
50
50
  "@types/better-sqlite3": "^7.6.13",
51
- "@types/node": "^24",
51
+ "@types/node": "^25",
52
52
  "@types/pg": "^8.15.5",
53
53
  "@types/ramda": "^0.31.1",
54
54
  "memfs": "^4.49.0",
55
55
  "prettier": "^3",
56
- "tsup": "^8.5.0",
56
+ "tsdown": "^0.18.4",
57
57
  "typescript": "^5",
58
58
  "vitest": "^3.2.4"
59
59
  },
60
60
  "scripts": {
61
- "dev": "NODE_ENV=development tsup --watch",
62
- "build": "tsup",
63
- "type-check": "tsc --noEmit --incremental --pretty",
61
+ "dev": "NODE_ENV=development tsdown --watch",
62
+ "build": "tsdown",
63
+ "type-check": "tsc",
64
64
  "test": "vitest run"
65
65
  }
66
66
  }
@@ -1 +0,0 @@
1
- var k=(c,a)=>(a=Symbol[c])?a:Symbol.for("Symbol."+c),l=c=>{throw TypeError(c)};var m=(c,a,d)=>{if(a!=null){typeof a!="object"&&typeof a!="function"&&l("Object expected");var e,f;d&&(e=a[k("asyncDispose")]),e===void 0&&(e=a[k("dispose")],d&&(f=e)),typeof e!="function"&&l("Object not disposable"),f&&(e=function(){try{f.call(this)}catch(g){return Promise.reject(g)}}),c.push([d,e,a])}else d&&c.push([d]);return a},n=(c,a,d)=>{var e=typeof SuppressedError=="function"?SuppressedError:function(b,j,h,i){return i=Error(h),i.name="SuppressedError",i.error=b,i.suppressed=j,i},f=b=>a=d?new e(b,a,"An error was suppressed during disposal"):(d=!0,b),g=b=>{for(;b=c.pop();)try{var j=b[1]&&b[1].call(b[2]);if(b[0])return Promise.resolve(j).then(g,h=>(f(h),g()))}catch(h){f(h)}if(d)throw a};return g()};export{m as a,n as b};
package/dist/index.d.ts DELETED
@@ -1,199 +0,0 @@
1
- import { ColumnDataType } from 'kysely';
2
- import z from 'zod';
3
-
4
- declare const columnSchema: z.ZodObject<{
5
- type: z.ZodString;
6
- primaryKey: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
7
- notNull: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
- unique: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
9
- defaultSql: z.ZodOptional<z.ZodString>;
10
- }, z.core.$strip>;
11
- type ColumnValue = z.infer<typeof columnSchema>;
12
- declare const indexSchema: z.ZodObject<{
13
- columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
14
- unique: z.ZodDefault<z.ZodBoolean>;
15
- table: z.ZodString;
16
- name: z.ZodString;
17
- }, z.core.$strip>;
18
- type IndexSchema = z.infer<typeof indexSchema>;
19
- declare const databaseSchema: z.ZodObject<{
20
- dialect: z.ZodEnum<{
21
- postgres: "postgres";
22
- cockroachdb: "cockroachdb";
23
- }>;
24
- connectionString: z.ZodString;
25
- }, z.core.$strip>;
26
- type DatabaseValue = z.infer<typeof databaseSchema>;
27
- declare const devDatabaseSchema: z.ZodUnion<readonly [z.ZodObject<{
28
- container: z.ZodObject<{
29
- image: z.ZodDefault<z.ZodString>;
30
- name: z.ZodOptional<z.ZodString>;
31
- }, z.core.$strip>;
32
- }, z.core.$strip>]>;
33
- type DevDatabaseValue = z.infer<typeof devDatabaseSchema>;
34
-
35
- declare const primaryKeyConstraintSchema: z.ZodObject<{
36
- columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
37
- table: z.ZodString;
38
- name: z.ZodString;
39
- }, z.core.$strip>;
40
- type PrimaryKeyConstraintSchema = z.infer<typeof primaryKeyConstraintSchema>;
41
- declare const uniqueConstraintSchema: z.ZodObject<{
42
- columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
43
- table: z.ZodString;
44
- name: z.ZodString;
45
- }, z.core.$strip>;
46
- type UniqueConstraintSchema = z.infer<typeof uniqueConstraintSchema>;
47
- declare const referentialActionsSchema: z.ZodEnum<{
48
- cascade: "cascade";
49
- "set null": "set null";
50
- "set default": "set default";
51
- restrict: "restrict";
52
- "no action": "no action";
53
- }>;
54
- type ReferentialActions = z.infer<typeof referentialActionsSchema>;
55
-
56
- /**
57
- * Defines a column in a table.
58
- */
59
- declare const column: (type: ColumnDataType, options?: Partial<Omit<ColumnValue, "type">>) => {
60
- type: ColumnDataType;
61
- notNull: boolean | undefined;
62
- primaryKey: boolean | undefined;
63
- unique: boolean | undefined;
64
- defaultSql: string | undefined;
65
- };
66
- type DefinedValue<T, K extends string> = Omit<T, "table"> & {
67
- kind: K;
68
- };
69
- type DefinedColumn = ReturnType<typeof column>;
70
- type DefinedIndex = DefinedValue<IndexSchema, "index">;
71
- type DefinedPrimaryKeyConstraint = DefinedValue<PrimaryKeyConstraintSchema, "primaryKey">;
72
- type DefinedUniqueConstraint = DefinedValue<UniqueConstraintSchema, "unique">;
73
- type DefinedForeignKeyConstraint = {
74
- kind: "foreignKey";
75
- name: string;
76
- columns: ReadonlyArray<string>;
77
- referencedTable: string;
78
- referencedColumns: ReadonlyArray<string>;
79
- onDelete?: ReferentialActions;
80
- onUpdate?: ReferentialActions;
81
- inline?: boolean;
82
- };
83
- type ExpressionBuilders<T extends Record<string, DefinedColumn>> = {
84
- /**
85
- * Creates an index on the specified columns.
86
- *
87
- * The default is non-unique, and name is autogenerated by joining the column names and table name.
88
- */
89
- index: (columns: ReadonlyArray<string & keyof T>, options?: {
90
- name?: string;
91
- unique?: boolean;
92
- }) => DefinedIndex;
93
- /**
94
- * Creates a primary key constraint on the specified columns.
95
- *
96
- * The default name is autogenerated by joining the column names and table name.
97
- */
98
- primaryKey: (columns: ReadonlyArray<string & keyof T>, options?: {
99
- name?: string;
100
- }) => DefinedPrimaryKeyConstraint;
101
- /**
102
- * Creates a unique constraint on the specified columns.
103
- *
104
- * The default name is autogenerated by joining the column names and table name.
105
- */
106
- unique: (columns: ReadonlyArray<string & keyof T>, options?: {
107
- name?: string;
108
- }) => DefinedUniqueConstraint;
109
- /**
110
- * Creates a foreign key constraint on the specified columns.
111
- *
112
- * The default name is autogenerated by joining the column names and table name.
113
- */
114
- reference: <R extends Record<string, DefinedColumn>>(columns: ReadonlyArray<string & keyof T> | (string & keyof T), referencedTable: {
115
- tableName: string;
116
- columns: R;
117
- }, referencedColumns: ReadonlyArray<string & keyof R> | (string & keyof R), options?: {
118
- name?: string;
119
- onDelete?: ReferentialActions;
120
- onUpdate?: ReferentialActions;
121
- inline?: boolean;
122
- }) => DefinedForeignKeyConstraint;
123
- };
124
- /**
125
- * Defines a table with its columns and optional expression builders.
126
- */
127
- declare const defineTable: <T extends Record<string, DefinedColumn>>(
128
- /**
129
- * The name of the table.
130
- */
131
- name: string,
132
- /**
133
- * The columns in the table.
134
- */
135
- columns: T,
136
- /**
137
- * The expression builders for the table.
138
- *
139
- * This is where you can define additional indexes, constraints, or other
140
- * database-specific features for the table.
141
- */
142
- tableExpBuilder?: (builder: ExpressionBuilders<T>) => ReadonlyArray<ReturnType<ExpressionBuilders<T>["index"]> | ReturnType<ExpressionBuilders<T>["primaryKey"]> | ReturnType<ExpressionBuilders<T>["unique"]> | ReturnType<ExpressionBuilders<T>["reference"]>>) => {
143
- tableName: string;
144
- columns: T;
145
- indexes: DefinedIndex[];
146
- primaryKeys: DefinedPrimaryKeyConstraint[];
147
- uniques: DefinedUniqueConstraint[];
148
- foreignKeys: DefinedForeignKeyConstraint[];
149
- };
150
- type DefinedTable = ReturnType<typeof defineTable> & {
151
- indexes: ReadonlyArray<DefinedIndex>;
152
- primaryKeys: ReadonlyArray<DefinedPrimaryKeyConstraint>;
153
- uniques: ReadonlyArray<DefinedUniqueConstraint>;
154
- foreignKeys: ReadonlyArray<DefinedForeignKeyConstraint>;
155
- };
156
- type DefinedTables = ReadonlyArray<DefinedTable>;
157
- type DefineConfigProp = {
158
- database: DatabaseValue;
159
- dev?: DevDatabaseValue;
160
- tables: DefinedTables;
161
- };
162
- declare const defineConfig: (config: DefineConfigProp) => {
163
- readonly dev: {
164
- container: {
165
- image: string;
166
- name?: string | undefined;
167
- };
168
- } | undefined;
169
- readonly indexes: {
170
- columns: readonly string[];
171
- unique: boolean;
172
- table: string;
173
- name: string;
174
- }[];
175
- readonly primaryKeyConstraints: {
176
- columns: readonly string[];
177
- table: string;
178
- name: string;
179
- }[];
180
- readonly uniqueConstraints: {
181
- columns: readonly string[];
182
- table: string;
183
- name: string;
184
- }[];
185
- readonly foreignKeyConstraints: {
186
- columns: readonly string[];
187
- referencedTable: string;
188
- referencedColumns: readonly string[];
189
- table: string;
190
- name: string;
191
- onDelete?: "cascade" | "set null" | "set default" | "restrict" | "no action" | undefined;
192
- onUpdate?: "cascade" | "set null" | "set default" | "restrict" | "no action" | undefined;
193
- inline?: boolean | undefined;
194
- }[];
195
- readonly database: DatabaseValue;
196
- readonly tables: DefinedTables;
197
- };
198
-
199
- export { type DefineConfigProp, type DefinedTable, type DefinedTables, column, defineConfig, defineTable };
package/dist/index.js DELETED
@@ -1 +0,0 @@
1
- import"./chunk-EY62Q3Z2.js";var f=(i,r)=>r.length===1?`${i}_${r[0]}_primary_key`:`pk_${i}_${r.join("_")}`,c=(i,r)=>r.length===1?`${i}_${r[0]}_unique`:`uq_${i}_${r.join("_")}`,p=(i,r)=>`idx_${i}_${r.join("_")}`,g=(i,r)=>`fk_${i}_${r.join("_")}`,m={primaryKey:f,unique:c,index:p,foreignKey:g};var D=(i,r)=>({type:i,notNull:r?.notNull,primaryKey:r?.primaryKey,unique:r?.unique,defaultSql:r?.defaultSql}),K=(i,r,y)=>{let t=e=>{if(e.length===0)throw new Error("At least one column must be specified.")},l=(e,n)=>`${e}_${i}_${n.join("_")}`,a=y?y({index:(e,n)=>(t(e),{kind:"index",name:n?.name??l("idx",e),columns:e,unique:n?.unique??!1}),primaryKey:(e,n)=>(t(e),{kind:"primaryKey",name:n?.name??l("pk",e),columns:e}),unique:(e,n)=>(t(e),{kind:"unique",name:n?.name??l("uq",e),columns:e}),reference:(e,n,u,o)=>{let s=Array.isArray(e)?e:[e],d=Array.isArray(u)?u:[u];return t(s),t(d),{kind:"foreignKey",name:o?.name??m.foreignKey(i,s),columns:s,referencedTable:n.tableName,referencedColumns:d,onDelete:o?.onDelete,onUpdate:o?.onUpdate,inline:o?.inline??!0}}}):[];return{tableName:i,columns:r,indexes:a.filter(e=>e.kind==="index"),primaryKeys:a.filter(e=>e.kind==="primaryKey"),uniques:a.filter(e=>e.kind==="unique"),foreignKeys:a.filter(e=>e.kind==="foreignKey")}},R=i=>{let r=new Map,y=new Map,t=new Map,l=new Map;for(let a of i.tables){let e=a.tableName;for(let n of a.indexes??[])r.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns,unique:n.unique});for(let n of a.primaryKeys??[])y.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns});for(let n of a.uniques??[])t.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns});for(let n of a.foreignKeys??[])l.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns,referencedTable:n.referencedTable,referencedColumns:n.referencedColumns,onDelete:n.onDelete,onUpdate:n.onUpdate,inline:n.inline});for(let[n,u]of Object.entries(a.columns)){if(u.primaryKey){let o=m.primaryKey(e,[n]),s=`${e}:${o}`;y.has(s)||y.set(s,{table:e,name:o,columns:[n]})}if(u.unique){let o=m.unique(e,[n]),s=`${e}:${o}`;t.has(s)||t.set(s,{table:e,name:o,columns:[n]})}}}return{...i,dev:i.dev,indexes:Array.from(r.values()),primaryKeyConstraints:Array.from(y.values()),uniqueConstraints:Array.from(t.values()),foreignKeyConstraints:Array.from(l.values())}};export{D as column,R as defineConfig,K as defineTable};
package/dist/main.d.ts DELETED
@@ -1,2 +0,0 @@
1
-
2
- export { }
package/dist/main.js DELETED
@@ -1,96 +0,0 @@
1
- import{a as N,b as A}from"./chunk-EY62Q3Z2.js";import{defineCommand as Qn,runMain as Wn}from"citty";var qe="1.5.2";import{defineCommand as _n}from"citty";import f from"zod";import{loadConfig as Et}from"c12";import b from"zod";var O=b.object({type:b.string()}).catchall(b.any()),C=b.object({table:b.string(),name:b.string()}),I=b.object({table:b.string(),column:b.string()}),G=b.object({...C.shape,columns:b.array(b.string()).readonly()}),J=b.object({...C.shape,columns:b.array(b.string()).readonly()}),F=b.enum(["cascade","set null","set default","restrict","no action"]),Y=b.object({...C.shape,columns:b.array(b.string()).readonly(),referencedTable:b.string(),referencedColumns:b.array(b.string()).readonly(),onDelete:F.optional(),onUpdate:F.optional(),inline:b.boolean().optional()});import{getContainerRuntimeClient as me}from"testcontainers";import Z from"zod";var k=e=>Z.object({container:Z.object({image:Z.string().default(e.defaultImage),name:Z.string().optional()})}),q=class{constructor(t,n){this.dialect=t;this.containerFactory=n}async setup(t,n){return new le({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 $e()}},ce="kyrage.dialect",pe="kyrage.managed",ke="kyrage.managed-by",le=class{constructor(t){this.options=t;this.startedContainer=null;this.container=this.setupContainer()}setupContainer(){let t=this.options.containerFactory();return t.withLabels({[ce]:this.options.dialect,[pe]:"true",[ke]: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 $e(),this.startedContainer=null}getConnectionString(){if(!this.startedContainer)throw new Error("Container is not started");return this.startedContainer.getConnectionUri()}async getStatus(){let n=await(await me()).container.fetchByLabel(ce,this.options.dialect,{status:["running"]});if(n){let r=await n.inspect();return{type:"container",imageName:r.Config.Image,containerID:r.Id}}return{type:"unavailable"}}async isAvailable(){return(await this.getStatus()).type==="container"}},L=async e=>(await(await me()).container.list()).some(r=>r.Labels[pe]==="true"&&r.Labels[ke]==="dev-start"&&r.Labels[ce]===e&&r.State==="running"),$e=async()=>{let e=await me(),n=(await e.container.list()).filter(r=>r.Labels[pe]==="true").map(r=>r.Id);await Promise.allSettled(n.map(async r=>e.container.getById(r).remove({force:!0})))};var Kt=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()}),Pt=f.object({tableName:f.string(),columns:f.record(f.string(),Kt)}),Rt=f.object({...C.shape,columns:f.array(f.string()).readonly(),unique:f.boolean().default(!1)}),It=f.enum(["postgres","cockroachdb"]),qt=f.object({dialect:It,connectionString:f.string()}),kt=f.union([k({defaultImage:""})]),$t=f.object({database:qt,dev:kt.optional(),tables:f.array(Pt).readonly(),indexes:f.array(Rt).readonly(),primaryKeyConstraints:f.array(G).readonly(),uniqueConstraints:f.array(J).readonly(),foreignKeyConstraints:f.array(Y).readonly()}),Me=async()=>{let e=await Et({name:"kyrage"});return $t.parse(e.config)};import{Kysely as Jt}from"kysely";import{PostgresDialect as Mt,sql as ue}from"kysely";import{Pool as Ut}from"pg";import{PostgreSqlContainer as jt}from"@testcontainers/postgresql";import*as v from"ramda";var Ue=(e,t)=>{let n=m=>i=>v.any(v.whereEq({name:i.name,table:i.table}),m),[r,o]=v.partition(n(e.uniqueConstraints),t.constraints.unique),[l,a]=v.partition(n(e.indexes),t.indexes),c=v.reject(n(l),o),s=v.reject(n(r),a);return{indexes:[...l,...s],uniqueConstraints:[...r,...c]}};var X=class{getName(){return"postgres"}createKyselyDialect(t){return new Mt({pool:new Ut({connectionString:t})})}createIntrospectionDriver(t){return{convertTypeName:ye,introspect:de(t)}}createDevDatabaseProvider(){return new q(this.getName(),t=>new jt(t))}parseDevDatabaseConfig(t){return k({defaultImage:"postgres:16"}).parse(t)}async hasReusableDevDatabase(){return L(this.getName())}},de=e=>async t=>{var s=[];try{let n=N(s,e.getDB(),!0);let[r,o,l]=await Promise.all([Ft(n),Lt(n),Bt(n)]);let{indexes:a,uniqueConstraints:c}=Ue(t.config,{indexes:o,constraints:l});return{tables:r,indexes:a,constraints:{...l,unique:c}}}catch(m){var i=m,p=!0}finally{var u=A(s,i,p);u&&await u}},ye=e=>({bool:"boolean",int2:"smallint",int4:"integer",int8:"bigint"})[e]??e,Ft=async e=>{let{rows:t}=await ue`
2
- SELECT
3
- n.nspname AS table_schema,
4
- c.relname AS table_name,
5
- a.attname AS column_name,
6
- pg_get_expr(d.adbin, d.adrelid) AS column_default,
7
- CASE
8
- WHEN t.typname = 'varchar' OR t.typname = 'char' THEN a.atttypmod - 4
9
- ELSE NULL
10
- END AS character_maximum_length
11
- FROM pg_class c
12
- JOIN pg_namespace n ON n.oid = c.relnamespace
13
- JOIN pg_attribute a ON a.attrelid = c.oid
14
- LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = a.attnum
15
- JOIN pg_type t ON t.oid = a.atttypid
16
- WHERE c.relkind = 'r'
17
- AND n.nspname = 'public'
18
- AND a.attnum > 0
19
- AND NOT a.attisdropped
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}))},Lt=async e=>{let{rows:t}=await ue`
22
- SELECT
23
- t.relname AS table_name,
24
- c.relname AS index_name,
25
- i.indisunique AS is_unique,
26
- jsonb_agg(a.attname ORDER BY array_position(i.indkey, a.attnum)) AS column_names
27
- FROM pg_class t
28
- JOIN pg_namespace n ON n.oid = t.relnamespace
29
- JOIN pg_index i ON i.indrelid = t.oid
30
- JOIN pg_class c ON c.oid = i.indexrelid
31
- JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY (i.indkey)
32
- WHERE t.relkind = 'r'
33
- AND n.nspname = 'public'
34
- AND NOT i.indisprimary
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}))},Bt=async e=>{let{rows:t}=await ue`
37
- SELECT
38
- n.nspname AS schema,
39
- t.relname AS table,
40
- c.conname AS name,
41
- CASE c.contype
42
- WHEN 'p' THEN 'PRIMARY KEY'
43
- WHEN 'u' THEN 'UNIQUE'
44
- WHEN 'f' THEN 'FOREIGN KEY'
45
- END AS type,
46
- jsonb_agg(a.attname ORDER BY array_position(c.conkey, a.attnum)) AS columns,
47
- -- Foreign Key専用の情報
48
- CASE
49
- WHEN c.contype = 'f' THEN rt.relname
50
- ELSE NULL
51
- END AS referenced_table,
52
- CASE
53
- WHEN c.contype = 'f' THEN jsonb_agg(ra.attname ORDER BY array_position(c.confkey, ra.attnum))
54
- ELSE NULL
55
- END AS referenced_columns,
56
- CASE
57
- WHEN c.contype = 'f' THEN
58
- CASE c.confdeltype
59
- WHEN 'c' THEN 'cascade'
60
- WHEN 'n' THEN 'set null'
61
- WHEN 'd' THEN 'set default'
62
- WHEN 'r' THEN 'restrict'
63
- WHEN 'a' THEN 'no action'
64
- END
65
- ELSE NULL
66
- END AS on_delete,
67
- CASE
68
- WHEN c.contype = 'f' THEN
69
- CASE c.confupdtype
70
- WHEN 'c' THEN 'cascade'
71
- WHEN 'n' THEN 'set null'
72
- WHEN 'd' THEN 'set default'
73
- WHEN 'r' THEN 'restrict'
74
- WHEN 'a' THEN 'no action'
75
- END
76
- ELSE NULL
77
- END AS on_update
78
- FROM pg_constraint c
79
- JOIN pg_class t ON c.conrelid = t.oid
80
- JOIN pg_namespace n ON t.relnamespace = n.oid
81
- JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey)
82
- -- Foreign Key用のJOIN
83
- LEFT JOIN pg_class rt ON c.confrelid = rt.oid
84
- LEFT JOIN pg_attribute ra ON ra.attrelid = c.confrelid AND ra.attnum = ANY(c.confkey)
85
- WHERE c.contype IN ('p', 'u', 'f') -- primary key, unique, foreign key constraints
86
- AND n.nspname = 'public'
87
- AND NOT a.attisdropped
88
- AND (c.contype != 'f' OR NOT ra.attisdropped) -- Foreign Key用の条件
89
- GROUP BY n.nspname, t.relname, c.conname, c.contype, c.oid, c.conkey, t.oid,
90
- rt.relname, c.confkey, c.confdeltype, c.confupdtype
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:r,referenced_columns:o,on_delete:l,on_update:a,...c}=n;return{...c,referencedTable:r,referencedColumns:o,onDelete:l,onUpdate:a}})}};import{CockroachDbContainer as zt}from"@testcontainers/cockroachdb";import{Pool as Ht}from"pg";import{PostgresAdapter as Vt,PostgresDialect as Qt}from"kysely";var ee=class{getName(){return"cockroachdb"}createKyselyDialect(t){return new ge({pool:new Ht({connectionString:t})})}createIntrospectionDriver(t){let n=["rowid"];return{convertTypeName:ye,introspect:async r=>{let o=await de(t)(r);return{tables:o.tables.filter(a=>!n.includes(a.name)),indexes:o.indexes,constraints:o.constraints}}}}createDevDatabaseProvider(){return new q(this.getName(),t=>new zt(t))}parseDevDatabaseConfig(t){return k({defaultImage:"cockroachdb/cockroach:latest-v24.3"}).parse(t)}async hasReusableDevDatabase(){return L(this.getName())}},fe=class extends Vt{async acquireMigrationLock(t,n){await t.selectFrom(n.lockTable).selectAll().forUpdate().execute()}},ge=class extends Qt{createAdapter(){return new fe}};var Wt={postgres:new X,cockroachdb:new ee},w=e=>{let t=Wt[e];if(!t)throw new Error(`Unsupported dialect: ${e}`);return t};import{DummyDriver as Gt}from"kysely";var te=class extends Gt{constructor(n){super();this.queries=n}async acquireConnection(){return new be(this.queries)}},be=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 ne=e=>new he({databaseProps:e.database,options:e.options}),he=class{constructor(t){this.constructorProps=t}getDB(t){let n=w(this.constructorProps.databaseProps.dialect).createKyselyDialect(this.constructorProps.databaseProps.connectionString);return new Ce({dialect:{createAdapter:()=>n.createAdapter(),createDriver:()=>n.createDriver(),createIntrospector:r=>n.createIntrospector(r),createQueryCompiler:()=>n.createQueryCompiler()}},{isPlan:t?.plan===!0})}getDialect(){return this.constructorProps.databaseProps.dialect}},Ce=class extends Jt{constructor(n,r){let o=[];super({dialect:{...n.dialect,createDriver:()=>r.isPlan?new te(o):n.dialect.createDriver()}});this.plannedQueries=[];this.plannedQueries=o}getPlannedQueries(){return this.plannedQueries}};import{createConsola as Yt}from"consola";var Zt=Yt({stdout:process.stderr}),S={stdout:e=>console.log(e),reporter:{...Zt}},xe={stdout:()=>{},reporter:{info:()=>{},warn:()=>{},success:()=>{},log:()=>{},error:()=>{}}};import*as Xt from"fs/promises";async function E(){let e=await Me();return{client:ne({database:e.database}),logger:S,fs:Xt,config:e}}import{Migrator as On}from"kysely";import{DEFAULT_MIGRATION_TABLE as Dt}from"kysely";import{join as Cn}from"path";import V from"zod";import rn from"zod";import g from"zod";import B from"zod";import{sql as tn}from"kysely";import{isColumnDataType as en}from"kysely";var $=e=>{if(!en(e))throw new Error(`Unsupported data type: ${e}`)};var y=e=>e;var je=y({typeName:"create_table",schema:B.object({type:B.literal("create_table"),table:B.string(),columns:B.record(B.string(),O)}),execute:async(e,t)=>{let n=e.schema.createTable(t.table);n=De(n,t.columns),await n.execute()}}),Fe=(e,t)=>({type:"create_table",table:e,columns:t});function De(e,t){let n=e;for(let[r,o]of Object.entries(t)){let l=o.type;$(l),n=n.addColumn(r,l,a=>{let c=a;return o.notNull&&(c=c.notNull()),typeof o.defaultSql=="string"&&(c=c.defaultTo(tn.raw(o.defaultSql))),c})}return n}var Le=y({typeName:"create_table_with_constraints",schema:g.object({type:g.literal("create_table_with_constraints"),table:g.string(),columns:g.record(g.string(),O),constraints:g.object({primaryKey:g.object({name:g.string(),columns:g.array(g.string()).readonly()}).optional(),unique:g.array(g.object({name:g.string(),columns:g.array(g.string()).readonly()})).readonly().optional(),foreignKeys:g.array(g.object({name:g.string(),columns:g.array(g.string()).readonly(),referencedTable:g.string(),referencedColumns:g.array(g.string()).readonly(),onDelete:F.optional(),onUpdate:F.optional(),inline:g.boolean().optional()})).readonly().optional()}).optional()}),execute:async(e,t)=>{let n=e.schema.createTable(t.table);if(n=De(n,t.columns),t.constraints){let{primaryKey:r,unique:o,foreignKeys:l}=t.constraints;if(r&&(n=n.addPrimaryKeyConstraint(r.name,r.columns)),o)for(let a of o)n=n.addUniqueConstraint(a.name,a.columns);if(l)for(let a of l)n=n.addForeignKeyConstraint(a.name,a.columns,a.referencedTable,a.referencedColumns,c=>{let s=c;return a.onDelete&&(s=s.onDelete(a.onDelete)),a.onUpdate&&(s=s.onUpdate(a.onUpdate)),s})}await n.execute()}}),Be=(e,t,n)=>({type:"create_table_with_constraints",table:e,columns:t,constraints:{primaryKey:n?.primaryKey,unique:n?.unique??[],foreignKeys:n?.foreignKeys??[]}});import _e from"zod";var ze=y({typeName:"drop_table",schema:_e.object({type:_e.literal("drop_table"),table:_e.string()}),execute:async(e,t)=>{await e.schema.dropTable(t.table).execute()}}),He=e=>({type:"drop_table",table:e});import Ve from"zod";import{sql as nn}from"kysely";var Qe=y({typeName:"add_column",schema:Ve.object({...I.shape,type:Ve.literal("add_column"),attributes:O}),execute:async(e,t)=>{let n=t.attributes.type;$(n),await e.schema.alterTable(t.table).addColumn(t.column,n,r=>{let o=r;return t.attributes.notNull&&(o=o.notNull()),typeof t.attributes.defaultSql=="string"&&(o=o.defaultTo(nn.raw(t.attributes.defaultSql))),o}).execute()}}),We=(e,t)=>({...e,type:"add_column",attributes:t});import Ge from"zod";var Je=y({typeName:"drop_column",schema:Ge.object({...I.shape,type:Ge.literal("drop_column"),attributes:O}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropColumn(t.column).execute()}}),Ye=(e,t)=>({...e,type:"drop_column",attributes:t});import Ze from"zod";var Xe=y({typeName:"alter_column",schema:Ze.object({...I.shape,type:Ze.literal("alter_column"),before:O,after:O}),execute:async(e,t)=>{let{table:n,column:r,before:o,after:l}=t;if(o.type!==l.type){let a=l.type;$(a),await e.schema.alterTable(n).alterColumn(r,c=>c.setDataType(a)).execute()}l.notNull!==o.notNull&&(l.notNull?await e.schema.alterTable(n).alterColumn(r,a=>a.setNotNull()).execute():await e.schema.alterTable(n).alterColumn(r,a=>a.dropNotNull()).execute())}}),et=(e,t,n)=>({...e,type:"alter_column",before:t,after:n});import z from"zod";var tt=y({typeName:"create_index",schema:z.object({...C.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 r of t.columns)n=n.column(r);t.unique&&(n=n.unique()),await n.execute()}}),Oe=e=>({...e,type:"create_index"});import nt from"zod";var rt=y({typeName:"drop_index",schema:nt.object({...C.shape,type:nt.literal("drop_index")}),execute:async(e,t)=>{await e.schema.dropIndex(t.name).execute()}}),Se=e=>({...e,type:"drop_index"});import at from"zod";var ot=y({typeName:"create_primary_key_constraint",schema:at.object({...G.shape,type:at.literal("create_primary_key_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).addPrimaryKeyConstraint(t.name,t.columns).execute()}}),Te=e=>({...e,type:"create_primary_key_constraint"});import it from"zod";var st=y({typeName:"drop_primary_key_constraint",schema:it.object({...C.shape,type:it.literal("drop_primary_key_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),ve=e=>({...e,type:"drop_primary_key_constraint"});import ct from"zod";var lt=y({typeName:"create_unique_constraint",schema:ct.object({...J.shape,type:ct.literal("create_unique_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).addUniqueConstraint(t.name,t.columns).execute()}}),Ne=e=>({...e,type:"create_unique_constraint"});import mt from"zod";var pt=y({typeName:"drop_unique_constraint",schema:mt.object({...C.shape,type:mt.literal("drop_unique_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),Ae=e=>({...e,type:"drop_unique_constraint"});import ut from"zod";var dt=y({typeName:"create_foreign_key_constraint",schema:ut.object({...Y.shape,type:ut.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()}}),we=(e,t)=>({...e,...t,type:"create_foreign_key_constraint"});import yt from"zod";var ft=y({typeName:"drop_foreign_key_constraint",schema:yt.object({...C.shape,type:yt.literal("drop_foreign_key_constraint")}),execute:async(e,t)=>{await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}}),Ee=e=>({...e,type:"drop_foreign_key_constraint"});var gt=[Le,je,ze,Qe,Je,Xe,tt,rt,ot,st,lt,pt,dt,ft],bt=rn.union(gt.map(e=>e.schema));async function ht(e,t){return await an(t.type)(e,t)}function an(e){let t=gt.find(n=>n.typeName===e);if(!t)throw new Error(`Unknown operation type: ${e}`);return t.execute}import*as H from"ramda";import{Graph as on,topologicalSort as sn,CycleError as cn}from"graph-data-structure";var ln=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))},mn=e=>{let t=new Set;if(e.forEach(a=>{a.type==="create_table"&&t.add(a.table)}),t.size===0)return e;let n=new Map,r=new Map,o=[];e.forEach(a=>{a.type==="create_table"&&n.set(a.table,a)}),e.forEach(a=>{switch(a.type){case"create_table":return;case"create_primary_key_constraint":case"create_unique_constraint":if(t.has(a.table)){let c=r.get(a.table)||[];r.set(a.table,[...c,a])}else o.push(a);break;case"create_foreign_key_constraint":if(t.has(a.table)&&a.inline!==!1){let c=n.get(a.table),s=a.columns.filter(i=>!(i in c.columns));if(s.length>0)throw new Error(`Foreign key constraint "${a.name}" references non-existent columns: ${s.join(", ")}`);let m=r.get(a.table)||[];r.set(a.table,[...m,a])}else o.push(a);break;default:o.push(a);break}});let l=[];return n.forEach((a,c)=>{let s=r.get(c)||[];if(s.length===0){l.push(a);return}let m={unique:[],foreignKeys:[]};s.forEach(i=>{switch(i.type){case"create_primary_key_constraint":m.primaryKey=i;break;case"create_unique_constraint":m.unique.push(i);break;case"create_foreign_key_constraint":m.foreignKeys.push(i);break}}),l.push(Be(a.table,a.columns,m))}),[...l,...o]},pn=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 r=`${n.table}.${n.name}`;if(t.has(r))return!1}return!0})},Ke=e=>"table"in e?e.table:null,un=e=>{let t=new Set;return e.forEach(n=>{let r=Ke(n);r&&t.add(r)}),t},dn=e=>{switch(e.type){case"create_foreign_key_constraint":return[{table:e.table,referencedTable:e.referencedTable}];case"create_table_with_constraints":return(e.constraints?.foreignKeys||[]).map(t=>({table:e.table,referencedTable:t.referencedTable}));default:return[]}},yn=e=>{let t=new on;return e.forEach(n=>dn(n).forEach(r=>{r.table!==r.referencedTable&&(n.type!=="create_foreign_key_constraint"||n.inline!==!1)&&t.addEdge(r.referencedTable,r.table)})),t},fn=(e,t)=>{try{let n=yn(t),r=sn(n),o=new Set(r);return[...Array.from(e).filter(a=>!o.has(a)).sort(),...r]}catch(n){throw n instanceof cn?new Error("Circular dependency detected in foreign key constraints. Please resolve this by setting 'inline: false' for one of the foreign key constraints in each circular relationship."):n}},gn=e=>new Map(e.map((t,n)=>[t,n])),bn=e=>(t,n)=>{let r=Ct[t.type],o=Ct[n.type];if(r!==o)return r-o;let l=Ke(t),a=Ke(n);if(l&&a){let c=e.get(l)??Number.MAX_SAFE_INTEGER,s=e.get(a)??Number.MAX_SAFE_INTEGER;if(c!==s)return c-s}return(l||"").localeCompare(a||"")},Ct={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},hn=e=>H.sort(bn(H.pipe(un,t=>fn(t,e),gn)(e)),e),xt=H.pipe(ln,mn,pn,hn);var _t=e=>({getMigrations:async()=>{let t=await e.migrationsResolver(),n={};return t.forEach(r=>{n[r.id]={up:async o=>{for(let l of xt(r.diff.operations))await ht(o,l)}}}),n}}),xn=V.object({operations:V.array(bt).readonly()}),Dn=V.object({id:V.string(),version:V.string(),diff:xn}),M="migrations",Pe=async e=>{let{fs:t}=e;try{let r=(await t.readdir(M)).filter(o=>o.endsWith(".json")).map(async o=>Dn.parse(JSON.parse(await t.readFile(Cn(M,o),"utf-8"))));return await Promise.all(r)}catch(n){if(n instanceof Object&&"code"in n&&n.code==="ENOENT")return[];throw n}},K=async e=>{var c=[];try{let{client:t,fs:n}=e;let r=N(c,t.getDB(),!0);let o=await Pe({fs:n});let l=(await r.introspection.getTables({withInternalKyselyTables:!0})).map(u=>u.name);if(!l.includes(Dt))return o;let a=await r.selectFrom(Dt).select(["name","timestamp"]).$narrowType().execute();return o.filter(u=>!a.some(h=>h.name===u.id))}catch(s){var m=s,i=!0}finally{var p=A(c,m,i);p&&await p}};import{format as Sn}from"sql-formatter";async function Q(e,t){var p=[];try{let{client:n,logger:r}=e;let{reporter:o}=r;let l=N(p,n.getDB({plan:t.plan}),!0);let a=_t({migrationsResolver:async()=>t.plan?await K(e):await Pe(e),options:{plan:t.plan}});let c=new On({db:l,provider:a});let{results:s,error:m}=await c.migrateToLatest();let i=l.getPlannedQueries();if(i.length>0){i.forEach(_=>{r.stdout(t.pretty?Sn(_.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 h=u,x=!0}finally{var D=A(p,h,x);D&&await D}}var Ot=_n({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 Q(t,{plan:e.args.plan,pretty:e.args.pretty})}catch(t){S.reporter.error(t),process.exit(1)}}});import{defineCommand as Rn}from"citty";import{join as In}from"path";import*as d from"ramda";var U=()=>({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,r)=>d.pipe(d.intersection(e),d.filter(n),d.map(r))(t)}),re=d.prop("name"),Tn=d.eqBy(e=>[e.type,e.notNull??!1,e.primaryKey??!1,e.unique??!1]);function vn(e,t){let n=[],r=U(),o=e.columns,l=t.columns,a=Object.keys(o),c=Object.keys(l);return r.added(a,c,s=>({column:s,attributes:l[s]})).forEach(s=>{n.push(We({table:e.name,column:s.column},s.attributes))}),r.removed(a,c,s=>({column:s,attributes:o[s]})).forEach(s=>{n.push(Ye({table:e.name,column:s.column},s.attributes))}),r.changed(a,c,s=>!Tn(o[s],l[s]),s=>({column:s,before:o[s],after:l[s]})).forEach(s=>{n.push(et({table:e.name,column:s.column},s.before,s.after))}),n}function Nn(e){let{current:t,ideal:n}=e,r=[],o=U(),l=d.map(re,t),a=d.map(re,n);return o.added(l,a,c=>n.find(m=>m.name===c)).forEach(c=>{r.push(Fe(c.name,c.columns))}),o.removed(l,a,d.identity).forEach(c=>{r.push(He(c))}),d.filter(c=>n.some(s=>s.name===c.name))(t).forEach(c=>{let s=n.find(m=>m.name===c.name);r.push(...vn(c,s))}),r}function An(e){let{current:t,ideal:n}=e,r=[],o=U(),l=i=>`${i.table}:${i.name}`,a=new Map(t.map(i=>[l(i),i])),c=new Map(n.map(i=>[l(i),i])),s=Array.from(a.keys()),m=Array.from(c.keys());return o.added(s,m,i=>c.get(i)).forEach(i=>{r.push(Oe(i))}),o.removed(s,m,i=>{let p=a.get(i);return{table:p.table,name:p.name}}).forEach(i=>{r.push(Se(i))}),o.changed(s,m,i=>{let p=a.get(i),u=c.get(i);return!d.equals(p.columns,u.columns)||p.unique!==u.unique},i=>{let p=a.get(i),u=c.get(i);return{current:p,ideal:u}}).forEach(({current:i,ideal:p})=>{r.push(Se(i)),r.push(Oe(p))}),r}function wn(e){let{current:t,ideal:n}=e,r=[],o=U(),l=i=>`${i.table}:${i.name}`,a=new Map(t.map(i=>[l(i),i])),c=new Map(n.map(i=>[l(i),i])),s=Array.from(a.keys()),m=Array.from(c.keys());return o.added(s,m,i=>c.get(i)).forEach(i=>{r.push(Te(i))}),o.removed(s,m,i=>{let p=a.get(i);return{table:p.table,name:p.name}}).forEach(i=>{r.push(ve(i))}),o.changed(s,m,i=>{let p=a.get(i),u=c.get(i);return!d.equals(p.columns,u.columns)},i=>{let p=a.get(i),u=c.get(i);return{current:p,ideal:u}}).forEach(({current:i,ideal:p})=>{r.push(ve(i)),r.push(Te(p))}),r}function En(e){let{current:t,ideal:n}=e,r=[],o=U(),l=i=>`${i.table}:${i.name}`,a=new Map(t.map(i=>[l(i),i])),c=new Map(n.map(i=>[l(i),i])),s=Array.from(a.keys()),m=Array.from(c.keys());return o.added(s,m,i=>c.get(i)).forEach(i=>{r.push(Ne(i))}),o.removed(s,m,i=>{let p=a.get(i);return{table:p.table,name:p.name}}).forEach(i=>{r.push(Ae(i))}),o.changed(s,m,i=>{let p=a.get(i),u=c.get(i);return!d.equals(p.columns,u.columns)},i=>{let p=a.get(i),u=c.get(i);return{current:p,ideal:u}}).forEach(({current:i,ideal:p})=>{r.push(Ae(i)),r.push(Ne(p))}),r}function Kn(e){let t=[],n=U(),r=e.current.map(re),o=e.ideal.map(re);t.push(...n.added(r,o,a=>{let c=e.ideal.find(p=>p.name===a),{table:s,name:m,...i}=c;return we({table:s,name:m},i)})),t.push(...n.removed(r,o,a=>{let c=e.current.find(s=>s.name===a);return Ee(c)}));let l=a=>{let c=e.current.find(m=>m.name===a),s=e.ideal.find(m=>m.name===a);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(r,o,l,a=>{let c=e.current.find(u=>u.name===a),s=e.ideal.find(u=>u.name===a),{table:m,name:i,...p}=s;return[Ee(c),we({table:m,name:i},p)]}).flat()),t}function St(e){let t=Nn({current:e.current.tables,ideal:e.ideal.tables}),n=An({current:e.current.indexes,ideal:e.ideal.indexes}),r=wn({current:e.current.primaryKeyConstraints,ideal:e.ideal.primaryKeyConstraints}),o=En({current:e.current.uniqueConstraints,ideal:e.ideal.uniqueConstraints}),l=Kn({current:e.current.foreignKeyConstraints,ideal:e.ideal.foreignKeyConstraints});return{operations:[...t,...n,...r,...o,...l]}}var Tt=e=>{let n=w(e.getDialect()).createIntrospectionDriver(e);return{introspect:async o=>{var x=[];try{let l=N(x,e.getDB(),!0);let a=await l.introspection.getTables();let{tables:c,indexes:s,constraints:m}=await n.introspect({config:o});let i=()=>a.map(T=>{let R={};for(let j of T.columns){let se=c.find(Ie=>Ie.table===T.name&&Ie.name===j.name);se&&(R[j.name]={schema:T.schema,table:T.name,name:j.name,dataType:n.convertTypeName(j.dataType),default:se.default??null,characterMaximumLength:se.characterMaximumLength??null,notNull:!j.isNullable})}return{schema:T.schema,name:T.name,columns:R}});let p=T=>!T.table.startsWith("kysely_");let u=()=>s.filter(p);let h=()=>({primaryKey:m.primaryKey.filter(p),unique:m.unique.filter(p),foreignKey:m.foreignKey.filter(p)});return{tables:i(),indexes:u(),constraints:h()}}catch(D){var _=D,P=!0}finally{var ie=A(x,_,P);ie&&await ie}}}};var ae=async(e,t,n)=>{let r=w(t),o=await r.createDevDatabaseProvider().setup(r.parseDevDatabaseConfig(e),n);return{manageType:n,instance:o}};async function Pn(e,t){let{config:n}=e,r=w(n.database.dialect);switch(t.mode){case"dev-start":{let{instance:o,manageType:l}=await ae(n.dev,n.database.dialect,"dev-start");return{manageType:l,manager:o,result:{reused:await o.isAvailable()}}}case"generate-dev":{let o=await r.hasReusableDevDatabase(),{instance:l,manageType:a}=await ae(n.dev,n.database.dialect,o?"dev-start":"one-off");return{manageType:a,manager:l,result:{reused:o}}}}}async function oe(e,t){let{config:n}=e,r=t.logger||xe,{reporter:o}=r;if(!n.dev)throw new Error("Dev database configuration is required");let{manageType:l,manager:a,result:c}=await Pn(e,t);c.reused?o.info("\u{1F504} Reusing existing dev database..."):o.info("\u{1F680} Starting dev database..."),await a.start(),o.success(`Dev database started: ${n.database.dialect}`);let s=ne({database:{dialect:n.database.dialect,connectionString:a.getConnectionString()}}),m=await K(e);return m.length>0?(o.info(`\u{1F504} Applying ${m.length} pending migrations...`),await Q({client:s,logger:xe,fs:e.fs,config:n},{plan:!1,pretty:!1}),o.success(`Applied ${m.length} migrations`)):o.info("No pending migrations found"),{client:s,manager:a,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 a.stop(),o.success("Temporary dev database stopped"));break}}}}async function qn(e,t){let{logger:n,config:r,fs:o}=e,{reporter:l}=n;t.squash&&await kn(e);let{client:a,cleanup:c}=t.dev?await oe(e,{mode:"generate-dev",logger:n}):{client:e.client,cleanup:async()=>{}};try{if(!t.ignorePending){let p=await K(e);if(p.length>0)if(t.dev)l.info(`Dev database has ${p.length} pending migrations. These will be applied automatically as baseline.`);else{l.warn([`There are pending migrations: ${p.map(u=>u.id).join(", ")}`,"Please apply them first before generating a new migration.","Otherwise, use --ignore-pending to skip this check."].join(`
93
- `));return}}let s=await $n({client:a,config:r});if(!s){l.info("No changes detected, no migration needed.");return}Mn(n,s.diff);let m=`${M}/${s.id}.json`;await o.mkdir(M,{recursive:!0}),await o.writeFile(m,JSON.stringify(s,null,2));let i=t.squash?`Generated squashed migration: ${m}`:`Migration file generated: ${m}`;l.success(i),t.dev&&await Q({...e,client:a},{plan:!1,pretty:!1})}finally{await c()}}var kn=async e=>{let{logger:t,fs:n}=e,{reporter:r}=t,o=await K(e);if(o.length===0){r.info("No pending migrations found, nothing to squash.");return}r.info(`Found ${o.length} pending migrations to squash:`),o.forEach(a=>{r.info(` - ${a.id}.json`)});let l=o.map(a=>In(M,`${a.id}.json`));try{await Promise.all(l.map(a=>n.unlink(a))),r.success(`\u{1F5D1}\uFE0F Removed ${l.length} pending migration files`)}catch(a){throw new Error(`Failed to remove pending migration files: ${a}`)}},$n=async e=>{let{client:t,config:n}=e,r=Tt(t),{tables:o,indexes:l,constraints:a}=await r.introspect(n),c=(u,h)=>x=>x.some(D=>D.table===u&&D.columns.length===1&&D.columns[0]===h),s=o.map(u=>({name:u.name,columns:Object.fromEntries(Object.entries(u.columns).map(([h,x])=>{let D=c(u.name,h),_=D(a.primaryKey),P=D(a.unique),T=a.primaryKey.some(R=>R.table===u.name&&R.columns.length>1&&R.columns.includes(h))?!0:x.notNull;return[h,{type:x.dataType,notNull:T,defaultSql:x.default??void 0,primaryKey:_,unique:P}]}))})),m=n.tables.map(u=>({name:u.tableName,columns:Object.fromEntries(Object.entries(u.columns).map(([h,x])=>{let D=(n.primaryKeyConstraints??[]).some(P=>P.table===u.tableName&&P.columns.includes(h)),_=x.primaryKey||x.notNull||D;return[h,{...x,notNull:_}]}))})),i=St({current:{tables:s,indexes:l,uniqueConstraints:a.unique,primaryKeyConstraints:a.primaryKey,foreignKeyConstraints:a.foreignKey},ideal:{...n,tables:m}});return i.operations.length===0?null:{version:"1",id:Date.now()+"",diff:i}},Mn=(e,t)=>{let n=[];t.operations.forEach(r=>{switch(r.type){case"create_table":n.push(`-- create_table: ${r.table}`),Object.entries(r.columns).forEach(([o,l])=>{n.push(` -> column: ${o} (${JSON.stringify(l)})`)});break;case"drop_table":n.push(`-- remove_table: ${r.table}`);break;case"add_column":n.push([`-- add_column: ${r.table}.${r.column}`,` -> to: ${JSON.stringify(r.attributes)}`].join(`
94
- `));break;case"drop_column":n.push(`-- remove_column: ${r.table}.${r.column}`);break;case"alter_column":n.push([`-- change_column: ${r.table}.${r.column}`,` -> from: ${JSON.stringify(r.before)}`,` -> to: ${JSON.stringify(r.after)}`].join(`
95
- `));break;case"create_index":n.push(`-- create_index: ${r.table}.${r.name} (${r.columns.join(", ")})${r.unique?" [unique]":""}`);break;case"drop_index":n.push(`-- drop_index: ${r.table}.${r.name}`);break;case"create_primary_key_constraint":n.push(`-- create_primary_key_constraint: ${r.table}.${r.name} (${r.columns.join(", ")})`);break;case"drop_primary_key_constraint":n.push(`-- drop_primary_key_constraint: ${r.table}.${r.name}`);break;case"create_unique_constraint":n.push(`-- create_unique_constraint: ${r.table}.${r.name} (${r.columns.join(", ")})`);break;case"drop_unique_constraint":n.push(`-- drop_unique_constraint: ${r.table}.${r.name}`);break;case"create_foreign_key_constraint":n.push(`-- create_foreign_key_constraint: ${r.table}.${r.name} (${r.columns.join(", ")}) -> ${r.referencedTable} (${r.referencedColumns.join(", ")})${r.onDelete?` ON DELETE ${r.onDelete.toUpperCase()}`:""}${r.onUpdate?` ON UPDATE ${r.onUpdate.toUpperCase()}`:""}`);break;case"drop_foreign_key_constraint":n.push(`-- drop_foreign_key_constraint: ${r.table}.${r.name}`);break;default:break}}),e.reporter.log(n.join(`
96
- `))},vt=Rn({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 qn(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 W}from"citty";async function Un(e){let{manager:t,logger:n}=e,r=await t.getStatus();if(!r||r.type!=="container"){n.reporter.info("No running dev containers found");return}n.reporter.info(`Running: ${r.containerID} (${r.imageName})`)}async function jn(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 Fn(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 Ln(e){let{logger:t}=e,{reporter:n}=t,{manager:r}=await oe(e,{mode:"dev-start",logger:t});n.success(`\u2728 Dev database ready: ${r.getConnectionString()}`)}async function Re(){let e=await E();if(!e.config.dev)throw new Error("No dev database configuration found");let{instance:t}=await ae(e.config.dev,e.config.database.dialect,"dev-start");return{...e,manager:t}}var Bn=W({meta:{name:"start",description:"Start development database with migrations applied"},run:async()=>{try{let e=await E();await Ln(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),zn=W({meta:{name:"status",description:"Show status of kyrage dev container"},run:async()=>{try{let e=await Re();await Un(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),Hn=W({meta:{name:"get-url",description:"Print connection URL for running dev container"},run:async()=>{try{let e=await Re();await jn(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),Vn=W({meta:{name:"clean",description:"Remove all kyrage dev containers"},run:async()=>{try{let e=await Re();await Fn(e)}catch(e){S.reporter.error(e),process.exit(1)}}}),Nt=W({meta:{name:"dev",description:"Manage development database containers"},subCommands:{start:Bn,status:zn,"get-url":Hn,clean:Vn}});var Gn=Qn({meta:{name:"kyrage",version:qe,description:"Kysely migration CLI with declarative schema"},subCommands:{apply:Ot,generate:vt,dev:Nt}});Wn(Gn);