@smartive/graphql-magic 22.0.2 → 22.2.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
- ## <small>22.0.2 (2025-10-29)</small>
1
+ ## 22.2.0-next.1 (2025-12-02)
2
2
 
3
- * fix: Add ?? token (#374) ([6b52676](https://github.com/smartive/graphql-magic/commit/6b52676)), closes [#374](https://github.com/smartive/graphql-magic/issues/374)
3
+ * feat: generated fields and migration check ([d0a275c](https://github.com/smartive/graphql-magic/commit/d0a275c))
4
+ * chore(deps): update dependency @types/lodash to v4.17.21 (#383) ([b0dd062](https://github.com/smartive/graphql-magic/commit/b0dd062)), closes [#383](https://github.com/smartive/graphql-magic/issues/383)
5
+ * chore(deps): update dependency esbuild to v0.26.0 (#380) ([c3065d6](https://github.com/smartive/graphql-magic/commit/c3065d6)), closes [#380](https://github.com/smartive/graphql-magic/issues/380)
6
+ * chore(deps): update dependency esbuild to v0.27.0 (#381) ([62cca2a](https://github.com/smartive/graphql-magic/commit/62cca2a)), closes [#381](https://github.com/smartive/graphql-magic/issues/381)
7
+ * chore(deps): update dependency prettier to v3.7.1 (#385) ([680ed83](https://github.com/smartive/graphql-magic/commit/680ed83)), closes [#385](https://github.com/smartive/graphql-magic/issues/385)
8
+ * chore(deps): update dependency prettier to v3.7.2 (#386) ([19e819d](https://github.com/smartive/graphql-magic/commit/19e819d)), closes [#386](https://github.com/smartive/graphql-magic/issues/386)
9
+ * chore(deps): update dependency prettier to v3.7.3 (#387) ([73f2af9](https://github.com/smartive/graphql-magic/commit/73f2af9)), closes [#387](https://github.com/smartive/graphql-magic/issues/387)
10
+ * chore(deps): update dependency ts-jest to v29.4.6 (#388) ([31776a8](https://github.com/smartive/graphql-magic/commit/31776a8)), closes [#388](https://github.com/smartive/graphql-magic/issues/388)
package/dist/bin/gqm.cjs CHANGED
@@ -750,6 +750,7 @@ var MigrationGenerator = class {
750
750
  columns = {};
751
751
  uuidUsed;
752
752
  nowUsed;
753
+ needsMigration = false;
753
754
  async generate() {
754
755
  const { writer, schema, models } = this;
755
756
  const enums = (await schema.knex("pg_type").where({ typtype: "e" }).select("typname")).map(({ typname }) => typname);
@@ -848,13 +849,23 @@ var MigrationGenerator = class {
848
849
  up,
849
850
  down
850
851
  );
851
- const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
852
- const col = this.getColumn(model.name, kind === "relation" ? `${name2}Id` : name2);
852
+ const rawExistingFields = model.fields.filter((field) => {
853
+ if (!field.generateAs) {
854
+ return false;
855
+ }
856
+ const col = this.getColumn(model.name, field.kind === "relation" ? `${field.name}Id` : field.name);
853
857
  if (!col) {
854
858
  return false;
855
859
  }
856
- return !nonNull2 && !col.is_nullable || nonNull2 && col.is_nullable;
860
+ if (col.generation_expression !== field.generateAs) {
861
+ return true;
862
+ }
863
+ return this.hasChanged(model, field);
857
864
  });
865
+ if (rawExistingFields.length) {
866
+ this.updateFieldsRaw(model, rawExistingFields, up, down);
867
+ }
868
+ const existingFields = model.fields.filter((field) => !field.generateAs && this.hasChanged(model, field));
858
869
  this.updateFields(model, existingFields, up, down);
859
870
  }
860
871
  if (isUpdatableModel(model)) {
@@ -952,6 +963,9 @@ var MigrationGenerator = class {
952
963
  if (this.nowUsed) {
953
964
  writer.writeLine(`const now = date();`).blankLine();
954
965
  }
966
+ if (up.length || down.length) {
967
+ this.needsMigration = true;
968
+ }
955
969
  this.migration("up", up);
956
970
  this.migration("down", down.reverse());
957
971
  return writer.toString();
@@ -994,6 +1008,9 @@ var MigrationGenerator = class {
994
1008
  const postAlter = [];
995
1009
  for (const field of fields2) {
996
1010
  alter.push(() => this.column(field, { setNonNull: field.defaultValue !== void 0 }));
1011
+ if (field.generateAs) {
1012
+ continue;
1013
+ }
997
1014
  if (field.nonNull && field.defaultValue === void 0) {
998
1015
  updates.push(() => this.writer.write(`${field.name}: 'TODO',`).newLine());
999
1016
  postAlter.push(() => this.column(field, { alter: true, foreign: false }));
@@ -1017,12 +1034,56 @@ var MigrationGenerator = class {
1017
1034
  });
1018
1035
  down.push(() => {
1019
1036
  this.alterTable(model.name, () => {
1020
- for (const { kind, name: name2 } of fields2) {
1037
+ for (const { kind, name: name2 } of fields2.toReversed()) {
1021
1038
  this.dropColumn(kind === "relation" ? `${name2}Id` : name2);
1022
1039
  }
1023
1040
  });
1024
1041
  });
1025
1042
  }
1043
+ updateFieldsRaw(model, fields2, up, down) {
1044
+ if (!fields2.length) {
1045
+ return;
1046
+ }
1047
+ up.push(() => {
1048
+ this.alterTableRaw(model.name, () => {
1049
+ for (const [index, field] of fields2.entries()) {
1050
+ this.columnRaw(field, { alter: true }, index);
1051
+ }
1052
+ });
1053
+ });
1054
+ down.push(() => {
1055
+ this.alterTableRaw(model.name, () => {
1056
+ for (const [index, field] of fields2.entries()) {
1057
+ this.columnRaw(field, { alter: true }, index);
1058
+ }
1059
+ });
1060
+ });
1061
+ if (isUpdatableModel(model)) {
1062
+ const updatableFields = fields2.filter(isUpdatableField);
1063
+ if (!updatableFields.length) {
1064
+ return;
1065
+ }
1066
+ up.push(() => {
1067
+ this.alterTable(`${model.name}Revision`, () => {
1068
+ for (const [index, field] of updatableFields.entries()) {
1069
+ this.columnRaw(field, { alter: true }, index);
1070
+ }
1071
+ });
1072
+ });
1073
+ down.push(() => {
1074
+ this.alterTable(`${model.name}Revision`, () => {
1075
+ for (const [index, field] of updatableFields.entries()) {
1076
+ this.columnRaw(
1077
+ field,
1078
+ { alter: true },
1079
+ index,
1080
+ summonByName(this.columns[model.name], field.kind === "relation" ? `${field.name}Id` : field.name)
1081
+ );
1082
+ }
1083
+ });
1084
+ });
1085
+ }
1086
+ }
1026
1087
  updateFields(model, fields2, up, down) {
1027
1088
  if (!fields2.length) {
1028
1089
  return;
@@ -1143,6 +1204,11 @@ var MigrationGenerator = class {
1143
1204
  createTable(table, block) {
1144
1205
  return this.writer.write(`await knex.schema.createTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
1145
1206
  }
1207
+ alterTableRaw(table, block) {
1208
+ this.writer.write(`await knex.raw('ALTER TABLE "${table}"`);
1209
+ block();
1210
+ this.writer.write(`');`).newLine().blankLine();
1211
+ }
1146
1212
  alterTable(table, block) {
1147
1213
  return this.writer.write(`await knex.schema.alterTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
1148
1214
  }
@@ -1164,25 +1230,107 @@ var MigrationGenerator = class {
1164
1230
  }
1165
1231
  return value2;
1166
1232
  }
1167
- column({ name: name2, primary, list: list2, ...field }, { setUnique = true, setNonNull = true, alter = false, foreign = true, setDefault = true } = {}, toColumn) {
1168
- const col = (what) => {
1169
- if (what) {
1170
- this.writer.write(what);
1171
- }
1233
+ columnRaw({ name: name2, ...field }, { setNonNull = true, alter = false } = {}, index, toColumn) {
1234
+ const nonNull2 = () => {
1172
1235
  if (setNonNull) {
1173
1236
  if (toColumn) {
1174
1237
  if (toColumn.is_nullable) {
1175
- this.writer.write(`.nullable()`);
1176
- } else {
1177
- this.writer.write(".notNullable()");
1238
+ return false;
1178
1239
  }
1179
- } else {
1180
- if (field.nonNull) {
1181
- this.writer.write(`.notNullable()`);
1240
+ return true;
1241
+ }
1242
+ if (field.nonNull) {
1243
+ return true;
1244
+ }
1245
+ return false;
1246
+ }
1247
+ };
1248
+ const kind = field.kind;
1249
+ if (field.generateAs) {
1250
+ let type = "";
1251
+ switch (kind) {
1252
+ case void 0:
1253
+ case "primitive":
1254
+ switch (field.type) {
1255
+ case "Float":
1256
+ type = `decimal(${field.precision ?? "undefined"}, ${field.scale ?? "undefined"})`;
1257
+ break;
1258
+ default:
1259
+ throw new Error(`Generated columns of kind ${kind} and type ${field.type} are not supported yet.`);
1260
+ }
1261
+ break;
1262
+ default:
1263
+ throw new Error(`Generated columns of kind ${kind} are not supported yet.`);
1264
+ }
1265
+ if (index) {
1266
+ this.writer.write(`,`);
1267
+ }
1268
+ if (alter) {
1269
+ this.writer.write(` ALTER COLUMN "${name2}" TYPE ${type}`);
1270
+ if (setNonNull) {
1271
+ if (nonNull2()) {
1272
+ this.writer.write(`, ALTER COLUMN "${name2}" SET NOT NULL`);
1182
1273
  } else {
1183
- this.writer.write(".nullable()");
1274
+ this.writer.write(`, ALTER COLUMN "${name2}" DROP NOT NULL`);
1275
+ }
1276
+ }
1277
+ this.writer.write(`, ALTER COLUMN "${name2}" SET EXPRESSION AS (${field.generateAs})`);
1278
+ } else {
1279
+ this.writer.write(
1280
+ `${alter ? "ALTER" : "ADD"} COLUMN "${name2}" ${type}${nonNull2() ? " not null" : ""} GENERATED ALWAYS AS (${field.generateAs}) STORED`
1281
+ );
1282
+ }
1283
+ return;
1284
+ }
1285
+ throw new Error(`Only generated columns can be created with columnRaw`);
1286
+ }
1287
+ column({ name: name2, primary, list: list2, ...field }, { setUnique = true, setNonNull = true, alter = false, foreign = true, setDefault = true } = {}, toColumn) {
1288
+ const nonNull2 = () => {
1289
+ if (setNonNull) {
1290
+ if (toColumn) {
1291
+ if (toColumn.is_nullable) {
1292
+ return false;
1184
1293
  }
1294
+ return true;
1295
+ }
1296
+ if (field.nonNull) {
1297
+ return true;
1185
1298
  }
1299
+ return false;
1300
+ }
1301
+ };
1302
+ const kind = field.kind;
1303
+ if (field.generateAs) {
1304
+ let type = "";
1305
+ switch (kind) {
1306
+ case void 0:
1307
+ case "primitive":
1308
+ switch (field.type) {
1309
+ case "Float":
1310
+ type = `decimal(${field.precision ?? "undefined"}, ${field.scale ?? "undefined"})`;
1311
+ break;
1312
+ default:
1313
+ throw new Error(`Generated columns of kind ${kind} and type ${field.type} are not supported yet.`);
1314
+ }
1315
+ break;
1316
+ default:
1317
+ throw new Error(`Generated columns of kind ${kind} are not supported yet.`);
1318
+ }
1319
+ this.writer.write(
1320
+ `table.specificType('${name2}', '${type}${nonNull2() ? " not null" : ""} GENERATED ALWAYS AS (${field.generateAs}) STORED')`
1321
+ );
1322
+ if (alter) {
1323
+ this.writer.write(".alter()");
1324
+ }
1325
+ this.writer.write(";").newLine();
1326
+ return;
1327
+ }
1328
+ const col = (what) => {
1329
+ if (what) {
1330
+ this.writer.write(what);
1331
+ }
1332
+ if (setNonNull) {
1333
+ this.writer.write(nonNull2() ? ".notNullable()" : ".nullable()");
1186
1334
  }
1187
1335
  if (setDefault && field.defaultValue !== void 0) {
1188
1336
  this.writer.write(`.defaultTo(${this.value(field.defaultValue)})`);
@@ -1197,7 +1345,6 @@ var MigrationGenerator = class {
1197
1345
  }
1198
1346
  this.writer.write(";").newLine();
1199
1347
  };
1200
- const kind = field.kind;
1201
1348
  switch (kind) {
1202
1349
  case void 0:
1203
1350
  case "primitive":
@@ -1267,6 +1414,39 @@ var MigrationGenerator = class {
1267
1414
  getColumn(tableName, columnName) {
1268
1415
  return this.columns[tableName].find((col) => col.name === columnName);
1269
1416
  }
1417
+ hasChanged(model, field) {
1418
+ const col = this.getColumn(model.name, field.kind === "relation" ? `${field.name}Id` : field.name);
1419
+ if (!col) {
1420
+ return false;
1421
+ }
1422
+ if (field.generateAs) {
1423
+ if (col.generation_expression !== field.generateAs) {
1424
+ throw new Error(
1425
+ `Column ${col.name} has specific type ${col.generation_expression} but expected ${field.generateAs}`
1426
+ );
1427
+ }
1428
+ }
1429
+ if (!field.nonNull && !col.is_nullable || field.nonNull && col.is_nullable) {
1430
+ return true;
1431
+ }
1432
+ if (!field.kind || field.kind === "primitive") {
1433
+ if (field.type === "Int") {
1434
+ if (col.data_type !== "integer") {
1435
+ return true;
1436
+ }
1437
+ }
1438
+ if (field.type === "Float") {
1439
+ if (field.double) {
1440
+ if (col.data_type !== "double precision") {
1441
+ return true;
1442
+ }
1443
+ } else if (col.data_type !== "numeric") {
1444
+ return true;
1445
+ }
1446
+ }
1447
+ }
1448
+ return false;
1449
+ }
1270
1450
  };
1271
1451
  var getMigrationDate = () => {
1272
1452
  const date = /* @__PURE__ */ new Date();
@@ -2478,6 +2658,21 @@ import_commander.program.command("generate-migration [<name>] [<date>]").descrip
2478
2658
  await db.destroy();
2479
2659
  }
2480
2660
  });
2661
+ import_commander.program.command("check-needs-migration").description("Check if a migration is needed").action(async () => {
2662
+ const knexfile = await parseKnexfile();
2663
+ const db = (0, import_knex.default)(knexfile);
2664
+ try {
2665
+ const models = await parseModels();
2666
+ const mg = new MigrationGenerator(db, models);
2667
+ await mg.generate();
2668
+ if (mg.needsMigration) {
2669
+ console.error("Migration is needed.");
2670
+ process.exit(1);
2671
+ }
2672
+ } finally {
2673
+ await db.destroy();
2674
+ }
2675
+ });
2481
2676
  import_commander.program.command("*", { noHelp: true }).description("Invalid command").action(() => {
2482
2677
  console.error("Invalid command: %s\nSee --help for a list of available commands.", import_commander.program.args.join(" "));
2483
2678
  process.exit(1);
@@ -1114,6 +1114,7 @@ var MigrationGenerator = class {
1114
1114
  columns = {};
1115
1115
  uuidUsed;
1116
1116
  nowUsed;
1117
+ needsMigration = false;
1117
1118
  async generate() {
1118
1119
  const { writer, schema, models } = this;
1119
1120
  const enums = (await schema.knex("pg_type").where({ typtype: "e" }).select("typname")).map(({ typname }) => typname);
@@ -1212,13 +1213,23 @@ var MigrationGenerator = class {
1212
1213
  up,
1213
1214
  down
1214
1215
  );
1215
- const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
1216
- const col = this.getColumn(model.name, kind === "relation" ? `${name2}Id` : name2);
1216
+ const rawExistingFields = model.fields.filter((field) => {
1217
+ if (!field.generateAs) {
1218
+ return false;
1219
+ }
1220
+ const col = this.getColumn(model.name, field.kind === "relation" ? `${field.name}Id` : field.name);
1217
1221
  if (!col) {
1218
1222
  return false;
1219
1223
  }
1220
- return !nonNull2 && !col.is_nullable || nonNull2 && col.is_nullable;
1224
+ if (col.generation_expression !== field.generateAs) {
1225
+ return true;
1226
+ }
1227
+ return this.hasChanged(model, field);
1221
1228
  });
1229
+ if (rawExistingFields.length) {
1230
+ this.updateFieldsRaw(model, rawExistingFields, up, down);
1231
+ }
1232
+ const existingFields = model.fields.filter((field) => !field.generateAs && this.hasChanged(model, field));
1222
1233
  this.updateFields(model, existingFields, up, down);
1223
1234
  }
1224
1235
  if (isUpdatableModel(model)) {
@@ -1316,6 +1327,9 @@ var MigrationGenerator = class {
1316
1327
  if (this.nowUsed) {
1317
1328
  writer.writeLine(`const now = date();`).blankLine();
1318
1329
  }
1330
+ if (up.length || down.length) {
1331
+ this.needsMigration = true;
1332
+ }
1319
1333
  this.migration("up", up);
1320
1334
  this.migration("down", down.reverse());
1321
1335
  return writer.toString();
@@ -1358,6 +1372,9 @@ var MigrationGenerator = class {
1358
1372
  const postAlter = [];
1359
1373
  for (const field of fields2) {
1360
1374
  alter.push(() => this.column(field, { setNonNull: field.defaultValue !== void 0 }));
1375
+ if (field.generateAs) {
1376
+ continue;
1377
+ }
1361
1378
  if (field.nonNull && field.defaultValue === void 0) {
1362
1379
  updates.push(() => this.writer.write(`${field.name}: 'TODO',`).newLine());
1363
1380
  postAlter.push(() => this.column(field, { alter: true, foreign: false }));
@@ -1381,12 +1398,56 @@ var MigrationGenerator = class {
1381
1398
  });
1382
1399
  down.push(() => {
1383
1400
  this.alterTable(model.name, () => {
1384
- for (const { kind, name: name2 } of fields2) {
1401
+ for (const { kind, name: name2 } of fields2.toReversed()) {
1385
1402
  this.dropColumn(kind === "relation" ? `${name2}Id` : name2);
1386
1403
  }
1387
1404
  });
1388
1405
  });
1389
1406
  }
1407
+ updateFieldsRaw(model, fields2, up, down) {
1408
+ if (!fields2.length) {
1409
+ return;
1410
+ }
1411
+ up.push(() => {
1412
+ this.alterTableRaw(model.name, () => {
1413
+ for (const [index, field] of fields2.entries()) {
1414
+ this.columnRaw(field, { alter: true }, index);
1415
+ }
1416
+ });
1417
+ });
1418
+ down.push(() => {
1419
+ this.alterTableRaw(model.name, () => {
1420
+ for (const [index, field] of fields2.entries()) {
1421
+ this.columnRaw(field, { alter: true }, index);
1422
+ }
1423
+ });
1424
+ });
1425
+ if (isUpdatableModel(model)) {
1426
+ const updatableFields = fields2.filter(isUpdatableField);
1427
+ if (!updatableFields.length) {
1428
+ return;
1429
+ }
1430
+ up.push(() => {
1431
+ this.alterTable(`${model.name}Revision`, () => {
1432
+ for (const [index, field] of updatableFields.entries()) {
1433
+ this.columnRaw(field, { alter: true }, index);
1434
+ }
1435
+ });
1436
+ });
1437
+ down.push(() => {
1438
+ this.alterTable(`${model.name}Revision`, () => {
1439
+ for (const [index, field] of updatableFields.entries()) {
1440
+ this.columnRaw(
1441
+ field,
1442
+ { alter: true },
1443
+ index,
1444
+ summonByName(this.columns[model.name], field.kind === "relation" ? `${field.name}Id` : field.name)
1445
+ );
1446
+ }
1447
+ });
1448
+ });
1449
+ }
1450
+ }
1390
1451
  updateFields(model, fields2, up, down) {
1391
1452
  if (!fields2.length) {
1392
1453
  return;
@@ -1507,6 +1568,11 @@ var MigrationGenerator = class {
1507
1568
  createTable(table, block) {
1508
1569
  return this.writer.write(`await knex.schema.createTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
1509
1570
  }
1571
+ alterTableRaw(table, block) {
1572
+ this.writer.write(`await knex.raw('ALTER TABLE "${table}"`);
1573
+ block();
1574
+ this.writer.write(`');`).newLine().blankLine();
1575
+ }
1510
1576
  alterTable(table, block) {
1511
1577
  return this.writer.write(`await knex.schema.alterTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
1512
1578
  }
@@ -1528,25 +1594,107 @@ var MigrationGenerator = class {
1528
1594
  }
1529
1595
  return value2;
1530
1596
  }
1531
- column({ name: name2, primary, list: list2, ...field }, { setUnique = true, setNonNull = true, alter = false, foreign = true, setDefault = true } = {}, toColumn) {
1532
- const col = (what) => {
1533
- if (what) {
1534
- this.writer.write(what);
1535
- }
1597
+ columnRaw({ name: name2, ...field }, { setNonNull = true, alter = false } = {}, index, toColumn) {
1598
+ const nonNull2 = () => {
1536
1599
  if (setNonNull) {
1537
1600
  if (toColumn) {
1538
1601
  if (toColumn.is_nullable) {
1539
- this.writer.write(`.nullable()`);
1540
- } else {
1541
- this.writer.write(".notNullable()");
1602
+ return false;
1542
1603
  }
1543
- } else {
1544
- if (field.nonNull) {
1545
- this.writer.write(`.notNullable()`);
1604
+ return true;
1605
+ }
1606
+ if (field.nonNull) {
1607
+ return true;
1608
+ }
1609
+ return false;
1610
+ }
1611
+ };
1612
+ const kind = field.kind;
1613
+ if (field.generateAs) {
1614
+ let type = "";
1615
+ switch (kind) {
1616
+ case void 0:
1617
+ case "primitive":
1618
+ switch (field.type) {
1619
+ case "Float":
1620
+ type = `decimal(${field.precision ?? "undefined"}, ${field.scale ?? "undefined"})`;
1621
+ break;
1622
+ default:
1623
+ throw new Error(`Generated columns of kind ${kind} and type ${field.type} are not supported yet.`);
1624
+ }
1625
+ break;
1626
+ default:
1627
+ throw new Error(`Generated columns of kind ${kind} are not supported yet.`);
1628
+ }
1629
+ if (index) {
1630
+ this.writer.write(`,`);
1631
+ }
1632
+ if (alter) {
1633
+ this.writer.write(` ALTER COLUMN "${name2}" TYPE ${type}`);
1634
+ if (setNonNull) {
1635
+ if (nonNull2()) {
1636
+ this.writer.write(`, ALTER COLUMN "${name2}" SET NOT NULL`);
1546
1637
  } else {
1547
- this.writer.write(".nullable()");
1638
+ this.writer.write(`, ALTER COLUMN "${name2}" DROP NOT NULL`);
1548
1639
  }
1549
1640
  }
1641
+ this.writer.write(`, ALTER COLUMN "${name2}" SET EXPRESSION AS (${field.generateAs})`);
1642
+ } else {
1643
+ this.writer.write(
1644
+ `${alter ? "ALTER" : "ADD"} COLUMN "${name2}" ${type}${nonNull2() ? " not null" : ""} GENERATED ALWAYS AS (${field.generateAs}) STORED`
1645
+ );
1646
+ }
1647
+ return;
1648
+ }
1649
+ throw new Error(`Only generated columns can be created with columnRaw`);
1650
+ }
1651
+ column({ name: name2, primary, list: list2, ...field }, { setUnique = true, setNonNull = true, alter = false, foreign = true, setDefault = true } = {}, toColumn) {
1652
+ const nonNull2 = () => {
1653
+ if (setNonNull) {
1654
+ if (toColumn) {
1655
+ if (toColumn.is_nullable) {
1656
+ return false;
1657
+ }
1658
+ return true;
1659
+ }
1660
+ if (field.nonNull) {
1661
+ return true;
1662
+ }
1663
+ return false;
1664
+ }
1665
+ };
1666
+ const kind = field.kind;
1667
+ if (field.generateAs) {
1668
+ let type = "";
1669
+ switch (kind) {
1670
+ case void 0:
1671
+ case "primitive":
1672
+ switch (field.type) {
1673
+ case "Float":
1674
+ type = `decimal(${field.precision ?? "undefined"}, ${field.scale ?? "undefined"})`;
1675
+ break;
1676
+ default:
1677
+ throw new Error(`Generated columns of kind ${kind} and type ${field.type} are not supported yet.`);
1678
+ }
1679
+ break;
1680
+ default:
1681
+ throw new Error(`Generated columns of kind ${kind} are not supported yet.`);
1682
+ }
1683
+ this.writer.write(
1684
+ `table.specificType('${name2}', '${type}${nonNull2() ? " not null" : ""} GENERATED ALWAYS AS (${field.generateAs}) STORED')`
1685
+ );
1686
+ if (alter) {
1687
+ this.writer.write(".alter()");
1688
+ }
1689
+ this.writer.write(";").newLine();
1690
+ return;
1691
+ }
1692
+ const col = (what) => {
1693
+ if (what) {
1694
+ this.writer.write(what);
1695
+ }
1696
+ if (setNonNull) {
1697
+ this.writer.write(nonNull2() ? ".notNullable()" : ".nullable()");
1550
1698
  }
1551
1699
  if (setDefault && field.defaultValue !== void 0) {
1552
1700
  this.writer.write(`.defaultTo(${this.value(field.defaultValue)})`);
@@ -1561,7 +1709,6 @@ var MigrationGenerator = class {
1561
1709
  }
1562
1710
  this.writer.write(";").newLine();
1563
1711
  };
1564
- const kind = field.kind;
1565
1712
  switch (kind) {
1566
1713
  case void 0:
1567
1714
  case "primitive":
@@ -1631,6 +1778,39 @@ var MigrationGenerator = class {
1631
1778
  getColumn(tableName, columnName) {
1632
1779
  return this.columns[tableName].find((col) => col.name === columnName);
1633
1780
  }
1781
+ hasChanged(model, field) {
1782
+ const col = this.getColumn(model.name, field.kind === "relation" ? `${field.name}Id` : field.name);
1783
+ if (!col) {
1784
+ return false;
1785
+ }
1786
+ if (field.generateAs) {
1787
+ if (col.generation_expression !== field.generateAs) {
1788
+ throw new Error(
1789
+ `Column ${col.name} has specific type ${col.generation_expression} but expected ${field.generateAs}`
1790
+ );
1791
+ }
1792
+ }
1793
+ if (!field.nonNull && !col.is_nullable || field.nonNull && col.is_nullable) {
1794
+ return true;
1795
+ }
1796
+ if (!field.kind || field.kind === "primitive") {
1797
+ if (field.type === "Int") {
1798
+ if (col.data_type !== "integer") {
1799
+ return true;
1800
+ }
1801
+ }
1802
+ if (field.type === "Float") {
1803
+ if (field.double) {
1804
+ if (col.data_type !== "double precision") {
1805
+ return true;
1806
+ }
1807
+ } else if (col.data_type !== "numeric") {
1808
+ return true;
1809
+ }
1810
+ }
1811
+ }
1812
+ return false;
1813
+ }
1634
1814
  };
1635
1815
  var getMigrationDate = () => {
1636
1816
  const date = /* @__PURE__ */ new Date();
@@ -7,23 +7,28 @@ export declare class MigrationGenerator {
7
7
  private columns;
8
8
  private uuidUsed?;
9
9
  private nowUsed?;
10
+ needsMigration: boolean;
10
11
  constructor(knex: Knex, models: Models);
11
12
  generate(): Promise<string>;
12
13
  private renameFields;
13
14
  private createFields;
15
+ private updateFieldsRaw;
14
16
  private updateFields;
15
17
  private createRevisionTable;
16
18
  private createRevisionFields;
17
19
  private createEnums;
18
20
  private migration;
19
21
  private createTable;
22
+ private alterTableRaw;
20
23
  private alterTable;
21
24
  private dropColumn;
22
25
  private dropTable;
23
26
  private renameTable;
24
27
  private renameColumn;
25
28
  private value;
29
+ private columnRaw;
26
30
  private column;
27
31
  private getColumn;
32
+ private hasChanged;
28
33
  }
29
34
  export declare const getMigrationDate: () => string;