arkormx 2.0.0-next.2 → 2.0.0-next.3
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/cli.mjs +164 -28
- package/dist/index.cjs +398 -29
- package/dist/index.d.cts +148 -96
- package/dist/index.d.mts +148 -96
- package/dist/index.mjs +387 -29
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -78,6 +78,8 @@ var UnsupportedAdapterFeatureException = class extends ArkormException {
|
|
|
78
78
|
* @since 2.0.0-next.0
|
|
79
79
|
*/
|
|
80
80
|
var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
81
|
+
static migrationStateTable = "arkormx_migrations";
|
|
82
|
+
static migrationRunTable = "arkormx_migration_runs";
|
|
81
83
|
capabilities = {
|
|
82
84
|
transactions: true,
|
|
83
85
|
returning: true,
|
|
@@ -95,6 +97,161 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
95
97
|
this.db = db;
|
|
96
98
|
this.mapping = mapping;
|
|
97
99
|
}
|
|
100
|
+
quoteIdentifier(value) {
|
|
101
|
+
return `"${value.replace(/"/g, "\"\"")}"`;
|
|
102
|
+
}
|
|
103
|
+
quoteLiteral(value) {
|
|
104
|
+
if (value == null) return "null";
|
|
105
|
+
if (typeof value === "number" || typeof value === "bigint") return String(value);
|
|
106
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
107
|
+
if (value instanceof Date) return `'${value.toISOString().replace(/'/g, "''")}'`;
|
|
108
|
+
return `'${String(value).replace(/'/g, "''")}'`;
|
|
109
|
+
}
|
|
110
|
+
async executeRawStatement(statement, executor = this.db) {
|
|
111
|
+
await sql.raw(statement).execute(executor);
|
|
112
|
+
}
|
|
113
|
+
resolveSchemaColumnName(columnName, columns = []) {
|
|
114
|
+
return columns.find((column) => column.name === columnName)?.map ?? columnName;
|
|
115
|
+
}
|
|
116
|
+
resolveSchemaIndexName(table, index) {
|
|
117
|
+
if (typeof index.name === "string" && index.name.trim().length > 0) return index.name;
|
|
118
|
+
return `${table}_${index.columns.join("_")}_idx`;
|
|
119
|
+
}
|
|
120
|
+
resolveSchemaForeignKeyName(table, foreignKey) {
|
|
121
|
+
return `${table}_${foreignKey.column}_fkey`;
|
|
122
|
+
}
|
|
123
|
+
resolveSchemaColumnType(column) {
|
|
124
|
+
if (column.type === "id") return "integer";
|
|
125
|
+
if (column.type === "uuid") return "uuid";
|
|
126
|
+
if (column.type === "enum") return this.quoteIdentifier(column.enumName ?? `${column.name}_enum`);
|
|
127
|
+
if (column.type === "string") return "varchar(255)";
|
|
128
|
+
if (column.type === "text") return "text";
|
|
129
|
+
if (column.type === "integer") return "integer";
|
|
130
|
+
if (column.type === "bigInteger") return "bigint";
|
|
131
|
+
if (column.type === "float") return "double precision";
|
|
132
|
+
if (column.type === "boolean") return "boolean";
|
|
133
|
+
if (column.type === "json") return "jsonb";
|
|
134
|
+
if (column.type === "date") return "date";
|
|
135
|
+
return "timestamptz";
|
|
136
|
+
}
|
|
137
|
+
resolveSchemaColumnDefault(column) {
|
|
138
|
+
const value = column.default ?? (column.updatedAt ? "now()" : void 0);
|
|
139
|
+
if (value === void 0) return null;
|
|
140
|
+
if (value === "now()") return "now()";
|
|
141
|
+
return this.quoteLiteral(value);
|
|
142
|
+
}
|
|
143
|
+
shouldUseIdentity(column) {
|
|
144
|
+
if (column.autoIncrement === false) return false;
|
|
145
|
+
if (column.type === "id") return column.default === void 0;
|
|
146
|
+
return column.autoIncrement === true;
|
|
147
|
+
}
|
|
148
|
+
buildSchemaColumnDefinition(column) {
|
|
149
|
+
const parts = [this.quoteIdentifier(column.map ?? column.name), this.resolveSchemaColumnType(column)];
|
|
150
|
+
if (this.shouldUseIdentity(column)) parts.push("generated by default as identity");
|
|
151
|
+
const defaultValue = this.resolveSchemaColumnDefault(column);
|
|
152
|
+
if (defaultValue && !this.shouldUseIdentity(column)) parts.push(`default ${defaultValue}`);
|
|
153
|
+
if (column.primary) parts.push("primary key");
|
|
154
|
+
else if (column.unique) parts.push("unique");
|
|
155
|
+
if (!column.nullable && !column.primary) parts.push("not null");
|
|
156
|
+
return parts.join(" ");
|
|
157
|
+
}
|
|
158
|
+
buildSchemaForeignKeyConstraint(table, foreignKey, columns = []) {
|
|
159
|
+
const localColumn = this.resolveSchemaColumnName(foreignKey.column, columns);
|
|
160
|
+
const referencedTable = this.resolveMappedTable(foreignKey.referencesTable);
|
|
161
|
+
const action = foreignKey.onDelete ? ` on delete ${foreignKey.onDelete === "setNull" ? "set null" : foreignKey.onDelete === "setDefault" ? "set default" : foreignKey.onDelete}` : "";
|
|
162
|
+
return `constraint ${this.quoteIdentifier(this.resolveSchemaForeignKeyName(table, foreignKey))} foreign key (${this.quoteIdentifier(localColumn)}) references ${this.quoteIdentifier(referencedTable)} (${this.quoteIdentifier(foreignKey.referencesColumn)})${action}`;
|
|
163
|
+
}
|
|
164
|
+
buildSchemaIndexStatement(table, index, columns = []) {
|
|
165
|
+
const mappedColumns = index.columns.map((column) => this.quoteIdentifier(this.resolveSchemaColumnName(column, columns))).join(", ");
|
|
166
|
+
return `create index if not exists ${this.quoteIdentifier(this.resolveSchemaIndexName(table, index))} on ${this.quoteIdentifier(table)} (${mappedColumns})`;
|
|
167
|
+
}
|
|
168
|
+
async ensureEnumTypes(columns, executor = this.db) {
|
|
169
|
+
for (const column of columns) {
|
|
170
|
+
if (column.type !== "enum") continue;
|
|
171
|
+
const enumName = column.enumName ?? `${column.name}_enum`;
|
|
172
|
+
if ((await sql`
|
|
173
|
+
select exists(
|
|
174
|
+
select 1
|
|
175
|
+
from pg_type
|
|
176
|
+
where typname = ${enumName}
|
|
177
|
+
) as exists
|
|
178
|
+
`.execute(executor)).rows[0]?.exists) continue;
|
|
179
|
+
const values = column.enumValues ?? [];
|
|
180
|
+
if (values.length === 0) throw new ArkormException(`Enum column [${column.name}] requires enum values for database-backed migrations.`);
|
|
181
|
+
await this.executeRawStatement(`create type ${this.quoteIdentifier(enumName)} as enum (${values.map((value) => this.quoteLiteral(value)).join(", ")})`, executor);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async executeCreateTableOperation(operation, executor) {
|
|
185
|
+
const table = this.resolveMappedTable(operation.table);
|
|
186
|
+
await this.ensureEnumTypes(operation.columns, executor);
|
|
187
|
+
const columnDefinitions = operation.columns.map((column) => this.buildSchemaColumnDefinition(column));
|
|
188
|
+
const foreignKeys = (operation.foreignKeys ?? []).map((foreignKey) => this.buildSchemaForeignKeyConstraint(table, foreignKey, operation.columns));
|
|
189
|
+
const definitions = [...columnDefinitions, ...foreignKeys].join(", ");
|
|
190
|
+
await this.executeRawStatement(`create table if not exists ${this.quoteIdentifier(table)} (${definitions})`, executor);
|
|
191
|
+
for (const index of operation.indexes ?? []) await this.executeRawStatement(this.buildSchemaIndexStatement(table, index, operation.columns), executor);
|
|
192
|
+
}
|
|
193
|
+
async executeAlterTableOperation(operation, executor) {
|
|
194
|
+
const table = this.resolveMappedTable(operation.table);
|
|
195
|
+
await this.ensureEnumTypes(operation.addColumns, executor);
|
|
196
|
+
for (const column of operation.addColumns) await this.executeRawStatement(`alter table ${this.quoteIdentifier(table)} add column if not exists ${this.buildSchemaColumnDefinition(column)}`, executor);
|
|
197
|
+
for (const column of operation.dropColumns) await this.executeRawStatement(`alter table ${this.quoteIdentifier(table)} drop column if exists ${this.quoteIdentifier(column)}`, executor);
|
|
198
|
+
for (const foreignKey of operation.addForeignKeys ?? []) await this.executeRawStatement(`alter table ${this.quoteIdentifier(table)} add ${this.buildSchemaForeignKeyConstraint(table, foreignKey, operation.addColumns)}`, executor);
|
|
199
|
+
for (const index of operation.addIndexes ?? []) await this.executeRawStatement(this.buildSchemaIndexStatement(table, index, operation.addColumns), executor);
|
|
200
|
+
}
|
|
201
|
+
async executeDropTableOperation(operation, executor) {
|
|
202
|
+
const table = this.resolveMappedTable(operation.table);
|
|
203
|
+
await this.executeRawStatement(`drop table if exists ${this.quoteIdentifier(table)} cascade`, executor);
|
|
204
|
+
}
|
|
205
|
+
async ensureMigrationStateTables(executor = this.db) {
|
|
206
|
+
await this.executeRawStatement(`
|
|
207
|
+
create table if not exists ${this.quoteIdentifier(KyselyDatabaseAdapter.migrationStateTable)} (
|
|
208
|
+
id text primary key,
|
|
209
|
+
file text not null,
|
|
210
|
+
class_name text not null,
|
|
211
|
+
applied_at timestamptz not null,
|
|
212
|
+
checksum text null
|
|
213
|
+
)
|
|
214
|
+
`, executor);
|
|
215
|
+
await this.executeRawStatement(`
|
|
216
|
+
create table if not exists ${this.quoteIdentifier(KyselyDatabaseAdapter.migrationRunTable)} (
|
|
217
|
+
id text primary key,
|
|
218
|
+
applied_at timestamptz not null,
|
|
219
|
+
migration_ids jsonb not null
|
|
220
|
+
)
|
|
221
|
+
`, executor);
|
|
222
|
+
}
|
|
223
|
+
async writeAppliedMigrationsStateInternal(state, executor) {
|
|
224
|
+
await this.ensureMigrationStateTables(executor);
|
|
225
|
+
await this.executeRawStatement(`delete from ${this.quoteIdentifier(KyselyDatabaseAdapter.migrationRunTable)}`, executor);
|
|
226
|
+
await this.executeRawStatement(`delete from ${this.quoteIdentifier(KyselyDatabaseAdapter.migrationStateTable)}`, executor);
|
|
227
|
+
for (const migration of state.migrations) await sql`
|
|
228
|
+
insert into ${sql.table(KyselyDatabaseAdapter.migrationStateTable)} (id, file, class_name, applied_at, checksum)
|
|
229
|
+
values (${migration.id}, ${migration.file}, ${migration.className}, ${migration.appliedAt}, ${migration.checksum ?? null})
|
|
230
|
+
`.execute(executor);
|
|
231
|
+
for (const run of state.runs ?? []) await sql`
|
|
232
|
+
insert into ${sql.table(KyselyDatabaseAdapter.migrationRunTable)} (id, applied_at, migration_ids)
|
|
233
|
+
values (${run.id}, ${run.appliedAt}, cast(${JSON.stringify(run.migrationIds)} as jsonb))
|
|
234
|
+
`.execute(executor);
|
|
235
|
+
}
|
|
236
|
+
async resetDatabaseInternal(executor) {
|
|
237
|
+
const tablesResult = await sql`
|
|
238
|
+
select table_name, table_schema
|
|
239
|
+
from information_schema.tables
|
|
240
|
+
where table_schema = current_schema()
|
|
241
|
+
and table_type = 'BASE TABLE'
|
|
242
|
+
order by table_name asc
|
|
243
|
+
`.execute(executor);
|
|
244
|
+
for (const row of tablesResult.rows) await this.executeRawStatement(`drop table if exists ${this.quoteIdentifier(row.table_schema)}.${this.quoteIdentifier(row.table_name)} cascade`, executor);
|
|
245
|
+
const enumTypesResult = await sql`
|
|
246
|
+
select t.typname as enum_name, n.nspname as enum_schema
|
|
247
|
+
from pg_type t
|
|
248
|
+
inner join pg_namespace n on n.oid = t.typnamespace
|
|
249
|
+
where t.typtype = 'e'
|
|
250
|
+
and n.nspname = current_schema()
|
|
251
|
+
order by t.typname asc
|
|
252
|
+
`.execute(executor);
|
|
253
|
+
for (const row of enumTypesResult.rows) await this.executeRawStatement(`drop type if exists ${this.quoteIdentifier(row.enum_schema)}.${this.quoteIdentifier(row.enum_name)} cascade`, executor);
|
|
254
|
+
}
|
|
98
255
|
introspectionTypeToTs(typeName, enumValues) {
|
|
99
256
|
if (enumValues && enumValues.length > 0) return enumValues.map((value) => `'${value.replace(/'/g, "\\'")}'`).join(" | ");
|
|
100
257
|
switch (typeName) {
|
|
@@ -721,6 +878,63 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
721
878
|
});
|
|
722
879
|
return [...models.values()];
|
|
723
880
|
}
|
|
881
|
+
async executeSchemaOperations(operations) {
|
|
882
|
+
if (operations.length === 0) return;
|
|
883
|
+
await this.transaction(async (adapter) => {
|
|
884
|
+
const transactionAdapter = adapter;
|
|
885
|
+
for (const operation of operations) {
|
|
886
|
+
if (operation.type === "createTable") {
|
|
887
|
+
await transactionAdapter.executeCreateTableOperation(operation, transactionAdapter.db);
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
if (operation.type === "alterTable") {
|
|
891
|
+
await transactionAdapter.executeAlterTableOperation(operation, transactionAdapter.db);
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
await transactionAdapter.executeDropTableOperation(operation, transactionAdapter.db);
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
async resetDatabase() {
|
|
899
|
+
await this.transaction(async (adapter) => {
|
|
900
|
+
const transactionAdapter = adapter;
|
|
901
|
+
await transactionAdapter.resetDatabaseInternal(transactionAdapter.db);
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
async readAppliedMigrationsState() {
|
|
905
|
+
await this.ensureMigrationStateTables();
|
|
906
|
+
const migrationsResult = await sql`
|
|
907
|
+
select id, file, class_name, applied_at, checksum
|
|
908
|
+
from ${sql.table(KyselyDatabaseAdapter.migrationStateTable)}
|
|
909
|
+
order by applied_at asc, id asc
|
|
910
|
+
`.execute(this.db);
|
|
911
|
+
const runsResult = await sql`
|
|
912
|
+
select id, applied_at, migration_ids
|
|
913
|
+
from ${sql.table(KyselyDatabaseAdapter.migrationRunTable)}
|
|
914
|
+
order by applied_at asc, id asc
|
|
915
|
+
`.execute(this.db);
|
|
916
|
+
return {
|
|
917
|
+
version: 1,
|
|
918
|
+
migrations: migrationsResult.rows.map((row) => ({
|
|
919
|
+
id: row.id,
|
|
920
|
+
file: row.file,
|
|
921
|
+
className: row.class_name,
|
|
922
|
+
appliedAt: row.applied_at instanceof Date ? row.applied_at.toISOString() : String(row.applied_at),
|
|
923
|
+
checksum: row.checksum ?? void 0
|
|
924
|
+
})),
|
|
925
|
+
runs: runsResult.rows.map((row) => ({
|
|
926
|
+
id: row.id,
|
|
927
|
+
appliedAt: row.applied_at instanceof Date ? row.applied_at.toISOString() : String(row.applied_at),
|
|
928
|
+
migrationIds: Array.isArray(row.migration_ids) ? row.migration_ids.filter((value) => typeof value === "string") : typeof row.migration_ids === "string" ? JSON.parse(row.migration_ids) : []
|
|
929
|
+
}))
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
async writeAppliedMigrationsState(state) {
|
|
933
|
+
await this.transaction(async (adapter) => {
|
|
934
|
+
const transactionAdapter = adapter;
|
|
935
|
+
await transactionAdapter.writeAppliedMigrationsStateInternal(state, transactionAdapter.db);
|
|
936
|
+
});
|
|
937
|
+
}
|
|
724
938
|
/**
|
|
725
939
|
* Executes a series of database operations within a transaction.
|
|
726
940
|
* The provided callback function is called with a new instance of the
|
|
@@ -2909,6 +3123,28 @@ const getMigrationPlan = async (migration, direction = "up") => {
|
|
|
2909
3123
|
else await instance.down(schema);
|
|
2910
3124
|
return schema.getOperations();
|
|
2911
3125
|
};
|
|
3126
|
+
const supportsDatabaseMigrationExecution = (adapter) => {
|
|
3127
|
+
return typeof adapter?.executeSchemaOperations === "function";
|
|
3128
|
+
};
|
|
3129
|
+
const supportsDatabaseReset = (adapter) => {
|
|
3130
|
+
return typeof adapter?.resetDatabase === "function";
|
|
3131
|
+
};
|
|
3132
|
+
const stripPrismaSchemaModelsAndEnums = (schema) => {
|
|
3133
|
+
const stripped = schema.replace(PRISMA_MODEL_REGEX, "").replace(PRISMA_ENUM_REGEX, "").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
3134
|
+
return stripped.length > 0 ? `${stripped}\n` : "";
|
|
3135
|
+
};
|
|
3136
|
+
const applyMigrationToDatabase = async (adapter, migration) => {
|
|
3137
|
+
if (!supportsDatabaseMigrationExecution(adapter)) throw new ArkormException("The configured adapter does not support database-backed migration execution.");
|
|
3138
|
+
const operations = await getMigrationPlan(migration, "up");
|
|
3139
|
+
await adapter.executeSchemaOperations(operations);
|
|
3140
|
+
return { operations };
|
|
3141
|
+
};
|
|
3142
|
+
const applyMigrationRollbackToDatabase = async (adapter, migration) => {
|
|
3143
|
+
if (!supportsDatabaseMigrationExecution(adapter)) throw new ArkormException("The configured adapter does not support database-backed migration execution.");
|
|
3144
|
+
const operations = await getMigrationPlan(migration, "down");
|
|
3145
|
+
await adapter.executeSchemaOperations(operations);
|
|
3146
|
+
return { operations };
|
|
3147
|
+
};
|
|
2912
3148
|
/**
|
|
2913
3149
|
* Apply the schema operations defined in a migration to a Prisma schema
|
|
2914
3150
|
* file, updating the file on disk if specified, and return the updated
|
|
@@ -3889,10 +4125,13 @@ var MakeSeederCommand = class extends Command {
|
|
|
3889
4125
|
|
|
3890
4126
|
//#endregion
|
|
3891
4127
|
//#region src/helpers/migration-history.ts
|
|
3892
|
-
const
|
|
4128
|
+
const createEmptyAppliedMigrationsState = () => ({
|
|
3893
4129
|
version: 1,
|
|
3894
4130
|
migrations: [],
|
|
3895
4131
|
runs: []
|
|
4132
|
+
});
|
|
4133
|
+
const supportsDatabaseMigrationState = (adapter) => {
|
|
4134
|
+
return typeof adapter?.readAppliedMigrationsState === "function" && typeof adapter?.writeAppliedMigrationsState === "function";
|
|
3896
4135
|
};
|
|
3897
4136
|
const resolveMigrationStateFilePath = (cwd, configuredPath) => {
|
|
3898
4137
|
if (configuredPath && configuredPath.trim().length > 0) return resolve(configuredPath);
|
|
@@ -3907,10 +4146,10 @@ const computeMigrationChecksum = (filePath) => {
|
|
|
3907
4146
|
return createHash("sha256").update(source).digest("hex");
|
|
3908
4147
|
};
|
|
3909
4148
|
const readAppliedMigrationsState = (stateFilePath) => {
|
|
3910
|
-
if (!existsSync$1(stateFilePath)) return
|
|
4149
|
+
if (!existsSync$1(stateFilePath)) return createEmptyAppliedMigrationsState();
|
|
3911
4150
|
try {
|
|
3912
4151
|
const parsed = JSON.parse(readFileSync$1(stateFilePath, "utf-8"));
|
|
3913
|
-
if (!Array.isArray(parsed.migrations)) return
|
|
4152
|
+
if (!Array.isArray(parsed.migrations)) return createEmptyAppliedMigrationsState();
|
|
3914
4153
|
return {
|
|
3915
4154
|
version: 1,
|
|
3916
4155
|
migrations: parsed.migrations.filter((migration) => {
|
|
@@ -3921,14 +4160,34 @@ const readAppliedMigrationsState = (stateFilePath) => {
|
|
|
3921
4160
|
}) : []
|
|
3922
4161
|
};
|
|
3923
4162
|
} catch {
|
|
3924
|
-
return
|
|
4163
|
+
return createEmptyAppliedMigrationsState();
|
|
3925
4164
|
}
|
|
3926
4165
|
};
|
|
4166
|
+
const readAppliedMigrationsStateFromStore = async (adapter, stateFilePath) => {
|
|
4167
|
+
if (supportsDatabaseMigrationState(adapter)) return await adapter.readAppliedMigrationsState();
|
|
4168
|
+
return readAppliedMigrationsState(stateFilePath);
|
|
4169
|
+
};
|
|
3927
4170
|
const writeAppliedMigrationsState = (stateFilePath, state) => {
|
|
3928
4171
|
const directory = dirname(stateFilePath);
|
|
3929
4172
|
if (!existsSync$1(directory)) mkdirSync$1(directory, { recursive: true });
|
|
3930
4173
|
writeFileSync$1(stateFilePath, JSON.stringify(state, null, 2));
|
|
3931
4174
|
};
|
|
4175
|
+
const writeAppliedMigrationsStateToStore = async (adapter, stateFilePath, state) => {
|
|
4176
|
+
if (supportsDatabaseMigrationState(adapter)) {
|
|
4177
|
+
await adapter.writeAppliedMigrationsState(state);
|
|
4178
|
+
return;
|
|
4179
|
+
}
|
|
4180
|
+
writeAppliedMigrationsState(stateFilePath, state);
|
|
4181
|
+
};
|
|
4182
|
+
const deleteAppliedMigrationsStateFromStore = async (adapter, stateFilePath) => {
|
|
4183
|
+
if (supportsDatabaseMigrationState(adapter)) {
|
|
4184
|
+
await adapter.writeAppliedMigrationsState(createEmptyAppliedMigrationsState());
|
|
4185
|
+
return "database";
|
|
4186
|
+
}
|
|
4187
|
+
if (!existsSync$1(stateFilePath)) return "missing-file";
|
|
4188
|
+
writeAppliedMigrationsState(stateFilePath, createEmptyAppliedMigrationsState());
|
|
4189
|
+
return "file";
|
|
4190
|
+
};
|
|
3932
4191
|
const isMigrationApplied = (state, identity, checksum) => {
|
|
3933
4192
|
const matched = state.migrations.find((migration) => migration.id === identity);
|
|
3934
4193
|
if (!matched) return false;
|
|
@@ -4047,7 +4306,9 @@ var MigrateCommand = class extends Command {
|
|
|
4047
4306
|
const classes = this.option("all") || !this.argument("name") ? await this.loadAllMigrations(migrationsDir) : (await this.loadNamedMigration(migrationsDir, this.argument("name"))).filter(([cls]) => cls !== void 0);
|
|
4048
4307
|
if (classes.length === 0) return void this.error("Error: No migration classes found to run.");
|
|
4049
4308
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
4050
|
-
let appliedState =
|
|
4309
|
+
let appliedState = await readAppliedMigrationsStateFromStore(this.app.getConfig("adapter"), stateFilePath);
|
|
4310
|
+
const adapter = this.app.getConfig("adapter");
|
|
4311
|
+
const useDatabaseMigrations = supportsDatabaseMigrationExecution(adapter);
|
|
4051
4312
|
const skipped = [];
|
|
4052
4313
|
const changed = [];
|
|
4053
4314
|
const pending = classes.filter(([migrationClass, file]) => {
|
|
@@ -4069,10 +4330,16 @@ var MigrateCommand = class extends Command {
|
|
|
4069
4330
|
this.success("No pending migration classes to apply.");
|
|
4070
4331
|
return;
|
|
4071
4332
|
}
|
|
4072
|
-
for (const [MigrationClassItem] of pending)
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4333
|
+
for (const [MigrationClassItem] of pending) {
|
|
4334
|
+
if (useDatabaseMigrations) {
|
|
4335
|
+
await applyMigrationToDatabase(adapter, MigrationClassItem);
|
|
4336
|
+
continue;
|
|
4337
|
+
}
|
|
4338
|
+
await applyMigrationToPrismaSchema(MigrationClassItem, {
|
|
4339
|
+
schemaPath,
|
|
4340
|
+
write: true
|
|
4341
|
+
});
|
|
4342
|
+
}
|
|
4076
4343
|
if (appliedState) {
|
|
4077
4344
|
const runAppliedIds = [];
|
|
4078
4345
|
for (const [migrationClass, file] of pending) {
|
|
@@ -4091,10 +4358,10 @@ var MigrateCommand = class extends Command {
|
|
|
4091
4358
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4092
4359
|
migrationIds: runAppliedIds
|
|
4093
4360
|
});
|
|
4094
|
-
|
|
4361
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
4095
4362
|
}
|
|
4096
|
-
if (!this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
4097
|
-
if (!this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
4363
|
+
if (!useDatabaseMigrations && !this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
4364
|
+
if (!useDatabaseMigrations && !this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
4098
4365
|
else runPrismaCommand([
|
|
4099
4366
|
"migrate",
|
|
4100
4367
|
"dev",
|
|
@@ -4154,6 +4421,85 @@ var MigrateCommand = class extends Command {
|
|
|
4154
4421
|
}
|
|
4155
4422
|
};
|
|
4156
4423
|
|
|
4424
|
+
//#endregion
|
|
4425
|
+
//#region src/cli/commands/MigrateFreshCommand.ts
|
|
4426
|
+
var MigrateFreshCommand = class extends Command {
|
|
4427
|
+
signature = `migrate:fresh
|
|
4428
|
+
{--skip-generate : Skip prisma generate}
|
|
4429
|
+
{--skip-migrate : Skip prisma database sync}
|
|
4430
|
+
{--state-file= : Path to applied migration state file}
|
|
4431
|
+
{--schema= : Explicit prisma schema path}
|
|
4432
|
+
`;
|
|
4433
|
+
description = "Reset the database and rerun all migration classes";
|
|
4434
|
+
async handle() {
|
|
4435
|
+
this.app.command = this;
|
|
4436
|
+
const configuredMigrationsDir = this.app.getConfig("paths")?.migrations ?? join(process.cwd(), "database", "migrations");
|
|
4437
|
+
const migrationsDir = this.app.resolveRuntimeDirectoryPath(configuredMigrationsDir);
|
|
4438
|
+
if (!existsSync$1(migrationsDir)) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
|
|
4439
|
+
const adapter = this.app.getConfig("adapter");
|
|
4440
|
+
const useDatabaseMigrations = supportsDatabaseMigrationExecution(adapter);
|
|
4441
|
+
const schemaPath = this.option("schema") ? resolve(String(this.option("schema"))) : join(process.cwd(), "prisma", "schema.prisma");
|
|
4442
|
+
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
4443
|
+
const migrations = await this.loadAllMigrations(migrationsDir);
|
|
4444
|
+
if (migrations.length === 0) return void this.error("Error: No migration classes found to run.");
|
|
4445
|
+
if (supportsDatabaseReset(adapter)) await adapter.resetDatabase();
|
|
4446
|
+
else {
|
|
4447
|
+
if (!existsSync$1(schemaPath)) return void this.error(`Error: Prisma schema file not found: ${this.app.formatPathForLog(schemaPath)}`);
|
|
4448
|
+
writeFileSync$1(schemaPath, stripPrismaSchemaModelsAndEnums(readFileSync$1(schemaPath, "utf-8")));
|
|
4449
|
+
}
|
|
4450
|
+
let appliedState = createEmptyAppliedMigrationsState();
|
|
4451
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
4452
|
+
for (const [MigrationClassItem] of migrations) {
|
|
4453
|
+
if (useDatabaseMigrations) {
|
|
4454
|
+
await applyMigrationToDatabase(adapter, MigrationClassItem);
|
|
4455
|
+
continue;
|
|
4456
|
+
}
|
|
4457
|
+
await applyMigrationToPrismaSchema(MigrationClassItem, {
|
|
4458
|
+
schemaPath,
|
|
4459
|
+
write: true
|
|
4460
|
+
});
|
|
4461
|
+
}
|
|
4462
|
+
for (const [migrationClass, file] of migrations) appliedState = markMigrationApplied(appliedState, {
|
|
4463
|
+
id: buildMigrationIdentity(file, migrationClass.name),
|
|
4464
|
+
file,
|
|
4465
|
+
className: migrationClass.name,
|
|
4466
|
+
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4467
|
+
checksum: computeMigrationChecksum(file)
|
|
4468
|
+
});
|
|
4469
|
+
appliedState = markMigrationRun(appliedState, {
|
|
4470
|
+
id: buildMigrationRunId(),
|
|
4471
|
+
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4472
|
+
migrationIds: appliedState.migrations.map((migration) => migration.id)
|
|
4473
|
+
});
|
|
4474
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
4475
|
+
if (!useDatabaseMigrations) {
|
|
4476
|
+
const schemaArgs = this.option("schema") ? ["--schema", schemaPath] : [];
|
|
4477
|
+
if (!this.option("skip-generate")) runPrismaCommand(["generate", ...schemaArgs], process.cwd());
|
|
4478
|
+
if (!this.option("skip-migrate")) runPrismaCommand([
|
|
4479
|
+
"db",
|
|
4480
|
+
"push",
|
|
4481
|
+
"--force-reset",
|
|
4482
|
+
...schemaArgs
|
|
4483
|
+
], process.cwd());
|
|
4484
|
+
}
|
|
4485
|
+
this.success(`Refreshed database with ${migrations.length} migration(s).`);
|
|
4486
|
+
migrations.forEach(([_, file]) => this.success(this.app.splitLogger("Migrated", file)));
|
|
4487
|
+
}
|
|
4488
|
+
async loadAllMigrations(migrationsDir) {
|
|
4489
|
+
const files = readdirSync$1(migrationsDir).filter((file) => /\.(ts|js|mjs|cjs)$/i.test(file)).sort((left, right) => left.localeCompare(right)).map((file) => this.app.resolveRuntimeScriptPath(join(migrationsDir, file)));
|
|
4490
|
+
return (await Promise.all(files.map(async (file) => (await this.loadMigrationClassesFromFile(file)).map((cls) => [cls, file])))).flat();
|
|
4491
|
+
}
|
|
4492
|
+
async loadMigrationClassesFromFile(filePath) {
|
|
4493
|
+
const imported = await RuntimeModuleLoader.load(filePath);
|
|
4494
|
+
return Object.values(imported).filter((value) => {
|
|
4495
|
+
if (typeof value !== "function") return false;
|
|
4496
|
+
const candidate = value;
|
|
4497
|
+
const prototype = candidate.prototype;
|
|
4498
|
+
return candidate[MIGRATION_BRAND] === true || typeof prototype?.up === "function" && typeof prototype?.down === "function";
|
|
4499
|
+
});
|
|
4500
|
+
}
|
|
4501
|
+
};
|
|
4502
|
+
|
|
4157
4503
|
//#endregion
|
|
4158
4504
|
//#region src/cli/commands/MigrateRollbackCommand.ts
|
|
4159
4505
|
/**
|
|
@@ -4182,7 +4528,9 @@ var MigrateRollbackCommand = class extends Command {
|
|
|
4182
4528
|
if (!existsSync$1(migrationsDir)) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
|
|
4183
4529
|
const schemaPath = this.option("schema") ? resolve(String(this.option("schema"))) : join(process.cwd(), "prisma", "schema.prisma");
|
|
4184
4530
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
4185
|
-
|
|
4531
|
+
const adapter = this.app.getConfig("adapter");
|
|
4532
|
+
const useDatabaseMigrations = supportsDatabaseMigrationExecution(adapter);
|
|
4533
|
+
let appliedState = await readAppliedMigrationsStateFromStore(adapter, stateFilePath);
|
|
4186
4534
|
const stepOption = this.option("step");
|
|
4187
4535
|
const stepCount = stepOption == null ? void 0 : Number(stepOption);
|
|
4188
4536
|
if (stepCount != null && (!Number.isFinite(stepCount) || stepCount <= 0 || !Number.isInteger(stepCount))) return void this.error("Error: --step must be a positive integer.");
|
|
@@ -4204,17 +4552,23 @@ var MigrateRollbackCommand = class extends Command {
|
|
|
4204
4552
|
rollbackClasses.forEach(([_, file]) => this.success(this.app.splitLogger("WouldRollback", file)));
|
|
4205
4553
|
return;
|
|
4206
4554
|
}
|
|
4207
|
-
for (const [MigrationClassItem] of rollbackClasses)
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4555
|
+
for (const [MigrationClassItem] of rollbackClasses) {
|
|
4556
|
+
if (useDatabaseMigrations) {
|
|
4557
|
+
await applyMigrationRollbackToDatabase(adapter, MigrationClassItem);
|
|
4558
|
+
continue;
|
|
4559
|
+
}
|
|
4560
|
+
await applyMigrationRollbackToPrismaSchema(MigrationClassItem, {
|
|
4561
|
+
schemaPath,
|
|
4562
|
+
write: true
|
|
4563
|
+
});
|
|
4564
|
+
}
|
|
4211
4565
|
for (const [migrationClass, file] of rollbackClasses) {
|
|
4212
4566
|
const identity = buildMigrationIdentity(file, migrationClass.name);
|
|
4213
4567
|
appliedState = removeAppliedMigration(appliedState, identity);
|
|
4214
4568
|
}
|
|
4215
|
-
|
|
4216
|
-
if (!this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
4217
|
-
if (!this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
4569
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
4570
|
+
if (!useDatabaseMigrations && !this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
4571
|
+
if (!useDatabaseMigrations && !this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
4218
4572
|
else runPrismaCommand([
|
|
4219
4573
|
"migrate",
|
|
4220
4574
|
"dev",
|
|
@@ -4258,7 +4612,14 @@ var MigrationHistoryCommand = class extends Command {
|
|
|
4258
4612
|
async handle() {
|
|
4259
4613
|
this.app.command = this;
|
|
4260
4614
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
4615
|
+
const adapter = this.app.getConfig("adapter");
|
|
4616
|
+
const usesDatabaseState = supportsDatabaseMigrationState(adapter);
|
|
4261
4617
|
if (this.option("delete")) {
|
|
4618
|
+
if (usesDatabaseState) {
|
|
4619
|
+
await adapter.writeAppliedMigrationsState(createEmptyAppliedMigrationsState());
|
|
4620
|
+
this.success("Deleted tracked migration state from database.");
|
|
4621
|
+
return;
|
|
4622
|
+
}
|
|
4262
4623
|
if (!existsSync$1(stateFilePath)) {
|
|
4263
4624
|
this.success(`No migration state file found at ${this.app.formatPathForLog(stateFilePath)}`);
|
|
4264
4625
|
return;
|
|
@@ -4268,22 +4629,19 @@ var MigrationHistoryCommand = class extends Command {
|
|
|
4268
4629
|
return;
|
|
4269
4630
|
}
|
|
4270
4631
|
if (this.option("reset")) {
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
migrations: []
|
|
4274
|
-
});
|
|
4275
|
-
this.success(`Reset migration state: ${this.app.formatPathForLog(stateFilePath)}`);
|
|
4632
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, createEmptyAppliedMigrationsState());
|
|
4633
|
+
this.success(usesDatabaseState ? "Reset migration state in database." : `Reset migration state: ${this.app.formatPathForLog(stateFilePath)}`);
|
|
4276
4634
|
return;
|
|
4277
4635
|
}
|
|
4278
|
-
const state =
|
|
4636
|
+
const state = await readAppliedMigrationsStateFromStore(adapter, stateFilePath);
|
|
4279
4637
|
if (this.option("json")) {
|
|
4280
4638
|
this.success(JSON.stringify({
|
|
4281
|
-
path: stateFilePath,
|
|
4639
|
+
path: usesDatabaseState ? "database" : stateFilePath,
|
|
4282
4640
|
...state
|
|
4283
4641
|
}, null, 2));
|
|
4284
4642
|
return;
|
|
4285
4643
|
}
|
|
4286
|
-
this.success(this.app.splitLogger("State", stateFilePath));
|
|
4644
|
+
this.success(this.app.splitLogger("State", usesDatabaseState ? "database" : stateFilePath));
|
|
4287
4645
|
this.success(this.app.splitLogger("Tracked", String(state.migrations.length)));
|
|
4288
4646
|
if (state.migrations.length === 0) {
|
|
4289
4647
|
this.success("No tracked migrations found.");
|
|
@@ -9250,4 +9608,4 @@ var Model = class Model {
|
|
|
9250
9608
|
};
|
|
9251
9609
|
|
|
9252
9610
|
//#endregion
|
|
9253
|
-
export { ArkormCollection, ArkormException, Attribute, CliApp, EnumBuilder, ForeignKeyBuilder, InitCommand, InlineFactory, KyselyDatabaseAdapter, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, MissingDelegateException, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_ENUM_MEMBER_REGEX, PRISMA_ENUM_REGEX, PRISMA_MODEL_REGEX, Paginator, PrismaDatabaseAdapter, QueryBuilder, QueryConstraintException, RelationResolutionException, RuntimeModuleLoader, SEEDER_BRAND, SchemaBuilder, ScopeNotDefinedException, SeedCommand, Seeder, TableBuilder, URLDriver, UniqueConstraintResolutionException, UnsupportedAdapterFeatureException, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToPrismaSchema, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, bindAdapterToModels, buildEnumBlock, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createKyselyAdapter, createMigrationTimestamp, createPrismaAdapter, createPrismaCompatibilityAdapter, createPrismaDatabaseAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationAlias, deriveRelationFieldName, deriveSingularFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findEnumBlock, findModelBlock, formatDefaultValue, formatEnumDefaultValue, formatRelationAction, generateMigrationFile, getActiveTransactionClient, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimeAdapter, getRuntimePaginationCurrentPageResolver, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, isTransactionCapableClient, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveEnumName, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runArkormTransaction, runMigrationWithPrisma, runPrismaCommand, toMigrationFileSlug, toModelName, writeAppliedMigrationsState };
|
|
9611
|
+
export { ArkormCollection, ArkormException, Attribute, CliApp, EnumBuilder, ForeignKeyBuilder, InitCommand, InlineFactory, KyselyDatabaseAdapter, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateFreshCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, MissingDelegateException, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_ENUM_MEMBER_REGEX, PRISMA_ENUM_REGEX, PRISMA_MODEL_REGEX, Paginator, PrismaDatabaseAdapter, QueryBuilder, QueryConstraintException, RelationResolutionException, RuntimeModuleLoader, SEEDER_BRAND, SchemaBuilder, ScopeNotDefinedException, SeedCommand, Seeder, TableBuilder, URLDriver, UniqueConstraintResolutionException, UnsupportedAdapterFeatureException, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToDatabase, applyMigrationRollbackToPrismaSchema, applyMigrationToDatabase, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, bindAdapterToModels, buildEnumBlock, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createEmptyAppliedMigrationsState, createKyselyAdapter, createMigrationTimestamp, createPrismaAdapter, createPrismaCompatibilityAdapter, createPrismaDatabaseAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deleteAppliedMigrationsStateFromStore, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationAlias, deriveRelationFieldName, deriveSingularFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findEnumBlock, findModelBlock, formatDefaultValue, formatEnumDefaultValue, formatRelationAction, generateMigrationFile, getActiveTransactionClient, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimeAdapter, getRuntimePaginationCurrentPageResolver, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, isTransactionCapableClient, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, readAppliedMigrationsStateFromStore, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveEnumName, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runArkormTransaction, runMigrationWithPrisma, runPrismaCommand, stripPrismaSchemaModelsAndEnums, supportsDatabaseMigrationExecution, supportsDatabaseMigrationState, supportsDatabaseReset, toMigrationFileSlug, toModelName, writeAppliedMigrationsState, writeAppliedMigrationsStateToStore };
|