@smartive/graphql-magic 22.1.0 → 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 +9 -5
- package/dist/bin/gqm.cjs +209 -33
- package/dist/cjs/index.cjs +194 -33
- package/dist/esm/migrations/generate.d.ts +5 -0
- package/dist/esm/migrations/generate.js +184 -35
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/models/model-definitions.d.ts +1 -0
- package/package.json +5 -5
- package/src/bin/gqm/gqm.ts +21 -0
- package/src/migrations/generate.ts +224 -35
- package/src/models/model-definitions.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
## 22.
|
|
1
|
+
## 22.2.0-next.1 (2025-12-02)
|
|
2
2
|
|
|
3
|
-
* feat:
|
|
4
|
-
* chore(deps): update dependency
|
|
5
|
-
* chore(deps): update dependency
|
|
6
|
-
* chore(deps): update dependency
|
|
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,32 +849,23 @@ var MigrationGenerator = class {
|
|
|
848
849
|
up,
|
|
849
850
|
down
|
|
850
851
|
);
|
|
851
|
-
const
|
|
852
|
+
const rawExistingFields = model.fields.filter((field) => {
|
|
853
|
+
if (!field.generateAs) {
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
852
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
|
-
if (
|
|
860
|
+
if (col.generation_expression !== field.generateAs) {
|
|
857
861
|
return true;
|
|
858
862
|
}
|
|
859
|
-
|
|
860
|
-
if (field.type === "Int") {
|
|
861
|
-
if (col.data_type !== "integer") {
|
|
862
|
-
return true;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
if (field.type === "Float") {
|
|
866
|
-
if (field.double) {
|
|
867
|
-
if (col.data_type !== "double precision") {
|
|
868
|
-
return true;
|
|
869
|
-
}
|
|
870
|
-
} else if (col.data_type !== "numeric") {
|
|
871
|
-
return true;
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
return false;
|
|
863
|
+
return this.hasChanged(model, field);
|
|
876
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));
|
|
877
869
|
this.updateFields(model, existingFields, up, down);
|
|
878
870
|
}
|
|
879
871
|
if (isUpdatableModel(model)) {
|
|
@@ -971,6 +963,9 @@ var MigrationGenerator = class {
|
|
|
971
963
|
if (this.nowUsed) {
|
|
972
964
|
writer.writeLine(`const now = date();`).blankLine();
|
|
973
965
|
}
|
|
966
|
+
if (up.length || down.length) {
|
|
967
|
+
this.needsMigration = true;
|
|
968
|
+
}
|
|
974
969
|
this.migration("up", up);
|
|
975
970
|
this.migration("down", down.reverse());
|
|
976
971
|
return writer.toString();
|
|
@@ -1013,6 +1008,9 @@ var MigrationGenerator = class {
|
|
|
1013
1008
|
const postAlter = [];
|
|
1014
1009
|
for (const field of fields2) {
|
|
1015
1010
|
alter.push(() => this.column(field, { setNonNull: field.defaultValue !== void 0 }));
|
|
1011
|
+
if (field.generateAs) {
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1016
1014
|
if (field.nonNull && field.defaultValue === void 0) {
|
|
1017
1015
|
updates.push(() => this.writer.write(`${field.name}: 'TODO',`).newLine());
|
|
1018
1016
|
postAlter.push(() => this.column(field, { alter: true, foreign: false }));
|
|
@@ -1036,12 +1034,56 @@ var MigrationGenerator = class {
|
|
|
1036
1034
|
});
|
|
1037
1035
|
down.push(() => {
|
|
1038
1036
|
this.alterTable(model.name, () => {
|
|
1039
|
-
for (const { kind, name: name2 } of fields2) {
|
|
1037
|
+
for (const { kind, name: name2 } of fields2.toReversed()) {
|
|
1040
1038
|
this.dropColumn(kind === "relation" ? `${name2}Id` : name2);
|
|
1041
1039
|
}
|
|
1042
1040
|
});
|
|
1043
1041
|
});
|
|
1044
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
|
+
}
|
|
1045
1087
|
updateFields(model, fields2, up, down) {
|
|
1046
1088
|
if (!fields2.length) {
|
|
1047
1089
|
return;
|
|
@@ -1162,6 +1204,11 @@ var MigrationGenerator = class {
|
|
|
1162
1204
|
createTable(table, block) {
|
|
1163
1205
|
return this.writer.write(`await knex.schema.createTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
|
|
1164
1206
|
}
|
|
1207
|
+
alterTableRaw(table, block) {
|
|
1208
|
+
this.writer.write(`await knex.raw('ALTER TABLE "${table}"`);
|
|
1209
|
+
block();
|
|
1210
|
+
this.writer.write(`');`).newLine().blankLine();
|
|
1211
|
+
}
|
|
1165
1212
|
alterTable(table, block) {
|
|
1166
1213
|
return this.writer.write(`await knex.schema.alterTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
|
|
1167
1214
|
}
|
|
@@ -1183,25 +1230,107 @@ var MigrationGenerator = class {
|
|
|
1183
1230
|
}
|
|
1184
1231
|
return value2;
|
|
1185
1232
|
}
|
|
1186
|
-
|
|
1187
|
-
const
|
|
1188
|
-
if (what) {
|
|
1189
|
-
this.writer.write(what);
|
|
1190
|
-
}
|
|
1233
|
+
columnRaw({ name: name2, ...field }, { setNonNull = true, alter = false } = {}, index, toColumn) {
|
|
1234
|
+
const nonNull2 = () => {
|
|
1191
1235
|
if (setNonNull) {
|
|
1192
1236
|
if (toColumn) {
|
|
1193
1237
|
if (toColumn.is_nullable) {
|
|
1194
|
-
|
|
1195
|
-
} else {
|
|
1196
|
-
this.writer.write(".notNullable()");
|
|
1238
|
+
return false;
|
|
1197
1239
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
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`);
|
|
1201
1273
|
} else {
|
|
1202
|
-
this.writer.write("
|
|
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;
|
|
1203
1293
|
}
|
|
1294
|
+
return true;
|
|
1204
1295
|
}
|
|
1296
|
+
if (field.nonNull) {
|
|
1297
|
+
return true;
|
|
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()");
|
|
1205
1334
|
}
|
|
1206
1335
|
if (setDefault && field.defaultValue !== void 0) {
|
|
1207
1336
|
this.writer.write(`.defaultTo(${this.value(field.defaultValue)})`);
|
|
@@ -1216,7 +1345,6 @@ var MigrationGenerator = class {
|
|
|
1216
1345
|
}
|
|
1217
1346
|
this.writer.write(";").newLine();
|
|
1218
1347
|
};
|
|
1219
|
-
const kind = field.kind;
|
|
1220
1348
|
switch (kind) {
|
|
1221
1349
|
case void 0:
|
|
1222
1350
|
case "primitive":
|
|
@@ -1286,6 +1414,39 @@ var MigrationGenerator = class {
|
|
|
1286
1414
|
getColumn(tableName, columnName) {
|
|
1287
1415
|
return this.columns[tableName].find((col) => col.name === columnName);
|
|
1288
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
|
+
}
|
|
1289
1450
|
};
|
|
1290
1451
|
var getMigrationDate = () => {
|
|
1291
1452
|
const date = /* @__PURE__ */ new Date();
|
|
@@ -2497,6 +2658,21 @@ import_commander.program.command("generate-migration [<name>] [<date>]").descrip
|
|
|
2497
2658
|
await db.destroy();
|
|
2498
2659
|
}
|
|
2499
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
|
+
});
|
|
2500
2676
|
import_commander.program.command("*", { noHelp: true }).description("Invalid command").action(() => {
|
|
2501
2677
|
console.error("Invalid command: %s\nSee --help for a list of available commands.", import_commander.program.args.join(" "));
|
|
2502
2678
|
process.exit(1);
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -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,32 +1213,23 @@ var MigrationGenerator = class {
|
|
|
1212
1213
|
up,
|
|
1213
1214
|
down
|
|
1214
1215
|
);
|
|
1215
|
-
const
|
|
1216
|
+
const rawExistingFields = model.fields.filter((field) => {
|
|
1217
|
+
if (!field.generateAs) {
|
|
1218
|
+
return false;
|
|
1219
|
+
}
|
|
1216
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
|
-
if (
|
|
1224
|
+
if (col.generation_expression !== field.generateAs) {
|
|
1221
1225
|
return true;
|
|
1222
1226
|
}
|
|
1223
|
-
|
|
1224
|
-
if (field.type === "Int") {
|
|
1225
|
-
if (col.data_type !== "integer") {
|
|
1226
|
-
return true;
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
if (field.type === "Float") {
|
|
1230
|
-
if (field.double) {
|
|
1231
|
-
if (col.data_type !== "double precision") {
|
|
1232
|
-
return true;
|
|
1233
|
-
}
|
|
1234
|
-
} else if (col.data_type !== "numeric") {
|
|
1235
|
-
return true;
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
return false;
|
|
1227
|
+
return this.hasChanged(model, field);
|
|
1240
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));
|
|
1241
1233
|
this.updateFields(model, existingFields, up, down);
|
|
1242
1234
|
}
|
|
1243
1235
|
if (isUpdatableModel(model)) {
|
|
@@ -1335,6 +1327,9 @@ var MigrationGenerator = class {
|
|
|
1335
1327
|
if (this.nowUsed) {
|
|
1336
1328
|
writer.writeLine(`const now = date();`).blankLine();
|
|
1337
1329
|
}
|
|
1330
|
+
if (up.length || down.length) {
|
|
1331
|
+
this.needsMigration = true;
|
|
1332
|
+
}
|
|
1338
1333
|
this.migration("up", up);
|
|
1339
1334
|
this.migration("down", down.reverse());
|
|
1340
1335
|
return writer.toString();
|
|
@@ -1377,6 +1372,9 @@ var MigrationGenerator = class {
|
|
|
1377
1372
|
const postAlter = [];
|
|
1378
1373
|
for (const field of fields2) {
|
|
1379
1374
|
alter.push(() => this.column(field, { setNonNull: field.defaultValue !== void 0 }));
|
|
1375
|
+
if (field.generateAs) {
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1380
1378
|
if (field.nonNull && field.defaultValue === void 0) {
|
|
1381
1379
|
updates.push(() => this.writer.write(`${field.name}: 'TODO',`).newLine());
|
|
1382
1380
|
postAlter.push(() => this.column(field, { alter: true, foreign: false }));
|
|
@@ -1400,12 +1398,56 @@ var MigrationGenerator = class {
|
|
|
1400
1398
|
});
|
|
1401
1399
|
down.push(() => {
|
|
1402
1400
|
this.alterTable(model.name, () => {
|
|
1403
|
-
for (const { kind, name: name2 } of fields2) {
|
|
1401
|
+
for (const { kind, name: name2 } of fields2.toReversed()) {
|
|
1404
1402
|
this.dropColumn(kind === "relation" ? `${name2}Id` : name2);
|
|
1405
1403
|
}
|
|
1406
1404
|
});
|
|
1407
1405
|
});
|
|
1408
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
|
+
}
|
|
1409
1451
|
updateFields(model, fields2, up, down) {
|
|
1410
1452
|
if (!fields2.length) {
|
|
1411
1453
|
return;
|
|
@@ -1526,6 +1568,11 @@ var MigrationGenerator = class {
|
|
|
1526
1568
|
createTable(table, block) {
|
|
1527
1569
|
return this.writer.write(`await knex.schema.createTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
|
|
1528
1570
|
}
|
|
1571
|
+
alterTableRaw(table, block) {
|
|
1572
|
+
this.writer.write(`await knex.raw('ALTER TABLE "${table}"`);
|
|
1573
|
+
block();
|
|
1574
|
+
this.writer.write(`');`).newLine().blankLine();
|
|
1575
|
+
}
|
|
1529
1576
|
alterTable(table, block) {
|
|
1530
1577
|
return this.writer.write(`await knex.schema.alterTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
|
|
1531
1578
|
}
|
|
@@ -1547,25 +1594,107 @@ var MigrationGenerator = class {
|
|
|
1547
1594
|
}
|
|
1548
1595
|
return value2;
|
|
1549
1596
|
}
|
|
1550
|
-
|
|
1551
|
-
const
|
|
1552
|
-
if (what) {
|
|
1553
|
-
this.writer.write(what);
|
|
1554
|
-
}
|
|
1597
|
+
columnRaw({ name: name2, ...field }, { setNonNull = true, alter = false } = {}, index, toColumn) {
|
|
1598
|
+
const nonNull2 = () => {
|
|
1555
1599
|
if (setNonNull) {
|
|
1556
1600
|
if (toColumn) {
|
|
1557
1601
|
if (toColumn.is_nullable) {
|
|
1558
|
-
|
|
1559
|
-
} else {
|
|
1560
|
-
this.writer.write(".notNullable()");
|
|
1602
|
+
return false;
|
|
1561
1603
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
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`);
|
|
1565
1637
|
} else {
|
|
1566
|
-
this.writer.write("
|
|
1638
|
+
this.writer.write(`, ALTER COLUMN "${name2}" DROP NOT NULL`);
|
|
1567
1639
|
}
|
|
1568
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()");
|
|
1569
1698
|
}
|
|
1570
1699
|
if (setDefault && field.defaultValue !== void 0) {
|
|
1571
1700
|
this.writer.write(`.defaultTo(${this.value(field.defaultValue)})`);
|
|
@@ -1580,7 +1709,6 @@ var MigrationGenerator = class {
|
|
|
1580
1709
|
}
|
|
1581
1710
|
this.writer.write(";").newLine();
|
|
1582
1711
|
};
|
|
1583
|
-
const kind = field.kind;
|
|
1584
1712
|
switch (kind) {
|
|
1585
1713
|
case void 0:
|
|
1586
1714
|
case "primitive":
|
|
@@ -1650,6 +1778,39 @@ var MigrationGenerator = class {
|
|
|
1650
1778
|
getColumn(tableName, columnName) {
|
|
1651
1779
|
return this.columns[tableName].find((col) => col.name === columnName);
|
|
1652
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
|
+
}
|
|
1653
1814
|
};
|
|
1654
1815
|
var getMigrationDate = () => {
|
|
1655
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;
|