arkormx 2.10.1 → 2.11.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.
@@ -1126,6 +1126,423 @@ var PrimaryKeyGenerationPlanner = class {
1126
1126
  }
1127
1127
  };
1128
1128
 
1129
+ //#endregion
1130
+ //#region src/Expression.ts
1131
+ /**
1132
+ * A composable SQL expression. Instances are immutable — every operator returns a
1133
+ * new expression — and are accepted by `select`, `where`, `groupBy`, `orderBy`,
1134
+ * `having`, and the aggregate helpers. Adapters compile the underlying node tree.
1135
+ */
1136
+ var Expression = class Expression {
1137
+ /**
1138
+ * Type guard for values that came out of the expression builder.
1139
+ */
1140
+ static isExpression(value) {
1141
+ return value instanceof Expression;
1142
+ }
1143
+ eq(value) {
1144
+ return binary("=", this, coerceValue(value));
1145
+ }
1146
+ ne(value) {
1147
+ return binary("!=", this, coerceValue(value));
1148
+ }
1149
+ gt(value) {
1150
+ return binary(">", this, coerceValue(value));
1151
+ }
1152
+ gte(value) {
1153
+ return binary(">=", this, coerceValue(value));
1154
+ }
1155
+ lt(value) {
1156
+ return binary("<", this, coerceValue(value));
1157
+ }
1158
+ lte(value) {
1159
+ return binary("<=", this, coerceValue(value));
1160
+ }
1161
+ like(value) {
1162
+ return binary("like", this, coerceValue(value));
1163
+ }
1164
+ ilike(value) {
1165
+ return binary("ilike", this, coerceValue(value));
1166
+ }
1167
+ notLike(value) {
1168
+ return binary("not-like", this, coerceValue(value));
1169
+ }
1170
+ notIlike(value) {
1171
+ return binary("not-ilike", this, coerceValue(value));
1172
+ }
1173
+ in(values) {
1174
+ return new NodeExpression({
1175
+ kind: "in",
1176
+ operand: this.toExpressionNode(),
1177
+ values: values.map((value) => coerceValue(value).toExpressionNode()),
1178
+ not: false
1179
+ });
1180
+ }
1181
+ notIn(values) {
1182
+ return new NodeExpression({
1183
+ kind: "in",
1184
+ operand: this.toExpressionNode(),
1185
+ values: values.map((value) => coerceValue(value).toExpressionNode()),
1186
+ not: true
1187
+ });
1188
+ }
1189
+ isNull() {
1190
+ return new NodeExpression({
1191
+ kind: "null-check",
1192
+ operand: this.toExpressionNode(),
1193
+ not: false
1194
+ });
1195
+ }
1196
+ isNotNull() {
1197
+ return new NodeExpression({
1198
+ kind: "null-check",
1199
+ operand: this.toExpressionNode(),
1200
+ not: true
1201
+ });
1202
+ }
1203
+ and(other) {
1204
+ return binary("and", this, other);
1205
+ }
1206
+ or(other) {
1207
+ return binary("or", this, other);
1208
+ }
1209
+ plus(value) {
1210
+ return binary("+", this, coerceValue(value));
1211
+ }
1212
+ minus(value) {
1213
+ return binary("-", this, coerceValue(value));
1214
+ }
1215
+ times(value) {
1216
+ return binary("*", this, coerceValue(value));
1217
+ }
1218
+ dividedBy(value) {
1219
+ return binary("/", this, coerceValue(value));
1220
+ }
1221
+ };
1222
+ /**
1223
+ * Concrete expression backed by a pre-built node.
1224
+ */
1225
+ var NodeExpression = class extends Expression {
1226
+ constructor(node) {
1227
+ super();
1228
+ this.node = node;
1229
+ }
1230
+ toExpressionNode() {
1231
+ return this.node;
1232
+ }
1233
+ };
1234
+ /**
1235
+ * Fluent `CASE … WHEN … THEN … ELSE … END` builder. Immutable.
1236
+ */
1237
+ var CaseExpression = class CaseExpression extends Expression {
1238
+ constructor(branches, elseExpr) {
1239
+ super();
1240
+ this.branches = branches;
1241
+ this.elseExpr = elseExpr;
1242
+ }
1243
+ when(condition, result) {
1244
+ return new CaseExpression([...this.branches, {
1245
+ when: condition,
1246
+ then: coerceValue(result)
1247
+ }], this.elseExpr);
1248
+ }
1249
+ else(result) {
1250
+ return new CaseExpression(this.branches, coerceValue(result));
1251
+ }
1252
+ toExpressionNode() {
1253
+ return {
1254
+ kind: "case",
1255
+ cases: this.branches.map((branch) => ({
1256
+ when: branch.when.toExpressionNode(),
1257
+ then: branch.then.toExpressionNode()
1258
+ })),
1259
+ else: this.elseExpr?.toExpressionNode()
1260
+ };
1261
+ }
1262
+ };
1263
+ /**
1264
+ * JSON-path value extraction (`metadata ->> 'billType'`), with optional casts.
1265
+ */
1266
+ var JsonExpression = class JsonExpression extends Expression {
1267
+ constructor(column, path, castTo) {
1268
+ super();
1269
+ this.column = column;
1270
+ this.path = path;
1271
+ this.castTo = castTo;
1272
+ }
1273
+ asText() {
1274
+ return new JsonExpression(this.column, this.path, "text");
1275
+ }
1276
+ asNumber() {
1277
+ return new JsonExpression(this.column, this.path, "number");
1278
+ }
1279
+ asBoolean() {
1280
+ return new JsonExpression(this.column, this.path, "boolean");
1281
+ }
1282
+ toExpressionNode() {
1283
+ return {
1284
+ kind: "json",
1285
+ column: this.column,
1286
+ path: this.path,
1287
+ cast: this.castTo
1288
+ };
1289
+ }
1290
+ };
1291
+ /**
1292
+ * Aggregate expression (`sum`, `count`, `avg`, `min`, `max`) with optional filter.
1293
+ */
1294
+ var AggregateExpression = class AggregateExpression extends Expression {
1295
+ constructor(fn, arg, options = {}) {
1296
+ super();
1297
+ this.fn = fn;
1298
+ this.arg = arg;
1299
+ this.options = options;
1300
+ }
1301
+ /**
1302
+ * Restricts the aggregate to rows matching `predicate` (`FILTER (WHERE …)`).
1303
+ */
1304
+ filter(predicate) {
1305
+ return new AggregateExpression(this.fn, this.arg, {
1306
+ ...this.options,
1307
+ filterExpr: predicate
1308
+ });
1309
+ }
1310
+ distinct() {
1311
+ return new AggregateExpression(this.fn, this.arg, {
1312
+ ...this.options,
1313
+ distinct: true
1314
+ });
1315
+ }
1316
+ toExpressionNode() {
1317
+ return {
1318
+ kind: "aggregate",
1319
+ fn: this.fn,
1320
+ arg: this.arg?.toExpressionNode(),
1321
+ distinct: this.options.distinct,
1322
+ filter: this.options.filterExpr?.toExpressionNode()
1323
+ };
1324
+ }
1325
+ };
1326
+ const binary = (operator, left, right) => new NodeExpression({
1327
+ kind: "binary",
1328
+ operator,
1329
+ left: left.toExpressionNode(),
1330
+ right: right.toExpressionNode()
1331
+ });
1332
+ /**
1333
+ * Coerces a raw value into a bound-literal expression; passes expressions through.
1334
+ */
1335
+ const coerceValue = (value) => {
1336
+ if (value instanceof Expression) return value;
1337
+ return new NodeExpression({
1338
+ kind: "value",
1339
+ value
1340
+ });
1341
+ };
1342
+ /**
1343
+ * Coerces a bare string into a column reference; passes expressions through.
1344
+ */
1345
+ const coerceColumn = (value) => {
1346
+ if (value instanceof Expression) return value;
1347
+ if (typeof value === "string") return col(value);
1348
+ return coerceValue(value);
1349
+ };
1350
+ /**
1351
+ * Rebuilds an {@link Expression} around an already-serialized node.
1352
+ */
1353
+ const fromExpressionNode = (node) => new NodeExpression(node);
1354
+ /**
1355
+ * A typed column reference. Supports joined `table.column` syntax.
1356
+ */
1357
+ const col = (name) => new NodeExpression({
1358
+ kind: "column",
1359
+ name
1360
+ });
1361
+ /**
1362
+ * A bound literal value (parameterized, never interpolated).
1363
+ */
1364
+ const val = (value) => new NodeExpression({
1365
+ kind: "value",
1366
+ value
1367
+ });
1368
+ /**
1369
+ * Raw SQL escape hatch with positional `?` bindings.
1370
+ */
1371
+ const raw = (sql, bindings = []) => new NodeExpression({
1372
+ kind: "raw",
1373
+ sql,
1374
+ bindings
1375
+ });
1376
+ /**
1377
+ * Starts a `CASE WHEN condition THEN result` expression.
1378
+ */
1379
+ const caseWhen = (condition, result) => new CaseExpression([{
1380
+ when: condition,
1381
+ then: coerceValue(result)
1382
+ }]);
1383
+ /**
1384
+ * `COALESCE(a, b, …)` — first non-null argument. Bare strings are columns.
1385
+ */
1386
+ const coalesce = (...args) => new NodeExpression({
1387
+ kind: "function",
1388
+ name: "coalesce",
1389
+ args: args.map((arg) => coerceColumn(arg).toExpressionNode())
1390
+ });
1391
+ /**
1392
+ * An arbitrary SQL function call. Bare-string arguments are treated as columns.
1393
+ */
1394
+ const fn = (name, ...args) => new NodeExpression({
1395
+ kind: "function",
1396
+ name,
1397
+ args: args.map((arg) => coerceColumn(arg).toExpressionNode())
1398
+ });
1399
+ /**
1400
+ * JSON value extraction: `json('metadata', 'billType')` => `metadata ->> 'billType'`.
1401
+ */
1402
+ const json = (column, ...path) => new JsonExpression(column, path.map(String));
1403
+ /**
1404
+ * `SUM(expr)`; a bare-string argument is treated as a column.
1405
+ */
1406
+ const sum = (arg) => new AggregateExpression("sum", coerceColumn(arg));
1407
+ /**
1408
+ * `AVG(expr)`; a bare-string argument is treated as a column.
1409
+ */
1410
+ const avg = (arg) => new AggregateExpression("avg", coerceColumn(arg));
1411
+ /**
1412
+ * `MIN(expr)`; a bare-string argument is treated as a column.
1413
+ */
1414
+ const min = (arg) => new AggregateExpression("min", coerceColumn(arg));
1415
+ /**
1416
+ * `MAX(expr)`; a bare-string argument is treated as a column.
1417
+ */
1418
+ const max = (arg) => new AggregateExpression("max", coerceColumn(arg));
1419
+ /**
1420
+ * `COUNT(expr)` — or `COUNT(*)` when called without an argument.
1421
+ */
1422
+ const count = (arg) => new AggregateExpression("count", arg === void 0 ? void 0 : coerceColumn(arg));
1423
+ const EXPRESSION_OPERATORS = {
1424
+ "=": "=",
1425
+ "==": "=",
1426
+ "!=": "!=",
1427
+ "<>": "!=",
1428
+ ">": ">",
1429
+ ">=": ">=",
1430
+ "<": "<",
1431
+ "<=": "<=",
1432
+ like: "like",
1433
+ ilike: "ilike",
1434
+ "not like": "not-like",
1435
+ "not ilike": "not-ilike"
1436
+ };
1437
+ /**
1438
+ * Builds a comparison predicate: `where('createdAt', '>=', boundary)`. Handy as an
1439
+ * inline predicate for `caseWhen`, `having`, and aggregate `.filter(…)`.
1440
+ */
1441
+ const where = (column, operator, value) => {
1442
+ const normalized = EXPRESSION_OPERATORS[operator];
1443
+ if (!normalized) throw new Error(`Unsupported expression operator [${operator}].`);
1444
+ return binary(normalized, col(column), coerceValue(value));
1445
+ };
1446
+ /**
1447
+ * The expression-builder namespace passed to `static computed` factories, so a
1448
+ * model can declare a virtual attribute as `category: (e) => e.coalesce(…)`.
1449
+ */
1450
+ const expressionBuilder = {
1451
+ col,
1452
+ val,
1453
+ raw,
1454
+ caseWhen,
1455
+ coalesce,
1456
+ fn,
1457
+ json,
1458
+ sum,
1459
+ avg,
1460
+ min,
1461
+ max,
1462
+ count,
1463
+ where
1464
+ };
1465
+
1466
+ //#endregion
1467
+ //#region src/helpers/generated-column.ts
1468
+ /**
1469
+ * Resolves a generated-column expression into raw Postgres SQL. Generated columns
1470
+ * cannot carry bind parameters (they must be immutable), so literal values are
1471
+ * inlined and aggregates are rejected.
1472
+ */
1473
+ const resolveGeneratedExpression = (expression) => {
1474
+ if (typeof expression === "string") return expression;
1475
+ return expressionNodeToSql(expression(expressionBuilder).toExpressionNode());
1476
+ };
1477
+ const quoteIdentifier = (name) => name.split(".").map((part) => `"${part.replace(/"/g, "\"\"")}"`).join(".");
1478
+ const quoteLiteral = (value) => {
1479
+ if (value === null || value === void 0) return "null";
1480
+ if (typeof value === "number" || typeof value === "bigint") return String(value);
1481
+ if (typeof value === "boolean") return value ? "true" : "false";
1482
+ if (value instanceof Date) return `'${value.toISOString()}'`;
1483
+ return `'${String(value).replace(/'/g, "''")}'`;
1484
+ };
1485
+ const BINARY_OPERATORS = {
1486
+ "=": "=",
1487
+ "!=": "!=",
1488
+ ">": ">",
1489
+ ">=": ">=",
1490
+ "<": "<",
1491
+ "<=": "<=",
1492
+ like: "like",
1493
+ ilike: "ilike",
1494
+ "not-like": "not like",
1495
+ "not-ilike": "not ilike",
1496
+ and: "and",
1497
+ or: "or",
1498
+ "+": "+",
1499
+ "-": "-",
1500
+ "*": "*",
1501
+ "/": "/"
1502
+ };
1503
+ const FUNCTION_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
1504
+ const jsonAccessorSql = (node) => {
1505
+ const base = `${quoteIdentifier(node.column)}::jsonb`;
1506
+ let accessor;
1507
+ if (node.path.length === 0) accessor = base;
1508
+ else if (node.path.length === 1) accessor = `(${base} ->> ${quoteLiteral(node.path[0])})`;
1509
+ else accessor = `(${base} #>> '{${node.path.join(",")}}'::text[])`;
1510
+ if (node.cast === "number") return `(${accessor})::numeric`;
1511
+ if (node.cast === "boolean") return `(${accessor})::boolean`;
1512
+ return accessor;
1513
+ };
1514
+ const expressionNodeToSql = (node) => {
1515
+ switch (node.kind) {
1516
+ case "column": return quoteIdentifier(node.name);
1517
+ case "value": return quoteLiteral(node.value);
1518
+ case "raw": return inlineRawSql(node.sql, node.bindings);
1519
+ case "json": return jsonAccessorSql(node);
1520
+ case "function":
1521
+ if (!FUNCTION_NAME.test(node.name)) throw new ArkormException(`Unsupported SQL function name [${node.name}].`);
1522
+ return `${node.name}(${node.args.map(expressionNodeToSql).join(", ")})`;
1523
+ case "case": return `case ${node.cases.map((branch) => `when ${expressionNodeToSql(branch.when)} then ${expressionNodeToSql(branch.then)}`).join(" ")}${node.else ? ` else ${expressionNodeToSql(node.else)}` : ""} end`;
1524
+ case "binary": {
1525
+ const operator = BINARY_OPERATORS[node.operator];
1526
+ return `(${expressionNodeToSql(node.left)} ${operator} ${expressionNodeToSql(node.right)})`;
1527
+ }
1528
+ case "in": {
1529
+ const values = node.values.map(expressionNodeToSql).join(", ");
1530
+ return `(${expressionNodeToSql(node.operand)} ${node.not ? "not in" : "in"} (${values}))`;
1531
+ }
1532
+ case "null-check": return `(${expressionNodeToSql(node.operand)} is ${node.not ? "not null" : "null"})`;
1533
+ case "aggregate": throw new ArkormException("Aggregate expressions are not allowed in generated columns.");
1534
+ default: throw new ArkormException(`Unsupported expression node [${node.kind}].`);
1535
+ }
1536
+ };
1537
+ const inlineRawSql = (sql, bindings) => {
1538
+ const segments = sql.split("?");
1539
+ if (segments.length !== bindings.length + 1) throw new ArkormException("Raw expression bindings do not match the number of placeholders.");
1540
+ return segments.reduce((accumulator, segment, index) => {
1541
+ const binding = index < bindings.length ? quoteLiteral(bindings[index]) : "";
1542
+ return accumulator + segment + binding;
1543
+ }, "");
1544
+ };
1545
+
1129
1546
  //#endregion
1130
1547
  //#region src/database/TableBuilder.ts
1131
1548
  const PRISMA_ENUM_MEMBER_REGEX$1 = /^[A-Za-z][A-Za-z0-9_]*$/;
@@ -1218,6 +1635,15 @@ var EnumBuilder = class {
1218
1635
  this.tableBuilder.map(name, this.columnName);
1219
1636
  return this;
1220
1637
  }
1638
+ /**
1639
+ * Marks the enum column as an in-place change to an existing column.
1640
+ *
1641
+ * @returns
1642
+ */
1643
+ change() {
1644
+ this.tableBuilder.change(this.columnName);
1645
+ return this;
1646
+ }
1221
1647
  };
1222
1648
  /**
1223
1649
  * The TableBuilder class provides a fluent interface for defining
@@ -1230,6 +1656,7 @@ var TableBuilder = class {
1230
1656
  constructor() {
1231
1657
  this.columns = [];
1232
1658
  this.dropColumnNames = [];
1659
+ this.changeColumnNames = /* @__PURE__ */ new Set();
1233
1660
  this.indexes = [];
1234
1661
  this.foreignKeys = [];
1235
1662
  this.compositeUniqueConstraints = [];
@@ -1419,6 +1846,30 @@ var TableBuilder = class {
1419
1846
  return this.column(name, "dateTime", options);
1420
1847
  }
1421
1848
  /**
1849
+ * Defines a database-computed column (`GENERATED ALWAYS AS (…) STORED`). The
1850
+ * expression may be a raw SQL string or an expression-builder factory, and must
1851
+ * be immutable and reference only the row's own columns. Combine with
1852
+ * {@link index} to index the generated value.
1853
+ *
1854
+ * @example
1855
+ * table.generated('category', "case when metadata->>'kind' = 'a' then 'x' else 'y' end", {
1856
+ * type: 'text',
1857
+ * })
1858
+ * table.generated('total', (e) => e.col('price').times(e.col('quantity')), { type: 'integer' })
1859
+ *
1860
+ * @param name The generated column name.
1861
+ * @param expression The SQL expression string, or a builder factory.
1862
+ * @param options Column type (default `text`), `stored` flag, and nullability.
1863
+ * @returns
1864
+ */
1865
+ generated(name, expression, options = {}) {
1866
+ return this.column(name, options.type ?? "text", {
1867
+ generatedExpression: resolveGeneratedExpression(expression),
1868
+ generatedStored: options.stored ?? true,
1869
+ nullable: options.nullable
1870
+ });
1871
+ }
1872
+ /**
1422
1873
  * Defines colonns for a polymorphic relationship in the table.
1423
1874
  *
1424
1875
  * @param name The base name for the polymorphic relationship columns.
@@ -1543,6 +1994,24 @@ var TableBuilder = class {
1543
1994
  return this;
1544
1995
  }
1545
1996
  /**
1997
+ * Marks a (re)defined column as a change to an existing column rather than an
1998
+ * addition. Use it at the end of a normal column chain inside `alterTable` to
1999
+ * redefine the column's type, nullability, default, or enum values in place:
2000
+ *
2001
+ * ```ts
2002
+ * table.string('status').default('active').change()
2003
+ * table.enum('role', ['admin', 'user', 'guest']).change()
2004
+ * ```
2005
+ *
2006
+ * @param columnName Optional explicit column name. When omitted, applies to the latest defined column.
2007
+ * @returns The current TableBuilder instance for chaining.
2008
+ */
2009
+ change(columnName) {
2010
+ const column = this.resolveColumn(columnName);
2011
+ this.changeColumnNames.add(column.name);
2012
+ return this;
2013
+ }
2014
+ /**
1546
2015
  * Marks a column as nullable.
1547
2016
  *
1548
2017
  * @param columnName Optional explicit column name. When omitted, applies to the latest defined column.
@@ -1651,7 +2120,18 @@ var TableBuilder = class {
1651
2120
  * @returns
1652
2121
  */
1653
2122
  getColumns() {
1654
- return this.columns.map((column) => ({
2123
+ return this.columns.filter((column) => !this.changeColumnNames.has(column.name)).map((column) => ({
2124
+ ...column,
2125
+ enumValues: column.enumValues ? [...column.enumValues] : void 0
2126
+ }));
2127
+ }
2128
+ /**
2129
+ * Returns a deep copy of the columns flagged for in-place change via `change()`.
2130
+ *
2131
+ * @returns
2132
+ */
2133
+ getChangeColumns() {
2134
+ return this.columns.filter((column) => this.changeColumnNames.has(column.name)).map((column) => ({
1655
2135
  ...column,
1656
2136
  enumValues: column.enumValues ? [...column.enumValues] : void 0
1657
2137
  }));
@@ -1725,6 +2205,8 @@ var TableBuilder = class {
1725
2205
  updatedAt: options.updatedAt,
1726
2206
  precision: options.precision,
1727
2207
  scale: options.scale,
2208
+ generatedExpression: options.generatedExpression,
2209
+ generatedStored: options.generatedStored,
1728
2210
  primaryKeyGeneration: options.primaryKeyGeneration
1729
2211
  });
1730
2212
  const column = this.columns[this.columns.length - 1];
@@ -1873,6 +2355,7 @@ var SchemaBuilder = class SchemaBuilder {
1873
2355
  type: "alterTable",
1874
2356
  table,
1875
2357
  addColumns: builder.getColumns(),
2358
+ changeColumns: builder.getChangeColumns(),
1876
2359
  dropColumns: builder.getDropColumns(),
1877
2360
  addIndexes: builder.getIndexes(),
1878
2361
  addForeignKeys: builder.getForeignKeys(),
@@ -1927,6 +2410,10 @@ var SchemaBuilder = class SchemaBuilder {
1927
2410
  ...column,
1928
2411
  enumValues: column.enumValues ? [...column.enumValues] : void 0
1929
2412
  })),
2413
+ changeColumns: operation.changeColumns?.map((column) => ({
2414
+ ...column,
2415
+ enumValues: column.enumValues ? [...column.enumValues] : void 0
2416
+ })),
1930
2417
  dropColumns: [...operation.dropColumns],
1931
2418
  addIndexes: operation.addIndexes.map((index) => ({
1932
2419
  ...index,
@@ -2103,6 +2590,10 @@ const buildFieldLine = (column) => {
2103
2590
  const mapped = typeof column.map === "string" && column.map.trim().length > 0 ? ` @map("${column.map.replace(/"/g, "\\\"")}")` : "";
2104
2591
  const updatedAt = column.updatedAt ? " @updatedAt" : "";
2105
2592
  const nativeType = column.type === "decimal" ? ` @db.Decimal(${column.precision ?? 8}, ${column.scale ?? 2})` : "";
2593
+ if (column.generatedExpression) {
2594
+ const escaped = column.generatedExpression.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
2595
+ return ` ${column.name} ${scalar}${nullable}${unique} @default(dbgenerated("${escaped}"))${mapped}${nativeType}`;
2596
+ }
2106
2597
  const defaultValue = column.type === "enum" ? formatEnumDefaultValue(column.default) : column.primaryKeyGeneration?.prismaDefault ?? formatDefaultValue(column.default);
2107
2598
  const defaultSuffix = defaultValue ? ` ${defaultValue}` : "";
2108
2599
  return ` ${column.name} ${scalar}${nullable}${primary}${unique}${defaultSuffix}${updatedAt}${mapped}${nativeType}`;
@@ -2431,11 +2922,18 @@ const applyCreateTableOperation = (schema, operation) => {
2431
2922
  const applyAlterTableOperation = (schema, operation) => {
2432
2923
  const model = findModelBlock(schema, operation.table);
2433
2924
  if (!model) throw new ArkormException(`Prisma model for table [${operation.table}] was not found.`);
2434
- const schemaWithEnums = ensureEnumBlocks(schema, operation.addColumns);
2925
+ const schemaWithEnums = ensureEnumBlocks(schema, [...operation.addColumns, ...operation.changeColumns ?? []]);
2435
2926
  const refreshedModel = findModelBlock(schemaWithEnums, operation.table);
2436
2927
  if (!refreshedModel) throw new ArkormException(`Prisma model for table [${operation.table}] was not found.`);
2437
2928
  let block = refreshedModel.block;
2438
2929
  const bodyLines = block.split("\n");
2930
+ (operation.changeColumns ?? []).forEach((column) => {
2931
+ const fieldLine = buildFieldLine(column);
2932
+ const columnRegex = new RegExp(`^\\s*${escapeRegex(column.name)}\\s+`);
2933
+ const index = bodyLines.findIndex((line) => columnRegex.test(line));
2934
+ if (index >= 0) bodyLines.splice(index, 1, fieldLine);
2935
+ else bodyLines.splice(Math.max(1, bodyLines.length - 1), 0, fieldLine);
2936
+ });
2439
2937
  operation.dropColumns.forEach((column) => {
2440
2938
  const columnRegex = new RegExp(`^\\s*${escapeRegex(column)}\\s+`);
2441
2939
  for (let index = 0; index < bodyLines.length; index += 1) if (columnRegex.test(bodyLines[index])) {
@@ -2660,14 +3158,18 @@ const stripPrismaSchemaModelsAndEnums = (schema) => {
2660
3158
  };
2661
3159
  const applyMigrationToDatabase = async (adapter, migration) => {
2662
3160
  if (!supportsDatabaseMigrationExecution(adapter)) throw new ArkormException("The configured adapter does not support database-backed migration execution.");
2663
- const operations = await getMigrationPlan(migration, "up");
3161
+ const instance = typeof migration === "function" ? new migration() : migration;
3162
+ const operations = await getMigrationPlan(instance, "up");
2664
3163
  await adapter.executeSchemaOperations(operations);
3164
+ await instance.done?.("up");
2665
3165
  return { operations };
2666
3166
  };
2667
3167
  const applyMigrationRollbackToDatabase = async (adapter, migration) => {
2668
3168
  if (!supportsDatabaseMigrationExecution(adapter)) throw new ArkormException("The configured adapter does not support database-backed migration execution.");
2669
- const operations = await getMigrationPlan(migration, "down");
3169
+ const instance = typeof migration === "function" ? new migration() : migration;
3170
+ const operations = await getMigrationPlan(instance, "down");
2670
3171
  await adapter.executeSchemaOperations(operations);
3172
+ await instance.done?.("down");
2671
3173
  return { operations };
2672
3174
  };
2673
3175
  /**
@@ -5970,6 +6472,12 @@ var MorphToRelation = class extends Relation {
5970
6472
  };
5971
6473
 
5972
6474
  //#endregion
6475
+ Object.defineProperty(exports, 'AggregateExpression', {
6476
+ enumerable: true,
6477
+ get: function () {
6478
+ return AggregateExpression;
6479
+ }
6480
+ });
5973
6481
  Object.defineProperty(exports, 'ArkormCollection', {
5974
6482
  enumerable: true,
5975
6483
  get: function () {
@@ -5994,12 +6502,24 @@ Object.defineProperty(exports, 'BelongsToRelation', {
5994
6502
  return BelongsToRelation;
5995
6503
  }
5996
6504
  });
6505
+ Object.defineProperty(exports, 'CaseExpression', {
6506
+ enumerable: true,
6507
+ get: function () {
6508
+ return CaseExpression;
6509
+ }
6510
+ });
5997
6511
  Object.defineProperty(exports, 'EnumBuilder', {
5998
6512
  enumerable: true,
5999
6513
  get: function () {
6000
6514
  return EnumBuilder;
6001
6515
  }
6002
6516
  });
6517
+ Object.defineProperty(exports, 'Expression', {
6518
+ enumerable: true,
6519
+ get: function () {
6520
+ return Expression;
6521
+ }
6522
+ });
6003
6523
  Object.defineProperty(exports, 'ForeignKeyBuilder', {
6004
6524
  enumerable: true,
6005
6525
  get: function () {
@@ -6030,6 +6550,12 @@ Object.defineProperty(exports, 'HasOneThroughRelation', {
6030
6550
  return HasOneThroughRelation;
6031
6551
  }
6032
6552
  });
6553
+ Object.defineProperty(exports, 'JsonExpression', {
6554
+ enumerable: true,
6555
+ get: function () {
6556
+ return JsonExpression;
6557
+ }
6558
+ });
6033
6559
  Object.defineProperty(exports, 'LengthAwarePaginator', {
6034
6560
  enumerable: true,
6035
6561
  get: function () {
@@ -6210,6 +6736,12 @@ Object.defineProperty(exports, 'applyOperationsToPrismaSchema', {
6210
6736
  return applyOperationsToPrismaSchema;
6211
6737
  }
6212
6738
  });
6739
+ Object.defineProperty(exports, 'avg', {
6740
+ enumerable: true,
6741
+ get: function () {
6742
+ return avg;
6743
+ }
6744
+ });
6213
6745
  Object.defineProperty(exports, 'awaitConfiguredModelsRegistration', {
6214
6746
  enumerable: true,
6215
6747
  get: function () {
@@ -6288,6 +6820,24 @@ Object.defineProperty(exports, 'buildUniqueConstraintLine', {
6288
6820
  return buildUniqueConstraintLine;
6289
6821
  }
6290
6822
  });
6823
+ Object.defineProperty(exports, 'caseWhen', {
6824
+ enumerable: true,
6825
+ get: function () {
6826
+ return caseWhen;
6827
+ }
6828
+ });
6829
+ Object.defineProperty(exports, 'coalesce', {
6830
+ enumerable: true,
6831
+ get: function () {
6832
+ return coalesce;
6833
+ }
6834
+ });
6835
+ Object.defineProperty(exports, 'col', {
6836
+ enumerable: true,
6837
+ get: function () {
6838
+ return col;
6839
+ }
6840
+ });
6291
6841
  Object.defineProperty(exports, 'computeMigrationChecksum', {
6292
6842
  enumerable: true,
6293
6843
  get: function () {
@@ -6300,6 +6850,12 @@ Object.defineProperty(exports, 'configureArkormRuntime', {
6300
6850
  return configureArkormRuntime;
6301
6851
  }
6302
6852
  });
6853
+ Object.defineProperty(exports, 'count', {
6854
+ enumerable: true,
6855
+ get: function () {
6856
+ return count;
6857
+ }
6858
+ });
6303
6859
  Object.defineProperty(exports, 'createEmptyAppliedMigrationsState', {
6304
6860
  enumerable: true,
6305
6861
  get: function () {
@@ -6384,6 +6940,12 @@ Object.defineProperty(exports, 'escapeRegex', {
6384
6940
  return escapeRegex;
6385
6941
  }
6386
6942
  });
6943
+ Object.defineProperty(exports, 'expressionBuilder', {
6944
+ enumerable: true,
6945
+ get: function () {
6946
+ return expressionBuilder;
6947
+ }
6948
+ });
6387
6949
  Object.defineProperty(exports, 'findAppliedMigration', {
6388
6950
  enumerable: true,
6389
6951
  get: function () {
@@ -6402,6 +6964,12 @@ Object.defineProperty(exports, 'findModelBlock', {
6402
6964
  return findModelBlock;
6403
6965
  }
6404
6966
  });
6967
+ Object.defineProperty(exports, 'fn', {
6968
+ enumerable: true,
6969
+ get: function () {
6970
+ return fn;
6971
+ }
6972
+ });
6405
6973
  Object.defineProperty(exports, 'formatDefaultValue', {
6406
6974
  enumerable: true,
6407
6975
  get: function () {
@@ -6420,6 +6988,12 @@ Object.defineProperty(exports, 'formatRelationAction', {
6420
6988
  return formatRelationAction;
6421
6989
  }
6422
6990
  });
6991
+ Object.defineProperty(exports, 'fromExpressionNode', {
6992
+ enumerable: true,
6993
+ get: function () {
6994
+ return fromExpressionNode;
6995
+ }
6996
+ });
6423
6997
  Object.defineProperty(exports, 'generateMigrationFile', {
6424
6998
  enumerable: true,
6425
6999
  get: function () {
@@ -6594,6 +7168,12 @@ Object.defineProperty(exports, 'isTransactionCapableClient', {
6594
7168
  return isTransactionCapableClient;
6595
7169
  }
6596
7170
  });
7171
+ Object.defineProperty(exports, 'json', {
7172
+ enumerable: true,
7173
+ get: function () {
7174
+ return json;
7175
+ }
7176
+ });
6597
7177
  Object.defineProperty(exports, 'loadArkormConfig', {
6598
7178
  enumerable: true,
6599
7179
  get: function () {
@@ -6636,12 +7216,30 @@ Object.defineProperty(exports, 'markMigrationRun', {
6636
7216
  return markMigrationRun;
6637
7217
  }
6638
7218
  });
7219
+ Object.defineProperty(exports, 'max', {
7220
+ enumerable: true,
7221
+ get: function () {
7222
+ return max;
7223
+ }
7224
+ });
7225
+ Object.defineProperty(exports, 'min', {
7226
+ enumerable: true,
7227
+ get: function () {
7228
+ return min;
7229
+ }
7230
+ });
6639
7231
  Object.defineProperty(exports, 'pad', {
6640
7232
  enumerable: true,
6641
7233
  get: function () {
6642
7234
  return pad;
6643
7235
  }
6644
7236
  });
7237
+ Object.defineProperty(exports, 'raw', {
7238
+ enumerable: true,
7239
+ get: function () {
7240
+ return raw;
7241
+ }
7242
+ });
6645
7243
  Object.defineProperty(exports, 'readAppliedMigrationsState', {
6646
7244
  enumerable: true,
6647
7245
  get: function () {
@@ -6732,6 +7330,12 @@ Object.defineProperty(exports, 'resolveEnumName', {
6732
7330
  return resolveEnumName;
6733
7331
  }
6734
7332
  });
7333
+ Object.defineProperty(exports, 'resolveGeneratedExpression', {
7334
+ enumerable: true,
7335
+ get: function () {
7336
+ return resolveGeneratedExpression;
7337
+ }
7338
+ });
6735
7339
  Object.defineProperty(exports, 'resolveMigrationClassName', {
6736
7340
  enumerable: true,
6737
7341
  get: function () {
@@ -6780,6 +7384,12 @@ Object.defineProperty(exports, 'stripPrismaSchemaModelsAndEnums', {
6780
7384
  return stripPrismaSchemaModelsAndEnums;
6781
7385
  }
6782
7386
  });
7387
+ Object.defineProperty(exports, 'sum', {
7388
+ enumerable: true,
7389
+ get: function () {
7390
+ return sum;
7391
+ }
7392
+ });
6783
7393
  Object.defineProperty(exports, 'supportsDatabaseCreation', {
6784
7394
  enumerable: true,
6785
7395
  get: function () {
@@ -6822,12 +7432,24 @@ Object.defineProperty(exports, 'toModelName', {
6822
7432
  return toModelName;
6823
7433
  }
6824
7434
  });
7435
+ Object.defineProperty(exports, 'val', {
7436
+ enumerable: true,
7437
+ get: function () {
7438
+ return val;
7439
+ }
7440
+ });
6825
7441
  Object.defineProperty(exports, 'validatePersistedMetadataFeaturesForMigrations', {
6826
7442
  enumerable: true,
6827
7443
  get: function () {
6828
7444
  return validatePersistedMetadataFeaturesForMigrations;
6829
7445
  }
6830
7446
  });
7447
+ Object.defineProperty(exports, 'where', {
7448
+ enumerable: true,
7449
+ get: function () {
7450
+ return where;
7451
+ }
7452
+ });
6831
7453
  Object.defineProperty(exports, 'writeAppliedMigrationsState', {
6832
7454
  enumerable: true,
6833
7455
  get: function () {