sasat 0.21.1 → 0.21.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/cli.cjs CHANGED
@@ -2,11 +2,10 @@
2
2
  'use strict';
3
3
 
4
4
  const cac = require('cac');
5
- const erDiagram = require('cli/commands/erDiagram');
6
- const fs = require('fs');
7
- const path = require('path');
8
5
  const error = require('../shared/sasat.f544328b.cjs');
9
6
  require('pluralize');
7
+ const fs = require('fs');
8
+ const path = require('path');
10
9
  const chalk = require('chalk');
11
10
  const console$1 = require('console');
12
11
  const esbuild = require('esbuild');
@@ -14,7 +13,6 @@ const fs$1 = require('fs-extra');
14
13
  require('js-yaml');
15
14
  const prettier = require('prettier');
16
15
  const typescript = require('typescript');
17
- const getCurrentStore = require('cli/commands/getCurrentStore');
18
16
  require('sqlstring');
19
17
  require('mysql2');
20
18
  require('util');
@@ -33,8 +31,8 @@ function _interopNamespaceCompat(e) {
33
31
  return n;
34
32
  }
35
33
 
36
- const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
37
34
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
35
+ const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
38
36
  const path__default = /*#__PURE__*/_interopDefaultCompat(path);
39
37
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
40
38
  const chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
@@ -44,233 +42,6 @@ const fs__default$1 = /*#__PURE__*/_interopDefaultCompat(fs$1);
44
42
  const prettier__namespace = /*#__PURE__*/_interopNamespaceCompat(prettier);
45
43
  const typescript__default = /*#__PURE__*/_interopDefaultCompat(typescript);
46
44
 
47
- const capitalizeFirstLetter = (str) => str.slice(0, 1).toUpperCase() + str.slice(1);
48
- const lowercaseFirstLetter = (str) => str.slice(0, 1).toLowerCase() + str.slice(1);
49
- const camelize = (str) => str.replace(
50
- /(?:^\w|[A-Z]|_\w|\b\w)/g,
51
- (word, index) => index == 0 ? word.toLowerCase() : word.toUpperCase()
52
- ).replace(/\s|_|-+/g, "");
53
-
54
- const Console = {
55
- success: (msg) => {
56
- console__namespace.log(chalk__default.green(msg));
57
- },
58
- error: (msg) => {
59
- console__namespace.error(chalk__default.bold.red(msg));
60
- },
61
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
- log: (msg) => {
63
- console__namespace.log(msg);
64
- },
65
- debug: (msg) => {
66
- console__namespace.debug("debug:: " + msg);
67
- }
68
- };
69
-
70
- const getMigrationFile = (className) => `import { SasatMigration, MigrationStore } from "sasat";
71
-
72
- export default class ${capitalizeFirstLetter(
73
- className
74
- )} implements SasatMigration {
75
-
76
- up: (store: MigrationStore) => void = store => {
77
-
78
- };
79
-
80
- down: (store: MigrationStore) => void = store => {
81
- throw new Error('Down is not implemented on ${className}');
82
- };
83
- }
84
- `;
85
- const createMigrationFile = (migrationName) => {
86
- const date = /* @__PURE__ */ new Date();
87
- const pad = (val) => val.toString().padStart(2, "0");
88
- const now = date.getFullYear() + pad(date.getMonth() + 1) + pad(date.getDate()) + `_` + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
89
- const fileName = now + migrationName;
90
- const outDir = path.join(error.config().migration.dir);
91
- error.mkDirIfNotExist(outDir);
92
- fs__namespace.writeFileSync(
93
- path.join(outDir, fileName) + ".ts",
94
- getMigrationFile(migrationName)
95
- );
96
- return fileName;
97
- };
98
- const createMigration = (args) => {
99
- if (!args) {
100
- Console.error("missing argument migration name");
101
- return;
102
- }
103
- if (!/^[$A-Za-z_][0-9A-Za-z_]+$/.test(args)) {
104
- Console.error("migration name should be match /^[$A-Za-z_][0-9A-Za-z_]+$/");
105
- return;
106
- }
107
- Console.success(createMigrationFile(args) + " Successfully created");
108
- return;
109
- };
110
-
111
- const getMigrationFileDir = () => {
112
- return path__default.join(process.cwd(), error.config().migration.dir);
113
- };
114
- const getMigrationFileNames = () => {
115
- return fs__default.readdirSync(getMigrationFileDir()).filter((it) => it.split(".").pop() === "ts");
116
- };
117
-
118
- var Direction = /* @__PURE__ */ ((Direction2) => {
119
- Direction2["Up"] = "up";
120
- Direction2["Down"] = "down";
121
- return Direction2;
122
- })(Direction || {});
123
- const calcRunMigrationFileNames = (records) => {
124
- const result = [];
125
- records.forEach((it) => {
126
- if (it.direction === "down" /* Down */) {
127
- if (result[result.length] !== it.name)
128
- throw new Error(
129
- "Invalid migration history: `down` migration must be the same migration as the last `up` migration "
130
- );
131
- result.pop();
132
- return;
133
- }
134
- result.push(it.name);
135
- });
136
- return result;
137
- };
138
- const getCurrentMigration = async (options) => {
139
- const migrationTable = error.SqlString.escapeId(error.config().migration.table);
140
- const files = getMigrationFileNames();
141
- const client = error.getDbClient();
142
- const query = `CREATE TABLE IF NOT EXISTS ${migrationTable} (id int auto_increment primary key , name varchar(100) not null,direction enum('up', 'down') not null, migrated_at timestamp default current_timestamp)`;
143
- if (!options.silent) {
144
- Console.log(
145
- `creating migration table: ${migrationTable} :: ${Buffer.from(
146
- migrationTable
147
- ).toString("base64")}`
148
- );
149
- Console.log(query);
150
- }
151
- await client.rawQuery(query);
152
- const q = `SELECT name, direction FROM ${migrationTable} ORDER BY id ASC`;
153
- if (!options.silent) {
154
- Console.debug(q);
155
- }
156
- const result = await client.rawQuery(q);
157
- console.debug(result);
158
- if (!result.length)
159
- return;
160
- const runs = calcRunMigrationFileNames(
161
- result
162
- );
163
- if (runs.length === 0)
164
- return;
165
- runs.forEach((run, i) => {
166
- if (files[i] !== run)
167
- throw new Error(`Invalid migration order: Migration must be performed in the same order
168
- Found : ${files[i]}
169
- in migration history: ${run}`);
170
- });
171
- return runs[runs.length - 1];
172
- };
173
-
174
- const changeExtTsToJs = (fileName) => fileName.slice(0, -3) + ".mjs";
175
- const compileMigrationFiles = () => {
176
- const tsFiles = getMigrationFileNames();
177
- const compiles = tsFiles.map(async (fileName) => {
178
- const filePath = path__default.join(getMigrationFileDir(), fileName);
179
- const r = await esbuild__namespace.build({
180
- entryPoints: [filePath],
181
- bundle: true,
182
- // loader: 'ts',
183
- outfile: changeExtTsToJs(filePath),
184
- platform: "node",
185
- format: "esm",
186
- outExtension: {
187
- ".js": ".mjs"
188
- },
189
- banner: {
190
- js: `
191
- import { createRequire as topLevelCreateRequire } from 'module';
192
- const require = topLevelCreateRequire(import.meta.url);
193
- `
194
- }
195
- });
196
- if (r.errors.length !== 0) {
197
- throw r.errors;
198
- }
199
- return fileName;
200
- });
201
- return Promise.all(compiles);
202
- };
203
-
204
- const readMigration = async (store, tsFileName, direction) => {
205
- const file = path__default.join(
206
- process.cwd(),
207
- error.config().migration.dir,
208
- changeExtTsToJs(tsFileName)
209
- );
210
- const module = await import(file);
211
- const instance = new module.default();
212
- if (direction === Direction.Up) {
213
- if (instance.beforeUp)
214
- await instance.beforeUp();
215
- await instance.up(store);
216
- if (instance.afterUp)
217
- await instance.afterUp();
218
- } else {
219
- if (instance.beforeDown)
220
- await instance.beforeDown();
221
- await instance.down(store);
222
- if (instance.afterDown)
223
- await instance.afterDown();
224
- }
225
- return store;
226
- };
227
-
228
- const runMigration = async (store, migrationName, direction, options) => {
229
- const sqls = store.getSql();
230
- store.resetQueue();
231
- if (!options.silent) {
232
- sqls.forEach(Console.log);
233
- }
234
- if (options.dry) {
235
- return;
236
- }
237
- const transaction = await error.getDbClient().transaction();
238
- try {
239
- for (const sql of sqls) {
240
- await transaction.rawQuery(sql).catch((e) => {
241
- Console.error(`ERROR ON ${migrationName}`);
242
- Console.error(`SQL: ${sql}`);
243
- Console.error(`MESSAGE: ${e.message}`);
244
- process.exit(1);
245
- });
246
- }
247
- await transaction.query`insert into ${() => error.config().migration.table} (name, direction) values (${[
248
- migrationName,
249
- direction
250
- ]})`;
251
- return await transaction.commit();
252
- } catch (e) {
253
- await transaction.rollback();
254
- throw e;
255
- }
256
- };
257
-
258
- const getMigrationTargets = (files, current) => {
259
- const currentIndex = current ? files.indexOf(current) + 1 : 0;
260
- const targetIndex = files.indexOf(error.config().migration.target || files[files.length - 1]) + 1;
261
- if (currentIndex === -1 || targetIndex === -1)
262
- throw new Error("migration target not found");
263
- if (targetIndex >= currentIndex)
264
- return {
265
- direction: Direction.Up,
266
- files: files.slice(currentIndex, targetIndex)
267
- };
268
- return {
269
- direction: Direction.Down,
270
- files: files.slice(targetIndex, currentIndex).reverse()
271
- };
272
- };
273
-
274
45
  var DBColumnTypes = /* @__PURE__ */ ((DBColumnTypes2) => {
275
46
  DBColumnTypes2["char"] = "char";
276
47
  DBColumnTypes2["varchar"] = "varchar";
@@ -518,6 +289,13 @@ const assembleColumn = (data, table) => {
518
289
  return new NormalColumn(data, table);
519
290
  };
520
291
 
292
+ const capitalizeFirstLetter = (str) => str.slice(0, 1).toUpperCase() + str.slice(1);
293
+ const lowercaseFirstLetter = (str) => str.slice(0, 1).toLowerCase() + str.slice(1);
294
+ const camelize = (str) => str.replace(
295
+ /(?:^\w|[A-Z]|_\w|\b\w)/g,
296
+ (word, index) => index == 0 ? word.toLowerCase() : word.toUpperCase()
297
+ ).replace(/\s|_|-+/g, "");
298
+
521
299
  class EntityName {
522
300
  constructor(name) {
523
301
  this.name = name;
@@ -1404,7 +1182,140 @@ class StoreMigrator {
1404
1182
  tables: this.tables.map((it) => it.serialize())
1405
1183
  };
1406
1184
  }
1407
- }
1185
+ }
1186
+
1187
+ const getMigrationFileDir = () => {
1188
+ return path__default.join(process.cwd(), error.config().migration.dir);
1189
+ };
1190
+ const getMigrationFileNames = () => {
1191
+ return fs__default.readdirSync(getMigrationFileDir()).filter((it) => it.split(".").pop() === "ts");
1192
+ };
1193
+
1194
+ const Console = {
1195
+ success: (msg) => {
1196
+ console__namespace.log(chalk__default.green(msg));
1197
+ },
1198
+ error: (msg) => {
1199
+ console__namespace.error(chalk__default.bold.red(msg));
1200
+ },
1201
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1202
+ log: (msg) => {
1203
+ console__namespace.log(msg);
1204
+ },
1205
+ debug: (msg) => {
1206
+ console__namespace.debug("debug:: " + msg);
1207
+ }
1208
+ };
1209
+
1210
+ var Direction = /* @__PURE__ */ ((Direction2) => {
1211
+ Direction2["Up"] = "up";
1212
+ Direction2["Down"] = "down";
1213
+ return Direction2;
1214
+ })(Direction || {});
1215
+ const calcRunMigrationFileNames = (records) => {
1216
+ const result = [];
1217
+ records.forEach((it) => {
1218
+ if (it.direction === "down" /* Down */) {
1219
+ if (result[result.length] !== it.name)
1220
+ throw new Error(
1221
+ "Invalid migration history: `down` migration must be the same migration as the last `up` migration "
1222
+ );
1223
+ result.pop();
1224
+ return;
1225
+ }
1226
+ result.push(it.name);
1227
+ });
1228
+ return result;
1229
+ };
1230
+ const getCurrentMigration = async (options) => {
1231
+ const migrationTable = error.SqlString.escapeId(error.config().migration.table);
1232
+ const files = getMigrationFileNames();
1233
+ const client = error.getDbClient();
1234
+ const query = `CREATE TABLE IF NOT EXISTS ${migrationTable} (id int auto_increment primary key , name varchar(100) not null,direction enum('up', 'down') not null, migrated_at timestamp default current_timestamp)`;
1235
+ if (!options.silent) {
1236
+ Console.log(
1237
+ `creating migration table: ${migrationTable} :: ${Buffer.from(
1238
+ migrationTable
1239
+ ).toString("base64")}`
1240
+ );
1241
+ Console.log(query);
1242
+ }
1243
+ await client.rawQuery(query);
1244
+ const q = `SELECT name, direction FROM ${migrationTable} ORDER BY id ASC`;
1245
+ if (!options.silent) {
1246
+ Console.debug(q);
1247
+ }
1248
+ const result = await client.rawQuery(q);
1249
+ console.debug(result);
1250
+ if (!result.length)
1251
+ return;
1252
+ const runs = calcRunMigrationFileNames(
1253
+ result
1254
+ );
1255
+ if (runs.length === 0)
1256
+ return;
1257
+ runs.forEach((run, i) => {
1258
+ if (files[i] !== run)
1259
+ throw new Error(`Invalid migration order: Migration must be performed in the same order
1260
+ Found : ${files[i]}
1261
+ in migration history: ${run}`);
1262
+ });
1263
+ return runs[runs.length - 1];
1264
+ };
1265
+
1266
+ const changeExtTsToJs = (fileName) => fileName.slice(0, -3) + ".mjs";
1267
+ const compileMigrationFiles = () => {
1268
+ const tsFiles = getMigrationFileNames();
1269
+ const compiles = tsFiles.map(async (fileName) => {
1270
+ const filePath = path__default.join(getMigrationFileDir(), fileName);
1271
+ const r = await esbuild__namespace.build({
1272
+ entryPoints: [filePath],
1273
+ bundle: true,
1274
+ // loader: 'ts',
1275
+ outfile: changeExtTsToJs(filePath),
1276
+ platform: "node",
1277
+ format: "esm",
1278
+ outExtension: {
1279
+ ".js": ".mjs"
1280
+ },
1281
+ banner: {
1282
+ js: `
1283
+ import { createRequire as topLevelCreateRequire } from 'module';
1284
+ const require = topLevelCreateRequire(import.meta.url);
1285
+ `
1286
+ }
1287
+ });
1288
+ if (r.errors.length !== 0) {
1289
+ throw r.errors;
1290
+ }
1291
+ return fileName;
1292
+ });
1293
+ return Promise.all(compiles);
1294
+ };
1295
+
1296
+ const readMigration = async (store, tsFileName, direction) => {
1297
+ const file = path__default.join(
1298
+ process.cwd(),
1299
+ error.config().migration.dir,
1300
+ changeExtTsToJs(tsFileName)
1301
+ );
1302
+ const module = await import(file);
1303
+ const instance = new module.default();
1304
+ if (direction === Direction.Up) {
1305
+ if (instance.beforeUp)
1306
+ await instance.beforeUp();
1307
+ await instance.up(store);
1308
+ if (instance.afterUp)
1309
+ await instance.afterUp();
1310
+ } else {
1311
+ if (instance.beforeDown)
1312
+ await instance.beforeDown();
1313
+ await instance.down(store);
1314
+ if (instance.afterDown)
1315
+ await instance.afterDown();
1316
+ }
1317
+ return store;
1318
+ };
1408
1319
 
1409
1320
  const createCurrentMigrationDataStore = async (targetMigrationName) => {
1410
1321
  const allFiles = getMigrationFileNames();
@@ -1419,28 +1330,38 @@ const createCurrentMigrationDataStore = async (targetMigrationName) => {
1419
1330
  return store;
1420
1331
  };
1421
1332
 
1422
- class MigrationController {
1423
- async migrate(options) {
1424
- const fileNames = getMigrationFileNames();
1425
- const currentMigration = await getCurrentMigration(options);
1426
- Console.log("--current migration--: " + currentMigration);
1427
- let store = await createCurrentMigrationDataStore(currentMigration);
1428
- const target = getMigrationTargets(fileNames, currentMigration);
1429
- for (const tsFileName of target.files) {
1430
- if (!options.silent) {
1431
- Console.log("---------\n" + tsFileName);
1432
- }
1433
- store = await readMigration(store, tsFileName, target.direction);
1434
- await runMigration(store, tsFileName, target.direction, options);
1435
- store.resetQueue();
1436
- }
1437
- return {
1438
- store: store.serialize(),
1439
- currentMigration: error.config().migration.target || fileNames[fileNames.length - 1]
1440
- };
1441
- }
1333
+ async function getCurrentStore() {
1334
+ await compileMigrationFiles();
1335
+ const files = getMigrationFileNames();
1336
+ const targetFile = files.find((it) => it === error.config().migration.target) || files[files.length - 1];
1337
+ return (await createCurrentMigrationDataStore(targetFile)).serialize();
1442
1338
  }
1443
1339
 
1340
+ const GeneratedDirName = "__generated__";
1341
+ const EntityDirName = "entities";
1342
+ const DataSourceDirName = "dataSources";
1343
+ const relative = (from, to) => {
1344
+ const result = path__namespace.posix.relative(from, to);
1345
+ if (result.startsWith("../"))
1346
+ return result;
1347
+ return "./" + result;
1348
+ };
1349
+ const GENERATED_PATH = `/${GeneratedDirName}/`;
1350
+ const paths = {
1351
+ BASE: "/",
1352
+ GENERATED: GENERATED_PATH,
1353
+ ENTITIES: `${GENERATED_PATH}${EntityDirName}/`,
1354
+ DATA_SOURCES: `/${DataSourceDirName}/db/`,
1355
+ GENERATED_DS: `${GENERATED_PATH}${DataSourceDirName}/db/`
1356
+ };
1357
+ const resolve = (from, source, fileName) => {
1358
+ return relative(paths[from], paths[source] + fileName);
1359
+ };
1360
+ const Directory = {
1361
+ paths,
1362
+ resolve
1363
+ };
1364
+
1444
1365
  var __defProp$k = Object.defineProperty;
1445
1366
  var __defNormalProp$k = (obj, key, value) => key in obj ? __defProp$k(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1446
1367
  var __publicField$k = (obj, key, value) => {
@@ -1472,6 +1393,164 @@ class DataStoreHandler {
1472
1393
  }
1473
1394
  }
1474
1395
 
1396
+ const writeDiagram = async () => {
1397
+ try {
1398
+ const store = new DataStoreHandler(await getCurrentStore());
1399
+ const entities = store.tables.map((it) => processTable(store, it));
1400
+ const result = `erDiagram
1401
+ ${entities.join("\n")}
1402
+ `;
1403
+ console.log();
1404
+ fs__default.writeFileSync(
1405
+ path__default.join(
1406
+ error.config().migration.out,
1407
+ Directory.paths.GENERATED,
1408
+ "er-diagram.mermaid"
1409
+ ),
1410
+ result
1411
+ );
1412
+ } catch (e) {
1413
+ Console.error(e.message);
1414
+ throw e;
1415
+ }
1416
+ };
1417
+ function getRefType(parent, rel) {
1418
+ const left = parent.isNullable() ? "|o" : "||";
1419
+ const getRight = () => {
1420
+ switch (rel) {
1421
+ case "One":
1422
+ return "||";
1423
+ case "Many":
1424
+ return "o{";
1425
+ case "OneOrZero":
1426
+ return "|o";
1427
+ }
1428
+ };
1429
+ return `${left} -- ${getRight()}`;
1430
+ }
1431
+ function processTable(store, table) {
1432
+ const rel = table.columns.filter((it) => it.isReference()).map((it) => {
1433
+ const rel2 = it;
1434
+ const ref = rel2.data.reference;
1435
+ const parent = store.table(ref.parentTable).column(ref.parentColumn);
1436
+ return `${ref.parentTable} ${getRefType(parent, ref.relation)} ${table.tableName} : ${ref.relationName}`;
1437
+ });
1438
+ return `${table.tableName} {
1439
+ ${table.columns.map((it) => ` ${it.columnName()} ${it.dataType()}`).join("\n")}
1440
+ }
1441
+ ${rel.join("\n")}
1442
+ `;
1443
+ }
1444
+
1445
+ const getMigrationFile = (className) => `import { SasatMigration, MigrationStore } from "sasat";
1446
+
1447
+ export default class ${capitalizeFirstLetter(
1448
+ className
1449
+ )} implements SasatMigration {
1450
+
1451
+ up: (store: MigrationStore) => void = store => {
1452
+
1453
+ };
1454
+
1455
+ down: (store: MigrationStore) => void = store => {
1456
+ throw new Error('Down is not implemented on ${className}');
1457
+ };
1458
+ }
1459
+ `;
1460
+ const createMigrationFile = (migrationName) => {
1461
+ const date = /* @__PURE__ */ new Date();
1462
+ const pad = (val) => val.toString().padStart(2, "0");
1463
+ const now = date.getFullYear() + pad(date.getMonth() + 1) + pad(date.getDate()) + `_` + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
1464
+ const fileName = now + migrationName;
1465
+ const outDir = path.join(error.config().migration.dir);
1466
+ error.mkDirIfNotExist(outDir);
1467
+ fs__namespace.writeFileSync(
1468
+ path.join(outDir, fileName) + ".ts",
1469
+ getMigrationFile(migrationName)
1470
+ );
1471
+ return fileName;
1472
+ };
1473
+ const createMigration = (args) => {
1474
+ if (!args) {
1475
+ Console.error("missing argument migration name");
1476
+ return;
1477
+ }
1478
+ if (!/^[$A-Za-z_][0-9A-Za-z_]+$/.test(args)) {
1479
+ Console.error("migration name should be match /^[$A-Za-z_][0-9A-Za-z_]+$/");
1480
+ return;
1481
+ }
1482
+ Console.success(createMigrationFile(args) + " Successfully created");
1483
+ return;
1484
+ };
1485
+
1486
+ const runMigration = async (store, migrationName, direction, options) => {
1487
+ const sqls = store.getSql();
1488
+ store.resetQueue();
1489
+ if (!options.silent) {
1490
+ sqls.forEach(Console.log);
1491
+ }
1492
+ if (options.dry) {
1493
+ return;
1494
+ }
1495
+ const transaction = await error.getDbClient().transaction();
1496
+ try {
1497
+ for (const sql of sqls) {
1498
+ await transaction.rawQuery(sql).catch((e) => {
1499
+ Console.error(`ERROR ON ${migrationName}`);
1500
+ Console.error(`SQL: ${sql}`);
1501
+ Console.error(`MESSAGE: ${e.message}`);
1502
+ process.exit(1);
1503
+ });
1504
+ }
1505
+ await transaction.query`insert into ${() => error.config().migration.table} (name, direction) values (${[
1506
+ migrationName,
1507
+ direction
1508
+ ]})`;
1509
+ return await transaction.commit();
1510
+ } catch (e) {
1511
+ await transaction.rollback();
1512
+ throw e;
1513
+ }
1514
+ };
1515
+
1516
+ const getMigrationTargets = (files, current) => {
1517
+ const currentIndex = current ? files.indexOf(current) + 1 : 0;
1518
+ const targetIndex = files.indexOf(error.config().migration.target || files[files.length - 1]) + 1;
1519
+ if (currentIndex === -1 || targetIndex === -1)
1520
+ throw new Error("migration target not found");
1521
+ if (targetIndex >= currentIndex)
1522
+ return {
1523
+ direction: Direction.Up,
1524
+ files: files.slice(currentIndex, targetIndex)
1525
+ };
1526
+ return {
1527
+ direction: Direction.Down,
1528
+ files: files.slice(targetIndex, currentIndex).reverse()
1529
+ };
1530
+ };
1531
+
1532
+ class MigrationController {
1533
+ async migrate(options) {
1534
+ const fileNames = getMigrationFileNames();
1535
+ const currentMigration = await getCurrentMigration(options);
1536
+ Console.log("--current migration--: " + currentMigration);
1537
+ let store = await createCurrentMigrationDataStore(currentMigration);
1538
+ const target = getMigrationTargets(fileNames, currentMigration);
1539
+ for (const tsFileName of target.files) {
1540
+ if (!options.silent) {
1541
+ Console.log("---------\n" + tsFileName);
1542
+ }
1543
+ store = await readMigration(store, tsFileName, target.direction);
1544
+ await runMigration(store, tsFileName, target.direction, options);
1545
+ store.resetQueue();
1546
+ }
1547
+ return {
1548
+ store: store.serialize(),
1549
+ currentMigration: error.config().migration.target || fileNames[fileNames.length - 1]
1550
+ };
1551
+ }
1552
+ }
1553
+
1475
1554
  class ImportDeclaration {
1476
1555
  constructor(types, module) {
1477
1556
  this.types = types;
@@ -2792,31 +2871,6 @@ const makeSubscription = (subscriptions) => {
2792
2871
  );
2793
2872
  };
2794
2873
 
2795
- const GeneratedDirName = "__generated__";
2796
- const EntityDirName = "entities";
2797
- const DataSourceDirName = "dataSources";
2798
- const relative = (from, to) => {
2799
- const result = path__namespace.posix.relative(from, to);
2800
- if (result.startsWith("../"))
2801
- return result;
2802
- return "./" + result;
2803
- };
2804
- const GENERATED_PATH = `/${GeneratedDirName}/`;
2805
- const paths = {
2806
- BASE: "/",
2807
- GENERATED: GENERATED_PATH,
2808
- ENTITIES: `${GENERATED_PATH}${EntityDirName}/`,
2809
- DATA_SOURCES: `/${DataSourceDirName}/db/`,
2810
- GENERATED_DS: `${GENERATED_PATH}${DataSourceDirName}/db/`
2811
- };
2812
- const resolve = (from, source, fileName) => {
2813
- return relative(paths[from], paths[source] + fileName);
2814
- };
2815
- const Directory = {
2816
- paths,
2817
- resolve
2818
- };
2819
-
2820
2874
  const typeRefs = {
2821
2875
  entity: {
2822
2876
  name: (entity) => entity.name,
@@ -5239,7 +5293,7 @@ const generate = async () => {
5239
5293
  await compileMigrationFiles();
5240
5294
  const files = getMigrationFileNames();
5241
5295
  const targetFile = files.find((it) => it === error.config().migration.target) || files[files.length - 1];
5242
- const store = await getCurrentStore.getCurrentStore();
5296
+ const store = await getCurrentStore();
5243
5297
  const storeHandler = new DataStoreHandler(store);
5244
5298
  error.writeCurrentSchema(store);
5245
5299
  await new CodeGen_v2(storeHandler).generate();
@@ -5805,7 +5859,7 @@ try {
5805
5859
  });
5806
5860
  cli.command("migration:build", "compile migration files").action(migrationBuild);
5807
5861
  cli.command("generate", "generate files").action(generate);
5808
- cli.command("generate:er", "generate mermaid er diagram").action(erDiagram.writeDiagram);
5862
+ cli.command("generate:er", "generate mermaid er diagram").action(writeDiagram);
5809
5863
  cli.command("migration:create [name]", "generate new migration file").action(createMigration);
5810
5864
  cli.command("dump-db", "dump database schema").action(dumpDB);
5811
5865
  cli.command("init").action(init);
package/dist/cli/cli.mjs CHANGED
@@ -1,12 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { cac } from 'cac';
3
- import { writeDiagram } from 'cli/commands/erDiagram';
3
+ import { S as SqlString, a as SasatError, c as config, r as readInitialSchema, g as getDbClient, m as mkDirIfNotExist, n as nonNullable, u as unique, C as Conditions, w as writeFileIfNotExist, b as writeCurrentSchema, d as writeYmlFile, e as defaultConf } from '../shared/sasat.01289068.mjs';
4
+ import 'pluralize';
4
5
  import * as fs from 'fs';
5
6
  import fs__default from 'fs';
6
7
  import * as path from 'path';
7
8
  import path__default, { join } from 'path';
8
- import { c as config, m as mkDirIfNotExist, S as SqlString, g as getDbClient, a as SasatError, r as readInitialSchema, n as nonNullable, u as unique, C as Conditions, w as writeFileIfNotExist, b as writeCurrentSchema, d as writeYmlFile, e as defaultConf } from '../shared/sasat.01289068.mjs';
9
- import 'pluralize';
10
9
  import chalk from 'chalk';
11
10
  import * as console$1 from 'console';
12
11
  import * as esbuild from 'esbuild';
@@ -14,238 +13,10 @@ import fs$1 from 'fs-extra';
14
13
  import 'js-yaml';
15
14
  import * as prettier from 'prettier';
16
15
  import typescript from 'typescript';
17
- import { getCurrentStore } from 'cli/commands/getCurrentStore';
18
16
  import 'sqlstring';
19
17
  import 'mysql2';
20
18
  import 'util';
21
19
 
22
- const capitalizeFirstLetter = (str) => str.slice(0, 1).toUpperCase() + str.slice(1);
23
- const lowercaseFirstLetter = (str) => str.slice(0, 1).toLowerCase() + str.slice(1);
24
- const camelize = (str) => str.replace(
25
- /(?:^\w|[A-Z]|_\w|\b\w)/g,
26
- (word, index) => index == 0 ? word.toLowerCase() : word.toUpperCase()
27
- ).replace(/\s|_|-+/g, "");
28
-
29
- const Console = {
30
- success: (msg) => {
31
- console$1.log(chalk.green(msg));
32
- },
33
- error: (msg) => {
34
- console$1.error(chalk.bold.red(msg));
35
- },
36
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
- log: (msg) => {
38
- console$1.log(msg);
39
- },
40
- debug: (msg) => {
41
- console$1.debug("debug:: " + msg);
42
- }
43
- };
44
-
45
- const getMigrationFile = (className) => `import { SasatMigration, MigrationStore } from "sasat";
46
-
47
- export default class ${capitalizeFirstLetter(
48
- className
49
- )} implements SasatMigration {
50
-
51
- up: (store: MigrationStore) => void = store => {
52
-
53
- };
54
-
55
- down: (store: MigrationStore) => void = store => {
56
- throw new Error('Down is not implemented on ${className}');
57
- };
58
- }
59
- `;
60
- const createMigrationFile = (migrationName) => {
61
- const date = /* @__PURE__ */ new Date();
62
- const pad = (val) => val.toString().padStart(2, "0");
63
- const now = date.getFullYear() + pad(date.getMonth() + 1) + pad(date.getDate()) + `_` + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
64
- const fileName = now + migrationName;
65
- const outDir = join(config().migration.dir);
66
- mkDirIfNotExist(outDir);
67
- fs.writeFileSync(
68
- join(outDir, fileName) + ".ts",
69
- getMigrationFile(migrationName)
70
- );
71
- return fileName;
72
- };
73
- const createMigration = (args) => {
74
- if (!args) {
75
- Console.error("missing argument migration name");
76
- return;
77
- }
78
- if (!/^[$A-Za-z_][0-9A-Za-z_]+$/.test(args)) {
79
- Console.error("migration name should be match /^[$A-Za-z_][0-9A-Za-z_]+$/");
80
- return;
81
- }
82
- Console.success(createMigrationFile(args) + " Successfully created");
83
- return;
84
- };
85
-
86
- const getMigrationFileDir = () => {
87
- return path__default.join(process.cwd(), config().migration.dir);
88
- };
89
- const getMigrationFileNames = () => {
90
- return fs__default.readdirSync(getMigrationFileDir()).filter((it) => it.split(".").pop() === "ts");
91
- };
92
-
93
- var Direction = /* @__PURE__ */ ((Direction2) => {
94
- Direction2["Up"] = "up";
95
- Direction2["Down"] = "down";
96
- return Direction2;
97
- })(Direction || {});
98
- const calcRunMigrationFileNames = (records) => {
99
- const result = [];
100
- records.forEach((it) => {
101
- if (it.direction === "down" /* Down */) {
102
- if (result[result.length] !== it.name)
103
- throw new Error(
104
- "Invalid migration history: `down` migration must be the same migration as the last `up` migration "
105
- );
106
- result.pop();
107
- return;
108
- }
109
- result.push(it.name);
110
- });
111
- return result;
112
- };
113
- const getCurrentMigration = async (options) => {
114
- const migrationTable = SqlString.escapeId(config().migration.table);
115
- const files = getMigrationFileNames();
116
- const client = getDbClient();
117
- const query = `CREATE TABLE IF NOT EXISTS ${migrationTable} (id int auto_increment primary key , name varchar(100) not null,direction enum('up', 'down') not null, migrated_at timestamp default current_timestamp)`;
118
- if (!options.silent) {
119
- Console.log(
120
- `creating migration table: ${migrationTable} :: ${Buffer.from(
121
- migrationTable
122
- ).toString("base64")}`
123
- );
124
- Console.log(query);
125
- }
126
- await client.rawQuery(query);
127
- const q = `SELECT name, direction FROM ${migrationTable} ORDER BY id ASC`;
128
- if (!options.silent) {
129
- Console.debug(q);
130
- }
131
- const result = await client.rawQuery(q);
132
- console.debug(result);
133
- if (!result.length)
134
- return;
135
- const runs = calcRunMigrationFileNames(
136
- result
137
- );
138
- if (runs.length === 0)
139
- return;
140
- runs.forEach((run, i) => {
141
- if (files[i] !== run)
142
- throw new Error(`Invalid migration order: Migration must be performed in the same order
143
- Found : ${files[i]}
144
- in migration history: ${run}`);
145
- });
146
- return runs[runs.length - 1];
147
- };
148
-
149
- const changeExtTsToJs = (fileName) => fileName.slice(0, -3) + ".mjs";
150
- const compileMigrationFiles = () => {
151
- const tsFiles = getMigrationFileNames();
152
- const compiles = tsFiles.map(async (fileName) => {
153
- const filePath = path__default.join(getMigrationFileDir(), fileName);
154
- const r = await esbuild.build({
155
- entryPoints: [filePath],
156
- bundle: true,
157
- // loader: 'ts',
158
- outfile: changeExtTsToJs(filePath),
159
- platform: "node",
160
- format: "esm",
161
- outExtension: {
162
- ".js": ".mjs"
163
- },
164
- banner: {
165
- js: `
166
- import { createRequire as topLevelCreateRequire } from 'module';
167
- const require = topLevelCreateRequire(import.meta.url);
168
- `
169
- }
170
- });
171
- if (r.errors.length !== 0) {
172
- throw r.errors;
173
- }
174
- return fileName;
175
- });
176
- return Promise.all(compiles);
177
- };
178
-
179
- const readMigration = async (store, tsFileName, direction) => {
180
- const file = path__default.join(
181
- process.cwd(),
182
- config().migration.dir,
183
- changeExtTsToJs(tsFileName)
184
- );
185
- const module = await import(file);
186
- const instance = new module.default();
187
- if (direction === Direction.Up) {
188
- if (instance.beforeUp)
189
- await instance.beforeUp();
190
- await instance.up(store);
191
- if (instance.afterUp)
192
- await instance.afterUp();
193
- } else {
194
- if (instance.beforeDown)
195
- await instance.beforeDown();
196
- await instance.down(store);
197
- if (instance.afterDown)
198
- await instance.afterDown();
199
- }
200
- return store;
201
- };
202
-
203
- const runMigration = async (store, migrationName, direction, options) => {
204
- const sqls = store.getSql();
205
- store.resetQueue();
206
- if (!options.silent) {
207
- sqls.forEach(Console.log);
208
- }
209
- if (options.dry) {
210
- return;
211
- }
212
- const transaction = await getDbClient().transaction();
213
- try {
214
- for (const sql of sqls) {
215
- await transaction.rawQuery(sql).catch((e) => {
216
- Console.error(`ERROR ON ${migrationName}`);
217
- Console.error(`SQL: ${sql}`);
218
- Console.error(`MESSAGE: ${e.message}`);
219
- process.exit(1);
220
- });
221
- }
222
- await transaction.query`insert into ${() => config().migration.table} (name, direction) values (${[
223
- migrationName,
224
- direction
225
- ]})`;
226
- return await transaction.commit();
227
- } catch (e) {
228
- await transaction.rollback();
229
- throw e;
230
- }
231
- };
232
-
233
- const getMigrationTargets = (files, current) => {
234
- const currentIndex = current ? files.indexOf(current) + 1 : 0;
235
- const targetIndex = files.indexOf(config().migration.target || files[files.length - 1]) + 1;
236
- if (currentIndex === -1 || targetIndex === -1)
237
- throw new Error("migration target not found");
238
- if (targetIndex >= currentIndex)
239
- return {
240
- direction: Direction.Up,
241
- files: files.slice(currentIndex, targetIndex)
242
- };
243
- return {
244
- direction: Direction.Down,
245
- files: files.slice(targetIndex, currentIndex).reverse()
246
- };
247
- };
248
-
249
20
  var DBColumnTypes = /* @__PURE__ */ ((DBColumnTypes2) => {
250
21
  DBColumnTypes2["char"] = "char";
251
22
  DBColumnTypes2["varchar"] = "varchar";
@@ -493,6 +264,13 @@ const assembleColumn = (data, table) => {
493
264
  return new NormalColumn(data, table);
494
265
  };
495
266
 
267
+ const capitalizeFirstLetter = (str) => str.slice(0, 1).toUpperCase() + str.slice(1);
268
+ const lowercaseFirstLetter = (str) => str.slice(0, 1).toLowerCase() + str.slice(1);
269
+ const camelize = (str) => str.replace(
270
+ /(?:^\w|[A-Z]|_\w|\b\w)/g,
271
+ (word, index) => index == 0 ? word.toLowerCase() : word.toUpperCase()
272
+ ).replace(/\s|_|-+/g, "");
273
+
496
274
  class EntityName {
497
275
  constructor(name) {
498
276
  this.name = name;
@@ -1379,7 +1157,140 @@ class StoreMigrator {
1379
1157
  tables: this.tables.map((it) => it.serialize())
1380
1158
  };
1381
1159
  }
1382
- }
1160
+ }
1161
+
1162
+ const getMigrationFileDir = () => {
1163
+ return path__default.join(process.cwd(), config().migration.dir);
1164
+ };
1165
+ const getMigrationFileNames = () => {
1166
+ return fs__default.readdirSync(getMigrationFileDir()).filter((it) => it.split(".").pop() === "ts");
1167
+ };
1168
+
1169
+ const Console = {
1170
+ success: (msg) => {
1171
+ console$1.log(chalk.green(msg));
1172
+ },
1173
+ error: (msg) => {
1174
+ console$1.error(chalk.bold.red(msg));
1175
+ },
1176
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1177
+ log: (msg) => {
1178
+ console$1.log(msg);
1179
+ },
1180
+ debug: (msg) => {
1181
+ console$1.debug("debug:: " + msg);
1182
+ }
1183
+ };
1184
+
1185
+ var Direction = /* @__PURE__ */ ((Direction2) => {
1186
+ Direction2["Up"] = "up";
1187
+ Direction2["Down"] = "down";
1188
+ return Direction2;
1189
+ })(Direction || {});
1190
+ const calcRunMigrationFileNames = (records) => {
1191
+ const result = [];
1192
+ records.forEach((it) => {
1193
+ if (it.direction === "down" /* Down */) {
1194
+ if (result[result.length] !== it.name)
1195
+ throw new Error(
1196
+ "Invalid migration history: `down` migration must be the same migration as the last `up` migration "
1197
+ );
1198
+ result.pop();
1199
+ return;
1200
+ }
1201
+ result.push(it.name);
1202
+ });
1203
+ return result;
1204
+ };
1205
+ const getCurrentMigration = async (options) => {
1206
+ const migrationTable = SqlString.escapeId(config().migration.table);
1207
+ const files = getMigrationFileNames();
1208
+ const client = getDbClient();
1209
+ const query = `CREATE TABLE IF NOT EXISTS ${migrationTable} (id int auto_increment primary key , name varchar(100) not null,direction enum('up', 'down') not null, migrated_at timestamp default current_timestamp)`;
1210
+ if (!options.silent) {
1211
+ Console.log(
1212
+ `creating migration table: ${migrationTable} :: ${Buffer.from(
1213
+ migrationTable
1214
+ ).toString("base64")}`
1215
+ );
1216
+ Console.log(query);
1217
+ }
1218
+ await client.rawQuery(query);
1219
+ const q = `SELECT name, direction FROM ${migrationTable} ORDER BY id ASC`;
1220
+ if (!options.silent) {
1221
+ Console.debug(q);
1222
+ }
1223
+ const result = await client.rawQuery(q);
1224
+ console.debug(result);
1225
+ if (!result.length)
1226
+ return;
1227
+ const runs = calcRunMigrationFileNames(
1228
+ result
1229
+ );
1230
+ if (runs.length === 0)
1231
+ return;
1232
+ runs.forEach((run, i) => {
1233
+ if (files[i] !== run)
1234
+ throw new Error(`Invalid migration order: Migration must be performed in the same order
1235
+ Found : ${files[i]}
1236
+ in migration history: ${run}`);
1237
+ });
1238
+ return runs[runs.length - 1];
1239
+ };
1240
+
1241
+ const changeExtTsToJs = (fileName) => fileName.slice(0, -3) + ".mjs";
1242
+ const compileMigrationFiles = () => {
1243
+ const tsFiles = getMigrationFileNames();
1244
+ const compiles = tsFiles.map(async (fileName) => {
1245
+ const filePath = path__default.join(getMigrationFileDir(), fileName);
1246
+ const r = await esbuild.build({
1247
+ entryPoints: [filePath],
1248
+ bundle: true,
1249
+ // loader: 'ts',
1250
+ outfile: changeExtTsToJs(filePath),
1251
+ platform: "node",
1252
+ format: "esm",
1253
+ outExtension: {
1254
+ ".js": ".mjs"
1255
+ },
1256
+ banner: {
1257
+ js: `
1258
+ import { createRequire as topLevelCreateRequire } from 'module';
1259
+ const require = topLevelCreateRequire(import.meta.url);
1260
+ `
1261
+ }
1262
+ });
1263
+ if (r.errors.length !== 0) {
1264
+ throw r.errors;
1265
+ }
1266
+ return fileName;
1267
+ });
1268
+ return Promise.all(compiles);
1269
+ };
1270
+
1271
+ const readMigration = async (store, tsFileName, direction) => {
1272
+ const file = path__default.join(
1273
+ process.cwd(),
1274
+ config().migration.dir,
1275
+ changeExtTsToJs(tsFileName)
1276
+ );
1277
+ const module = await import(file);
1278
+ const instance = new module.default();
1279
+ if (direction === Direction.Up) {
1280
+ if (instance.beforeUp)
1281
+ await instance.beforeUp();
1282
+ await instance.up(store);
1283
+ if (instance.afterUp)
1284
+ await instance.afterUp();
1285
+ } else {
1286
+ if (instance.beforeDown)
1287
+ await instance.beforeDown();
1288
+ await instance.down(store);
1289
+ if (instance.afterDown)
1290
+ await instance.afterDown();
1291
+ }
1292
+ return store;
1293
+ };
1383
1294
 
1384
1295
  const createCurrentMigrationDataStore = async (targetMigrationName) => {
1385
1296
  const allFiles = getMigrationFileNames();
@@ -1394,28 +1305,38 @@ const createCurrentMigrationDataStore = async (targetMigrationName) => {
1394
1305
  return store;
1395
1306
  };
1396
1307
 
1397
- class MigrationController {
1398
- async migrate(options) {
1399
- const fileNames = getMigrationFileNames();
1400
- const currentMigration = await getCurrentMigration(options);
1401
- Console.log("--current migration--: " + currentMigration);
1402
- let store = await createCurrentMigrationDataStore(currentMigration);
1403
- const target = getMigrationTargets(fileNames, currentMigration);
1404
- for (const tsFileName of target.files) {
1405
- if (!options.silent) {
1406
- Console.log("---------\n" + tsFileName);
1407
- }
1408
- store = await readMigration(store, tsFileName, target.direction);
1409
- await runMigration(store, tsFileName, target.direction, options);
1410
- store.resetQueue();
1411
- }
1412
- return {
1413
- store: store.serialize(),
1414
- currentMigration: config().migration.target || fileNames[fileNames.length - 1]
1415
- };
1416
- }
1308
+ async function getCurrentStore() {
1309
+ await compileMigrationFiles();
1310
+ const files = getMigrationFileNames();
1311
+ const targetFile = files.find((it) => it === config().migration.target) || files[files.length - 1];
1312
+ return (await createCurrentMigrationDataStore(targetFile)).serialize();
1417
1313
  }
1418
1314
 
1315
+ const GeneratedDirName = "__generated__";
1316
+ const EntityDirName = "entities";
1317
+ const DataSourceDirName = "dataSources";
1318
+ const relative = (from, to) => {
1319
+ const result = path.posix.relative(from, to);
1320
+ if (result.startsWith("../"))
1321
+ return result;
1322
+ return "./" + result;
1323
+ };
1324
+ const GENERATED_PATH = `/${GeneratedDirName}/`;
1325
+ const paths = {
1326
+ BASE: "/",
1327
+ GENERATED: GENERATED_PATH,
1328
+ ENTITIES: `${GENERATED_PATH}${EntityDirName}/`,
1329
+ DATA_SOURCES: `/${DataSourceDirName}/db/`,
1330
+ GENERATED_DS: `${GENERATED_PATH}${DataSourceDirName}/db/`
1331
+ };
1332
+ const resolve = (from, source, fileName) => {
1333
+ return relative(paths[from], paths[source] + fileName);
1334
+ };
1335
+ const Directory = {
1336
+ paths,
1337
+ resolve
1338
+ };
1339
+
1419
1340
  var __defProp$k = Object.defineProperty;
1420
1341
  var __defNormalProp$k = (obj, key, value) => key in obj ? __defProp$k(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1421
1342
  var __publicField$k = (obj, key, value) => {
@@ -1447,6 +1368,164 @@ class DataStoreHandler {
1447
1368
  }
1448
1369
  }
1449
1370
 
1371
+ const writeDiagram = async () => {
1372
+ try {
1373
+ const store = new DataStoreHandler(await getCurrentStore());
1374
+ const entities = store.tables.map((it) => processTable(store, it));
1375
+ const result = `erDiagram
1376
+ ${entities.join("\n")}
1377
+ `;
1378
+ console.log();
1379
+ fs__default.writeFileSync(
1380
+ path__default.join(
1381
+ config().migration.out,
1382
+ Directory.paths.GENERATED,
1383
+ "er-diagram.mermaid"
1384
+ ),
1385
+ result
1386
+ );
1387
+ } catch (e) {
1388
+ Console.error(e.message);
1389
+ throw e;
1390
+ }
1391
+ };
1392
+ function getRefType(parent, rel) {
1393
+ const left = parent.isNullable() ? "|o" : "||";
1394
+ const getRight = () => {
1395
+ switch (rel) {
1396
+ case "One":
1397
+ return "||";
1398
+ case "Many":
1399
+ return "o{";
1400
+ case "OneOrZero":
1401
+ return "|o";
1402
+ }
1403
+ };
1404
+ return `${left} -- ${getRight()}`;
1405
+ }
1406
+ function processTable(store, table) {
1407
+ const rel = table.columns.filter((it) => it.isReference()).map((it) => {
1408
+ const rel2 = it;
1409
+ const ref = rel2.data.reference;
1410
+ const parent = store.table(ref.parentTable).column(ref.parentColumn);
1411
+ return `${ref.parentTable} ${getRefType(parent, ref.relation)} ${table.tableName} : ${ref.relationName}`;
1412
+ });
1413
+ return `${table.tableName} {
1414
+ ${table.columns.map((it) => ` ${it.columnName()} ${it.dataType()}`).join("\n")}
1415
+ }
1416
+ ${rel.join("\n")}
1417
+ `;
1418
+ }
1419
+
1420
+ const getMigrationFile = (className) => `import { SasatMigration, MigrationStore } from "sasat";
1421
+
1422
+ export default class ${capitalizeFirstLetter(
1423
+ className
1424
+ )} implements SasatMigration {
1425
+
1426
+ up: (store: MigrationStore) => void = store => {
1427
+
1428
+ };
1429
+
1430
+ down: (store: MigrationStore) => void = store => {
1431
+ throw new Error('Down is not implemented on ${className}');
1432
+ };
1433
+ }
1434
+ `;
1435
+ const createMigrationFile = (migrationName) => {
1436
+ const date = /* @__PURE__ */ new Date();
1437
+ const pad = (val) => val.toString().padStart(2, "0");
1438
+ const now = date.getFullYear() + pad(date.getMonth() + 1) + pad(date.getDate()) + `_` + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
1439
+ const fileName = now + migrationName;
1440
+ const outDir = join(config().migration.dir);
1441
+ mkDirIfNotExist(outDir);
1442
+ fs.writeFileSync(
1443
+ join(outDir, fileName) + ".ts",
1444
+ getMigrationFile(migrationName)
1445
+ );
1446
+ return fileName;
1447
+ };
1448
+ const createMigration = (args) => {
1449
+ if (!args) {
1450
+ Console.error("missing argument migration name");
1451
+ return;
1452
+ }
1453
+ if (!/^[$A-Za-z_][0-9A-Za-z_]+$/.test(args)) {
1454
+ Console.error("migration name should be match /^[$A-Za-z_][0-9A-Za-z_]+$/");
1455
+ return;
1456
+ }
1457
+ Console.success(createMigrationFile(args) + " Successfully created");
1458
+ return;
1459
+ };
1460
+
1461
+ const runMigration = async (store, migrationName, direction, options) => {
1462
+ const sqls = store.getSql();
1463
+ store.resetQueue();
1464
+ if (!options.silent) {
1465
+ sqls.forEach(Console.log);
1466
+ }
1467
+ if (options.dry) {
1468
+ return;
1469
+ }
1470
+ const transaction = await getDbClient().transaction();
1471
+ try {
1472
+ for (const sql of sqls) {
1473
+ await transaction.rawQuery(sql).catch((e) => {
1474
+ Console.error(`ERROR ON ${migrationName}`);
1475
+ Console.error(`SQL: ${sql}`);
1476
+ Console.error(`MESSAGE: ${e.message}`);
1477
+ process.exit(1);
1478
+ });
1479
+ }
1480
+ await transaction.query`insert into ${() => config().migration.table} (name, direction) values (${[
1481
+ migrationName,
1482
+ direction
1483
+ ]})`;
1484
+ return await transaction.commit();
1485
+ } catch (e) {
1486
+ await transaction.rollback();
1487
+ throw e;
1488
+ }
1489
+ };
1490
+
1491
+ const getMigrationTargets = (files, current) => {
1492
+ const currentIndex = current ? files.indexOf(current) + 1 : 0;
1493
+ const targetIndex = files.indexOf(config().migration.target || files[files.length - 1]) + 1;
1494
+ if (currentIndex === -1 || targetIndex === -1)
1495
+ throw new Error("migration target not found");
1496
+ if (targetIndex >= currentIndex)
1497
+ return {
1498
+ direction: Direction.Up,
1499
+ files: files.slice(currentIndex, targetIndex)
1500
+ };
1501
+ return {
1502
+ direction: Direction.Down,
1503
+ files: files.slice(targetIndex, currentIndex).reverse()
1504
+ };
1505
+ };
1506
+
1507
+ class MigrationController {
1508
+ async migrate(options) {
1509
+ const fileNames = getMigrationFileNames();
1510
+ const currentMigration = await getCurrentMigration(options);
1511
+ Console.log("--current migration--: " + currentMigration);
1512
+ let store = await createCurrentMigrationDataStore(currentMigration);
1513
+ const target = getMigrationTargets(fileNames, currentMigration);
1514
+ for (const tsFileName of target.files) {
1515
+ if (!options.silent) {
1516
+ Console.log("---------\n" + tsFileName);
1517
+ }
1518
+ store = await readMigration(store, tsFileName, target.direction);
1519
+ await runMigration(store, tsFileName, target.direction, options);
1520
+ store.resetQueue();
1521
+ }
1522
+ return {
1523
+ store: store.serialize(),
1524
+ currentMigration: config().migration.target || fileNames[fileNames.length - 1]
1525
+ };
1526
+ }
1527
+ }
1528
+
1450
1529
  class ImportDeclaration {
1451
1530
  constructor(types, module) {
1452
1531
  this.types = types;
@@ -2767,31 +2846,6 @@ const makeSubscription = (subscriptions) => {
2767
2846
  );
2768
2847
  };
2769
2848
 
2770
- const GeneratedDirName = "__generated__";
2771
- const EntityDirName = "entities";
2772
- const DataSourceDirName = "dataSources";
2773
- const relative = (from, to) => {
2774
- const result = path.posix.relative(from, to);
2775
- if (result.startsWith("../"))
2776
- return result;
2777
- return "./" + result;
2778
- };
2779
- const GENERATED_PATH = `/${GeneratedDirName}/`;
2780
- const paths = {
2781
- BASE: "/",
2782
- GENERATED: GENERATED_PATH,
2783
- ENTITIES: `${GENERATED_PATH}${EntityDirName}/`,
2784
- DATA_SOURCES: `/${DataSourceDirName}/db/`,
2785
- GENERATED_DS: `${GENERATED_PATH}${DataSourceDirName}/db/`
2786
- };
2787
- const resolve = (from, source, fileName) => {
2788
- return relative(paths[from], paths[source] + fileName);
2789
- };
2790
- const Directory = {
2791
- paths,
2792
- resolve
2793
- };
2794
-
2795
2849
  const typeRefs = {
2796
2850
  entity: {
2797
2851
  name: (entity) => entity.name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sasat",
3
- "version": "0.21.1",
3
+ "version": "0.21.3",
4
4
  "repository": "https://github.com/nin138/sasat.git",
5
5
  "author": "nin138 <ninian138@gmail.com>",
6
6
  "license": "MIT",