@izumisy/kyrage 0.6.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +165 -10
- package/dist/index.js +1 -1
- package/dist/main.js +100 -23
- package/package.json +7 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import { ColumnDataType } from 'kysely';
|
|
2
|
+
import z from 'zod';
|
|
3
3
|
|
|
4
4
|
declare const columnSchema: z.ZodObject<{
|
|
5
5
|
type: z.ZodString;
|
|
@@ -9,6 +9,13 @@ declare const columnSchema: z.ZodObject<{
|
|
|
9
9
|
defaultSql: z.ZodOptional<z.ZodString>;
|
|
10
10
|
}, z.core.$strip>;
|
|
11
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>;
|
|
12
19
|
declare const databaseSchema: z.ZodObject<{
|
|
13
20
|
dialect: z.ZodEnum<{
|
|
14
21
|
postgres: "postgres";
|
|
@@ -19,7 +26,39 @@ declare const databaseSchema: z.ZodObject<{
|
|
|
19
26
|
connectionString: z.ZodString;
|
|
20
27
|
}, z.core.$strip>;
|
|
21
28
|
type DatabaseValue = z.infer<typeof databaseSchema>;
|
|
29
|
+
declare const devDatabaseSchema: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
30
|
+
container: z.ZodObject<{
|
|
31
|
+
image: z.ZodString;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
34
|
+
connectionString: z.ZodString;
|
|
35
|
+
}, z.core.$strip>]>>;
|
|
36
|
+
type DevDatabaseValue = z.infer<typeof devDatabaseSchema>;
|
|
37
|
+
|
|
38
|
+
declare const primaryKeyConstraintSchema: z.ZodObject<{
|
|
39
|
+
columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
40
|
+
table: z.ZodString;
|
|
41
|
+
name: z.ZodString;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
type PrimaryKeyConstraintSchema = z.infer<typeof primaryKeyConstraintSchema>;
|
|
44
|
+
declare const uniqueConstraintSchema: z.ZodObject<{
|
|
45
|
+
columns: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
46
|
+
table: z.ZodString;
|
|
47
|
+
name: z.ZodString;
|
|
48
|
+
}, z.core.$strip>;
|
|
49
|
+
type UniqueConstraintSchema = z.infer<typeof uniqueConstraintSchema>;
|
|
50
|
+
declare const referentialActionsSchema: z.ZodEnum<{
|
|
51
|
+
cascade: "cascade";
|
|
52
|
+
"set null": "set null";
|
|
53
|
+
"set default": "set default";
|
|
54
|
+
restrict: "restrict";
|
|
55
|
+
"no action": "no action";
|
|
56
|
+
}>;
|
|
57
|
+
type ReferentialActions = z.infer<typeof referentialActionsSchema>;
|
|
22
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Defines a column in a table.
|
|
61
|
+
*/
|
|
23
62
|
declare const column: (type: ColumnDataType, options?: Partial<Omit<ColumnValue, "type">>) => {
|
|
24
63
|
type: ColumnDataType;
|
|
25
64
|
notNull: boolean | undefined;
|
|
@@ -27,19 +66,135 @@ declare const column: (type: ColumnDataType, options?: Partial<Omit<ColumnValue,
|
|
|
27
66
|
unique: boolean | undefined;
|
|
28
67
|
defaultSql: string | undefined;
|
|
29
68
|
};
|
|
69
|
+
type DefinedValue<T, K extends string> = Omit<T, "table"> & {
|
|
70
|
+
kind: K;
|
|
71
|
+
};
|
|
30
72
|
type DefinedColumn = ReturnType<typeof column>;
|
|
31
|
-
|
|
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
|
+
};
|
|
85
|
+
type ExpressionBuilders<T extends Record<string, DefinedColumn>> = {
|
|
86
|
+
/**
|
|
87
|
+
* Creates an index on the specified columns.
|
|
88
|
+
*
|
|
89
|
+
* The default is non-unique, and name is autogenerated by joining the column names and table name.
|
|
90
|
+
*/
|
|
91
|
+
index: (columns: ReadonlyArray<string & keyof T>, options?: {
|
|
92
|
+
name?: string;
|
|
93
|
+
unique?: boolean;
|
|
94
|
+
}) => DefinedIndex;
|
|
95
|
+
/**
|
|
96
|
+
* Creates a primary key constraint on the specified columns.
|
|
97
|
+
*
|
|
98
|
+
* The default name is autogenerated by joining the column names and table name.
|
|
99
|
+
*/
|
|
100
|
+
primaryKey: (columns: ReadonlyArray<string & keyof T>, options?: {
|
|
101
|
+
name?: string;
|
|
102
|
+
}) => DefinedPrimaryKeyConstraint;
|
|
103
|
+
/**
|
|
104
|
+
* Creates a unique constraint on the specified columns.
|
|
105
|
+
*
|
|
106
|
+
* The default name is autogenerated by joining the column names and table name.
|
|
107
|
+
*/
|
|
108
|
+
unique: (columns: ReadonlyArray<string & keyof T>, options?: {
|
|
109
|
+
name?: string;
|
|
110
|
+
}) => DefinedUniqueConstraint;
|
|
111
|
+
/**
|
|
112
|
+
* Creates a foreign key constraint on the specified columns.
|
|
113
|
+
*
|
|
114
|
+
* The default name is autogenerated by joining the column names and table name.
|
|
115
|
+
*/
|
|
116
|
+
reference: <R extends Record<string, DefinedColumn>>(columns: ReadonlyArray<string & keyof T> | (string & keyof T), referencedTable: {
|
|
117
|
+
tableName: string;
|
|
118
|
+
columns: R;
|
|
119
|
+
}, referencedColumns: ReadonlyArray<string & keyof R> | (string & keyof R), options?: {
|
|
120
|
+
name?: string;
|
|
121
|
+
onDelete?: ReferentialActions;
|
|
122
|
+
onUpdate?: ReferentialActions;
|
|
123
|
+
}) => DefinedForeignKeyConstraint;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Defines a table with its columns and optional expression builders.
|
|
127
|
+
*/
|
|
128
|
+
declare const defineTable: <T extends Record<string, DefinedColumn>>(
|
|
129
|
+
/**
|
|
130
|
+
* The name of the table.
|
|
131
|
+
*/
|
|
132
|
+
name: string,
|
|
133
|
+
/**
|
|
134
|
+
* The columns in the table.
|
|
135
|
+
*/
|
|
136
|
+
columns: T,
|
|
137
|
+
/**
|
|
138
|
+
* The expression builders for the table.
|
|
139
|
+
*
|
|
140
|
+
* This is where you can define additional indexes, constraints, or other
|
|
141
|
+
* database-specific features for the table.
|
|
142
|
+
*/
|
|
143
|
+
tableExpBuilder?: (builder: ExpressionBuilders<T>) => ReadonlyArray<ReturnType<ExpressionBuilders<T>["index"]> | ReturnType<ExpressionBuilders<T>["primaryKey"]> | ReturnType<ExpressionBuilders<T>["unique"]> | ReturnType<ExpressionBuilders<T>["reference"]>>) => {
|
|
32
144
|
tableName: string;
|
|
33
145
|
columns: T;
|
|
146
|
+
indexes: DefinedIndex[];
|
|
147
|
+
primaryKeys: DefinedPrimaryKeyConstraint[];
|
|
148
|
+
uniques: DefinedUniqueConstraint[];
|
|
149
|
+
foreignKeys: DefinedForeignKeyConstraint[];
|
|
34
150
|
};
|
|
35
|
-
type DefinedTable = ReturnType<typeof defineTable
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
151
|
+
type DefinedTable = ReturnType<typeof defineTable> & {
|
|
152
|
+
indexes: DefinedIndex[];
|
|
153
|
+
primaryKeys: DefinedPrimaryKeyConstraint[];
|
|
154
|
+
uniques: DefinedUniqueConstraint[];
|
|
155
|
+
foreignKeys: DefinedForeignKeyConstraint[];
|
|
156
|
+
};
|
|
157
|
+
type DefinedTables = ReadonlyArray<DefinedTable>;
|
|
158
|
+
type DefineConfigProp = {
|
|
41
159
|
database: DatabaseValue;
|
|
42
|
-
|
|
160
|
+
dev?: DevDatabaseValue;
|
|
161
|
+
tables: DefinedTables;
|
|
162
|
+
};
|
|
163
|
+
declare const defineConfig: (config: DefineConfigProp) => {
|
|
164
|
+
readonly dev: {
|
|
165
|
+
container: {
|
|
166
|
+
image: string;
|
|
167
|
+
};
|
|
168
|
+
} | {
|
|
169
|
+
connectionString: string;
|
|
170
|
+
} | undefined;
|
|
171
|
+
readonly indexes: {
|
|
172
|
+
columns: readonly string[];
|
|
173
|
+
unique: boolean;
|
|
174
|
+
table: string;
|
|
175
|
+
name: string;
|
|
176
|
+
}[];
|
|
177
|
+
readonly primaryKeyConstraints: {
|
|
178
|
+
columns: readonly string[];
|
|
179
|
+
table: string;
|
|
180
|
+
name: string;
|
|
181
|
+
}[];
|
|
182
|
+
readonly uniqueConstraints: {
|
|
183
|
+
columns: readonly string[];
|
|
184
|
+
table: string;
|
|
185
|
+
name: string;
|
|
186
|
+
}[];
|
|
187
|
+
readonly foreignKeyConstraints: {
|
|
188
|
+
columns: readonly string[];
|
|
189
|
+
referencedTable: string;
|
|
190
|
+
referencedColumns: readonly string[];
|
|
191
|
+
table: string;
|
|
192
|
+
name: string;
|
|
193
|
+
onDelete?: "cascade" | "set null" | "set default" | "restrict" | "no action" | undefined;
|
|
194
|
+
onUpdate?: "cascade" | "set null" | "set default" | "restrict" | "no action" | undefined;
|
|
195
|
+
}[];
|
|
196
|
+
readonly database: DatabaseValue;
|
|
197
|
+
readonly tables: DefinedTables;
|
|
43
198
|
};
|
|
44
199
|
|
|
45
|
-
export { type DefinedTable, type DefinedTables, column, defineConfig, defineTable };
|
|
200
|
+
export { type DefineConfigProp, type DefinedTable, type DefinedTables, column, defineConfig, defineTable };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./chunk-EY62Q3Z2.js";var t=(
|
|
1
|
+
import"./chunk-EY62Q3Z2.js";var f=(t,r)=>r.length===1?`${t}_${r[0]}_primary_key`:`pk_${t}_${r.join("_")}`,c=(t,r)=>r.length===1?`${t}_${r[0]}_unique`:`uq_${t}_${r.join("_")}`,p=(t,r)=>`idx_${t}_${r.join("_")}`,g=(t,r)=>`fk_${t}_${r.join("_")}`,l={primaryKey:f,unique:c,index:p,foreignKey:g};var D=(t,r)=>({type:t,notNull:r?.notNull,primaryKey:r?.primaryKey,unique:r?.unique,defaultSql:r?.defaultSql}),K=(t,r,y)=>{let a=e=>{if(e.length===0)throw new Error("At least one column must be specified.")},u=(e,n)=>`${e}_${t}_${n.join("_")}`,i=y?y({index:(e,n)=>(a(e),{kind:"index",name:n?.name??u("idx",e),columns:e,unique:n?.unique??!1}),primaryKey:(e,n)=>(a(e),{kind:"primaryKey",name:n?.name??u("pk",e),columns:e}),unique:(e,n)=>(a(e),{kind:"unique",name:n?.name??u("uq",e),columns:e}),reference:(e,n,m,o)=>{let s=Array.isArray(e)?e:[e],d=Array.isArray(m)?m:[m];return a(s),a(d),{kind:"foreignKey",name:o?.name??l.foreignKey(t,s),columns:s,referencedTable:n.tableName,referencedColumns:d,onDelete:o?.onDelete,onUpdate:o?.onUpdate}}}):[];return{tableName:t,columns:r,indexes:i.filter(e=>e.kind==="index"),primaryKeys:i.filter(e=>e.kind==="primaryKey"),uniques:i.filter(e=>e.kind==="unique"),foreignKeys:i.filter(e=>e.kind==="foreignKey")}},q=t=>{let r=new Map,y=new Map,a=new Map,u=new Map;for(let i of t.tables){let e=i.tableName;for(let n of i.indexes??[])r.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns,unique:n.unique});for(let n of i.primaryKeys??[])y.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns});for(let n of i.uniques??[])a.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns});for(let n of i.foreignKeys??[])u.set(`${e}:${n.name}`,{table:e,name:n.name,columns:n.columns,referencedTable:n.referencedTable,referencedColumns:n.referencedColumns,onDelete:n.onDelete,onUpdate:n.onUpdate});for(let[n,m]of Object.entries(i.columns)){if(m.primaryKey){let o=l.primaryKey(e,[n]),s=`${e}:${o}`;y.has(s)||y.set(s,{table:e,name:o,columns:[n]})}if(m.unique){let o=l.unique(e,[n]),s=`${e}:${o}`;a.has(s)||a.set(s,{table:e,name:o,columns:[n]})}}}return{...t,dev:t.dev,indexes:Array.from(r.values()),primaryKeyConstraints:Array.from(y.values()),uniqueConstraints:Array.from(a.values()),foreignKeyConstraints:Array.from(u.values())}};export{D as column,q as defineConfig,K as defineTable};
|
package/dist/main.js
CHANGED
|
@@ -1,24 +1,101 @@
|
|
|
1
|
-
import{a as b,b as h}from"./chunk-EY62Q3Z2.js";import{defineCommand as M,runMain as Ne}from"citty";import{Kysely as Y,MysqlDialect as G,PostgresDialect as W,SqliteDialect as H}from"kysely";import{Pool as A}from"pg";import{createPool as X}from"mysql2";import Z from"better-sqlite3";import{PostgresAdapter as U,PostgresDialect as V}from"kysely";var v=class extends U{async acquireMigrationLock(t,n){await t.selectFrom(n.lockTable).selectAll().forUpdate().execute()}},N=class extends V{createAdapter(){return new v}};import{DummyDriver as J}from"kysely";var D=class extends J{constructor(n){super();this.queries=n}async acquireConnection(){return new P(this.queries)}},P=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_migration"))return{rows:[]};this.queries.push(t)}return{rows:[]}}async*streamQuery(){}};var ee=e=>{switch(e.dialect){case"cockroachdb":return new N({pool:new A({connectionString:e.connectionString})});case"postgres":return new W({pool:new A({connectionString:e.connectionString})});case"mysql":return new G({pool:X(e.connectionString)});case"sqlite":return new H({database:new Z(e.connectionString)});default:throw new Error(`Unsupported dialect: ${e.dialect}`)}},S=e=>new E({databaseProps:e.database,options:e.options}),E=class{constructor(t){this.constructorProps=t;this.plannedQueries=[]}getDB(t){let n=ee(this.constructorProps.databaseProps),a=t?.plan===!0;return new Y({dialect:{createAdapter:()=>n.createAdapter(),createDriver:()=>a?new D(this.plannedQueries):n.createDriver(),createIntrospector:i=>n.createIntrospector(i),createQueryCompiler:()=>n.createQueryCompiler()}})}getPlannedQueries(){return this.plannedQueries}getDialect(){return this.constructorProps.databaseProps.dialect}};var O="0.6.0";import{z as c}from"zod";var ae=c.object({type:c.string(),primaryKey:c.boolean().optional().default(!1),notNull:c.boolean().optional().default(!1),unique:c.boolean().optional().default(!1),defaultSql:c.string().optional()}),oe=c.object({tableName:c.string(),columns:c.record(c.string(),ae)}),re=c.object({table:c.string(),columns:c.array(c.string()),unique:c.boolean().optional()}),ie=c.enum(["postgres","cockroachdb","mysql","sqlite"]),se=c.object({dialect:ie,connectionString:c.string()}),R=c.object({database:se,tables:c.array(oe),indexes:c.array(re).optional()}),j=c.object({id:c.string(),version:c.string(),diff:c.any()});import{Migrator as ge}from"kysely";import{isColumnDataType as le,sql as $}from"kysely";import{readdir as ce,readFile as me}from"fs/promises";import{join as pe}from"path";var w="migrations",I=async()=>{try{let t=(await ce(w)).filter(n=>n.endsWith(".json")).map(async n=>j.parse(JSON.parse(await me(pe(w,n),"utf-8"))));return await Promise.all(t)}catch(e){if(e instanceof Object&&"code"in e&&e.code==="ENOENT")return[];throw e}},Q=e=>({getMigrations:async()=>{let t=await I(),n={};return t.forEach(a=>{n[a.id]={up:async()=>{await ue(e.db,a.diff)}}}),n}});async function ue(e,t){for(let n of t.addedTables){let a=e.schema.createTable(n.table);for(let[i,s]of Object.entries(n.columns)){let l=s.type;k(l),a=a.addColumn(i,l,g=>{let o=g;return s.notNull&&(o=o.notNull()),s.primaryKey&&(o=o.primaryKey()),s.unique&&(o=o.unique()),s.defaultSql&&(o=o.defaultTo($.raw(s.defaultSql))),o})}await a.execute()}for(let n of t.removedTables)await e.schema.dropTable(n).execute();for(let n of t.changedTables){for(let a of n.addedColumns){let i=a.attributes.type;k(i),await e.schema.alterTable(n.table).addColumn(a.column,i,s=>{let l=s;return a.attributes.notNull&&(l=l.notNull()),a.attributes.primaryKey&&(l=l.primaryKey()),a.attributes.unique&&(l=l.unique()),a.attributes.defaultSql&&(l=l.defaultTo($.raw(a.attributes.defaultSql))),l}).execute()}for(let a of n.removedColumns)await e.schema.alterTable(n.table).dropColumn(a.column).execute();for(let a of n.changedColumns){if(a.before.type!==a.after.type){let i=a.after.type;k(i),await e.schema.alterTable(n.table).alterColumn(a.column,s=>s.setDataType(i)).execute()}a.after.notNull!==a.before.notNull&&(a.after.notNull?await e.schema.alterTable(n.table).alterColumn(a.column,i=>i.setNotNull()).execute():await e.schema.alterTable(n.table).alterColumn(a.column,i=>i.dropNotNull()).execute())}}}var k=e=>{if(!le(e))throw new Error(`Unsupported data type: ${e}`)};import{createConsola as de}from"consola";var d=de({stdout:process.stderr});import{format as fe}from"sql-formatter";var _=async e=>{var l=[];try{let t=b(l,e.client.getDB({plan:e.options.plan}),!0);let n=new ge({db:t,provider:Q({db:t,options:{plan:e.options.plan}})});let{results:a,error:i}=await n.migrateToLatest();let s=e.client.getPlannedQueries();if(s.length>0){s.forEach(r=>{console.log(e.options.pretty?fe(r.sql):r.sql)});return}a&&a.length>0?a.forEach(r=>{r.status==="Error"?d.error(`Migration failed: ${r.migrationName}`):r.status==="Success"&&d.success(`Migration applied: ${r.migrationName}`)}):d.info("No migrations to run");i&&(d.error(`Migration error: ${i}`),process.exit(1))}catch(g){var o=g,u=!0}finally{var f=h(l,o,u);f&&await f}};import{mkdir as he,writeFile as Ce}from"fs/promises";function K(e){let{current:t,ideal:n}=e,a=t.map(o=>o.name),i=n.map(o=>o.name),s=n.filter(o=>!a.includes(o.name)).map(o=>({table:o.name,columns:o.columns})),l=t.filter(o=>!i.includes(o.name)).map(o=>o.name),g=t.reduce((o,u)=>{let f=n.find(m=>m.name===u.name);if(!f)return o;let r=u.columns,p=f.columns,y=Object.keys(r),T=Object.keys(p),x=T.filter(m=>!y.includes(m)).map(m=>({column:m,attributes:p[m]})),C=y.filter(m=>!T.includes(m)).map(m=>({column:m,attributes:r[m]})),q=y.filter(m=>T.includes(m)&&(r[m].type!==p[m].type||r[m].notNull!==p[m].notNull)).map(m=>({column:m,before:r[m],after:p[m]}));return(x.length>0||C.length>0||q.length>0)&&o.push({table:u.name,addedColumns:x,removedColumns:C,changedColumns:q}),o},[]);return{addedTables:s,removedTables:l,changedTables:g}}import{sql as ye}from"kysely";var B=e=>{let t=async()=>{var g=[];try{let i=e.client;let s=b(g,i.getDB(),!0);let{rows:l}=await ye`
|
|
1
|
+
import{a as C,b as x}from"./chunk-EY62Q3Z2.js";import{defineCommand as z,runMain as Et}from"citty";import{Kysely as fe,MysqlDialect as be,PostgresDialect as he,SqliteDialect as _e}from"kysely";import{Pool as J}from"pg";import{createPool as Ce}from"mysql2";import xe from"better-sqlite3";import{PostgresAdapter as de,PostgresDialect as ye}from"kysely";var q=class extends de{async acquireMigrationLock(t,n){await t.selectFrom(n.lockTable).selectAll().forUpdate().execute()}},K=class extends ye{createAdapter(){return new q}};import{DummyDriver as ge}from"kysely";var A=class extends ge{constructor(n){super();this.queries=n}async acquireConnection(){return new k(this.queries)}},k=class{constructor(t){this.queries=t}async executeQuery(t){let n=t.query.kind;if(n==="CreateTableNode"||n==="DropTableNode"||n==="AlterTableNode"){if(t.query.table.table.identifier.name.startsWith("kysely_"))return{rows:[]};this.queries.push(t)}else(n==="CreateIndexNode"||n==="DropIndexNode")&&this.queries.push(t);return{rows:[]}}async*streamQuery(){}};var Ee=e=>{switch(e.dialect){case"cockroachdb":return new K({pool:new J({connectionString:e.connectionString})});case"postgres":return new he({pool:new J({connectionString:e.connectionString})});case"mysql":return new be({pool:Ce(e.connectionString)});case"sqlite":return new _e({database:new xe(e.connectionString)});default:throw new Error(`Unsupported dialect: ${e.dialect}`)}},D=e=>new I({databaseProps:e.database,options:e.options}),I=class{constructor(t){this.constructorProps=t}getDB(t){let n=Ee(this.constructorProps.databaseProps);return new $({dialect:{createAdapter:()=>n.createAdapter(),createDriver:()=>n.createDriver(),createIntrospector:a=>n.createIntrospector(a),createQueryCompiler:()=>n.createQueryCompiler()}},{isPlan:t?.plan===!0})}getDialect(){return this.constructorProps.databaseProps.dialect}},$=class extends fe{constructor(n,a){let o=[];super({dialect:{...n.dialect,createDriver:()=>a.isPlan?new A(o):n.dialect.createDriver()}});this.plannedQueries=[];this.plannedQueries=o}getPlannedQueries(){return this.plannedQueries}};var Y="1.0.0";import{Migrator as Qe}from"kysely";import{DEFAULT_MIGRATION_TABLE as Z,isColumnDataType as Se,sql as ne}from"kysely";import{readdir as Te,readFile as Oe}from"fs/promises";import{join as we}from"path";import T from"zod";import u from"zod";var S=u.object({type:u.string()}).catchall(u.any()),E=u.object({table:u.string(),name:u.string()}),j=u.object({table:u.string(),column:u.string()}),M=u.object({...E.shape,columns:u.array(u.string()).readonly()}),U=u.object({...E.shape,columns:u.array(u.string()).readonly()}),G=u.enum(["cascade","set null","set default","restrict","no action"]),L=u.object({...E.shape,columns:u.array(u.string()).readonly(),referencedTable:u.string(),referencedColumns:u.array(u.string()).readonly(),onDelete:G.optional(),onUpdate:G.optional()}),X=u.discriminatedUnion("type",[u.object({type:u.literal("create_table"),table:u.string(),columns:u.record(u.string(),S)}),u.object({type:u.literal("drop_table"),table:u.string()}),u.object({...j.shape,type:u.literal("add_column"),attributes:S}),u.object({...j.shape,type:u.literal("drop_column"),attributes:S}),u.object({...j.shape,type:u.literal("alter_column"),before:S,after:S}),u.object({...E.shape,type:u.literal("create_index"),columns:u.array(u.string()).readonly(),unique:u.boolean()}),u.object({...E.shape,type:u.literal("drop_index")}),u.object({...M.shape,type:u.literal("create_primary_key_constraint")}),u.object({...E.shape,type:u.literal("drop_primary_key_constraint")}),u.object({...U.shape,type:u.literal("create_unique_constraint")}),u.object({...E.shape,type:u.literal("drop_unique_constraint")}),u.object({...L.shape,type:u.literal("create_foreign_key_constraint")}),u.object({...E.shape,type:u.literal("drop_foreign_key_constraint")})]),f={createTable:(e,t)=>({type:"create_table",table:e,columns:t}),dropTable:e=>({type:"drop_table",table:e}),addColumn:(e,t)=>({...e,type:"add_column",attributes:t}),dropColumn:(e,t)=>({...e,type:"drop_column",attributes:t}),alterColumn:(e,t,n)=>({...e,type:"alter_column",before:t,after:n}),createIndex:e=>({...e,type:"create_index"}),dropIndex:e=>({...e,type:"drop_index"}),createPrimaryKeyConstraint:e=>({...e,type:"create_primary_key_constraint"}),dropPrimaryKeyConstraint:e=>({...e,type:"drop_primary_key_constraint"}),createUniqueConstraint:e=>({...e,type:"create_unique_constraint"}),dropUniqueConstraint:e=>({...e,type:"drop_unique_constraint"}),createForeignKeyConstraint:(e,t)=>({...e,...t,type:"create_foreign_key_constraint"}),dropForeignKeyConstraint:e=>({...e,type:"drop_foreign_key_constraint"})};var O="migrations",Ke=T.object({operations:T.array(X).readonly()}),Ae=T.object({id:T.string(),version:T.string(),diff:Ke}),F=async()=>{try{let t=(await Te(O)).filter(n=>n.endsWith(".json")).map(async n=>Ae.parse(JSON.parse(await Oe(we(O,n),"utf-8"))));return await Promise.all(t)}catch(e){if(e instanceof Object&&"code"in e&&e.code==="ENOENT")return[];throw e}},v=async e=>{var m=[];try{let t=C(m,e.getDB(),!0);let n=await F();let a=(await t.introspection.getTables({withInternalKyselyTables:!0})).map(r=>r.name);if(!a.includes(Z))return n;let o=await t.selectFrom(Z).select(["name","timestamp"]).$narrowType().execute();return n.filter(r=>!o.some(p=>p.name===r.id))}catch(s){var i=s,c=!0}finally{var d=x(m,i,c);d&&await d}},ae=e=>({getMigrations:async()=>{let t=await e.migrationsResolver(),n={};return t.forEach(a=>{n[a.id]={up:async()=>{await ve(e.db,a.diff)}}}),n}});async function ve(e,t){let n=We(t.operations);for(let a of n)await Pe(e,a)}async function Pe(e,t){switch(t.type){case"create_table":return Re(e,t);case"drop_table":return qe(e,t);case"add_column":return ke(e,t);case"drop_column":return Ie(e,t);case"alter_column":return $e(e,t);case"create_index":return je(e,t);case"drop_index":return Me(e,t);case"create_primary_key_constraint":return Ue(e,t);case"drop_primary_key_constraint":return Le(e,t);case"create_unique_constraint":return Fe(e,t);case"drop_unique_constraint":return Be(e,t);case"create_foreign_key_constraint":return He(e,t);case"drop_foreign_key_constraint":return Ve(e,t);default:throw new Error(`Unknown operation type: ${t.type}`)}}async function Re(e,t){let n=e.schema.createTable(t.table);for(let[a,o]of Object.entries(t.columns)){let m=o.type;B(m),n=n.addColumn(a,m,s=>{let i=s;return o.notNull&&(i=i.notNull()),typeof o.defaultSql=="string"&&(i=i.defaultTo(ne.raw(o.defaultSql))),i})}await n.execute()}async function qe(e,t){await e.schema.dropTable(t.table).execute()}async function ke(e,t){let n=t.attributes.type;B(n),await e.schema.alterTable(t.table).addColumn(t.column,n,a=>{let o=a;return t.attributes.notNull&&(o=o.notNull()),typeof t.attributes.defaultSql=="string"&&(o=o.defaultTo(ne.raw(t.attributes.defaultSql))),o}).execute()}async function Ie(e,t){await e.schema.alterTable(t.table).dropColumn(t.column).execute()}async function $e(e,t){let{table:n,column:a,before:o,after:m}=t;if(o.type!==m.type){let s=m.type;B(s),await e.schema.alterTable(n).alterColumn(a,i=>i.setDataType(s)).execute()}m.notNull!==o.notNull&&(m.notNull?await e.schema.alterTable(n).alterColumn(a,s=>s.setNotNull()).execute():await e.schema.alterTable(n).alterColumn(a,s=>s.dropNotNull()).execute())}async function je(e,t){let n=e.schema.createIndex(t.name).on(t.table);for(let a of t.columns)n=n.column(a);t.unique&&(n=n.unique()),await n.execute()}async function Me(e,t){await e.schema.dropIndex(t.name).execute()}async function Ue(e,t){await e.schema.alterTable(t.table).addPrimaryKeyConstraint(t.name,t.columns).execute()}async function Le(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function Fe(e,t){await e.schema.alterTable(t.table).addUniqueConstraint(t.name,t.columns).execute()}async function Be(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}async function He(e,t){let n=e.schema.alterTable(t.table).addForeignKeyConstraint(t.name,t.columns,t.referencedTable,t.referencedColumns);t.onDelete&&(n=n.onDelete(t.onDelete)),t.onUpdate&&(n=n.onUpdate(t.onUpdate)),await n.execute()}async function Ve(e,t){await e.schema.alterTable(t.table).dropConstraint(t.name).execute()}var B=e=>{if(!Se(e))throw new Error(`Unsupported data type: ${e}`)},ee={drop_foreign_key_constraint:0,drop_unique_constraint:1,drop_primary_key_constraint:2,drop_index:3,drop_column:4,drop_table:5,create_table:6,add_column:7,alter_column:8,create_index:9,create_primary_key_constraint:10,create_unique_constraint:11,create_foreign_key_constraint:12},We=e=>e.slice().sort((t,n)=>{let a=ee[t.type],o=ee[n.type];return a!==o?a-o:te(t).localeCompare(te(n))});function te(e){return e.table}import{format as ze}from"sql-formatter";var w=async e=>{var i=[];try{let{reporter:t}=e.logger;let n=C(i,e.client.getDB({plan:e.options.plan}),!0);let a=new Qe({db:n,provider:ae({db:n,migrationsResolver:async()=>e.options.plan?await v(e.client):await F(),options:{plan:e.options.plan}})});let{results:o,error:m}=await a.migrateToLatest();let s=n.getPlannedQueries();if(s.length>0){s.forEach(l=>{e.logger.stdout(e.options.pretty?ze(l.sql):l.sql)});return}o&&o.length>0?o.forEach(l=>{l.status==="Error"?t.error(`Migration failed: ${l.migrationName}`):l.status==="Success"&&t.success(`Migration applied: ${l.migrationName}`)}):t.info("No migrations to run");if(m)throw m instanceof Error?m:new Error(`Migration error: ${m}`)}catch(c){var d=c,r=!0}finally{var p=x(i,d,r);p&&await p}};import{createConsola as Je}from"consola";var Ye=Je({stdout:process.stderr}),re={stdout:e=>console.log(e),reporter:{...Ye}},oe={stdout:()=>{},reporter:{info:()=>{},warn:()=>{},success:()=>{},log:()=>{},error:()=>{}}};import{mkdir as lt,writeFile as mt}from"fs/promises";import*as y from"ramda";var N=()=>({added:(e,t,n)=>y.pipe(y.difference(t),y.map(n))(e),removed:(e,t,n)=>y.pipe(y.difference(e),y.map(n))(t),changed:(e,t,n,a)=>y.pipe(y.intersection(e),y.filter(n),y.map(a))(t)}),P=y.prop("name"),Ge=y.eqBy(e=>[e.type,e.notNull??!1,e.primaryKey??!1,e.unique??!1]);function Xe(e,t){let n=[],a=N(),o=e.columns,m=t.columns,s=Object.keys(o),i=Object.keys(m);return a.added(s,i,c=>({column:c,attributes:m[c]})).forEach(c=>{n.push(f.addColumn({table:e.name,column:c.column},c.attributes))}),a.removed(s,i,c=>({column:c,attributes:o[c]})).forEach(c=>{n.push(f.dropColumn({table:e.name,column:c.column},c.attributes))}),a.changed(s,i,c=>!Ge(o[c],m[c]),c=>({column:c,before:o[c],after:m[c]})).forEach(c=>{n.push(f.alterColumn({table:e.name,column:c.column},c.before,c.after))}),n}function Ze(e){let{current:t,ideal:n}=e,a=[],o=N(),m=y.map(P,t),s=y.map(P,n);return o.added(m,s,i=>n.find(d=>d.name===i)).forEach(i=>{a.push(f.createTable(i.name,i.columns))}),o.removed(m,s,y.identity).forEach(i=>{a.push(f.dropTable(i))}),y.filter(i=>n.some(c=>c.name===i.name))(t).forEach(i=>{let c=n.find(d=>d.name===i.name);a.push(...Xe(i,c))}),a}function et(e){let{current:t,ideal:n}=e,a=[],o=N(),m=r=>`${r.table}:${r.name}`,s=new Map(t.map(r=>[m(r),r])),i=new Map(n.map(r=>[m(r),r])),c=Array.from(s.keys()),d=Array.from(i.keys());return o.added(c,d,r=>i.get(r)).forEach(r=>{a.push(f.createIndex(r))}),o.removed(c,d,r=>{let p=s.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropIndex(r))}),o.changed(c,d,r=>{let p=s.get(r),l=i.get(r);return!y.equals(p.columns,l.columns)||p.unique!==l.unique},r=>{let p=s.get(r),l=i.get(r);return{current:p,ideal:l}}).forEach(({current:r,ideal:p})=>{a.push(f.dropIndex(r)),a.push(f.createIndex(p))}),a}function tt(e){let{current:t,ideal:n}=e,a=[],o=N(),m=r=>`${r.table}:${r.name}`,s=new Map(t.map(r=>[m(r),r])),i=new Map(n.map(r=>[m(r),r])),c=Array.from(s.keys()),d=Array.from(i.keys());return o.added(c,d,r=>i.get(r)).forEach(r=>{a.push(f.createPrimaryKeyConstraint(r))}),o.removed(c,d,r=>{let p=s.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropPrimaryKeyConstraint(r))}),o.changed(c,d,r=>{let p=s.get(r),l=i.get(r);return!y.equals(p.columns,l.columns)},r=>{let p=s.get(r),l=i.get(r);return{current:p,ideal:l}}).forEach(({current:r,ideal:p})=>{a.push(f.dropPrimaryKeyConstraint(r)),a.push(f.createPrimaryKeyConstraint(p))}),a}function nt(e){let{current:t,ideal:n}=e,a=[],o=N(),m=r=>`${r.table}:${r.name}`,s=new Map(t.map(r=>[m(r),r])),i=new Map(n.map(r=>[m(r),r])),c=Array.from(s.keys()),d=Array.from(i.keys());return o.added(c,d,r=>i.get(r)).forEach(r=>{a.push(f.createUniqueConstraint(r))}),o.removed(c,d,r=>{let p=s.get(r);return{table:p.table,name:p.name}}).forEach(r=>{a.push(f.dropUniqueConstraint(r))}),o.changed(c,d,r=>{let p=s.get(r),l=i.get(r);return!y.equals(p.columns,l.columns)},r=>{let p=s.get(r),l=i.get(r);return{current:p,ideal:l}}).forEach(({current:r,ideal:p})=>{a.push(f.dropUniqueConstraint(r)),a.push(f.createUniqueConstraint(p))}),a}function at(e){let t=[],n=N(),a=e.current.map(P),o=e.ideal.map(P);t.push(...n.added(a,o,s=>{let i=e.ideal.find(p=>p.name===s),{table:c,name:d,...r}=i;return f.createForeignKeyConstraint({table:c,name:d},r)})),t.push(...n.removed(a,o,s=>{let i=e.current.find(c=>c.name===s);return f.dropForeignKeyConstraint(i)}));let m=s=>{let i=e.current.find(d=>d.name===s),c=e.ideal.find(d=>d.name===s);return!i||!c?!1:!(y.equals(i.columns,c.columns)&&i.referencedTable===c.referencedTable&&y.equals(i.referencedColumns,c.referencedColumns)&&i.onDelete===c.onDelete&&i.onUpdate===c.onUpdate)};return t.push(...n.changed(a,o,m,s=>{let i=e.current.find(l=>l.name===s),c=e.ideal.find(l=>l.name===s),{table:d,name:r,...p}=c;return[f.dropForeignKeyConstraint(i),f.createForeignKeyConstraint({table:d,name:r},p)]}).flat()),t}function ie(e){let t=Ze({current:e.current.tables,ideal:e.ideal.tables}),n=et({current:e.current.indexes,ideal:e.ideal.indexes}),a=tt({current:e.current.primaryKeyConstraints,ideal:e.ideal.primaryKeyConstraints}),o=nt({current:e.current.uniqueConstraints,ideal:e.ideal.uniqueConstraints}),m=at({current:e.current.foreignKeyConstraints,ideal:e.ideal.foreignKeyConstraints});return{operations:[...t,...n,...a,...o,...m]}}import{sql as H}from"kysely";var rt={bool:"boolean",int2:"smallint",int4:"integer",int8:"bigint"},ot=e=>rt[e]??e,se=e=>({introspectTables:async()=>{var i=[];try{let o=e.client;let m=C(i,o.getDB(),!0);let{rows:s}=await H`
|
|
2
2
|
SELECT
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
JOIN
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ORDER BY c.
|
|
21
|
-
`.$castTo().execute(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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(m);return s.map(l=>({schema:l.table_schema,table:l.table_name,name:l.column_name,default:l.column_default,characterMaximumLength:l.character_maximum_length}))}catch(c){var d=c,r=!0}finally{var p=x(i,d,r);p&&await p}},introspectIndexes:async()=>{var i=[];try{let o=e.client;let m=C(i,o.getDB(),!0);let{rows:s}=await H`
|
|
22
|
+
SELECT
|
|
23
|
+
t.relname AS table_name,
|
|
24
|
+
i.relname AS index_name,
|
|
25
|
+
pg_index.indisunique AS is_unique,
|
|
26
|
+
jsonb_agg(a.attname ORDER BY array_position(pg_index.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 ON pg_index.indrelid = t.oid
|
|
30
|
+
JOIN pg_class i ON i.oid = pg_index.indexrelid
|
|
31
|
+
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY (pg_index.indkey)
|
|
32
|
+
WHERE t.relkind = 'r'
|
|
33
|
+
AND n.nspname = 'public'
|
|
34
|
+
AND NOT pg_index.indisprimary
|
|
35
|
+
AND NOT EXISTS (
|
|
36
|
+
SELECT 1 FROM pg_constraint con
|
|
37
|
+
WHERE con.conindid = i.oid
|
|
38
|
+
AND con.contype IN ('p', 'u')
|
|
39
|
+
)
|
|
40
|
+
GROUP BY t.relname, i.relname, pg_index.indisunique, pg_index.indisprimary, i.oid;
|
|
41
|
+
`.$castTo().execute(m);return s.map(l=>({table:l.table_name,name:l.index_name,columns:l.column_names,unique:l.is_unique}))}catch(c){var d=c,r=!0}finally{var p=x(i,d,r);p&&await p}},introspectConstraints:async()=>{var i=[];try{let o=e.client;let m=C(i,o.getDB(),!0);let{rows:s}=await H`
|
|
42
|
+
SELECT
|
|
43
|
+
n.nspname AS schema,
|
|
44
|
+
t.relname AS table,
|
|
45
|
+
c.conname AS name,
|
|
46
|
+
CASE c.contype
|
|
47
|
+
WHEN 'p' THEN 'PRIMARY KEY'
|
|
48
|
+
WHEN 'u' THEN 'UNIQUE'
|
|
49
|
+
WHEN 'f' THEN 'FOREIGN KEY'
|
|
50
|
+
END AS type,
|
|
51
|
+
jsonb_agg(a.attname ORDER BY array_position(c.conkey, a.attnum)) AS columns,
|
|
52
|
+
-- Foreign Key専用の情報
|
|
53
|
+
CASE
|
|
54
|
+
WHEN c.contype = 'f' THEN rt.relname
|
|
55
|
+
ELSE NULL
|
|
56
|
+
END AS referenced_table,
|
|
57
|
+
CASE
|
|
58
|
+
WHEN c.contype = 'f' THEN jsonb_agg(ra.attname ORDER BY array_position(c.confkey, ra.attnum))
|
|
59
|
+
ELSE NULL
|
|
60
|
+
END AS referenced_columns,
|
|
61
|
+
CASE
|
|
62
|
+
WHEN c.contype = 'f' THEN
|
|
63
|
+
CASE c.confdeltype
|
|
64
|
+
WHEN 'c' THEN 'cascade'
|
|
65
|
+
WHEN 'n' THEN 'set null'
|
|
66
|
+
WHEN 'd' THEN 'set default'
|
|
67
|
+
WHEN 'r' THEN 'restrict'
|
|
68
|
+
WHEN 'a' THEN 'no action'
|
|
69
|
+
END
|
|
70
|
+
ELSE NULL
|
|
71
|
+
END AS on_delete,
|
|
72
|
+
CASE
|
|
73
|
+
WHEN c.contype = 'f' THEN
|
|
74
|
+
CASE c.confupdtype
|
|
75
|
+
WHEN 'c' THEN 'cascade'
|
|
76
|
+
WHEN 'n' THEN 'set null'
|
|
77
|
+
WHEN 'd' THEN 'set default'
|
|
78
|
+
WHEN 'r' THEN 'restrict'
|
|
79
|
+
WHEN 'a' THEN 'no action'
|
|
80
|
+
END
|
|
81
|
+
ELSE NULL
|
|
82
|
+
END AS on_update
|
|
83
|
+
FROM pg_constraint c
|
|
84
|
+
JOIN pg_class t ON c.conrelid = t.oid
|
|
85
|
+
JOIN pg_namespace n ON t.relnamespace = n.oid
|
|
86
|
+
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey)
|
|
87
|
+
-- Foreign Key用のJOIN
|
|
88
|
+
LEFT JOIN pg_class rt ON c.confrelid = rt.oid
|
|
89
|
+
LEFT JOIN pg_attribute ra ON ra.attrelid = c.confrelid AND ra.attnum = ANY(c.confkey)
|
|
90
|
+
WHERE c.contype IN ('p', 'u', 'f') -- primary key, unique, foreign key constraints
|
|
91
|
+
AND n.nspname = 'public'
|
|
92
|
+
AND NOT a.attisdropped
|
|
93
|
+
AND (c.contype != 'f' OR NOT ra.attisdropped) -- Foreign Key用の条件
|
|
94
|
+
GROUP BY n.nspname, t.relname, c.conname, c.contype, c.oid, c.conkey, t.oid,
|
|
95
|
+
rt.relname, c.confkey, c.confdeltype, c.confupdtype
|
|
96
|
+
ORDER BY t.relname, c.conname;
|
|
97
|
+
`.$castTo().execute(m);return{primaryKey:s.filter(l=>l.type==="PRIMARY KEY"),unique:s.filter(l=>l.type==="UNIQUE"),foreignKey:s.filter(l=>l.type==="FOREIGN KEY").map(l=>{let{referenced_table:_,referenced_columns:b,on_delete:h,on_update:ue,...pe}=l;return{...pe,referencedTable:_,referencedColumns:b,onDelete:h,onUpdate:ue}})}}catch(c){var d=c,r=!0}finally{var p=x(i,d,r);p&&await p}},convertTypeName:ot});var it=e=>{let t=e.getDialect();switch(t){case"postgres":case"cockroachdb":return se({client:e});default:throw new Error(`Unsupported dialect: ${t}`)}},ce=e=>{let t=it(e);return{getTables:async()=>{var m=[];try{let n=C(m,e.getDB(),!0);let a=await n.introspection.getTables();let o=await t.introspectTables();return a.map(r=>{let p=Object.fromEntries(r.columns.map(l=>{let b=o.filter(h=>h.table===r.name&&h.name===l.name)[0]||{};return[l.name,{schema:r.schema,table:r.name,name:l.name,dataType:t.convertTypeName(l.dataType),default:b.default??null,characterMaximumLength:b.characterMaximumLength??null,notNull:!l.isNullable}]}));return{schema:r.schema,name:r.name,columns:p}})}catch(s){var i=s,c=!0}finally{var d=x(m,i,c);d&&await d}},getIndexes:async()=>(await t.introspectIndexes()).filter(n=>!n.table.startsWith("kysely_")),getConstraints:async()=>{let n=await t.introspectConstraints(),a=n.primaryKey.filter(s=>!s.table.startsWith("kysely_")),o=n.unique.filter(s=>!s.table.startsWith("kysely_")),m=n.foreignKey.filter(s=>!s.table.startsWith("kysely_"));return{primaryKey:a,unique:o,foreignKey:m}}}};import{PostgreSqlContainer as st}from"@testcontainers/postgresql";import{CockroachDbContainer as ct}from"@testcontainers/cockroachdb";var V=class{constructor(t,n){this.image=t;this.dialect=n}async start(){let n=await this.getContainer().start();return{dialect:this.dialect,connectionString:n.getConnectionUri()}}async stop(){}getContainer(){if(this.image.includes("postgres"))return new st(this.image);if(this.image.includes("cockroach"))return new ct(this.image);throw new Error(`Unsupported container image: ${this.image}`)}},W=class{constructor(t,n){this.connectionString=t;this.dialect=n}async start(){return{dialect:this.dialect,connectionString:this.connectionString}}async stop(){}},le=(e,t)=>{if("connectionString"in e)return new W(e.connectionString,t);if("container"in e)return new V(e.container.image,t);throw new Error("Invalid dev database configuration")};var me=async e=>{let{reporter:t}=e.logger,{client:n,cleanup:a}=await ut(e);try{if(!e.options.dev&&!e.options.ignorePending){let s=await v(e.client);if(s.length>0){t.warn([`There are pending migrations: ${s.map(i=>i.id).join(", ")}`,"Please apply them first before generating a new migration.","Otherwise, use --ignore-pending to skip this check."].join(`
|
|
98
|
+
`));return}}let o=await pt({client:n,config:e.config});if(!o){t.info("No changes detected, no migration needed.");return}dt(e.logger,o.diff);let m=`${O}/${o.id}.json`;await lt(O,{recursive:!0}),await mt(m,JSON.stringify(o,null,2)),t.success(`Migration file generated: ${m}`),e.options.apply&&(e.options.dev?t.warn("--apply flag is ignored when using --dev. Use 'kyrage apply' to apply to production database."):await w({client:e.client,logger:e.logger,options:{plan:e.options.plan,pretty:!1}}))}finally{await a()}},ut=async e=>{let{reporter:t}=e.logger;if(!e.options.dev)return{client:e.client,cleanup:async()=>{}};if(!e.config.dev)throw new Error("Dev database configuration is required when using --dev flag");t.info("\u{1F680} Starting dev database for migration generation...");let n=le(e.config.dev,e.config.database.dialect),a=await n.start();t.success(`Dev database started: ${a.dialect}`);let o=D({database:a});return await w({client:o,logger:oe,options:{plan:!1,pretty:!1}}),{client:o,cleanup:async()=>{await n.stop(),t.success("Dev database stopped")}}},pt=async e=>{let{client:t,config:n}=e,a=ce(t),o=await a.getTables(),m=await a.getConstraints(),s=(l,_)=>b=>b.some(h=>h.table===l&&h.columns.length===1&&h.columns[0]===_),i=o.map(l=>({name:l.name,columns:Object.fromEntries(Object.entries(l.columns).map(([_,b])=>{let h=s(l.name,_);return[_,{type:b.dataType,notNull:b.notNull,primaryKey:h(m.primaryKey),unique:h(m.unique),defaultSql:b.default??void 0}]}))})),c=n.tables.map(l=>({name:l.tableName,columns:Object.fromEntries(Object.entries(l.columns).map(([_,b])=>[_,{...b,notNull:b.primaryKey||b.notNull}]))})),d=await a.getIndexes(),r=ie({current:{tables:i,indexes:d,primaryKeyConstraints:m.primaryKey,uniqueConstraints:m.unique,foreignKeyConstraints:m.foreignKey},ideal:{tables:c,indexes:n.indexes.map(l=>({table:l.table,name:l.name,columns:l.columns,unique:l.unique})),primaryKeyConstraints:n.primaryKeyConstraints||[],uniqueConstraints:n.uniqueConstraints||[],foreignKeyConstraints:n.foreignKeyConstraints||[]}});return r.operations.length===0?null:{version:"1",id:Date.now()+"",diff:r}},dt=(e,t)=>{let n=[];t.operations.forEach(a=>{switch(a.type){case"create_table":n.push(`-- create_table: ${a.table}`),Object.entries(a.columns).forEach(([o,m])=>{n.push(` -> column: ${o} (${JSON.stringify(m)})`)});break;case"drop_table":n.push(`-- remove_table: ${a.table}`);break;case"add_column":n.push([`-- add_column: ${a.table}.${a.column}`,` -> to: ${JSON.stringify(a.attributes)}`].join(`
|
|
99
|
+
`));break;case"drop_column":n.push(`-- remove_column: ${a.table}.${a.column}`);break;case"alter_column":n.push([`-- change_column: ${a.table}.${a.column}`,` -> from: ${JSON.stringify(a.before)}`,` -> to: ${JSON.stringify(a.after)}`].join(`
|
|
100
|
+
`));break;case"create_index":n.push(`-- create_index: ${a.table}.${a.name} (${a.columns.join(", ")})${a.unique?" [unique]":""}`);break;case"drop_index":n.push(`-- drop_index: ${a.table}.${a.name}`);break;case"create_primary_key_constraint":n.push(`-- create_primary_key_constraint: ${a.table}.${a.name} (${a.columns.join(", ")})`);break;case"drop_primary_key_constraint":n.push(`-- drop_primary_key_constraint: ${a.table}.${a.name}`);break;case"create_unique_constraint":n.push(`-- create_unique_constraint: ${a.table}.${a.name} (${a.columns.join(", ")})`);break;case"drop_unique_constraint":n.push(`-- drop_unique_constraint: ${a.table}.${a.name}`);break;case"create_foreign_key_constraint":n.push(`-- create_foreign_key_constraint: ${a.table}.${a.name} (${a.columns.join(", ")}) -> ${a.referencedTable} (${a.referencedColumns.join(", ")})${a.onDelete?` ON DELETE ${a.onDelete.toUpperCase()}`:""}${a.onUpdate?` ON UPDATE ${a.onUpdate.toUpperCase()}`:""}`);break;case"drop_foreign_key_constraint":n.push(`-- drop_foreign_key_constraint: ${a.table}.${a.name}`);break;default:break}}),e.reporter.log(n.join(`
|
|
101
|
+
`))};import g from"zod";import{loadConfig as yt}from"c12";var gt=g.object({type:g.string(),primaryKey:g.boolean().optional().default(!1),notNull:g.boolean().optional().default(!1),unique:g.boolean().optional().default(!1),defaultSql:g.string().optional()}),ft=g.object({tableName:g.string(),columns:g.record(g.string(),gt)}),bt=g.object({...E.shape,columns:g.array(g.string()).readonly(),unique:g.boolean().default(!1)}),ht=g.enum(["postgres","cockroachdb","mysql","sqlite"]),_t=g.object({dialect:ht,connectionString:g.string()}),Ct=g.union([g.object({container:g.object({image:g.string()})}),g.object({connectionString:g.string()})]).optional(),xt=g.object({database:_t,dev:Ct,tables:g.array(ft).readonly(),indexes:g.array(bt).readonly(),primaryKeyConstraints:g.array(M).readonly(),uniqueConstraints:g.array(U).readonly(),foreignKeyConstraints:g.array(L).readonly()}),Q=async()=>{let e=await yt({name:"kyrage"});return xt.parse(e.config)};var R=re,Nt=z({meta:{name:"generate",description:"Generate migration files based on the current schema"},args:{apply:{type:"boolean",description:"Apply the migration after generating it",default:!1},plan:{type:"boolean",description:"Plan the migration without applying it (only for --apply)",default:!1},"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}},run:async e=>{try{let t=await Q(),n=D({database:t.database});await me({client:n,logger:R,config:t,options:{ignorePending:e.args["ignore-pending"],apply:e.args.apply,plan:e.args.plan,dev:e.args.dev}})}catch(t){R.reporter.error(t),process.exit(1)}}}),Dt=z({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 Q(),n=D({database:t.database});await w({client:n,logger:R,options:{plan:e.args.plan,pretty:e.args.pretty}})}catch(t){R.reporter.error(t),process.exit(1)}}}),St=z({meta:{name:"kyrage",version:Y,description:"Kysely migration CLI with declarative schema"},subCommands:{apply:Dt,generate:Nt}});Et(St);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@izumisy/kyrage",
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "1.0.0",
|
|
6
6
|
"description": "A minimal, schema-based declarative migration tool for Node.js ecosystem",
|
|
7
7
|
"author": "Seiya Izumi (https://github.com/IzumiSy)",
|
|
8
8
|
"license": "MIT",
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
"kyrage": "./dist/main.js"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@testcontainers/cockroachdb": "^11.5.1",
|
|
34
|
+
"@testcontainers/postgresql": "^11.5.1",
|
|
33
35
|
"better-sqlite3": "^12.2.0",
|
|
34
36
|
"c12": "^3.2.0",
|
|
35
37
|
"citty": "^0.1.6",
|
|
@@ -38,19 +40,19 @@
|
|
|
38
40
|
"kysely-codegen": "^0.18.5",
|
|
39
41
|
"mysql2": "^3.14.3",
|
|
40
42
|
"pg": "^8.16.3",
|
|
43
|
+
"ramda": "^0.31.3",
|
|
41
44
|
"sql-formatter": "^15.6.6",
|
|
45
|
+
"testcontainers": "^11.5.1",
|
|
42
46
|
"zod": "^4.0.17"
|
|
43
47
|
},
|
|
44
48
|
"devDependencies": {
|
|
45
49
|
"@swc/core": "^1.13.3",
|
|
46
|
-
"@testcontainers/cockroachdb": "^11.5.1",
|
|
47
|
-
"@testcontainers/postgresql": "^11.5.1",
|
|
48
50
|
"@types/better-sqlite3": "^7.6.13",
|
|
49
|
-
"@types/node": "^24.
|
|
51
|
+
"@types/node": "^24.3.0",
|
|
50
52
|
"@types/pg": "^8.15.5",
|
|
53
|
+
"@types/ramda": "^0.31.0",
|
|
51
54
|
"memfs": "^4.36.0",
|
|
52
55
|
"prettier": "^3.6.2",
|
|
53
|
-
"testcontainers": "^11.5.1",
|
|
54
56
|
"tsup": "^8.5.0",
|
|
55
57
|
"typescript": "^5.9.2",
|
|
56
58
|
"vitest": "^3.2.4"
|