sasat 0.22.0 → 0.22.2
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/index.cjs +604 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.mjs +604 -0
- package/dist/index.cjs +32 -3981
- package/dist/index.mjs +4 -3928
- package/dist/migrate-BRNxkHCx.cjs +4162 -0
- package/dist/migrate-Cbj2OVbY.mjs +3944 -0
- package/package.json +3 -3
|
@@ -0,0 +1,4162 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
let node_fs = require("node:fs");
|
|
24
|
+
node_fs = __toESM(node_fs, 1);
|
|
25
|
+
let node_path = require("node:path");
|
|
26
|
+
node_path = __toESM(node_path, 1);
|
|
27
|
+
let node_fs_promises = require("node:fs/promises");
|
|
28
|
+
let js_yaml = require("js-yaml");
|
|
29
|
+
js_yaml = __toESM(js_yaml, 1);
|
|
30
|
+
require("pluralize");
|
|
31
|
+
let typescript = require("typescript");
|
|
32
|
+
typescript = __toESM(typescript, 1);
|
|
33
|
+
let chalk = require("chalk");
|
|
34
|
+
chalk = __toESM(chalk, 1);
|
|
35
|
+
let sqlstring = require("sqlstring");
|
|
36
|
+
sqlstring = __toESM(sqlstring, 1);
|
|
37
|
+
let mysql2_promise = require("mysql2/promise");
|
|
38
|
+
let esbuild = require("esbuild");
|
|
39
|
+
//#region src/util/assignDeep.ts
|
|
40
|
+
const assignDeep = (base, ...objects) => {
|
|
41
|
+
const assign = (target, key, value) => {
|
|
42
|
+
if (key === "__proto__" || key === "constructor") return;
|
|
43
|
+
if (Array.isArray(target[key]) && Array.isArray(value)) target[key] = [...target[key], ...value];
|
|
44
|
+
else if (typeof target[key] === "object" && typeof value === "object") assignDeep(target[key], value);
|
|
45
|
+
else target[key] = value;
|
|
46
|
+
};
|
|
47
|
+
objects.forEach((obj) => {
|
|
48
|
+
if (typeof obj === "object") Object.entries(obj).forEach(([key, value]) => {
|
|
49
|
+
assign(base, key, value);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
return base;
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/util/fsUtil.ts
|
|
56
|
+
const readYmlFile = (filepath) => js_yaml.default.load((0, node_fs.readFileSync)(filepath, "utf8"));
|
|
57
|
+
const mkDirIfNotExist = (path) => {
|
|
58
|
+
if (!(0, node_fs.existsSync)(path)) (0, node_fs.mkdirSync)(path, { recursive: true });
|
|
59
|
+
};
|
|
60
|
+
const writeFileIfNotExist = (path, data) => {
|
|
61
|
+
if ((0, node_fs.existsSync)(path)) return Promise.resolve();
|
|
62
|
+
return (0, node_fs_promises.writeFile)(path, data);
|
|
63
|
+
};
|
|
64
|
+
const writeYmlFile = (path, fileName, obj) => {
|
|
65
|
+
mkDirIfNotExist(path);
|
|
66
|
+
(0, node_fs.writeFileSync)((0, node_path.join)(path, fileName), js_yaml.default.dump(obj, {
|
|
67
|
+
skipInvalid: true,
|
|
68
|
+
noRefs: true,
|
|
69
|
+
sortKeys: (a, b) => {
|
|
70
|
+
if (b === "tableName") return 1;
|
|
71
|
+
if (a === "tableName") return -1;
|
|
72
|
+
if (a > b) return 1;
|
|
73
|
+
if (a < b) return -1;
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
};
|
|
78
|
+
const readInitialSchema = () => {
|
|
79
|
+
return readYmlFile((0, node_path.join)(config().migration.dir, "initialSchema.yml"));
|
|
80
|
+
};
|
|
81
|
+
const writeCurrentSchema = (schema) => {
|
|
82
|
+
writeYmlFile(config().migration.dir, "currentSchema.yml", schema);
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/config/loader.ts
|
|
86
|
+
var SasatConfigLoader = class SasatConfigLoader {
|
|
87
|
+
static loadConfig() {
|
|
88
|
+
const filepath = node_path.default.join(process.cwd(), "sasat.yml");
|
|
89
|
+
if (!(0, node_fs.existsSync)(filepath)) return defaultConf;
|
|
90
|
+
return readYmlFile(filepath);
|
|
91
|
+
}
|
|
92
|
+
constructor() {
|
|
93
|
+
const conf = this.readValue({
|
|
94
|
+
...defaultConf,
|
|
95
|
+
...SasatConfigLoader.loadConfig()
|
|
96
|
+
});
|
|
97
|
+
this.conf = { ...conf };
|
|
98
|
+
}
|
|
99
|
+
getConfig() {
|
|
100
|
+
return this.conf;
|
|
101
|
+
}
|
|
102
|
+
readValue(value) {
|
|
103
|
+
if (!value) return value;
|
|
104
|
+
if (Array.isArray(value)) return value.map((it) => this.readValue(it));
|
|
105
|
+
if (typeof value === "string" && value.startsWith("$")) return process.env[value.slice(1)];
|
|
106
|
+
if (typeof value === "object") {
|
|
107
|
+
for (const key in value) if (Object.hasOwn(value, key)) value[key] = this.readValue(value[key]);
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const defaultConf = {
|
|
114
|
+
db: {
|
|
115
|
+
host: "127.0.0.1",
|
|
116
|
+
port: 3306,
|
|
117
|
+
user: "root",
|
|
118
|
+
database: "sasat",
|
|
119
|
+
password: ""
|
|
120
|
+
},
|
|
121
|
+
migration: {
|
|
122
|
+
table: "__migrate__",
|
|
123
|
+
dir: "migrations",
|
|
124
|
+
out: "sasat"
|
|
125
|
+
},
|
|
126
|
+
generator: {
|
|
127
|
+
addJsExtToImportStatement: false,
|
|
128
|
+
gql: { subscription: true }
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
let conf;
|
|
132
|
+
const config = () => {
|
|
133
|
+
if (conf === void 0) conf = new SasatConfigLoader().getConfig();
|
|
134
|
+
return conf;
|
|
135
|
+
};
|
|
136
|
+
function setConfig(update) {
|
|
137
|
+
conf = assignDeep(config(), update);
|
|
138
|
+
return conf;
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/generatorv2/fs/emptyDir.ts
|
|
142
|
+
async function emptyDir(dir) {
|
|
143
|
+
let items;
|
|
144
|
+
try {
|
|
145
|
+
items = await (0, node_fs_promises.readdir)(dir);
|
|
146
|
+
} catch {
|
|
147
|
+
return (0, node_fs_promises.mkdir)(dir, {
|
|
148
|
+
mode: 511,
|
|
149
|
+
recursive: true
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return Promise.all(items.map((item) => (0, node_fs_promises.rm)(node_path.default.join(dir, item), {
|
|
153
|
+
recursive: true,
|
|
154
|
+
force: true
|
|
155
|
+
})));
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/generatorv2/codegen/ts/tsFileNames.ts
|
|
159
|
+
const tsFileNames = {
|
|
160
|
+
encoder: "idEncoder",
|
|
161
|
+
conditions: "conditions",
|
|
162
|
+
middleware: "middlewares"
|
|
163
|
+
};
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region src/migration/column/columnTypes.ts
|
|
166
|
+
let DBColumnTypes = /* @__PURE__ */ function(DBColumnTypes) {
|
|
167
|
+
DBColumnTypes["char"] = "char";
|
|
168
|
+
DBColumnTypes["varchar"] = "varchar";
|
|
169
|
+
DBColumnTypes["text"] = "text";
|
|
170
|
+
DBColumnTypes["tinyInt"] = "tinyint";
|
|
171
|
+
DBColumnTypes["smallInt"] = "smallint";
|
|
172
|
+
DBColumnTypes["mediumInt"] = "mediumint";
|
|
173
|
+
DBColumnTypes["int"] = "int";
|
|
174
|
+
DBColumnTypes["bigInt"] = "bigint";
|
|
175
|
+
DBColumnTypes["float"] = "float";
|
|
176
|
+
DBColumnTypes["double"] = "double";
|
|
177
|
+
DBColumnTypes["decimal"] = "decimal";
|
|
178
|
+
DBColumnTypes["year"] = "year";
|
|
179
|
+
DBColumnTypes["date"] = "date";
|
|
180
|
+
DBColumnTypes["time"] = "time";
|
|
181
|
+
DBColumnTypes["dateTime"] = "datetime";
|
|
182
|
+
DBColumnTypes["timestamp"] = "timestamp";
|
|
183
|
+
DBColumnTypes["boolean"] = "boolean";
|
|
184
|
+
return DBColumnTypes;
|
|
185
|
+
}({});
|
|
186
|
+
const columnTypeToTsType = (type) => {
|
|
187
|
+
switch (type) {
|
|
188
|
+
case "tinyint":
|
|
189
|
+
case "smallint":
|
|
190
|
+
case "mediumint":
|
|
191
|
+
case "int":
|
|
192
|
+
case "bigint":
|
|
193
|
+
case "float":
|
|
194
|
+
case "double":
|
|
195
|
+
case "decimal":
|
|
196
|
+
case "year": return "number";
|
|
197
|
+
case "char":
|
|
198
|
+
case "varchar":
|
|
199
|
+
case "text":
|
|
200
|
+
case "time":
|
|
201
|
+
case "date":
|
|
202
|
+
case "datetime":
|
|
203
|
+
case "timestamp": return "string";
|
|
204
|
+
case "boolean": return "boolean";
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/tsg/importDeclaration.ts
|
|
209
|
+
var ImportDeclaration = class {
|
|
210
|
+
constructor(types, module) {
|
|
211
|
+
this.types = types;
|
|
212
|
+
this.module = module;
|
|
213
|
+
}
|
|
214
|
+
toString() {
|
|
215
|
+
const addJsExt = config().generator.addJsExtToImportStatement && this.module.startsWith(".");
|
|
216
|
+
return `import {${this.types.join(",")}} from "${addJsExt ? this.module + ".js" : this.module}";`;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region src/tsg/abstruct/tsCode.ts
|
|
221
|
+
var TsCode = class {
|
|
222
|
+
constructor() {
|
|
223
|
+
this.importDeclarations = [];
|
|
224
|
+
}
|
|
225
|
+
addImport(types, module) {
|
|
226
|
+
this.importDeclarations.push(new ImportDeclaration(types, module));
|
|
227
|
+
return this;
|
|
228
|
+
}
|
|
229
|
+
toString() {
|
|
230
|
+
return this.codePrefix() + this.toTsString();
|
|
231
|
+
}
|
|
232
|
+
codePrefix() {
|
|
233
|
+
return "";
|
|
234
|
+
}
|
|
235
|
+
mergeImport(...code) {
|
|
236
|
+
code.forEach((it) => {
|
|
237
|
+
if (it) this.importDeclarations.push(...it.importDeclarations);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/tsg/abstruct/statement.ts
|
|
243
|
+
var TsStatement = class extends TsCode {
|
|
244
|
+
constructor(..._args) {
|
|
245
|
+
super(..._args);
|
|
246
|
+
this.codeType = "statement";
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
//#endregion
|
|
250
|
+
//#region src/tsg/node/block.ts
|
|
251
|
+
const notNull = (v) => {
|
|
252
|
+
return v !== null;
|
|
253
|
+
};
|
|
254
|
+
var Block = class extends TsStatement {
|
|
255
|
+
constructor(...statements) {
|
|
256
|
+
super();
|
|
257
|
+
const sts = statements.filter(notNull);
|
|
258
|
+
this.mergeImport(...sts);
|
|
259
|
+
this.statements = sts;
|
|
260
|
+
}
|
|
261
|
+
toTsString() {
|
|
262
|
+
return `{${this.statements.map((it) => it.toString()).join("\n")}}`;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/tsg/abstruct/exportableDeclaration.ts
|
|
267
|
+
var ExportableDeclaration = class extends TsStatement {
|
|
268
|
+
constructor(..._args) {
|
|
269
|
+
super(..._args);
|
|
270
|
+
this.isExported = false;
|
|
271
|
+
}
|
|
272
|
+
codePrefix() {
|
|
273
|
+
return this.isExported ? "export " : "";
|
|
274
|
+
}
|
|
275
|
+
export() {
|
|
276
|
+
this.isExported = true;
|
|
277
|
+
return this;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/tsg/node/class.ts
|
|
282
|
+
var Class = class extends ExportableDeclaration {
|
|
283
|
+
constructor(name) {
|
|
284
|
+
super();
|
|
285
|
+
this.name = name;
|
|
286
|
+
this.properties = [];
|
|
287
|
+
this.methods = [];
|
|
288
|
+
this.isAbstract = false;
|
|
289
|
+
}
|
|
290
|
+
abstract() {
|
|
291
|
+
this.isAbstract = true;
|
|
292
|
+
return this;
|
|
293
|
+
}
|
|
294
|
+
extends(value) {
|
|
295
|
+
this._extends = value;
|
|
296
|
+
this.mergeImport(value);
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
implements(value) {
|
|
300
|
+
this._implements = value;
|
|
301
|
+
this.mergeImport(value);
|
|
302
|
+
return this;
|
|
303
|
+
}
|
|
304
|
+
addProperty(...properties) {
|
|
305
|
+
this.properties.push(...properties);
|
|
306
|
+
this.mergeImport(...properties);
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
addMethod(...methods) {
|
|
310
|
+
this.methods.push(...methods);
|
|
311
|
+
this.mergeImport(...methods);
|
|
312
|
+
return this;
|
|
313
|
+
}
|
|
314
|
+
toTsString() {
|
|
315
|
+
const properties = this.properties.map((it) => it.toString()).join("");
|
|
316
|
+
const methods = this.methods.map((it) => it.toString()).join("");
|
|
317
|
+
const implement = this._implements ? this._implements.toString() + " " : "";
|
|
318
|
+
const extend = this._extends ? this._extends.toString() + "" : "";
|
|
319
|
+
return (this.isAbstract ? "abstract " : "") + `class ${this.name} ${implement}${extend}{${properties}${methods}}`;
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/tsg/node/enumDeclaration.ts
|
|
324
|
+
var EnumDeclaration = class extends ExportableDeclaration {
|
|
325
|
+
constructor(identifier, members) {
|
|
326
|
+
super();
|
|
327
|
+
this.identifier = identifier;
|
|
328
|
+
this.members = members;
|
|
329
|
+
this.mergeImport(identifier, ...members);
|
|
330
|
+
}
|
|
331
|
+
addMembers(...members) {
|
|
332
|
+
this.members.push(...members);
|
|
333
|
+
this.mergeImport(...members);
|
|
334
|
+
return this;
|
|
335
|
+
}
|
|
336
|
+
toTsString() {
|
|
337
|
+
return `enum ${this.identifier}{${this.members.map((it) => it.toString() + ",").join("")}}`;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/tsg/node/enumMember.ts
|
|
342
|
+
var EnumMember = class extends TsCode {
|
|
343
|
+
constructor(identifier, value) {
|
|
344
|
+
super();
|
|
345
|
+
this.identifier = identifier;
|
|
346
|
+
this.value = value;
|
|
347
|
+
this.mergeImport(identifier);
|
|
348
|
+
if (value) this.mergeImport(value);
|
|
349
|
+
}
|
|
350
|
+
toTsString() {
|
|
351
|
+
if (!this.value) return this.identifier.toString();
|
|
352
|
+
return this.identifier + "=" + this.value;
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region src/tsg/node/expressionStatement.ts
|
|
357
|
+
var ExpressionStatement = class extends TsStatement {
|
|
358
|
+
constructor(expression) {
|
|
359
|
+
super();
|
|
360
|
+
this.expression = expression;
|
|
361
|
+
this.mergeImport(expression);
|
|
362
|
+
}
|
|
363
|
+
toTsString() {
|
|
364
|
+
return this.expression.toString() + ";";
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/tsg/tsValueString.ts
|
|
369
|
+
const tsValueString = (value) => {
|
|
370
|
+
if (value === null) return "null";
|
|
371
|
+
if (value === void 0) return "undefined";
|
|
372
|
+
if (typeof value === "number") return "" + value;
|
|
373
|
+
if (typeof value === "boolean") return "" + value;
|
|
374
|
+
if (typeof value === "string") return `'${value.replaceAll("'", "\\'")}'`;
|
|
375
|
+
if (typeof value === "bigint") return "" + value;
|
|
376
|
+
if (typeof value === "function") return value.toString();
|
|
377
|
+
if (Array.isArray(value)) return `[${value.map(tsValueString).join(",")}]`;
|
|
378
|
+
if (typeof value === "object") return `{${Object.entries(value).map(([key, value]) => [key, tsValueString(value)]).map(([key, value]) => `${key}: ${value}`).join(",")}}`;
|
|
379
|
+
throw new TypeError(`tsValueString::unsupported data type ${typeof value}`);
|
|
380
|
+
};
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region src/tsg/node/parameter.ts
|
|
383
|
+
var Parameter = class extends TsCode {
|
|
384
|
+
constructor(paramName, type) {
|
|
385
|
+
super();
|
|
386
|
+
this.paramName = paramName;
|
|
387
|
+
this.type = type;
|
|
388
|
+
this.mergeImport(type);
|
|
389
|
+
}
|
|
390
|
+
toTsString() {
|
|
391
|
+
if (!this.type) return this.paramName;
|
|
392
|
+
return `${this.paramName}: ${this.type.toString()}`;
|
|
393
|
+
}
|
|
394
|
+
static arrayToString(params) {
|
|
395
|
+
return params.map((it) => it.toString()).join(",");
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region src/tsg/node/expressions.ts
|
|
400
|
+
var TsExpression = class extends TsCode {
|
|
401
|
+
constructor(..._args) {
|
|
402
|
+
super(..._args);
|
|
403
|
+
this._codeType = "expression";
|
|
404
|
+
}
|
|
405
|
+
toStatement() {
|
|
406
|
+
return new ExpressionStatement(this);
|
|
407
|
+
}
|
|
408
|
+
call(...args) {
|
|
409
|
+
return new CallExpression(this, ...args);
|
|
410
|
+
}
|
|
411
|
+
nonNull() {
|
|
412
|
+
return new NonNullExpression(this);
|
|
413
|
+
}
|
|
414
|
+
property(propertyName) {
|
|
415
|
+
return new PropertyAccessExpression(this, propertyName);
|
|
416
|
+
}
|
|
417
|
+
as(type) {
|
|
418
|
+
return new AsExpression(this, type);
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
var CallExpression = class extends TsExpression {
|
|
422
|
+
constructor(identifier, ...args) {
|
|
423
|
+
super();
|
|
424
|
+
this.identifier = identifier;
|
|
425
|
+
this._typeArgs = [];
|
|
426
|
+
this.mergeImport(identifier, ...args);
|
|
427
|
+
this.args = args;
|
|
428
|
+
}
|
|
429
|
+
typeArgs(...typeArgs) {
|
|
430
|
+
this._typeArgs = typeArgs;
|
|
431
|
+
this.mergeImport(...typeArgs);
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
toTsString() {
|
|
435
|
+
return this.identifier.toString() + (this._typeArgs.length !== 0 ? `<${this._typeArgs.map((it) => it.toString()).join(",")}>` : "") + `(${this.args.map((it) => it.toString()).join(",")})`;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
var Literal = class extends TsExpression {};
|
|
439
|
+
var StringLiteral = class extends Literal {
|
|
440
|
+
constructor(value) {
|
|
441
|
+
super();
|
|
442
|
+
this.value = value;
|
|
443
|
+
}
|
|
444
|
+
toTsString() {
|
|
445
|
+
return tsValueString(this.value);
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
var NumericLiteral = class extends Literal {
|
|
449
|
+
constructor(value) {
|
|
450
|
+
super();
|
|
451
|
+
this.value = value;
|
|
452
|
+
}
|
|
453
|
+
toTsString() {
|
|
454
|
+
return this.value.toString();
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
var Boolean = class extends Literal {
|
|
458
|
+
constructor(value) {
|
|
459
|
+
super();
|
|
460
|
+
this.value = value;
|
|
461
|
+
}
|
|
462
|
+
toTsString() {
|
|
463
|
+
return this.value.toString();
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
var ArrayLiteral = class extends Literal {
|
|
467
|
+
constructor(literals) {
|
|
468
|
+
super();
|
|
469
|
+
this.literals = literals;
|
|
470
|
+
this.mergeImport(...literals);
|
|
471
|
+
}
|
|
472
|
+
toTsString() {
|
|
473
|
+
return `[${this.literals.map((it) => it.toString()).join(",")}]`;
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
var ObjectLiteral = class extends Literal {
|
|
477
|
+
constructor(...properties) {
|
|
478
|
+
super();
|
|
479
|
+
this.properties = [];
|
|
480
|
+
this.addProperties(...properties);
|
|
481
|
+
}
|
|
482
|
+
addProperties(...properties) {
|
|
483
|
+
this.properties.push(...properties);
|
|
484
|
+
this.mergeImport(...properties);
|
|
485
|
+
return this;
|
|
486
|
+
}
|
|
487
|
+
toTsString() {
|
|
488
|
+
return `{${this.properties.map((it) => it.toString()).join(",")}}`;
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
var ArrowFunction = class extends Literal {
|
|
492
|
+
constructor(params, returnType, body) {
|
|
493
|
+
super();
|
|
494
|
+
this.params = params;
|
|
495
|
+
this.returnType = returnType;
|
|
496
|
+
this.body = body;
|
|
497
|
+
this.mergeImport(...params, body, returnType);
|
|
498
|
+
}
|
|
499
|
+
toTsString() {
|
|
500
|
+
const returnType = this.returnType ? `: ${this.returnType}` : "";
|
|
501
|
+
return `(${Parameter.arrayToString(this.params)})${returnType} => ${this.body.toString()}`;
|
|
502
|
+
}
|
|
503
|
+
toAsync() {
|
|
504
|
+
return new AsyncExpression(this);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
var AsyncExpression = class extends TsExpression {
|
|
508
|
+
constructor(expression) {
|
|
509
|
+
super();
|
|
510
|
+
this.expression = expression;
|
|
511
|
+
this.mergeImport(expression);
|
|
512
|
+
}
|
|
513
|
+
toTsString() {
|
|
514
|
+
return "async " + this.expression.toString();
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
var AwaitExpression = class extends TsExpression {
|
|
518
|
+
constructor(expression) {
|
|
519
|
+
super();
|
|
520
|
+
this.expression = expression;
|
|
521
|
+
this.mergeImport(expression);
|
|
522
|
+
}
|
|
523
|
+
toTsString() {
|
|
524
|
+
return "await " + this.expression.toString();
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
var BinaryExpression = class extends TsExpression {
|
|
528
|
+
constructor(left, operator, right) {
|
|
529
|
+
super();
|
|
530
|
+
this.left = left;
|
|
531
|
+
this.operator = operator;
|
|
532
|
+
this.right = right;
|
|
533
|
+
this.mergeImport(left, right);
|
|
534
|
+
}
|
|
535
|
+
toTsString() {
|
|
536
|
+
return this.left + this.operator + this.right;
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
var Identifier = class extends TsExpression {
|
|
540
|
+
constructor(name) {
|
|
541
|
+
super();
|
|
542
|
+
this.name = name;
|
|
543
|
+
}
|
|
544
|
+
toTsString() {
|
|
545
|
+
return this.name;
|
|
546
|
+
}
|
|
547
|
+
importFrom(path) {
|
|
548
|
+
this.addImport([this.name], path);
|
|
549
|
+
return this;
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
var NewExpression = class extends CallExpression {
|
|
553
|
+
toTsString() {
|
|
554
|
+
return "new " + super.toTsString();
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
var ParenthesizedExpression = class extends TsExpression {
|
|
558
|
+
constructor(expression) {
|
|
559
|
+
super();
|
|
560
|
+
this.expression = expression;
|
|
561
|
+
this.mergeImport(expression);
|
|
562
|
+
}
|
|
563
|
+
toTsString() {
|
|
564
|
+
return `(${this.expression})`;
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
var NonNullExpression = class extends TsExpression {
|
|
568
|
+
constructor(expression) {
|
|
569
|
+
super();
|
|
570
|
+
this.expression = expression;
|
|
571
|
+
this.mergeImport(expression);
|
|
572
|
+
}
|
|
573
|
+
toTsString() {
|
|
574
|
+
return `${this.expression}!`;
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
var PropertyAccessExpression = class extends TsExpression {
|
|
578
|
+
constructor(expression, propertyName) {
|
|
579
|
+
super();
|
|
580
|
+
this.expression = expression;
|
|
581
|
+
this.propertyName = propertyName;
|
|
582
|
+
this.mergeImport(expression);
|
|
583
|
+
}
|
|
584
|
+
toTsString() {
|
|
585
|
+
return `${this.expression.toString()}.${this.propertyName}`;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
var AsExpression = class extends TsExpression {
|
|
589
|
+
constructor(expression, asType) {
|
|
590
|
+
super();
|
|
591
|
+
this.expression = expression;
|
|
592
|
+
this.asType = asType;
|
|
593
|
+
this.mergeImport(expression, asType);
|
|
594
|
+
}
|
|
595
|
+
toTsString() {
|
|
596
|
+
return this.expression.toString() + " as " + this.asType.toString();
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
var TernaryExpression = class extends TsExpression {
|
|
600
|
+
constructor(condition, left, right) {
|
|
601
|
+
super();
|
|
602
|
+
this.condition = condition;
|
|
603
|
+
this.left = left;
|
|
604
|
+
this.right = right;
|
|
605
|
+
this.mergeImport(condition, left, right);
|
|
606
|
+
}
|
|
607
|
+
toTsString() {
|
|
608
|
+
return `(${this.condition})?${this.left}:${this.right}`;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
var SpreadElement = class extends TsExpression {
|
|
612
|
+
constructor(expression) {
|
|
613
|
+
super();
|
|
614
|
+
this.expression = expression;
|
|
615
|
+
this.mergeImport(expression);
|
|
616
|
+
}
|
|
617
|
+
toTsString() {
|
|
618
|
+
return `...${this.expression}`;
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
//#endregion
|
|
622
|
+
//#region src/tsg/node/extendsClause.ts
|
|
623
|
+
var ExtendsClause = class extends TsCode {
|
|
624
|
+
constructor(type) {
|
|
625
|
+
super();
|
|
626
|
+
this.type = type;
|
|
627
|
+
this.mergeImport(type);
|
|
628
|
+
}
|
|
629
|
+
toTsString() {
|
|
630
|
+
return `extends ${this.type}`;
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
//#endregion
|
|
634
|
+
//#region src/tsg/node/ifStatement.ts
|
|
635
|
+
var IfStatement = class extends TsStatement {
|
|
636
|
+
constructor(condition, statement) {
|
|
637
|
+
super();
|
|
638
|
+
this.condition = condition;
|
|
639
|
+
this.statement = statement;
|
|
640
|
+
this.mergeImport(condition, statement);
|
|
641
|
+
}
|
|
642
|
+
toTsString() {
|
|
643
|
+
return `if(${this.condition})${this.statement}`;
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
//#endregion
|
|
647
|
+
//#region src/tsg/node/implementsClause.ts
|
|
648
|
+
var ImplementsClause = class extends TsCode {
|
|
649
|
+
constructor(...types) {
|
|
650
|
+
super();
|
|
651
|
+
this.types = types;
|
|
652
|
+
this.mergeImport(...types);
|
|
653
|
+
}
|
|
654
|
+
toTsString() {
|
|
655
|
+
return `implements ${this.types.join(",")}`;
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
//#endregion
|
|
659
|
+
//#region src/tsg/tsUtil.ts
|
|
660
|
+
const TsUtil = {
|
|
661
|
+
readonly: (isReadonly) => isReadonly ? "readonly " : "",
|
|
662
|
+
questionToken: (isOptional) => isOptional ? "?" : ""
|
|
663
|
+
};
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region src/tsg/node/propertySignature.ts
|
|
666
|
+
var PropertySignature = class extends TsCode {
|
|
667
|
+
constructor(propertyName, type, isOptional = false, isReadOnly = false) {
|
|
668
|
+
super();
|
|
669
|
+
this.propertyName = propertyName;
|
|
670
|
+
this.type = type;
|
|
671
|
+
this.isOptional = isOptional;
|
|
672
|
+
this.isReadOnly = isReadOnly;
|
|
673
|
+
this.mergeImport(type);
|
|
674
|
+
}
|
|
675
|
+
codePrefix() {
|
|
676
|
+
return TsUtil.readonly(this.isReadOnly);
|
|
677
|
+
}
|
|
678
|
+
toTsString() {
|
|
679
|
+
return `${this.propertyName}${TsUtil.questionToken(this.isOptional)}: ${this.type}`;
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
//#endregion
|
|
683
|
+
//#region src/tsg/node/interface.ts
|
|
684
|
+
var TsInterface = class extends ExportableDeclaration {
|
|
685
|
+
constructor(name) {
|
|
686
|
+
super();
|
|
687
|
+
this.name = name;
|
|
688
|
+
this.properties = [];
|
|
689
|
+
}
|
|
690
|
+
addProperty(propertyName, type, isOptional = false, isReadOnly = false) {
|
|
691
|
+
this.properties.push(new PropertySignature(propertyName, type, isOptional, isReadOnly));
|
|
692
|
+
return this;
|
|
693
|
+
}
|
|
694
|
+
addProperties(properties) {
|
|
695
|
+
this.properties.push(...properties);
|
|
696
|
+
this.mergeImport(...properties);
|
|
697
|
+
return this;
|
|
698
|
+
}
|
|
699
|
+
extends(value) {
|
|
700
|
+
this._extends = value;
|
|
701
|
+
this.mergeImport(value);
|
|
702
|
+
return this;
|
|
703
|
+
}
|
|
704
|
+
toTsString() {
|
|
705
|
+
const extend = this._extends ? this._extends.toString() + " " : "";
|
|
706
|
+
return `interface ${this.name} ${extend}{${this.properties.map((it) => it.toString()).join(";")}}`;
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
//#endregion
|
|
710
|
+
//#region src/tsg/node/modifier/modifiers.ts
|
|
711
|
+
var Modifiers = class extends TsCode {
|
|
712
|
+
constructor(..._args) {
|
|
713
|
+
super(..._args);
|
|
714
|
+
this._accessor = "";
|
|
715
|
+
this.isReadOnly = false;
|
|
716
|
+
this.isStatic = false;
|
|
717
|
+
this.isAbstract = false;
|
|
718
|
+
this.isAsync = false;
|
|
719
|
+
}
|
|
720
|
+
accessor(accessor) {
|
|
721
|
+
this._accessor = accessor;
|
|
722
|
+
return this;
|
|
723
|
+
}
|
|
724
|
+
private() {
|
|
725
|
+
return this.accessor("private");
|
|
726
|
+
}
|
|
727
|
+
protected() {
|
|
728
|
+
return this.accessor("protected ");
|
|
729
|
+
}
|
|
730
|
+
abstract() {
|
|
731
|
+
this.isAbstract = true;
|
|
732
|
+
return this;
|
|
733
|
+
}
|
|
734
|
+
readonly() {
|
|
735
|
+
this.isReadOnly = true;
|
|
736
|
+
return this;
|
|
737
|
+
}
|
|
738
|
+
static() {
|
|
739
|
+
this.isStatic = true;
|
|
740
|
+
return this;
|
|
741
|
+
}
|
|
742
|
+
async() {
|
|
743
|
+
this.isAsync = true;
|
|
744
|
+
return this;
|
|
745
|
+
}
|
|
746
|
+
toTsString() {
|
|
747
|
+
const optional = (bool, string) => bool ? string : "";
|
|
748
|
+
return this._accessor + " " + optional(this.isAbstract, "abstract ") + optional(this.isStatic, "static ") + optional(this.isReadOnly, "readonly ") + optional(this.isAsync, "async ");
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
//#endregion
|
|
752
|
+
//#region src/tsg/node/modifier/methodModifiers.ts
|
|
753
|
+
var MethodModifiers = class extends Modifiers {
|
|
754
|
+
private() {
|
|
755
|
+
return super.private();
|
|
756
|
+
}
|
|
757
|
+
protected() {
|
|
758
|
+
return super.protected();
|
|
759
|
+
}
|
|
760
|
+
abstract() {
|
|
761
|
+
return super.abstract();
|
|
762
|
+
}
|
|
763
|
+
static() {
|
|
764
|
+
return super.static();
|
|
765
|
+
}
|
|
766
|
+
async() {
|
|
767
|
+
return super.async();
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
//#endregion
|
|
771
|
+
//#region src/tsg/node/type/type.ts
|
|
772
|
+
const isCode = (t) => t instanceof TsCode;
|
|
773
|
+
const pickCode = (types) => types.filter((it) => it instanceof TsCode);
|
|
774
|
+
//#endregion
|
|
775
|
+
//#region src/tsg/node/methodDeclaration.ts
|
|
776
|
+
var MethodDeclaration = class extends TsCode {
|
|
777
|
+
constructor(methodName, params, returnType, body) {
|
|
778
|
+
super();
|
|
779
|
+
this.methodName = methodName;
|
|
780
|
+
this.params = params;
|
|
781
|
+
this.returnType = returnType;
|
|
782
|
+
this.body = body;
|
|
783
|
+
this._modifiers = new MethodModifiers();
|
|
784
|
+
this.mergeImport(...params, ...body);
|
|
785
|
+
if (isCode(returnType)) this.mergeImport(returnType);
|
|
786
|
+
}
|
|
787
|
+
modifiers(modifiers) {
|
|
788
|
+
this._modifiers = modifiers;
|
|
789
|
+
return this;
|
|
790
|
+
}
|
|
791
|
+
importFrom(from) {
|
|
792
|
+
this.addImport([this.methodName], from);
|
|
793
|
+
return this;
|
|
794
|
+
}
|
|
795
|
+
toTsString() {
|
|
796
|
+
const params = this.params.map((it) => it.toString()).join(",");
|
|
797
|
+
return this._modifiers.toString() + `${this.methodName}(${params}): ${this.returnType}{${this.body.map((it) => it.toString()).join("")}}\n`;
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
//#endregion
|
|
801
|
+
//#region src/tsg/node/modifier/propertyModifiers.ts
|
|
802
|
+
var PropertyModifiers = class extends Modifiers {
|
|
803
|
+
accessor(accessor) {
|
|
804
|
+
return super.accessor(accessor);
|
|
805
|
+
}
|
|
806
|
+
private() {
|
|
807
|
+
return super.private();
|
|
808
|
+
}
|
|
809
|
+
protected() {
|
|
810
|
+
return super.protected();
|
|
811
|
+
}
|
|
812
|
+
abstract() {
|
|
813
|
+
return super.abstract();
|
|
814
|
+
}
|
|
815
|
+
readonly() {
|
|
816
|
+
return super.readonly();
|
|
817
|
+
}
|
|
818
|
+
static() {
|
|
819
|
+
return super.static();
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
//#endregion
|
|
823
|
+
//#region src/tsg/node/propertyAssignment.ts
|
|
824
|
+
var PropertyAssignment = class extends TsCode {
|
|
825
|
+
constructor(key, value) {
|
|
826
|
+
super();
|
|
827
|
+
this.key = key;
|
|
828
|
+
this.value = value;
|
|
829
|
+
this.mergeImport(value);
|
|
830
|
+
}
|
|
831
|
+
toTsString() {
|
|
832
|
+
if (!this.value) return this.key;
|
|
833
|
+
return `${this.key}: ${this.value.toString()}`;
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
//#endregion
|
|
837
|
+
//#region src/tsg/node/propertyDeclaration.ts
|
|
838
|
+
var PropertyDeclaration = class extends TsCode {
|
|
839
|
+
constructor(propertyName, type, optional = false) {
|
|
840
|
+
super();
|
|
841
|
+
this.propertyName = propertyName;
|
|
842
|
+
this.type = type;
|
|
843
|
+
this.optional = optional;
|
|
844
|
+
this._modifiers = new PropertyModifiers();
|
|
845
|
+
this._initializer = void 0;
|
|
846
|
+
if (isCode(type)) this.mergeImport(type);
|
|
847
|
+
}
|
|
848
|
+
modifiers(modifiers) {
|
|
849
|
+
this._modifiers = modifiers;
|
|
850
|
+
return this;
|
|
851
|
+
}
|
|
852
|
+
initializer(initializer) {
|
|
853
|
+
this._initializer = initializer;
|
|
854
|
+
this.mergeImport(initializer);
|
|
855
|
+
return this;
|
|
856
|
+
}
|
|
857
|
+
toTsString() {
|
|
858
|
+
const initializer = this._initializer ? ` = ${this._initializer.toString()}` : "";
|
|
859
|
+
return this._modifiers.toString() + `${this.propertyName}${TsUtil.questionToken(this.optional)}: ${this.type}` + initializer + ";";
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
//#endregion
|
|
863
|
+
//#region src/tsg/node/returnStatement.ts
|
|
864
|
+
var ReturnStatement = class extends TsStatement {
|
|
865
|
+
constructor(expression) {
|
|
866
|
+
super();
|
|
867
|
+
this.expression = expression;
|
|
868
|
+
this.mergeImport(expression);
|
|
869
|
+
}
|
|
870
|
+
toTsString() {
|
|
871
|
+
return `return ${this.expression.toString()};`;
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
//#endregion
|
|
875
|
+
//#region src/tsg/node/spreadAssignment.ts
|
|
876
|
+
var SpreadAssignment = class extends TsCode {
|
|
877
|
+
constructor(identifier) {
|
|
878
|
+
super();
|
|
879
|
+
this.identifier = identifier;
|
|
880
|
+
this.mergeImport(identifier);
|
|
881
|
+
}
|
|
882
|
+
toTsString() {
|
|
883
|
+
return `...${this.identifier.toString()}`;
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
//#endregion
|
|
887
|
+
//#region src/tsg/node/throwStatement.ts
|
|
888
|
+
var ThrowStatement = class extends TsStatement {
|
|
889
|
+
constructor(expression) {
|
|
890
|
+
super();
|
|
891
|
+
this.expression = expression;
|
|
892
|
+
this.mergeImport(expression);
|
|
893
|
+
}
|
|
894
|
+
toTsString() {
|
|
895
|
+
return "throw " + this.expression.toString() + ";";
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
//#endregion
|
|
899
|
+
//#region src/tsg/node/type/arrayType.ts
|
|
900
|
+
var ArrayType = class extends TsCode {
|
|
901
|
+
constructor(type) {
|
|
902
|
+
super();
|
|
903
|
+
this.type = type;
|
|
904
|
+
if (isCode(type)) this.mergeImport(type);
|
|
905
|
+
}
|
|
906
|
+
toTsString() {
|
|
907
|
+
return `Array<${this.type.toString()}>`;
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
//#endregion
|
|
911
|
+
//#region src/tsg/node/type/intersectionType.ts
|
|
912
|
+
var IntersectionType = class extends TsCode {
|
|
913
|
+
constructor(...types) {
|
|
914
|
+
super();
|
|
915
|
+
this.types = types;
|
|
916
|
+
this.mergeImport(...types);
|
|
917
|
+
}
|
|
918
|
+
toTsString() {
|
|
919
|
+
return this.types.map((it) => it.toString()).join(" & ");
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
//#endregion
|
|
923
|
+
//#region src/tsg/node/type/typeAliasDeclaration.ts
|
|
924
|
+
var TypeAliasDeclaration = class extends ExportableDeclaration {
|
|
925
|
+
constructor(alias, type) {
|
|
926
|
+
super();
|
|
927
|
+
this.alias = alias;
|
|
928
|
+
this.type = type;
|
|
929
|
+
if (isCode(type)) this.mergeImport(type);
|
|
930
|
+
}
|
|
931
|
+
toTsString() {
|
|
932
|
+
return `type ${this.alias} = ${this.type.toString()}`;
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
//#endregion
|
|
936
|
+
//#region src/tsg/node/type/typeLiteral.ts
|
|
937
|
+
var TypeLiteral = class extends TsCode {
|
|
938
|
+
constructor(properties = []) {
|
|
939
|
+
super();
|
|
940
|
+
this.properties = properties;
|
|
941
|
+
this.mergeImport(...properties);
|
|
942
|
+
}
|
|
943
|
+
addProperty(propertyName, type, isOptional = false, isReadOnly = false) {
|
|
944
|
+
this.properties.push(new PropertySignature(propertyName, type, isOptional, isReadOnly));
|
|
945
|
+
return this;
|
|
946
|
+
}
|
|
947
|
+
toTsString() {
|
|
948
|
+
return `{${this.properties.map((it) => it.toString()).join(";")}}`;
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
//#endregion
|
|
952
|
+
//#region src/tsg/node/type/typeReference.ts
|
|
953
|
+
var TypeReference = class TypeReference extends TsCode {
|
|
954
|
+
constructor(typeName, typeArguments = []) {
|
|
955
|
+
super();
|
|
956
|
+
this.typeName = typeName;
|
|
957
|
+
this.typeArguments = typeArguments;
|
|
958
|
+
this.mergeImport(...pickCode(typeArguments));
|
|
959
|
+
}
|
|
960
|
+
importFrom(path) {
|
|
961
|
+
this.addImport([this.typeName], path);
|
|
962
|
+
return this;
|
|
963
|
+
}
|
|
964
|
+
partial() {
|
|
965
|
+
return new TypeReference("Partial", [this]);
|
|
966
|
+
}
|
|
967
|
+
pick(...properties) {
|
|
968
|
+
return new TypeReference("Pick", [this, new Identifier(properties.map((it) => `'${it}'`).join("|"))]);
|
|
969
|
+
}
|
|
970
|
+
toTsString() {
|
|
971
|
+
const typeArgs = this.typeArguments.length === 0 ? "" : `<${this.typeArguments.join(",")}>`;
|
|
972
|
+
return `${this.typeName}${typeArgs}`;
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
//#endregion
|
|
976
|
+
//#region src/tsg/node/type/unionType.ts
|
|
977
|
+
var UnionType = class extends TsCode {
|
|
978
|
+
constructor(...types) {
|
|
979
|
+
super();
|
|
980
|
+
this.types = types;
|
|
981
|
+
const codeTypes = types.filter((it) => isCode(it));
|
|
982
|
+
this.mergeImport(...codeTypes);
|
|
983
|
+
}
|
|
984
|
+
toTsString() {
|
|
985
|
+
return this.types.map((it) => it.toString()).join(" | ");
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/tsg/node/variableDeclaration.ts
|
|
990
|
+
var VariableDeclaration = class extends ExportableDeclaration {
|
|
991
|
+
constructor(flag, variableName, expression, type) {
|
|
992
|
+
super();
|
|
993
|
+
this.flag = flag;
|
|
994
|
+
this.expression = expression;
|
|
995
|
+
this.type = type;
|
|
996
|
+
this.variableName = typeof variableName === "string" ? new Identifier(variableName) : variableName;
|
|
997
|
+
this.mergeImport(expression, this.variableName, type);
|
|
998
|
+
}
|
|
999
|
+
toTsString() {
|
|
1000
|
+
const type = this.type ? ": " + this.type.toString() : "";
|
|
1001
|
+
return `${this.flag} ${this.variableName}${type} = ${this.expression.toString()};`;
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
//#endregion
|
|
1005
|
+
//#region src/tsg/factory.ts
|
|
1006
|
+
const createFactory = (Constructor) => {
|
|
1007
|
+
return (...args) => new Constructor(...args);
|
|
1008
|
+
};
|
|
1009
|
+
const expressions = {
|
|
1010
|
+
arrowFunc: createFactory(ArrowFunction),
|
|
1011
|
+
async: createFactory(AsyncExpression),
|
|
1012
|
+
await: createFactory(AwaitExpression),
|
|
1013
|
+
binary: createFactory(BinaryExpression),
|
|
1014
|
+
call: createFactory(CallExpression),
|
|
1015
|
+
identifier: createFactory(Identifier),
|
|
1016
|
+
new: createFactory(NewExpression),
|
|
1017
|
+
nonNull: createFactory(NonNullExpression),
|
|
1018
|
+
parenthesis: createFactory(ParenthesizedExpression),
|
|
1019
|
+
propertyAccess: createFactory(PropertyAccessExpression),
|
|
1020
|
+
string: createFactory(StringLiteral),
|
|
1021
|
+
number: createFactory(NumericLiteral),
|
|
1022
|
+
boolean: createFactory(Boolean),
|
|
1023
|
+
array: createFactory(ArrayLiteral),
|
|
1024
|
+
object: createFactory(ObjectLiteral),
|
|
1025
|
+
as: createFactory(AsExpression),
|
|
1026
|
+
ternary: createFactory(TernaryExpression)
|
|
1027
|
+
};
|
|
1028
|
+
const types = {
|
|
1029
|
+
arrayType: createFactory(ArrayType),
|
|
1030
|
+
intersectionType: createFactory(IntersectionType),
|
|
1031
|
+
unionType: createFactory(UnionType),
|
|
1032
|
+
typeAlias: createFactory(TypeAliasDeclaration),
|
|
1033
|
+
typeLiteral: createFactory(TypeLiteral),
|
|
1034
|
+
typeRef: createFactory(TypeReference)
|
|
1035
|
+
};
|
|
1036
|
+
const others = {
|
|
1037
|
+
block: createFactory(Block),
|
|
1038
|
+
class: createFactory(Class),
|
|
1039
|
+
enum: createFactory(EnumDeclaration),
|
|
1040
|
+
enumMember: createFactory(EnumMember),
|
|
1041
|
+
ExpStatement: createFactory(ExpressionStatement),
|
|
1042
|
+
extends: createFactory(ExtendsClause),
|
|
1043
|
+
if: createFactory(IfStatement),
|
|
1044
|
+
implements: createFactory(ImplementsClause),
|
|
1045
|
+
interface: createFactory(TsInterface),
|
|
1046
|
+
method: createFactory(MethodDeclaration),
|
|
1047
|
+
parameter: createFactory(Parameter),
|
|
1048
|
+
propertyAssign: createFactory(PropertyAssignment),
|
|
1049
|
+
propertyDeclaration: createFactory(PropertyDeclaration),
|
|
1050
|
+
propertySignature: createFactory(PropertySignature),
|
|
1051
|
+
return: createFactory(ReturnStatement),
|
|
1052
|
+
spreadAssign: createFactory(SpreadAssignment),
|
|
1053
|
+
variable: createFactory(VariableDeclaration),
|
|
1054
|
+
methodModifiers: createFactory(MethodModifiers),
|
|
1055
|
+
propertyModifiers: createFactory(PropertyModifiers),
|
|
1056
|
+
throw: createFactory(ThrowStatement),
|
|
1057
|
+
spread: createFactory(SpreadElement)
|
|
1058
|
+
};
|
|
1059
|
+
const tsg = {
|
|
1060
|
+
...expressions,
|
|
1061
|
+
...types,
|
|
1062
|
+
...others
|
|
1063
|
+
};
|
|
1064
|
+
//#endregion
|
|
1065
|
+
//#region src/tsg/file.ts
|
|
1066
|
+
var TsFile = class extends TsCode {
|
|
1067
|
+
constructor(...statements) {
|
|
1068
|
+
super();
|
|
1069
|
+
this.esLintDisabled = false;
|
|
1070
|
+
this.mergeImport(...statements);
|
|
1071
|
+
this.statements = statements;
|
|
1072
|
+
}
|
|
1073
|
+
toTsString() {
|
|
1074
|
+
const string = [...this.resolveImport(this.importDeclarations), ...this.statements].map((it) => it.toString()).join("\n");
|
|
1075
|
+
return (this.esLintDisabled ? "/* eslint-disable */\n" : "") + string;
|
|
1076
|
+
}
|
|
1077
|
+
resolveImport(imports) {
|
|
1078
|
+
const map = {};
|
|
1079
|
+
imports.forEach((it) => {
|
|
1080
|
+
if (!map[it.module]) map[it.module] = it.types;
|
|
1081
|
+
else map[it.module] = [...map[it.module], ...it.types];
|
|
1082
|
+
});
|
|
1083
|
+
return Object.entries(map).map(([module, types]) => new ImportDeclaration([...new Set(types)], module));
|
|
1084
|
+
}
|
|
1085
|
+
disableEsLint() {
|
|
1086
|
+
this.esLintDisabled = true;
|
|
1087
|
+
return this;
|
|
1088
|
+
}
|
|
1089
|
+
enableEsLint() {
|
|
1090
|
+
this.esLintDisabled = false;
|
|
1091
|
+
return this;
|
|
1092
|
+
}
|
|
1093
|
+
async generate() {
|
|
1094
|
+
return this.toString();
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
//#endregion
|
|
1098
|
+
//#region src/tsg/node/type/typeKeyword.ts
|
|
1099
|
+
const KeywordTypeNode = {
|
|
1100
|
+
any: new TypeReference("any"),
|
|
1101
|
+
unknown: new TypeReference("unknown"),
|
|
1102
|
+
number: new TypeReference("number"),
|
|
1103
|
+
bigInt: new TypeReference("BigInt"),
|
|
1104
|
+
boolean: new TypeReference("boolean"),
|
|
1105
|
+
string: new TypeReference("string"),
|
|
1106
|
+
symbol: new TypeReference("Symbol"),
|
|
1107
|
+
this: new TypeReference("this"),
|
|
1108
|
+
void: new TypeReference("void"),
|
|
1109
|
+
undefined: new TypeReference("undefined"),
|
|
1110
|
+
null: new TypeReference("null"),
|
|
1111
|
+
never: new TypeReference("never")
|
|
1112
|
+
};
|
|
1113
|
+
//#endregion
|
|
1114
|
+
//#region src/generatorv2/directory.ts
|
|
1115
|
+
const GeneratedDirName = "__generated__";
|
|
1116
|
+
const EntityDirName = "entities";
|
|
1117
|
+
const DataSourceDirName = "dataSources";
|
|
1118
|
+
const relative = (from, to) => {
|
|
1119
|
+
const result = node_path.posix.relative(from, to);
|
|
1120
|
+
if (result.startsWith("../")) return result;
|
|
1121
|
+
return "./" + result;
|
|
1122
|
+
};
|
|
1123
|
+
const GENERATED_PATH = `/${GeneratedDirName}/`;
|
|
1124
|
+
const paths = {
|
|
1125
|
+
BASE: "/",
|
|
1126
|
+
GENERATED: GENERATED_PATH,
|
|
1127
|
+
ENTITIES: `${GENERATED_PATH}${EntityDirName}/`,
|
|
1128
|
+
DATA_SOURCES: `/${DataSourceDirName}/db/`,
|
|
1129
|
+
GENERATED_DS: `${GENERATED_PATH}${DataSourceDirName}/db/`
|
|
1130
|
+
};
|
|
1131
|
+
const resolve = (from, source, fileName) => {
|
|
1132
|
+
return relative(paths[from], paths[source] + fileName);
|
|
1133
|
+
};
|
|
1134
|
+
const Directory = {
|
|
1135
|
+
paths,
|
|
1136
|
+
resolve
|
|
1137
|
+
};
|
|
1138
|
+
//#endregion
|
|
1139
|
+
//#region src/generatorv2/codegen/ts/scripts/getEntityTypeRefs.ts
|
|
1140
|
+
const typeRefs = {
|
|
1141
|
+
entity: {
|
|
1142
|
+
name: (entity) => entity.name,
|
|
1143
|
+
dir: "ENTITIES",
|
|
1144
|
+
file: (entity) => entity.name
|
|
1145
|
+
},
|
|
1146
|
+
creatable: {
|
|
1147
|
+
name: (entity) => entity.creatableInterface(),
|
|
1148
|
+
dir: "ENTITIES",
|
|
1149
|
+
file: (entity) => entity.name
|
|
1150
|
+
},
|
|
1151
|
+
updatable: {
|
|
1152
|
+
name: (entity) => entity.updatable(),
|
|
1153
|
+
dir: "ENTITIES",
|
|
1154
|
+
file: (entity) => entity.name
|
|
1155
|
+
},
|
|
1156
|
+
identifiable: {
|
|
1157
|
+
name: (entity) => entity.identifiableInterfaceName(),
|
|
1158
|
+
dir: "ENTITIES",
|
|
1159
|
+
file: (entity) => entity.name
|
|
1160
|
+
},
|
|
1161
|
+
fields: {
|
|
1162
|
+
name: (entity) => entity.fieldsTypeName(),
|
|
1163
|
+
dir: "GENERATED",
|
|
1164
|
+
file: () => "fields"
|
|
1165
|
+
},
|
|
1166
|
+
withRelation: {
|
|
1167
|
+
name: (entity) => entity.entityWithRelationTypeName(),
|
|
1168
|
+
dir: "GENERATED",
|
|
1169
|
+
file: () => "relationMap"
|
|
1170
|
+
},
|
|
1171
|
+
result: {
|
|
1172
|
+
name: (entity) => entity.resultType(),
|
|
1173
|
+
dir: "GENERATED",
|
|
1174
|
+
file: () => "relationMap"
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
const makeTypeRef = (entity, type, importFrom) => {
|
|
1178
|
+
const info = typeRefs[type];
|
|
1179
|
+
return tsg.typeRef(info.name(entity)).importFrom(Directory.resolve(importFrom, info.dir, info.file(entity)));
|
|
1180
|
+
};
|
|
1181
|
+
const makeContextTypeRef = (importFrom) => {
|
|
1182
|
+
return tsg.typeRef("GQLContext").importFrom(Directory.resolve(importFrom, "BASE", "context"));
|
|
1183
|
+
};
|
|
1184
|
+
//#endregion
|
|
1185
|
+
//#region src/generatorv2/codegen/ts/scripts/sqlValueToTsExpression.ts
|
|
1186
|
+
const sqlValueToTsExpression = (value) => {
|
|
1187
|
+
if (typeof value === "string") return tsg.string(value);
|
|
1188
|
+
if (typeof value === "number") return tsg.number(value);
|
|
1189
|
+
return tsg.identifier("null");
|
|
1190
|
+
};
|
|
1191
|
+
//#endregion
|
|
1192
|
+
//#region src/generatorv2/codegen/ts/generateAutoGeneratedDatasource.ts
|
|
1193
|
+
const DIR$2 = "GENERATED_DS";
|
|
1194
|
+
const generateAutoGeneratedDatasource = (node) => {
|
|
1195
|
+
return new TsFile(tsg.typeAlias("QueryResult", tsg.intersectionType(makeTypeRef(node.name, "withRelation", DIR$2).partial(), makeTypeRef(node.name, "identifiable", DIR$2))), tsg.class(node.name.generatedDataSourceName()).export().abstract().extends(tsg.extends(tsg.typeRef("BaseDBDataSource", [
|
|
1196
|
+
makeTypeRef(node.name, "entity", DIR$2),
|
|
1197
|
+
makeTypeRef(node.name, "identifiable", DIR$2),
|
|
1198
|
+
makeTypeRef(node.name, "creatable", DIR$2),
|
|
1199
|
+
makeTypeRef(node.name, "updatable", DIR$2),
|
|
1200
|
+
makeTypeRef(node.name, "fields", DIR$2),
|
|
1201
|
+
tsg.typeRef("QueryResult")
|
|
1202
|
+
])).addImport(["BaseDBDataSource"], Directory.resolve(DIR$2, "BASE", "baseDBDataSource"))).addProperty(...makeClassProperties(node)).addMethod(makeDefaultValueMethod(node), ...makeFindMethods(node))).disableEsLint();
|
|
1203
|
+
};
|
|
1204
|
+
const makeClassProperties = (node) => {
|
|
1205
|
+
const ai = node.fields.find((it) => it.isAutoIncrement);
|
|
1206
|
+
return [
|
|
1207
|
+
tsg.propertyDeclaration("tableName", KeywordTypeNode.string, false).modifiers(tsg.propertyModifiers().readonly()).initializer(tsg.string(node.tableName)),
|
|
1208
|
+
tsg.propertyDeclaration("fields", tsg.arrayType(KeywordTypeNode.string), false).modifiers(tsg.propertyModifiers().readonly()).initializer(tsg.array(node.fields.map((it) => tsg.string(it.fieldName)))),
|
|
1209
|
+
tsg.propertyDeclaration("primaryKeys", tsg.arrayType(KeywordTypeNode.string), false).modifiers(tsg.propertyModifiers().readonly().protected()).initializer(tsg.array(node.identifyKeys.map((it) => tsg.string(it)))),
|
|
1210
|
+
tsg.propertyDeclaration("identifyFields", tsg.arrayType(KeywordTypeNode.string), false).modifiers(tsg.propertyModifiers().readonly().protected()).initializer(tsg.array(node.identifyKeys.map((it) => node.fields.find((f) => it === f.columnName).fieldName).map(tsg.string))),
|
|
1211
|
+
tsg.propertyDeclaration("autoIncrementColumn", tsg.unionType(KeywordTypeNode.string, KeywordTypeNode.undefined), true).modifiers(tsg.propertyModifiers().readonly().protected()).initializer(ai ? tsg.string(ai.fieldName) : tsg.identifier("undefined"))
|
|
1212
|
+
];
|
|
1213
|
+
};
|
|
1214
|
+
const fieldToExpression = (node) => {
|
|
1215
|
+
if (node.column.defaultCurrentTimeStamp) return tsg.identifier("getCurrentDateTimeString").addImport(["getCurrentDateTimeString"], "sasat").call();
|
|
1216
|
+
return sqlValueToTsExpression(node.column.default);
|
|
1217
|
+
};
|
|
1218
|
+
const makeDefaultValueMethod = (node) => {
|
|
1219
|
+
const columns = node.fields.filter((it) => it.column.defaultCurrentTimeStamp || it.column.default !== void 0);
|
|
1220
|
+
const properties = columns.map((it) => {
|
|
1221
|
+
return tsg.propertyAssign(it.fieldName, fieldToExpression(it));
|
|
1222
|
+
});
|
|
1223
|
+
const body = tsg.return(tsg.object(...properties));
|
|
1224
|
+
return tsg.method("getDefaultValueString", [], columns.length !== 0 ? tsg.typeRef(node.name.name).pick(...columns.map((it) => it.fieldName)) : tsg.typeRef(node.name.name).partial(), [body]).modifiers(tsg.methodModifiers().protected());
|
|
1225
|
+
};
|
|
1226
|
+
const makeFindMethods = (node) => {
|
|
1227
|
+
const qExpr = tsg.identifier("qe").importFrom("sasat");
|
|
1228
|
+
return node.findMethods.map((it) => {
|
|
1229
|
+
const bve = it.params.flatMap((it) => {
|
|
1230
|
+
if (!it.entity) return qExpr.property("eq").call(qExpr.property("field").call(tsg.identifier("tableName"), tsg.string(it.columnName.toString())), qExpr.property("value").call(tsg.identifier(it.fieldName.toString())));
|
|
1231
|
+
return it.fields.map((field) => {
|
|
1232
|
+
return qExpr.property("eq").call(qExpr.property("field").call(tsg.identifier("tableName"), tsg.string(field.columnName)), qExpr.property("value").call(tsg.identifier(it.name).property(field.fieldName)));
|
|
1233
|
+
});
|
|
1234
|
+
});
|
|
1235
|
+
const body = [tsg.variable("const", "tableName", tsg.identifier("fields?.tableAlias || \"t0\"")), tsg.return(tsg.identifier(it.isArray ? "this.find" : "this.first").call(tsg.identifier("fields"), tsg.object().addProperties(tsg.spreadAssign(tsg.identifier("options")), tsg.propertyAssign("where", qExpr.property("and").call(...bve, tsg.identifier("options?").property("where")))), tsg.identifier("context")))];
|
|
1236
|
+
const returnType = tsg.typeRef("QueryResult");
|
|
1237
|
+
return tsg.method(it.name, [
|
|
1238
|
+
...it.params.map((it) => tsg.parameter(it.entity ? it.name.toString() : it.fieldName, it.entity ? makeTypeRef(it.entityName, "identifiable", "GENERATED_DS") : tsg.typeRef(columnTypeToTsType(it.dbtype)))),
|
|
1239
|
+
tsg.parameter(`fields?`, makeTypeRef(node.name, "fields", DIR$2)),
|
|
1240
|
+
tsg.parameter("options?", it.isArray ? tsg.typeRef("QueryOptions").importFrom("sasat") : tsg.typeRef("Omit", [tsg.typeRef("QueryOptions").importFrom("sasat"), tsg.typeRef("\"offset\" | \"limit\" | \"sort\"")])),
|
|
1241
|
+
tsg.parameter("context?", makeContextTypeRef(DIR$2))
|
|
1242
|
+
], tsg.typeRef("Promise", [it.isArray ? tsg.arrayType(returnType) : tsg.unionType(returnType, tsg.typeRef("null"))]), body);
|
|
1243
|
+
});
|
|
1244
|
+
};
|
|
1245
|
+
//#endregion
|
|
1246
|
+
//#region src/generatorv2/codegen/ts/generateContext.ts
|
|
1247
|
+
const generateContext = (root) => {
|
|
1248
|
+
return new TsFile(tsg.interface("BaseGQLContext").addProperties(root.contexts.map((it) => tsg.propertySignature(it.name, tsg.typeRef(columnTypeToTsType(it.dbtype))))).export()).disableEsLint();
|
|
1249
|
+
};
|
|
1250
|
+
//#endregion
|
|
1251
|
+
//#region src/generatorv2/codegen/ts/generateDatasource.ts
|
|
1252
|
+
const generateDatasource = (node) => {
|
|
1253
|
+
return new TsFile(tsg.class(node.name.dataSourceName()).extends(tsg.extends(tsg.typeRef(node.name.generatedDataSourceName()).importFrom(Directory.resolve("DATA_SOURCES", "GENERATED_DS", node.name.name)))).export());
|
|
1254
|
+
};
|
|
1255
|
+
//#endregion
|
|
1256
|
+
//#region src/generatorv2/codegen/ts/scripts/fieldToProperty.ts
|
|
1257
|
+
const fieldToPropertySignature = (field) => {
|
|
1258
|
+
const type = tsg.typeRef(columnTypeToTsType(field.dbType));
|
|
1259
|
+
return tsg.propertySignature(field.fieldName, field.isNullable ? tsg.unionType(type, KeywordTypeNode.null) : type, field.isNullable, true);
|
|
1260
|
+
};
|
|
1261
|
+
//#endregion
|
|
1262
|
+
//#region src/generatorv2/codegen/ts/generateEntity.ts
|
|
1263
|
+
const generateEntityFile = (node) => {
|
|
1264
|
+
return new TsFile(generateEntity(node), generateCreatable(node), generateUpdatable(node), generateIdentifiable(node)).disableEsLint();
|
|
1265
|
+
};
|
|
1266
|
+
const generateEntity = (node) => {
|
|
1267
|
+
return tsg.typeAlias(node.name.name, tsg.typeLiteral(node.fields.map(fieldToPropertySignature))).export();
|
|
1268
|
+
};
|
|
1269
|
+
const generateCreatable = (node) => {
|
|
1270
|
+
return tsg.typeAlias(node.name.creatableInterface(), node.creatable.fields.length === 0 ? tsg.typeRef("Record<string, never>") : tsg.typeLiteral(node.creatable.fields.map(fieldToPropertySignature))).export();
|
|
1271
|
+
};
|
|
1272
|
+
const generateUpdatable = (node) => {
|
|
1273
|
+
return tsg.typeAlias(node.name.updatable(), node.updateInput.fields.length === 0 ? tsg.typeRef("Record<string, never>") : tsg.typeLiteral(node.updateInput.fields.map(fieldToPropertySignature))).export();
|
|
1274
|
+
};
|
|
1275
|
+
const generateIdentifiable = (node) => {
|
|
1276
|
+
return tsg.typeAlias(node.name.identifiableInterfaceName(), tsg.typeLiteral(node.fields.filter((it) => it.isPrimary).map(fieldToPropertySignature))).export();
|
|
1277
|
+
};
|
|
1278
|
+
//#endregion
|
|
1279
|
+
//#region src/util/stringUtil.ts
|
|
1280
|
+
const capitalizeFirstLetter = (str) => str.slice(0, 1).toUpperCase() + str.slice(1);
|
|
1281
|
+
const lowercaseFirstLetter = (str) => str.slice(0, 1).toLowerCase() + str.slice(1);
|
|
1282
|
+
const camelize = (str) => str.replace(/(?:^\w|[A-Z]|_\w|\b\w)/g, (word, index) => index === 0 ? word.toLowerCase() : word.toUpperCase()).replace(/\s|_|-+/g, "");
|
|
1283
|
+
//#endregion
|
|
1284
|
+
//#region src/generatorv2/nodes/entityName.ts
|
|
1285
|
+
var EntityName = class EntityName {
|
|
1286
|
+
static fromTableName(tableName) {
|
|
1287
|
+
return new EntityName(capitalizeFirstLetter(camelize(tableName)));
|
|
1288
|
+
}
|
|
1289
|
+
constructor(name) {
|
|
1290
|
+
this.name = name;
|
|
1291
|
+
}
|
|
1292
|
+
toString() {
|
|
1293
|
+
return this.name;
|
|
1294
|
+
}
|
|
1295
|
+
creatableInterface() {
|
|
1296
|
+
return `${this.name}Creatable`;
|
|
1297
|
+
}
|
|
1298
|
+
updatable() {
|
|
1299
|
+
return `${this.name}Updatable`;
|
|
1300
|
+
}
|
|
1301
|
+
identifiableInterfaceName() {
|
|
1302
|
+
return `${this.name}Identifiable`;
|
|
1303
|
+
}
|
|
1304
|
+
relationTypeName() {
|
|
1305
|
+
return this.name + "Relations";
|
|
1306
|
+
}
|
|
1307
|
+
entityWithRelationTypeName() {
|
|
1308
|
+
return this.name + "WithRelations";
|
|
1309
|
+
}
|
|
1310
|
+
resultType() {
|
|
1311
|
+
return this.name + "Result";
|
|
1312
|
+
}
|
|
1313
|
+
fieldsTypeName() {
|
|
1314
|
+
return this.name + "Fields";
|
|
1315
|
+
}
|
|
1316
|
+
dataSourceName() {
|
|
1317
|
+
return `${this.name}DBDataSource`;
|
|
1318
|
+
}
|
|
1319
|
+
generatedDataSourceName() {
|
|
1320
|
+
return `Generated${this.name}DBDataSource`;
|
|
1321
|
+
}
|
|
1322
|
+
lowerCase() {
|
|
1323
|
+
return lowercaseFirstLetter(this.name);
|
|
1324
|
+
}
|
|
1325
|
+
createInputName() {
|
|
1326
|
+
return this.name + "CreateInput";
|
|
1327
|
+
}
|
|
1328
|
+
updateInputName() {
|
|
1329
|
+
return this.name + "UpdateInput";
|
|
1330
|
+
}
|
|
1331
|
+
identifyInputName() {
|
|
1332
|
+
return `${this.name}IdentifyInput`;
|
|
1333
|
+
}
|
|
1334
|
+
IDEncoderName() {
|
|
1335
|
+
return `${this.name}HashId`;
|
|
1336
|
+
}
|
|
1337
|
+
};
|
|
1338
|
+
//#endregion
|
|
1339
|
+
//#region src/generatorv2/codegen/ts/generateFields.ts
|
|
1340
|
+
const generateFields = (root) => {
|
|
1341
|
+
return new TsFile(...root.entities.map((it) => tsg.typeAlias(it.name.fieldsTypeName(), tsg.typeRef("Fields", [makeTypeRef(it.name, "entity", "GENERATED"), makeTypeLiteral(it)]).importFrom("sasat")).export())).disableEsLint();
|
|
1342
|
+
};
|
|
1343
|
+
const makeTypeLiteral = (entity) => {
|
|
1344
|
+
return tsg.typeLiteral([...entity.references.map((it) => tsg.propertySignature(`${it.fieldName}?`, tsg.typeRef(EntityName.fromTableName(it.parentTableName).fieldsTypeName()))), ...entity.referencedBy.map((it) => tsg.propertySignature(`${it.fieldName}?`, tsg.typeRef(EntityName.fromTableName(it.childTable).fieldsTypeName())))]);
|
|
1345
|
+
};
|
|
1346
|
+
//#endregion
|
|
1347
|
+
//#region src/runtime/util.ts
|
|
1348
|
+
const pick = (target, keys) => Object.fromEntries(keys.map((key) => [key, target[key]]));
|
|
1349
|
+
const unique = (array) => {
|
|
1350
|
+
const result = [];
|
|
1351
|
+
for (let i = 0, l = array.length; i < l; i += 1) if (!result.includes(array[i])) result.push(array[i]);
|
|
1352
|
+
return result;
|
|
1353
|
+
};
|
|
1354
|
+
const nonNullable = (value) => value != null;
|
|
1355
|
+
//#endregion
|
|
1356
|
+
//#region src/generatorv2/codegen/ts/scripts/ast/getExportedVariables.ts
|
|
1357
|
+
const { SyntaxKind: SyntaxKind$1 } = typescript.default;
|
|
1358
|
+
const getExportedVariables = (sourceFile) => {
|
|
1359
|
+
return sourceFile.statements.filter((it) => it.kind === SyntaxKind$1.VariableStatement && it.modifiers?.some((it) => it.kind === SyntaxKind$1.ExportKeyword));
|
|
1360
|
+
};
|
|
1361
|
+
//#endregion
|
|
1362
|
+
//#region src/generatorv2/codegen/ts/scripts/ast/isImported.ts
|
|
1363
|
+
const { SyntaxKind } = typescript.default;
|
|
1364
|
+
const isImported = (sourceFile, type, paths) => {
|
|
1365
|
+
return sourceFile.statements.filter((it) => it.kind === SyntaxKind.ImportDeclaration).some((it) => {
|
|
1366
|
+
if (!paths.some((path) => {
|
|
1367
|
+
const text = it.moduleSpecifier.getText(sourceFile);
|
|
1368
|
+
return `'${path}'` === text || `"${path}"` === text;
|
|
1369
|
+
})) return false;
|
|
1370
|
+
const binding = it.importClause?.namedBindings;
|
|
1371
|
+
if (it.importClause?.name?.getText(sourceFile) === type) return true;
|
|
1372
|
+
if (binding?.kind !== SyntaxKind.NamedImports) return false;
|
|
1373
|
+
return binding.elements.some((it) => {
|
|
1374
|
+
return it.name.text.trim() === type;
|
|
1375
|
+
});
|
|
1376
|
+
});
|
|
1377
|
+
};
|
|
1378
|
+
//#endregion
|
|
1379
|
+
//#region src/generatorv2/codegen/ts/generateIDEncoder.ts
|
|
1380
|
+
const { createSourceFile: createSourceFile$2, ScriptTarget: ScriptTarget$2 } = typescript.default;
|
|
1381
|
+
const hashIds = "HashIds";
|
|
1382
|
+
const generateIDEncoder = (root, content) => {
|
|
1383
|
+
const fields = root.entities.map((it) => it.fields.find((it) => it.column.option.autoIncrementHashId)).filter(nonNullable);
|
|
1384
|
+
if (fields.length === 0) return null;
|
|
1385
|
+
const sourceFile = createSourceFile$2(tsFileNames.encoder + ".ts", content, ScriptTarget$2.ESNext);
|
|
1386
|
+
sourceFile.getChildren().map((it) => it);
|
|
1387
|
+
const exportedVariables = getExportedVariables(sourceFile);
|
|
1388
|
+
const hashIdImported = isImported(sourceFile, hashIds, ["hashids"]);
|
|
1389
|
+
const statements = [];
|
|
1390
|
+
fields.forEach((field) => {
|
|
1391
|
+
const name = field.entity.name.IDEncoderName();
|
|
1392
|
+
if (exportedVariables.some((it) => {
|
|
1393
|
+
return it.declarationList.declarations[0].name.getText(sourceFile) === name;
|
|
1394
|
+
})) return;
|
|
1395
|
+
statements.push(tsg.variable("const", name, tsg.identifier("makeNumberIdEncoder").call(tsg.new(tsg.identifier(hashIds), tsg.string(field.column.option.hashSalt || field.entity.name.name)))).export());
|
|
1396
|
+
});
|
|
1397
|
+
const imports = hashIdImported ? "" : "import HashIds from \"hashids\";\n";
|
|
1398
|
+
const makeEncoder = isImported(sourceFile, "makeNumberIdEncoder", ["sasat"]) ? "" : new ImportDeclaration(["makeNumberIdEncoder"], "sasat").toString();
|
|
1399
|
+
const addition = statements.length === 0 ? "" : "\n" + new TsFile(...statements).toString();
|
|
1400
|
+
return imports + makeEncoder + content + addition;
|
|
1401
|
+
};
|
|
1402
|
+
//#endregion
|
|
1403
|
+
//#region src/generatorv2/codegen/ts/generateMiddlewares.ts
|
|
1404
|
+
const { createSourceFile: createSourceFile$1, ScriptTarget: ScriptTarget$1 } = typescript.default;
|
|
1405
|
+
const generateMiddlewares = (root, content) => {
|
|
1406
|
+
const middlewares = unique(root.entities.flatMap((it) => [...it.queries.flatMap((it) => it.middlewares), ...it.mutations.flatMap((it) => it.middlewares)]));
|
|
1407
|
+
if (middlewares.length === 0) return null;
|
|
1408
|
+
const sourceFile = createSourceFile$1(tsFileNames.middleware + ".ts", content, ScriptTarget$1.ESNext);
|
|
1409
|
+
const exportedVariables = getExportedVariables(sourceFile);
|
|
1410
|
+
const statements = [];
|
|
1411
|
+
middlewares.forEach((middleware) => {
|
|
1412
|
+
if (exportedVariables.some((it) => {
|
|
1413
|
+
return it.declarationList.declarations[0].name.getText(sourceFile) === middleware;
|
|
1414
|
+
})) return;
|
|
1415
|
+
statements.push(tsg.variable("const", middleware, tsg.arrowFunc([tsg.parameter("args")], void 0, tsg.block(tsg.throw(tsg.new(tsg.identifier("Error"), tsg.string("TODO: Not implemented"))), tsg.return(tsg.identifier("args")))), tsg.typeRef("ResolverMiddleware", [tsg.typeRef("GQLContext")])).export());
|
|
1416
|
+
});
|
|
1417
|
+
const contextImported = isImported(sourceFile, "GQLContext", ["./context", "./context.js"]);
|
|
1418
|
+
const resolverMiddlewareImported = isImported(sourceFile, "ResolverMiddleware", ["sasat"]);
|
|
1419
|
+
const imports = [contextImported ? "" : new ImportDeclaration(["GQLContext"], "./context").toString() + "\n", resolverMiddlewareImported ? "" : new ImportDeclaration(["ResolverMiddleware"], "sasat").toString() + "\n"].join("");
|
|
1420
|
+
const addition = statements.length === 0 ? "" : "\n" + new TsFile(...statements).toString();
|
|
1421
|
+
return imports + content + addition;
|
|
1422
|
+
};
|
|
1423
|
+
//#endregion
|
|
1424
|
+
//#region src/generatorv2/codegen/names.ts
|
|
1425
|
+
const map = {
|
|
1426
|
+
create: "Created",
|
|
1427
|
+
update: "Updated",
|
|
1428
|
+
delete: "Deleted"
|
|
1429
|
+
};
|
|
1430
|
+
const publishFunctionName = (entityName, type) => {
|
|
1431
|
+
return `publish${entityName}${map[type]}`;
|
|
1432
|
+
};
|
|
1433
|
+
const makeFindQueryName = (keys) => "findBy" + keys.map(capitalizeFirstLetter).join("And");
|
|
1434
|
+
//#endregion
|
|
1435
|
+
//#region src/generatorv2/codegen/ts/mutation/makeMutationInputDecoder.ts
|
|
1436
|
+
const DIR$1 = "GENERATED";
|
|
1437
|
+
const makeMutationMiddlewareAndTypes = (entity) => {
|
|
1438
|
+
return entity.mutations.map((node) => makeMutationResolverMiddleware(entity, node));
|
|
1439
|
+
};
|
|
1440
|
+
const makeParamType = (node) => {
|
|
1441
|
+
if (node.mutationType === "create") return makeTypeRef(node.entityName, "creatable", "GENERATED");
|
|
1442
|
+
if (node.mutationType === "update") return tsg.intersectionType(makeTypeRef(node.entityName, "identifiable", "GENERATED"), makeTypeRef(node.entityName, "updatable", "GENERATED"));
|
|
1443
|
+
return makeTypeRef(node.entityName, "identifiable", "GENERATED");
|
|
1444
|
+
};
|
|
1445
|
+
const makeEncoder = (name) => tsg.identifier(name).importFrom(Directory.resolve(DIR$1, "BASE", tsFileNames.encoder));
|
|
1446
|
+
const makeIdDecodeMiddleware = (fields, node) => {
|
|
1447
|
+
const params = tsg.identifier("args[1]");
|
|
1448
|
+
const entityName = node.entity.name.lowerCase();
|
|
1449
|
+
return tsg.arrowFunc([tsg.parameter("args")], void 0, tsg.block(tsg.binary(params, "=", tsg.object(tsg.spreadAssign(params), tsg.propertyAssign(entityName, tsg.object(tsg.spreadAssign(params.property(entityName)), ...fields.filter((it) => it.hashId).map((it) => tsg.propertyAssign(it.fieldName, makeEncoder(it.hashId.encoder).property("decode").call(params.property(entityName).property(it.fieldName).as(tsg.typeRef("string"))))))))).toStatement(), tsg.return(tsg.identifier("args"))));
|
|
1450
|
+
};
|
|
1451
|
+
const makeResolverMiddleware = (typeName, entity, fields, node) => {
|
|
1452
|
+
const sig = fields.map((it) => tsg.propertySignature(it.fieldName, tsg.typeRef(it.hashId ? "string" : columnTypeToTsType(it.dbType))));
|
|
1453
|
+
const requiredType = tsg.typeAlias(typeName, tsg.typeLiteral([tsg.propertySignature(entity.name.lowerCase(), makeParamType(node))]));
|
|
1454
|
+
const middlewareName = node.mutationName + "Middleware";
|
|
1455
|
+
if (!node.requireIdDecodeMiddleware) return [requiredType, tsg.variable("const", middlewareName, tsg.array(node.middlewares.map((it) => tsg.identifier(it).importFrom("../" + tsFileNames.middleware))), tsg.arrayType(tsg.typeRef("ResolverMiddleware", [makeContextTypeRef(DIR$1), tsg.identifier(typeName)]).importFrom("sasat")))];
|
|
1456
|
+
return [
|
|
1457
|
+
tsg.typeAlias("GQL" + typeName, tsg.typeLiteral([tsg.propertySignature(entity.name.lowerCase(), tsg.typeLiteral(sig))])),
|
|
1458
|
+
requiredType,
|
|
1459
|
+
tsg.variable("const", node.mutationName + "Middleware", tsg.array([makeIdDecodeMiddleware(fields, node), ...node.middlewares.map((it) => tsg.identifier(it).importFrom("../" + tsFileNames.middleware))]), tsg.arrayType(tsg.typeRef("ResolverMiddleware", [
|
|
1460
|
+
makeContextTypeRef(DIR$1),
|
|
1461
|
+
tsg.identifier(typeName),
|
|
1462
|
+
tsg.identifier("GQL" + typeName)
|
|
1463
|
+
]).importFrom("sasat")))
|
|
1464
|
+
];
|
|
1465
|
+
};
|
|
1466
|
+
const makeMutationResolverMiddleware = (entity, node) => {
|
|
1467
|
+
switch (node.mutationType) {
|
|
1468
|
+
case "create": return makeResolverMiddleware(entity.name.createInputName(), entity, entity.creatable.fields, node);
|
|
1469
|
+
case "update": return makeResolverMiddleware(entity.name.updateInputName(), entity, entity.updateInput.fields, node);
|
|
1470
|
+
case "delete": return makeResolverMiddleware(entity.name.identifyInputName(), entity, entity.identifyFields(), node);
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
//#endregion
|
|
1474
|
+
//#region src/generatorv2/codegen/ts/scripts/makeDatasource.ts
|
|
1475
|
+
const makeDatasource = (entity, importFrom, args) => {
|
|
1476
|
+
return tsg.new(tsg.identifier(entity.dataSourceName()).importFrom(Directory.resolve(importFrom, "DATA_SOURCES", entity.name)), ...args || []);
|
|
1477
|
+
};
|
|
1478
|
+
//#endregion
|
|
1479
|
+
//#region src/generatorv2/codegen/ts/generateMutationResolver.ts
|
|
1480
|
+
const generateMutationResolver = (root) => {
|
|
1481
|
+
return new TsFile(...root.entities.flatMap(makeMutationMiddlewareAndTypes).flat(), tsg.variable("const", "mutation", tsg.object(...root.entities.flatMap((it) => it.mutations).map(makeMutation$1))).export()).disableEsLint();
|
|
1482
|
+
};
|
|
1483
|
+
const result = tsg.identifier("result");
|
|
1484
|
+
const refetched = tsg.identifier("fetched");
|
|
1485
|
+
const ds = tsg.identifier("ds");
|
|
1486
|
+
const ident = tsg.identifier("identifiable");
|
|
1487
|
+
const makeMutation$1 = (node) => {
|
|
1488
|
+
return tsg.propertyAssign(node.mutationName, makeResolver$1.call(tsg.arrowFunc(makeResolverArgs(node), void 0, makeMutationBody(node)).toAsync(), tsg.identifier(node.mutationName + "Middleware")).typeArgs(...[
|
|
1489
|
+
context,
|
|
1490
|
+
tsg.typeRef(node.inputName),
|
|
1491
|
+
node.requireIdDecodeMiddleware ? tsg.typeRef("GQL" + node.inputName) : null
|
|
1492
|
+
].filter(nonNullable)));
|
|
1493
|
+
};
|
|
1494
|
+
const makeMutationBody = (node) => {
|
|
1495
|
+
if (node.mutationType === "create") return makeCreateMutationBody(node);
|
|
1496
|
+
if (node.mutationType === "update") return makeUpdateMutationBody(node);
|
|
1497
|
+
return makeDeleteMutationBody(node);
|
|
1498
|
+
};
|
|
1499
|
+
const makeResolver$1 = tsg.identifier("makeResolver").importFrom("sasat");
|
|
1500
|
+
const context = tsg.typeRef("GQLContext").importFrom(Directory.resolve("GENERATED", "BASE", "context"));
|
|
1501
|
+
const makeResolverArgs = (node) => [
|
|
1502
|
+
tsg.parameter("_"),
|
|
1503
|
+
tsg.parameter(`{${node.entityName.lowerCase()}}`),
|
|
1504
|
+
node.contextFields.length === 0 ? null : tsg.parameter("context")
|
|
1505
|
+
].filter(nonNullable);
|
|
1506
|
+
const makeCreateMutationBody = (node) => {
|
|
1507
|
+
const entity = tsg.identifier(node.entityName.lowerCase());
|
|
1508
|
+
const dsVariable = tsg.variable("const", ds, makeDatasource(node.entityName, "GENERATED"));
|
|
1509
|
+
const createCall = ds.property("create").call(entity);
|
|
1510
|
+
if (!node.subscription && !node.refetch) return tsg.block(dsVariable, tsg.return(createCall));
|
|
1511
|
+
if (!node.refetch) return tsg.block(dsVariable, tsg.variable("const", result, tsg.await(createCall)), node.subscription ? makePublishCall(node, result) : null, tsg.return(result));
|
|
1512
|
+
return tsg.block(dsVariable, tsg.variable("const", result, tsg.await(createCall)), ...makeRefetched(node), node.subscription ? makePublishCall(node, refetched) : null, tsg.return(refetched));
|
|
1513
|
+
};
|
|
1514
|
+
const makeRefetched = (node) => {
|
|
1515
|
+
return [tsg.variable("const", ident, tsg.identifier("pick").importFrom("sasat").call(node.mutationType === "create" ? result : tsg.identifier(node.entityName.lowerCase()), tsg.array(node.identifyFields.map(tsg.string))).as(tsg.typeRef("unknown")).as(makeTypeRef(node.entityName, "identifiable", "GENERATED"))), tsg.variable("const", refetched, tsg.await(ds.property(makeFindQueryName(node.identifyFields)).call(...node.identifyFields.map((it) => ident.property(it)))))];
|
|
1516
|
+
};
|
|
1517
|
+
const makePublishCall = (node, identifier) => {
|
|
1518
|
+
return tsg.await(tsg.identifier(publishFunctionName(node.entityName, node.mutationType)).importFrom("./subscription").call(identifier.as(makeTypeRef(node.entityName, "entity", "GENERATED")))).toStatement();
|
|
1519
|
+
};
|
|
1520
|
+
const makeDatasourceParam = (entity, contextParams) => {
|
|
1521
|
+
if (contextParams.length === 0) return entity;
|
|
1522
|
+
return tsg.object(tsg.spreadAssign(entity), ...contextParams.map((it) => tsg.propertyAssign(it.fieldName, tsg.identifier(`context.${it.contextName}`))));
|
|
1523
|
+
};
|
|
1524
|
+
const makeUpdateMutationBody = (node) => {
|
|
1525
|
+
const entity = tsg.identifier(node.entityName.lowerCase());
|
|
1526
|
+
const statements = [tsg.variable("const", ds, makeDatasource(node.entityName, "GENERATED")), tsg.variable("const", result, tsg.await(ds.property("update").call(makeDatasourceParam(entity, node.contextFields)).property("then").call(tsg.arrowFunc([tsg.parameter("it", tsg.typeRef("CommandResponse").importFrom("sasat"))], KeywordTypeNode.boolean, tsg.binary(tsg.identifier("it.changedRows"), "===", tsg.number(1))))))];
|
|
1527
|
+
if (!node.refetch && !node.subscription) return tsg.block(...statements, tsg.return(result));
|
|
1528
|
+
return tsg.block(...statements, ...makeRefetched(node), node.subscription ? makePublishCall(node, refetched) : null, tsg.return(node.refetch ? refetched : result));
|
|
1529
|
+
};
|
|
1530
|
+
const makeDeleteMutationBody = (node) => {
|
|
1531
|
+
const entity = tsg.identifier(node.entityName.lowerCase());
|
|
1532
|
+
const dsV = tsg.variable("const", ds, makeDatasource(node.entityName, "GENERATED"));
|
|
1533
|
+
const deleteCall = ds.property("delete").call(entity).property("then").call(tsg.arrowFunc([tsg.parameter("it", tsg.typeRef("CommandResponse").importFrom("sasat"))], KeywordTypeNode.boolean, tsg.binary(tsg.identifier("it.affectedRows"), "===", new NumericLiteral(1))));
|
|
1534
|
+
return tsg.block(dsV, tsg.variable("const", result, tsg.await(deleteCall)), node.subscription ? tsg.if(result, tsg.block(makePublishCall(node, entity))) : null, tsg.return(result));
|
|
1535
|
+
};
|
|
1536
|
+
//#endregion
|
|
1537
|
+
//#region src/cli/console.ts
|
|
1538
|
+
const Console = {
|
|
1539
|
+
success: (msg) => {
|
|
1540
|
+
console.log(chalk.default.green(msg));
|
|
1541
|
+
},
|
|
1542
|
+
error: (msg) => {
|
|
1543
|
+
console.error(chalk.default.bold.red(msg));
|
|
1544
|
+
},
|
|
1545
|
+
log: (msg) => {
|
|
1546
|
+
console.log(msg);
|
|
1547
|
+
},
|
|
1548
|
+
debug: (msg) => {
|
|
1549
|
+
console.debug("debug:: " + msg);
|
|
1550
|
+
}
|
|
1551
|
+
};
|
|
1552
|
+
//#endregion
|
|
1553
|
+
//#region src/migration/data/GQLOption.ts
|
|
1554
|
+
const defaultGQLOption = () => ({
|
|
1555
|
+
enabled: false,
|
|
1556
|
+
queries: [],
|
|
1557
|
+
mutations: []
|
|
1558
|
+
});
|
|
1559
|
+
const getArgs = (query, entity) => {
|
|
1560
|
+
if (query.type === "primary") return entity.fields.filter((it) => it.isPrimary).map((it) => ({
|
|
1561
|
+
kind: "arg",
|
|
1562
|
+
name: it.fieldName,
|
|
1563
|
+
type: it.gqlType
|
|
1564
|
+
}));
|
|
1565
|
+
const r = [];
|
|
1566
|
+
if (query.type === "list-paging") r.push({
|
|
1567
|
+
kind: "arg",
|
|
1568
|
+
name: "option",
|
|
1569
|
+
type: "PagingOption"
|
|
1570
|
+
});
|
|
1571
|
+
query.conditions.forEach((it) => {
|
|
1572
|
+
if (it.left.kind === "arg") r.push(it.left);
|
|
1573
|
+
if (it.kind === "between") {
|
|
1574
|
+
if (it.begin.kind === "arg") r.push(it.begin);
|
|
1575
|
+
if (it.end.kind === "arg") r.push(it.end);
|
|
1576
|
+
} else if (it.right.kind === "arg") r.push(it.right);
|
|
1577
|
+
});
|
|
1578
|
+
return r;
|
|
1579
|
+
};
|
|
1580
|
+
//#endregion
|
|
1581
|
+
//#region src/tsg/node/rawCodeStatement.ts
|
|
1582
|
+
var RawCodeStatement = class extends TsStatement {
|
|
1583
|
+
constructor(code) {
|
|
1584
|
+
super();
|
|
1585
|
+
this.code = code;
|
|
1586
|
+
}
|
|
1587
|
+
toTsString() {
|
|
1588
|
+
return this.code;
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
//#endregion
|
|
1592
|
+
//#region src/generatorv2/scripts/gqlTypes.ts
|
|
1593
|
+
const toTsType = (type) => {
|
|
1594
|
+
switch (type) {
|
|
1595
|
+
case "Int":
|
|
1596
|
+
case "Float": return "number";
|
|
1597
|
+
case "ID":
|
|
1598
|
+
case "String": return "string";
|
|
1599
|
+
case "Boolean": return "boolean";
|
|
1600
|
+
default: return type;
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
//#endregion
|
|
1604
|
+
//#region src/generatorv2/codegen/ts/scripts/makeConditonValueExpr.ts
|
|
1605
|
+
const qExpr$3 = tsg.identifier("qe").importFrom("sasat");
|
|
1606
|
+
const makeConditionValueRaw = (cv) => {
|
|
1607
|
+
const context = tsg.identifier("arg").property("context?");
|
|
1608
|
+
switch (cv.kind) {
|
|
1609
|
+
case "context": {
|
|
1610
|
+
const value = context.property(cv.field);
|
|
1611
|
+
if (cv.onNotDefined.action !== "defaultValue") return value;
|
|
1612
|
+
return tsg.binary(context.property(cv.field), "||", typeof cv.onNotDefined.value === "string" ? tsg.string(cv.onNotDefined.value) : tsg.number(cv.onNotDefined.value));
|
|
1613
|
+
}
|
|
1614
|
+
case "fixed": return typeof cv.value === "string" ? tsg.string(cv.value) : tsg.number(cv.value);
|
|
1615
|
+
case "today": return tsg.identifier(cv.type === "datetime" ? "getTodayDateTimeString" : "getTodayDateString").importFrom("sasat").call();
|
|
1616
|
+
case "now": return tsg.identifier("dateString").importFrom("sasat").call(tsg.new(tsg.identifier("Date")));
|
|
1617
|
+
default: throw Error(`not implemented: makeConditionValue.${cv.kind}`);
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
const makeConditionValueQExpr = (cv) => {
|
|
1621
|
+
const context = tsg.identifier("arg").property("context?");
|
|
1622
|
+
switch (cv.kind) {
|
|
1623
|
+
case "context": {
|
|
1624
|
+
const value = context.property(cv.field);
|
|
1625
|
+
if (cv.onNotDefined.action !== "defaultValue") return qExpr$3.property("value").call(value);
|
|
1626
|
+
return qExpr$3.property("value").call(tsg.binary(context.property(cv.field), "||", typeof cv.onNotDefined.value === "string" ? tsg.string(cv.onNotDefined.value) : tsg.number(cv.onNotDefined.value)));
|
|
1627
|
+
}
|
|
1628
|
+
case "fixed": return qExpr$3.property("value").call(typeof cv.value === "string" ? tsg.string(cv.value) : tsg.number(cv.value));
|
|
1629
|
+
case "today": return qExpr$3.property("value").call(tsg.identifier(cv.type === "datetime" ? "getTodayDateTimeString" : "getTodayDateString").importFrom("sasat").call());
|
|
1630
|
+
case "now": return qExpr$3.property("value").call(tsg.identifier("dateString").importFrom("sasat").call(tsg.new(tsg.identifier("Date"))));
|
|
1631
|
+
case "arg": return qExpr$3.property("value").call(tsg.identifier(cv.name));
|
|
1632
|
+
case "field": return qExpr$3.property("field").call(tsg.string("t0"), tsg.string(cv.column));
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
//#endregion
|
|
1636
|
+
//#region src/generatorv2/codegen/ts/scripts/makeQueryConditionExpr.ts
|
|
1637
|
+
const qExpr$2 = tsg.identifier("qe").importFrom("sasat");
|
|
1638
|
+
const makeQueryConditionExpr = (condition) => {
|
|
1639
|
+
if (condition.kind === "between") return qExpr$2.property("between").call(makeConditionValueQExpr(condition.left), makeConditionValueQExpr(condition.begin), makeConditionValueQExpr(condition.end));
|
|
1640
|
+
return qExpr$2.property("comparison").call(makeConditionValueQExpr(condition.left), tsg.string(condition.operator), makeConditionValueQExpr(condition.right));
|
|
1641
|
+
};
|
|
1642
|
+
//#endregion
|
|
1643
|
+
//#region src/generatorv2/codegen/ts/generateQueryResolver.ts
|
|
1644
|
+
const DIR = "GENERATED";
|
|
1645
|
+
const generateQueryResolver = (root) => {
|
|
1646
|
+
return new TsFile(tsg.variable("const", "query", tsg.object(...root.entities.flatMap((entity) => entity.queries.map((query) => makeGQLQuery(entity, query))).filter(nonNullable))).export()).disableEsLint();
|
|
1647
|
+
};
|
|
1648
|
+
const makeResolver = () => tsg.identifier("makeResolver").importFrom("sasat");
|
|
1649
|
+
const makeGQLQuery = (entity, query) => {
|
|
1650
|
+
if (!entity.gqlEnabled) {
|
|
1651
|
+
Console.log(`Query.${query.name || entity.name.lowerCase()} generation skipped. Reason: Entity:${entity.name.name} is not Open to GQL.`);
|
|
1652
|
+
return null;
|
|
1653
|
+
}
|
|
1654
|
+
const args = getArgs(query, entity);
|
|
1655
|
+
return tsg.propertyAssign(query.type === "primary" ? entity.name.lowerCase() : query.name, makeResolver().call(...[tsg.arrowFunc([
|
|
1656
|
+
tsg.parameter("_"),
|
|
1657
|
+
tsg.parameter(`{${args.map((it) => it.name).join(",")}}`),
|
|
1658
|
+
tsg.parameter("context"),
|
|
1659
|
+
tsg.parameter("info")
|
|
1660
|
+
], void 0, makeGQLQueryBody(entity, query)).toAsync(), makeMiddlewares(entity, query)].filter(nonNullable)).typeArgs(...makeTypeArgs(args)));
|
|
1661
|
+
};
|
|
1662
|
+
const getHashIdArgs = (entity, query) => {
|
|
1663
|
+
if (query.type === "primary") {
|
|
1664
|
+
const hashIDs = entity.identifyFields().filter((it) => it.option.autoIncrementHashId);
|
|
1665
|
+
if (hashIDs.length === 0) return null;
|
|
1666
|
+
return hashIDs.map((it) => ({
|
|
1667
|
+
encoder: it.hashId.encoder,
|
|
1668
|
+
name: it.fieldName
|
|
1669
|
+
}));
|
|
1670
|
+
}
|
|
1671
|
+
const getHashIdArg = (arg, field) => {
|
|
1672
|
+
const columnName = field.column;
|
|
1673
|
+
const hashIdOpt = entity.fields.find((e) => e.columnName === columnName)?.hashId;
|
|
1674
|
+
if (!hashIdOpt) return null;
|
|
1675
|
+
return {
|
|
1676
|
+
name: arg.name,
|
|
1677
|
+
encoder: hashIdOpt.encoder
|
|
1678
|
+
};
|
|
1679
|
+
};
|
|
1680
|
+
return query.conditions.map((it) => {
|
|
1681
|
+
if (it.kind === "comparison") {
|
|
1682
|
+
if (it.left.kind === "arg") {
|
|
1683
|
+
if (it.right.kind === "field") return getHashIdArg(it.left, it.right);
|
|
1684
|
+
}
|
|
1685
|
+
if (it.right.kind === "arg") {
|
|
1686
|
+
if (it.left.kind === "field") return getHashIdArg(it.right, it.left);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
return null;
|
|
1690
|
+
}).filter(nonNullable);
|
|
1691
|
+
};
|
|
1692
|
+
const makeHashIdMiddleware = (entity, query) => {
|
|
1693
|
+
const args = getHashIdArgs(entity, query);
|
|
1694
|
+
if (!args || args?.length === 0) return null;
|
|
1695
|
+
return tsg.arrowFunc([tsg.parameter("args")], void 0, tsg.block(new RawCodeStatement(`args[1] = {...args[1], ${args.map((it) => `${it.name}: ${it.encoder}.decode(args[1].${it.name} as string),`).join("")}};`).addImport(args.map((it) => it.encoder), Directory.resolve(DIR, "BASE", tsFileNames.encoder)), tsg.return(tsg.identifier("args"))));
|
|
1696
|
+
};
|
|
1697
|
+
const makeMiddlewares = (entity, query) => {
|
|
1698
|
+
const hashId = makeHashIdMiddleware(entity, query);
|
|
1699
|
+
if (!hashId && query.middlewares.length === 0) return null;
|
|
1700
|
+
if (query.middlewares.length === 0) return tsg.array([hashId]);
|
|
1701
|
+
const middlewares = query.middlewares.map((it) => tsg.identifier(it).importFrom("../" + tsFileNames.middleware));
|
|
1702
|
+
if (!hashId) return tsg.array(middlewares);
|
|
1703
|
+
return tsg.array([hashId, ...middlewares]);
|
|
1704
|
+
};
|
|
1705
|
+
const makeTypeArgs = (args) => {
|
|
1706
|
+
let hashIds = false;
|
|
1707
|
+
const getType = (arg, checkHashId) => {
|
|
1708
|
+
if (arg.type === "PagingOption") return tsg.typeRef(arg.type).importFrom("sasat");
|
|
1709
|
+
if (checkHashId && arg.type === "ID") {
|
|
1710
|
+
hashIds = true;
|
|
1711
|
+
return tsg.typeRef("number");
|
|
1712
|
+
}
|
|
1713
|
+
return tsg.typeRef(toTsType(arg.type));
|
|
1714
|
+
};
|
|
1715
|
+
const params = tsg.typeLiteral(args.map((it) => tsg.propertySignature(it.name, getType(it, true))));
|
|
1716
|
+
if (!hashIds) return [makeContextTypeRef("GENERATED"), params];
|
|
1717
|
+
return [
|
|
1718
|
+
makeContextTypeRef("GENERATED"),
|
|
1719
|
+
params,
|
|
1720
|
+
tsg.typeLiteral(args.map((it) => tsg.propertySignature(it.name, getType(it, false))))
|
|
1721
|
+
];
|
|
1722
|
+
};
|
|
1723
|
+
const qExpr$1 = tsg.identifier("qe").importFrom("sasat");
|
|
1724
|
+
const makeGQLQueryBody = (entity, query) => {
|
|
1725
|
+
const fields = tsg.variable("const", "fields", tsg.identifier("gqlResolveInfoToField").importFrom("sasat").call(tsg.identifier("info")).as(makeTypeRef(entity.name, "fields", "GENERATED")));
|
|
1726
|
+
const where = query.conditions && query.conditions.length !== 0 ? tsg.variable("const", "where", qExpr$1.property("and").call(...(query.conditions || []).map(makeQueryConditionExpr))) : null;
|
|
1727
|
+
const method = {
|
|
1728
|
+
single: "first",
|
|
1729
|
+
primary: entity.primaryQueryName(),
|
|
1730
|
+
"list-all": "find",
|
|
1731
|
+
"list-paging": "findPageable"
|
|
1732
|
+
};
|
|
1733
|
+
const queryArgs = getArgs(query, entity);
|
|
1734
|
+
const args = [
|
|
1735
|
+
...query.type === "primary" ? queryArgs.map((it) => tsg.identifier(it.name)) : [],
|
|
1736
|
+
query.type === "list-paging" ? tsg.identifier("pagingOption").importFrom("sasat").call(tsg.identifier("option")) : null,
|
|
1737
|
+
tsg.identifier("fields"),
|
|
1738
|
+
tsg.identifier(where ? "{ where }" : "undefined"),
|
|
1739
|
+
tsg.identifier("context")
|
|
1740
|
+
].filter(nonNullable);
|
|
1741
|
+
const result = makeDatasource(entity.name, DIR).property(method[query.type]).call(...args);
|
|
1742
|
+
return tsg.block(fields, where, tsg.return(result));
|
|
1743
|
+
};
|
|
1744
|
+
//#endregion
|
|
1745
|
+
//#region src/generatorv2/codegen/ts/generateResolver.ts
|
|
1746
|
+
const generateResolver = (root) => {
|
|
1747
|
+
const hasSubscription = root.subscriptions.some((it) => it.gqlEnabled);
|
|
1748
|
+
const properties = [tsg.propertyAssign("Query", tsg.identifier("query").importFrom("./query")), tsg.propertyAssign("Mutation", tsg.identifier("mutation").importFrom("./mutation"))];
|
|
1749
|
+
if (hasSubscription) properties.push(tsg.propertyAssign("Subscription", tsg.identifier("subscription").importFrom("./subscription")));
|
|
1750
|
+
return new TsFile(tsg.variable("const", tsg.identifier("resolvers"), tsg.object(...properties, tsg.spreadAssign(tsg.object(...root.entities.filter((it) => it.gqlEnabled).map(makeEntityResolver))))).export()).disableEsLint();
|
|
1751
|
+
};
|
|
1752
|
+
const makeEntityResolver = (node) => {
|
|
1753
|
+
return tsg.propertyAssign(node.name.name, tsg.object(...node.fields.filter((it) => it.hashId).map(makeHashIdProperty).filter(nonNullable), ...node.references.filter((it) => it.isGQLOpen).map((ref) => makeRelationProperty(ref)), ...node.referencedBy.filter((it) => it.isGQLOpen).map((ref) => makeReferencedByProperty(ref))));
|
|
1754
|
+
};
|
|
1755
|
+
const makeHashIdProperty = (field) => {
|
|
1756
|
+
if (!field.hashId) return null;
|
|
1757
|
+
const paramName = field.entity.name.lowerCase();
|
|
1758
|
+
return tsg.propertyAssign(field.fieldName, tsg.arrowFunc([tsg.parameter(paramName, makeTypeRef(field.entity.name, "result", "GENERATED"))], void 0, tsg.binary(tsg.identifier(paramName).property(field.fieldName), "&&", tsg.identifier(field.hashId.encoder).importFrom(Directory.resolve("GENERATED", "BASE", tsFileNames.encoder)).property("encode").call(tsg.identifier(paramName).property(field.fieldName)))));
|
|
1759
|
+
};
|
|
1760
|
+
const makeRelationProperty = (ref) => {
|
|
1761
|
+
const paramName = ref.entity.name.lowerCase();
|
|
1762
|
+
return tsg.propertyAssign(ref.fieldName, tsg.arrowFunc([tsg.parameter(paramName, makeTypeRef(ref.entity.name, "result", "GENERATED")), tsg.parameter("context", makeContextTypeRef("GENERATED"))], void 0, tsg.block(tsg.if(tsg.binary(tsg.identifier(paramName).property(ref.fieldName), "!==", tsg.identifier("undefined")), tsg.return(tsg.identifier(paramName).property(ref.fieldName))), tsg.variable("const", "ds", makeDatasource(EntityName.fromTableName(ref.parentTableName), "GENERATED")), tsg.variable("const", "where", tsg.identifier("ds").property("getRelationMap").call().property(ref.fieldName).property("condition").call(tsg.object(tsg.propertyAssign("parent", tsg.identifier(paramName)), tsg.propertyAssign("childTableAlias", tsg.string("t0")), tsg.propertyAssign("context")))), tsg.return(tsg.identifier("ds").property("first").call(tsg.identifier("undefined"), tsg.object(tsg.propertyAssign("where")))))));
|
|
1763
|
+
};
|
|
1764
|
+
const makeReferencedByProperty = (ref) => {
|
|
1765
|
+
const paramName = ref.entity.name.lowerCase();
|
|
1766
|
+
const propertyName = ref.fieldName;
|
|
1767
|
+
return tsg.propertyAssign(propertyName, tsg.arrowFunc([tsg.parameter(paramName, makeTypeRef(ref.entity.name, "result", "GENERATED")), tsg.parameter("context", makeContextTypeRef("GENERATED"))], void 0, tsg.block(tsg.if(tsg.binary(tsg.identifier(paramName).property(propertyName), "!==", tsg.identifier("undefined")), tsg.return(tsg.identifier(paramName).property(propertyName))), tsg.variable("const", "ds", makeDatasource(EntityName.fromTableName(ref.childTable), "GENERATED")), tsg.variable("const", "where", tsg.identifier("ds").property("getRelationMap").call().property(propertyName).property("condition").call(tsg.object(tsg.propertyAssign("parent", tsg.identifier(paramName)), tsg.propertyAssign("childTableAlias", tsg.string("t0")), tsg.propertyAssign("context")))), tsg.return(tsg.identifier("ds").property(ref.isArray ? "find" : "first").call(tsg.identifier("undefined"), tsg.object(tsg.propertyAssign("where")))))));
|
|
1768
|
+
};
|
|
1769
|
+
//#endregion
|
|
1770
|
+
//#region src/generatorv2/codegen/ts/generateSubscription.ts
|
|
1771
|
+
const generateSubscription = (root) => {
|
|
1772
|
+
const subscriptionEnum = tsg.enum(tsg.identifier("SubscriptionName"), []).export();
|
|
1773
|
+
const subscriptions = tsg.object();
|
|
1774
|
+
const publishFunctions = [];
|
|
1775
|
+
root.subscriptions.forEach((it) => {
|
|
1776
|
+
subscriptionEnum.addMembers(tsg.enumMember(tsg.identifier(it.subscriptionName), tsg.string(it.subscriptionName)));
|
|
1777
|
+
if (it.gqlEnabled) {
|
|
1778
|
+
const fn = it.filters.length === 0 ? makeAsyncIteratorCall(it.subscriptionName) : makeWithFilter(it.subscriptionName, it.filters);
|
|
1779
|
+
subscriptions.addProperties(tsg.propertyAssign(it.subscriptionName, tsg.object(tsg.propertyAssign("subscribe", fn))));
|
|
1780
|
+
}
|
|
1781
|
+
publishFunctions.push(tsg.variable("const", tsg.identifier(it.publishFunctionName), tsg.arrowFunc([tsg.parameter("entity", makeTypeRef(it.entity, it.mutationType === "delete" ? "identifiable" : "entity", "GENERATED"))], tsg.typeRef("Promise", [KeywordTypeNode.void]), tsg.identifier("pubsub.publish").call(tsg.identifier(`SubscriptionName.${it.subscriptionName}`), tsg.object(tsg.propertyAssign(it.subscriptionName, tsg.identifier("entity")))))).export());
|
|
1782
|
+
});
|
|
1783
|
+
return new TsFile(subscriptionEnum, tsg.variable("const", tsg.identifier("subscription"), subscriptions).export(), ...publishFunctions).disableEsLint();
|
|
1784
|
+
};
|
|
1785
|
+
const makeAsyncIteratorCall = (event) => {
|
|
1786
|
+
return tsg.arrowFunc([], void 0, tsg.identifier("pubsub").importFrom("../pubsub").property("asyncIterator").call(tsg.array([tsg.identifier(`SubscriptionName.${event}`)])));
|
|
1787
|
+
};
|
|
1788
|
+
const makeWithFilter = (event, filters) => {
|
|
1789
|
+
const binaryExpressions = filters.map((it) => tsg.binary(tsg.identifier(`result.${it.field}`), "===", tsg.identifier(`variables.${it.field}`))).reduce((previousValue, currentValue) => tsg.binary(previousValue, "&&", currentValue));
|
|
1790
|
+
return tsg.identifier("withFilter").importFrom("graphql-subscriptions").call(makeAsyncIteratorCall(event), tsg.arrowFunc([tsg.parameter("payload", KeywordTypeNode.any), tsg.parameter("variables", KeywordTypeNode.any)], tsg.typeRef("Promise", [KeywordTypeNode.boolean]), tsg.block(tsg.variable("const", tsg.identifier("result"), tsg.await(tsg.identifier(`payload.${event}`))), tsg.return(binaryExpressions))).toAsync());
|
|
1791
|
+
};
|
|
1792
|
+
//#endregion
|
|
1793
|
+
//#region src/generatorv2/codegen/ts/scripts/gqlString.ts
|
|
1794
|
+
const GQLString = {
|
|
1795
|
+
args: (args) => {
|
|
1796
|
+
if (args.length === 0) return "";
|
|
1797
|
+
return `(${args.map((arg) => `${arg.name}: ${GQLString.type(arg.type)}`).join(",")})`;
|
|
1798
|
+
},
|
|
1799
|
+
field: (field) => {
|
|
1800
|
+
return `${field.fieldName}: ${fieldGqlType(field)}`;
|
|
1801
|
+
},
|
|
1802
|
+
referenceField: (ref) => {
|
|
1803
|
+
return `${ref.fieldName}: ${makeGQLType(EntityName.fromTableName(ref.parentTableName).name, ref.isNullable, ref.isArray)}`;
|
|
1804
|
+
},
|
|
1805
|
+
referencedField: (ref) => {
|
|
1806
|
+
return `${ref.fieldName}: ${makeGQLType(EntityName.fromTableName(ref.childTable).name, ref.isNullable, ref.isArray)}`;
|
|
1807
|
+
},
|
|
1808
|
+
query: (node) => {
|
|
1809
|
+
return `${node.queryName}${GQLString.args(node.args)}: ${GQLString.type(node.returnType)}`;
|
|
1810
|
+
},
|
|
1811
|
+
mutation: (node) => {
|
|
1812
|
+
return `${node.mutationName}${GQLString.args(node.args)}: ${GQLString.type(node.returnType)}`;
|
|
1813
|
+
},
|
|
1814
|
+
subscription: (node) => {
|
|
1815
|
+
return `${node.subscriptionName}${GQLString.args(node.args)}: ${GQLString.type(node.returnType)}`;
|
|
1816
|
+
},
|
|
1817
|
+
type: (node) => {
|
|
1818
|
+
const type = node.nullable ? node.typeName : node.typeName + "!";
|
|
1819
|
+
if (node.array) return `[${type}]!`;
|
|
1820
|
+
return type;
|
|
1821
|
+
}
|
|
1822
|
+
};
|
|
1823
|
+
const fieldGqlType = (field) => {
|
|
1824
|
+
return makeGQLType(field.gqlType, field.isNullable, field.isArray);
|
|
1825
|
+
};
|
|
1826
|
+
const makeGQLType = (typeName, isNullable, isArray) => {
|
|
1827
|
+
const type = isNullable ? typeName : typeName + "!";
|
|
1828
|
+
if (isArray) return `[${type}]!`;
|
|
1829
|
+
return type;
|
|
1830
|
+
};
|
|
1831
|
+
//#endregion
|
|
1832
|
+
//#region src/generatorv2/codegen/ts/scripts/typeDefinition.ts
|
|
1833
|
+
const typeFieldDefinitionToTsg = (def) => {
|
|
1834
|
+
const properties = [tsg.propertyAssign("return", tsg.string(def.return)), def.args ? tsg.propertyAssign("args", tsg.array(def.args.map((it) => {
|
|
1835
|
+
return tsg.object(tsg.propertyAssign("name", tsg.string(it.name)), tsg.propertyAssign("type", tsg.string(it.type)));
|
|
1836
|
+
}))) : null];
|
|
1837
|
+
return tsg.object(...properties.filter(nonNullable));
|
|
1838
|
+
};
|
|
1839
|
+
//#endregion
|
|
1840
|
+
//#region src/generatorv2/codegen/ts/generateTypeDefs.ts
|
|
1841
|
+
const generateTypeDefs = (root) => {
|
|
1842
|
+
const types = [
|
|
1843
|
+
...root.entities.map(makeEntityType),
|
|
1844
|
+
makeQuery(root),
|
|
1845
|
+
makeMutation(root.entities.flatMap((it) => it.mutations)),
|
|
1846
|
+
makeSubscription(root.subscriptions.filter((it) => it.gqlEnabled))
|
|
1847
|
+
].filter(nonNullable);
|
|
1848
|
+
const inputs = [
|
|
1849
|
+
tsg.propertyAssign("PagingOption", tsg.object(tsg.propertyAssign("numberOfItem", typeFieldDefinitionToTsg({ return: "Int!" })), tsg.propertyAssign("offset", typeFieldDefinitionToTsg({ return: "Int" })), tsg.propertyAssign("order", typeFieldDefinitionToTsg({ return: "String" })), tsg.propertyAssign("asc", typeFieldDefinitionToTsg({ return: "Boolean" })))),
|
|
1850
|
+
...root.entities.map(makeCreateInput),
|
|
1851
|
+
...root.entities.map(makeUpdateInput),
|
|
1852
|
+
...root.entities.map(makeIdentifyInput)
|
|
1853
|
+
].filter(nonNullable);
|
|
1854
|
+
return new TsFile(tsg.variable("const", tsg.identifier("typeDefs"), tsg.object(...types)).export(), tsg.variable("const", tsg.identifier("inputs"), tsg.object(...inputs)).export()).disableEsLint();
|
|
1855
|
+
};
|
|
1856
|
+
const makeEntityType = (node) => {
|
|
1857
|
+
if (!node.gqlEnabled) return null;
|
|
1858
|
+
return tsg.propertyAssign(node.name.name, tsg.object(...node.fields.filter((it) => it.isGQLOpen).map((it) => {
|
|
1859
|
+
return tsg.propertyAssign(it.fieldName, typeFieldDefinitionToTsg({ return: makeGQLType(it.gqlType, it.isNullable, it.isArray) }));
|
|
1860
|
+
}), ...node.references.filter((it) => it.isGQLOpen).map((it) => {
|
|
1861
|
+
return tsg.propertyAssign(it.fieldName, typeFieldDefinitionToTsg({ return: makeGQLType(EntityName.fromTableName(it.parentTableName).name, it.isNullable, it.isArray) }));
|
|
1862
|
+
}), ...node.referencedBy.filter((it) => it.isGQLOpen).map((it) => {
|
|
1863
|
+
return tsg.propertyAssign(it.fieldName, typeFieldDefinitionToTsg({ return: makeGQLType(EntityName.fromTableName(it.childTable).name, it.isNullable, it.isArray) }));
|
|
1864
|
+
})));
|
|
1865
|
+
};
|
|
1866
|
+
const makeInput = (inputName, fields) => {
|
|
1867
|
+
return tsg.propertyAssign(inputName, tsg.object(...fields.filter((it) => it.isGQLOpen).map((it) => tsg.propertyAssign(it.fieldName, typeFieldDefinitionToTsg({ return: makeGQLType(it.gqlType, it.isNullable, it.isArray) })))));
|
|
1868
|
+
};
|
|
1869
|
+
const makeCreateInput = (node) => {
|
|
1870
|
+
if (!node.gqlEnabled || !node.creatable.gqlEnabled) return null;
|
|
1871
|
+
return makeInput(node.name.createInputName(), node.creatable.fields);
|
|
1872
|
+
};
|
|
1873
|
+
const makeUpdateInput = (node) => {
|
|
1874
|
+
if (!node.gqlEnabled || !node.updateInput.gqlEnabled) return null;
|
|
1875
|
+
return makeInput(node.name.updateInputName(), node.updateInput.fields);
|
|
1876
|
+
};
|
|
1877
|
+
const makeIdentifyInput = (node) => {
|
|
1878
|
+
if (!node.gqlEnabled || !node.mutations.find((it) => it.mutationType === "delete")) return null;
|
|
1879
|
+
return makeInput(node.name.identifyInputName(), node.fields.filter((it) => it.isPrimary));
|
|
1880
|
+
};
|
|
1881
|
+
const makeQueryTypeDef = (entity, query) => {
|
|
1882
|
+
const args = getArgs(query, entity);
|
|
1883
|
+
return tsg.propertyAssign(query.type === "primary" ? entity.name.lowerCase() : query.name, typeFieldDefinitionToTsg({
|
|
1884
|
+
return: GQLString.type({
|
|
1885
|
+
typeName: entity.name.name,
|
|
1886
|
+
entity: true,
|
|
1887
|
+
array: query.type === "list-paging" || query.type === "list-all",
|
|
1888
|
+
nullable: query.type !== "list-paging" && query.type !== "list-all"
|
|
1889
|
+
}),
|
|
1890
|
+
args: args.map((it) => ({
|
|
1891
|
+
name: it.name,
|
|
1892
|
+
type: it.type + "!"
|
|
1893
|
+
}))
|
|
1894
|
+
}));
|
|
1895
|
+
};
|
|
1896
|
+
const makeQueryProperties = (root) => {
|
|
1897
|
+
return root.entities.filter((it) => it.gqlEnabled).flatMap((entity) => entity.queries.map((it) => makeQueryTypeDef(entity, it)));
|
|
1898
|
+
};
|
|
1899
|
+
const makeQuery = (root) => {
|
|
1900
|
+
const properties = makeQueryProperties(root);
|
|
1901
|
+
if (properties.length === 0) return null;
|
|
1902
|
+
return tsg.propertyAssign("Query", tsg.object(...properties));
|
|
1903
|
+
};
|
|
1904
|
+
const makeMutation = (mutations) => {
|
|
1905
|
+
if (mutations.length === 0) return null;
|
|
1906
|
+
return tsg.propertyAssign("Mutation", tsg.object(...mutations.map((mutation) => {
|
|
1907
|
+
return tsg.propertyAssign(mutation.mutationName, typeFieldDefinitionToTsg({
|
|
1908
|
+
return: GQLString.type(mutation.returnType),
|
|
1909
|
+
args: mutation.args.map((arg) => ({
|
|
1910
|
+
name: arg.name,
|
|
1911
|
+
type: GQLString.type(arg.type)
|
|
1912
|
+
}))
|
|
1913
|
+
}));
|
|
1914
|
+
})));
|
|
1915
|
+
};
|
|
1916
|
+
const makeSubscription = (subscriptions) => {
|
|
1917
|
+
if (subscriptions.length === 0) return null;
|
|
1918
|
+
return tsg.propertyAssign("Subscription", tsg.object(...subscriptions.map((subscription) => {
|
|
1919
|
+
return tsg.propertyAssign(subscription.subscriptionName, typeFieldDefinitionToTsg({
|
|
1920
|
+
return: GQLString.type(subscription.returnType),
|
|
1921
|
+
args: subscription.args.map((arg) => ({
|
|
1922
|
+
name: arg.name,
|
|
1923
|
+
type: GQLString.type(arg.type)
|
|
1924
|
+
}))
|
|
1925
|
+
}));
|
|
1926
|
+
})));
|
|
1927
|
+
};
|
|
1928
|
+
//#endregion
|
|
1929
|
+
//#region src/generatorv2/codegen/ts/generateUserDefinedCondition.ts
|
|
1930
|
+
const { createSourceFile, ScriptTarget } = typescript.default;
|
|
1931
|
+
const generateUserDefinedCondition = (root, content) => {
|
|
1932
|
+
const customConditionNames = unique(root.entities.flatMap((it) => [...it.references.flatMap((it) => it.joinCondition.filter((it) => it.kind === "custom").map((it) => it.conditionName)), ...it.referencedBy.flatMap((it) => it.joinCondition.filter((it) => it.kind === "custom").map((it) => it.conditionName))]));
|
|
1933
|
+
if (customConditionNames.length === 0) return null;
|
|
1934
|
+
const sourceFile = createSourceFile(tsFileNames.conditions + ".ts", content, ScriptTarget.ESNext);
|
|
1935
|
+
const exportedVariables = getExportedVariables(sourceFile);
|
|
1936
|
+
const contextImported = isImported(sourceFile, "GQLContext", ["./context", "./context.js"]);
|
|
1937
|
+
const customConditionImported = isImported(sourceFile, "CustomCondition", ["sasat"]);
|
|
1938
|
+
const statements = [];
|
|
1939
|
+
customConditionNames.forEach((conditionName) => {
|
|
1940
|
+
if (!exportedVariables.some((it) => {
|
|
1941
|
+
return it.declarationList.declarations[0].name.getText(sourceFile) === conditionName;
|
|
1942
|
+
})) statements.push(tsg.variable("const", conditionName, tsg.arrowFunc([], void 0, tsg.block(tsg.throw(tsg.new(tsg.identifier("Error"), tsg.string("TODO: Not Implemented"))))), tsg.typeRef("CustomCondition", [tsg.typeRef("GQLContext")])).export());
|
|
1943
|
+
});
|
|
1944
|
+
const context = contextImported ? "" : new ImportDeclaration(["GQLContext"], "./context").toString() + "\n";
|
|
1945
|
+
const condition = customConditionImported ? "" : new ImportDeclaration(["CustomCondition"], "sasat").toString() + "\n";
|
|
1946
|
+
const addition = statements.length === 0 ? "" : "\n" + new TsFile(...statements).toString();
|
|
1947
|
+
return context + condition + content + addition;
|
|
1948
|
+
};
|
|
1949
|
+
//#endregion
|
|
1950
|
+
//#region src/generatorv2/codegen/ts/relationMap/getRequiredColumnNames.ts
|
|
1951
|
+
const getChildConditionValue = (cv) => {
|
|
1952
|
+
if (cv.kind === "child") return cv.field;
|
|
1953
|
+
return null;
|
|
1954
|
+
};
|
|
1955
|
+
const getConditionChildColumnNames = (getConditionValue) => (c) => {
|
|
1956
|
+
if (c.kind === "custom") return c.childRequiredFields || [];
|
|
1957
|
+
if (c.kind === "isNull") return [];
|
|
1958
|
+
const result = [getConditionValue(c.left)];
|
|
1959
|
+
if (c.operator === "IN") {
|
|
1960
|
+
result.push(getConditionValue(c.left));
|
|
1961
|
+
c.right.forEach((it) => {
|
|
1962
|
+
result.push(getConditionValue(it));
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
if (c.operator !== "BETWEEN") result.push(getConditionValue(c.right));
|
|
1966
|
+
else if (c.right.kind === "range") result.push(getConditionValue(c.right.begin), getConditionValue(c.right.end));
|
|
1967
|
+
return result;
|
|
1968
|
+
};
|
|
1969
|
+
const getChildRequiredNames = (ref) => {
|
|
1970
|
+
const getNames = getConditionChildColumnNames(getChildConditionValue);
|
|
1971
|
+
return ref.joinCondition.flatMap(getNames).filter(nonNullable);
|
|
1972
|
+
};
|
|
1973
|
+
//#endregion
|
|
1974
|
+
//#region src/generatorv2/codegen/ts/relationMap/makeNoContexError.ts
|
|
1975
|
+
const makeJoinRangeConditionThrowExpressions = (cv) => {
|
|
1976
|
+
if (cv.kind === "range") {
|
|
1977
|
+
const result = [];
|
|
1978
|
+
if (cv.begin.kind === "context") result.push(makeJoinConditionThrowExpressions(cv.begin));
|
|
1979
|
+
if (cv.end.kind === "context") result.push(makeJoinConditionThrowExpressions(cv.end));
|
|
1980
|
+
return result;
|
|
1981
|
+
}
|
|
1982
|
+
return [];
|
|
1983
|
+
};
|
|
1984
|
+
const makeJoinConditionThrowExpressions = (cv) => {
|
|
1985
|
+
if (cv.kind !== "context") return null;
|
|
1986
|
+
if (cv.onNotDefined.action !== "error") return null;
|
|
1987
|
+
return tsg.if(tsg.binary(tsg.identifier("!arg.context"), "||", tsg.binary(tsg.identifier("arg.context").property(cv.field), "===", tsg.identifier("undefined"))), tsg.throw(tsg.new(tsg.identifier("Error"), tsg.string(cv.onNotDefined.message))));
|
|
1988
|
+
};
|
|
1989
|
+
const makeThrowExpressions = (condition) => {
|
|
1990
|
+
if (condition.kind === "custom") return [];
|
|
1991
|
+
if (condition.kind === "isNull") return [makeJoinConditionThrowExpressions(condition.value)];
|
|
1992
|
+
if (condition.operator === "BETWEEN") return [makeJoinConditionThrowExpressions(condition.left), ...condition.right.kind === "range" ? makeJoinRangeConditionThrowExpressions(condition.right) : []];
|
|
1993
|
+
if (condition.operator === "IN") return [makeJoinConditionThrowExpressions(condition.left), ...condition.right.map(makeJoinConditionThrowExpressions)];
|
|
1994
|
+
return [makeJoinConditionThrowExpressions(condition.left), makeJoinConditionThrowExpressions(condition.right)];
|
|
1995
|
+
};
|
|
1996
|
+
//#endregion
|
|
1997
|
+
//#region src/generatorv2/codegen/ts/relationMap/makeJoinConditionValue.ts
|
|
1998
|
+
const qExpr = tsg.identifier("qe").importFrom("sasat");
|
|
1999
|
+
const parentTableAlias = "parentTableAlias";
|
|
2000
|
+
const childTableAlias = "childTableAlias";
|
|
2001
|
+
const makeJoinConditionValueQExpr = (node, cv) => {
|
|
2002
|
+
const arg = tsg.identifier("arg");
|
|
2003
|
+
switch (cv.kind) {
|
|
2004
|
+
case "parent": {
|
|
2005
|
+
const columnName = node.fields.find((it) => it.fieldName === cv.field)?.columnName || cv.field;
|
|
2006
|
+
return qExpr.property("field").call(arg.property(childTableAlias), tsg.string(columnName));
|
|
2007
|
+
}
|
|
2008
|
+
case "child": {
|
|
2009
|
+
const columnName = node.fields.find((it) => it.fieldName === cv.field)?.columnName || cv.field;
|
|
2010
|
+
return tsg.ternary(arg.property(parentTableAlias), qExpr.property("field").call(arg.property(parentTableAlias), tsg.string(columnName)), qExpr.property("value").call(arg.property("parent?").property(cv.field)));
|
|
2011
|
+
}
|
|
2012
|
+
default: return makeConditionValueQExpr(cv);
|
|
2013
|
+
}
|
|
2014
|
+
};
|
|
2015
|
+
const makeRangeCondition = (entity, range) => {
|
|
2016
|
+
if (range.kind === "range") return [makeJoinConditionValueQExpr(entity, range.begin), makeJoinConditionValueQExpr(entity, range.end)];
|
|
2017
|
+
return [tsg.spread(tsg.identifier("getDayRangeQExpr").importFrom("sasat").call(tsg.new(tsg.identifier("Date")), range.thresholdHour ? tsg.number(range.thresholdHour) : tsg.identifier("undefined")))];
|
|
2018
|
+
};
|
|
2019
|
+
const makeConditionExpr = (entity, condition) => {
|
|
2020
|
+
if (condition.kind === "custom") return tsg.identifier(condition.conditionName).importFrom("../conditions").call(tsg.identifier("arg"));
|
|
2021
|
+
if (condition.kind === "isNull") return qExpr.property(condition.not ? "isNotNull" : "isNull").call(makeJoinConditionValueQExpr(entity, condition.value));
|
|
2022
|
+
if (condition.operator === "BETWEEN") return qExpr.property("between").call(makeJoinConditionValueQExpr(entity, condition.left), ...makeRangeCondition(entity, condition.right));
|
|
2023
|
+
if (condition.operator === "IN") return qExpr.property("in").call(makeJoinConditionValueQExpr(entity, condition.left), tsg.array(condition.right.map((it) => makeConditionValueRaw(it))));
|
|
2024
|
+
return qExpr.property("comparison").call(makeJoinConditionValueQExpr(entity, condition.left), tsg.string(condition.operator), makeJoinConditionValueQExpr(entity, condition.right));
|
|
2025
|
+
};
|
|
2026
|
+
const makeJoinConditionValue = (node, ref) => {
|
|
2027
|
+
const arg = tsg.identifier("arg");
|
|
2028
|
+
return tsg.propertyAssign("condition", tsg.arrowFunc([tsg.parameter(arg.toString())], tsg.typeRef("BooleanValueExpression").importFrom("sasat"), tsg.block(...ref.joinCondition.flatMap((it) => makeThrowExpressions(it)).filter(nonNullable), tsg.return(qExpr.property("and").call(...ref.joinCondition.map((it) => makeConditionExpr(node, it)))))));
|
|
2029
|
+
};
|
|
2030
|
+
//#endregion
|
|
2031
|
+
//#region src/generatorv2/codegen/ts/relationMap/index.ts
|
|
2032
|
+
const generateRelationMap = (root) => {
|
|
2033
|
+
return new TsFile(makeRelationMap(root), makeTableInfo(root), ...root.entities.flatMap(entityRelationType)).disableEsLint();
|
|
2034
|
+
};
|
|
2035
|
+
const makeRelationMap = (root) => {
|
|
2036
|
+
return tsg.variable("const", tsg.identifier("relationMap"), tsg.object(...root.entities.map((it) => makeEntityRelationMap(it))), tsg.typeRef("RelationMap", [makeContextTypeRef("GENERATED")]).importFrom("sasat")).export();
|
|
2037
|
+
};
|
|
2038
|
+
const fieldNameToColumnNameAndFilterPrimary = (node) => (field) => {
|
|
2039
|
+
const column = node.fields.find((it) => it.fieldName === field || it.columnName === field);
|
|
2040
|
+
if (!column) throw new Error(`${node.name.name}.${field} Not Found`);
|
|
2041
|
+
if (column.isPrimary) return null;
|
|
2042
|
+
return column.columnName;
|
|
2043
|
+
};
|
|
2044
|
+
const makeEntityRelationMap = (node) => {
|
|
2045
|
+
return tsg.propertyAssign(node.tableName, tsg.object(...node.references.map((ref) => {
|
|
2046
|
+
const toColumnName = fieldNameToColumnNameAndFilterPrimary(ref.entity);
|
|
2047
|
+
return tsg.propertyAssign(ref.fieldName, tsg.object(tsg.propertyAssign("table", tsg.string(ref.parentTableName)), makeJoinConditionValue(node, ref), tsg.propertyAssign("array", tsg.boolean(ref.isArray)), tsg.propertyAssign("nullable", tsg.boolean(ref.isNullable)), tsg.propertyAssign("requiredColumns", tsg.array(getChildRequiredNames(ref).map(toColumnName).filter(nonNullable).map(tsg.string)))));
|
|
2048
|
+
}), ...node.referencedBy.map((rel) => {
|
|
2049
|
+
const toColumnName = fieldNameToColumnNameAndFilterPrimary(rel.entity);
|
|
2050
|
+
return tsg.propertyAssign(rel.fieldName, tsg.object(tsg.propertyAssign("table", tsg.string(rel.childTable)), makeJoinConditionValue(node, rel), tsg.propertyAssign("array", tsg.boolean(rel.isArray)), tsg.propertyAssign("nullable", tsg.boolean(rel.isNullable)), tsg.propertyAssign("requiredColumns", tsg.array(getChildRequiredNames(rel).map(toColumnName).filter(nonNullable).map(tsg.string)))));
|
|
2051
|
+
})));
|
|
2052
|
+
};
|
|
2053
|
+
const makeTableInfo = (root) => {
|
|
2054
|
+
const columnMap = (entity) => tsg.propertyAssign("columnMap", tsg.object(...entity.fields.map((field) => tsg.propertyAssign(field.fieldName, tsg.string(field.columnName)))));
|
|
2055
|
+
return tsg.variable("const", "tableInfo", tsg.object(...root.entities.map((entity) => tsg.propertyAssign(entity.tableName, tsg.object(tsg.propertyAssign("identifiableKeys", tsg.array(entity.identifyKeys.map(tsg.string))), tsg.propertyAssign("identifiableFields", tsg.array(entity.fields.filter((it) => it.isPrimary).map((it) => it.fieldName).map(tsg.string))), columnMap(entity))))), tsg.typeRef("TableInfo").importFrom("sasat")).export();
|
|
2056
|
+
};
|
|
2057
|
+
const referenceRelationType = (ref) => {
|
|
2058
|
+
const parentEntityName = EntityName.fromTableName(ref.parentTableName);
|
|
2059
|
+
const type = tsg.typeRef("EntityResult", [tsg.typeRef(parentEntityName.entityWithRelationTypeName()), tsg.typeRef(parentEntityName.relationTypeName())]).importFrom("sasat");
|
|
2060
|
+
return tsg.propertySignature(ref.fieldName, ref.isArray ? tsg.arrayType(type) : type);
|
|
2061
|
+
};
|
|
2062
|
+
const referencedRelationType = (node) => {
|
|
2063
|
+
const child = EntityName.fromTableName(node.childTable);
|
|
2064
|
+
const type = tsg.typeRef("EntityResult", [tsg.typeRef(child.entityWithRelationTypeName()), makeTypeRef(child, "identifiable", "GENERATED")]).importFrom("sasat");
|
|
2065
|
+
return tsg.propertySignature(node.fieldName, node.isArray ? tsg.arrayType(type) : type);
|
|
2066
|
+
};
|
|
2067
|
+
const entityRelationType = (node) => {
|
|
2068
|
+
const typeProperties = [...node.references.map(referenceRelationType), ...node.referencedBy.map(referencedRelationType)];
|
|
2069
|
+
return [
|
|
2070
|
+
tsg.typeAlias(node.name.relationTypeName(), typeProperties.length !== 0 ? tsg.typeLiteral(typeProperties) : tsg.typeRef("Record<never, never>")).export(),
|
|
2071
|
+
tsg.typeAlias(node.name.entityWithRelationTypeName(), tsg.intersectionType(makeTypeRef(node.name, "entity", "GENERATED"), tsg.typeRef(node.name.relationTypeName()))).export(),
|
|
2072
|
+
tsg.typeAlias(node.name.resultType(), tsg.typeRef("EntityResult", [tsg.typeRef(node.name.entityWithRelationTypeName()), makeTypeRef(node.name, "identifiable", "GENERATED")]).importFrom("sasat")).export()
|
|
2073
|
+
];
|
|
2074
|
+
};
|
|
2075
|
+
//#endregion
|
|
2076
|
+
//#region src/generatorv2/codegen/ts/staticFiles.ts
|
|
2077
|
+
const contextFile = `\
|
|
2078
|
+
${new ImportDeclaration(["BaseGQLContext"], "./__generated__/context").toString()}
|
|
2079
|
+
export type GQLContext = BaseGQLContext & Record<string, never>;
|
|
2080
|
+
`;
|
|
2081
|
+
const pubsubFile = `\
|
|
2082
|
+
${new ImportDeclaration(["PubSub", "PubSubEngine"], "graphql-subscriptions").toString()}
|
|
2083
|
+
|
|
2084
|
+
export const pubsub: PubSubEngine = new PubSub();
|
|
2085
|
+
`;
|
|
2086
|
+
const schemaFile = `\
|
|
2087
|
+
${new ImportDeclaration(["assignDeep", "createTypeDef"], "sasat").toString()}
|
|
2088
|
+
${new ImportDeclaration(["typeDefs", "inputs"], "./__generated__/typeDefs").toString()}
|
|
2089
|
+
${new ImportDeclaration(["resolvers"], "./__generated__/resolver").toString()}
|
|
2090
|
+
|
|
2091
|
+
export const schema = {
|
|
2092
|
+
typeDefs: createTypeDef(
|
|
2093
|
+
assignDeep(typeDefs, {}),
|
|
2094
|
+
assignDeep(inputs, {}),
|
|
2095
|
+
),
|
|
2096
|
+
resolvers: assignDeep(resolvers, {}),
|
|
2097
|
+
};
|
|
2098
|
+
`;
|
|
2099
|
+
const baseDBDataSourceFile = `\
|
|
2100
|
+
${new ImportDeclaration([
|
|
2101
|
+
"Fields",
|
|
2102
|
+
"SasatDBDatasource",
|
|
2103
|
+
"EntityType"
|
|
2104
|
+
], "sasat").toString()}
|
|
2105
|
+
${new ImportDeclaration(["relationMap", "tableInfo"], "./__generated__/relationMap").toString()}
|
|
2106
|
+
|
|
2107
|
+
export abstract class BaseDBDataSource<
|
|
2108
|
+
Entity extends EntityType,
|
|
2109
|
+
Identifiable extends object,
|
|
2110
|
+
Creatable extends EntityType,
|
|
2111
|
+
Updatable extends Identifiable,
|
|
2112
|
+
EntityFields extends Fields<Entity>,
|
|
2113
|
+
QueryResult extends Partial<Entity> & Identifiable,
|
|
2114
|
+
> extends SasatDBDatasource<Entity, Identifiable, Creatable, Updatable, EntityFields, QueryResult> {
|
|
2115
|
+
protected relationMap = relationMap;
|
|
2116
|
+
protected tableInfo = tableInfo;
|
|
2117
|
+
}
|
|
2118
|
+
`;
|
|
2119
|
+
const staticFiles = [
|
|
2120
|
+
{
|
|
2121
|
+
name: "context",
|
|
2122
|
+
body: contextFile
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
name: "pubsub",
|
|
2126
|
+
body: pubsubFile
|
|
2127
|
+
},
|
|
2128
|
+
{
|
|
2129
|
+
name: "schema",
|
|
2130
|
+
body: schemaFile
|
|
2131
|
+
},
|
|
2132
|
+
{
|
|
2133
|
+
name: "baseDBDataSource",
|
|
2134
|
+
body: baseDBDataSourceFile
|
|
2135
|
+
}
|
|
2136
|
+
];
|
|
2137
|
+
//#endregion
|
|
2138
|
+
//#region src/generatorv2/codegen/tscodegen_v2.ts
|
|
2139
|
+
var TsCodegen_v2 = class {
|
|
2140
|
+
constructor() {
|
|
2141
|
+
this.fileExtension = "ts";
|
|
2142
|
+
this.generateEntity = (node) => generateEntityFile(node).generate();
|
|
2143
|
+
this.generateDatasource = (node) => generateDatasource(node).generate();
|
|
2144
|
+
this.generateGeneratedDatasource = (node) => generateAutoGeneratedDatasource(node).generate();
|
|
2145
|
+
this.generateGqlTypeDefs = (root) => generateTypeDefs(root).generate();
|
|
2146
|
+
this.generateGqlResolver = (root) => generateResolver(root).generate();
|
|
2147
|
+
this.generateGqlQuery = (root) => generateQueryResolver(root).generate();
|
|
2148
|
+
this.generateGqlMutation = (root) => generateMutationResolver(root).generate();
|
|
2149
|
+
this.generateGqlSubscription = (root) => generateSubscription(root).generate();
|
|
2150
|
+
this.generateGQLContext = (root) => generateContext(root).generate();
|
|
2151
|
+
this.generateFiles = async (root) => {
|
|
2152
|
+
return [{
|
|
2153
|
+
name: "relationMap",
|
|
2154
|
+
body: await generateRelationMap(root).generate()
|
|
2155
|
+
}, {
|
|
2156
|
+
name: "fields",
|
|
2157
|
+
body: await generateFields(root).generate()
|
|
2158
|
+
}];
|
|
2159
|
+
};
|
|
2160
|
+
this.generateOnceFiles = () => {
|
|
2161
|
+
return staticFiles;
|
|
2162
|
+
};
|
|
2163
|
+
this.generateConditions = (root, currentFile) => {
|
|
2164
|
+
return generateUserDefinedCondition(root, currentFile);
|
|
2165
|
+
};
|
|
2166
|
+
this.generateIDEncoders = (root, currentFile) => {
|
|
2167
|
+
return generateIDEncoder(root, currentFile);
|
|
2168
|
+
};
|
|
2169
|
+
this.generateMiddlewares = (root, currentFile) => {
|
|
2170
|
+
return generateMiddlewares(root, currentFile);
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
//#endregion
|
|
2175
|
+
//#region src/generatorv2/parser/makeContextNodes.ts
|
|
2176
|
+
const makeContextNodes = (store) => {
|
|
2177
|
+
return store.tables.flatMap((table) => {
|
|
2178
|
+
return table.gqlOption.mutations.flatMap((mutation) => mutation.contextFields.map((it) => ({
|
|
2179
|
+
name: it.contextName || it.column,
|
|
2180
|
+
dbtype: table.column(it.column).dataType()
|
|
2181
|
+
})));
|
|
2182
|
+
});
|
|
2183
|
+
};
|
|
2184
|
+
//#endregion
|
|
2185
|
+
//#region src/generatorv2/parser/makeMutationNodes.ts
|
|
2186
|
+
const makeEntityMutationNodes = (table, entity) => {
|
|
2187
|
+
if (!table.gqlOption.enabled) return [];
|
|
2188
|
+
return table.gqlOption.mutations.map((mutation) => {
|
|
2189
|
+
switch (mutation.type) {
|
|
2190
|
+
case "create": return makeCreateMutationNode(table, entity, mutation);
|
|
2191
|
+
case "update": return makeUpdateMutationNode(table, entity, mutation);
|
|
2192
|
+
case "delete": return makeDeleteMutationNode(table, entity, mutation);
|
|
2193
|
+
default: throw new Error(`invalid mutation type: ${mutation.type}`);
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
};
|
|
2197
|
+
const makeContextField = (params) => ({
|
|
2198
|
+
fieldName: params.column,
|
|
2199
|
+
contextName: params.contextName || params.column
|
|
2200
|
+
});
|
|
2201
|
+
const makeCreateMutationNode = (table, entity, mutation) => {
|
|
2202
|
+
return {
|
|
2203
|
+
entity,
|
|
2204
|
+
contextFields: mutation.contextFields.map(makeContextField),
|
|
2205
|
+
entityName: table.getEntityName(),
|
|
2206
|
+
identifyFields: table.getPrimaryKeyColumns().map((it) => it.fieldName()),
|
|
2207
|
+
mutationName: `create${table.getEntityName().name}`,
|
|
2208
|
+
inputName: entity.name.createInputName(),
|
|
2209
|
+
refetch: !mutation.noReFetch,
|
|
2210
|
+
returnType: {
|
|
2211
|
+
typeName: table.getEntityName().name,
|
|
2212
|
+
nullable: false,
|
|
2213
|
+
array: false,
|
|
2214
|
+
entity: true
|
|
2215
|
+
},
|
|
2216
|
+
args: [{
|
|
2217
|
+
name: table.getEntityName().lowerCase(),
|
|
2218
|
+
type: {
|
|
2219
|
+
typeName: table.getEntityName().createInputName(),
|
|
2220
|
+
nullable: false,
|
|
2221
|
+
array: false,
|
|
2222
|
+
entity: true
|
|
2223
|
+
}
|
|
2224
|
+
}],
|
|
2225
|
+
mutationType: "create",
|
|
2226
|
+
subscription: mutation.subscription.enabled,
|
|
2227
|
+
requireIdDecodeMiddleware: entity.creatable.fields.some((it) => it.hashId),
|
|
2228
|
+
middlewares: mutation.middlewares
|
|
2229
|
+
};
|
|
2230
|
+
};
|
|
2231
|
+
const makeUpdateMutationNode = (table, entity, mutation) => {
|
|
2232
|
+
return {
|
|
2233
|
+
entity,
|
|
2234
|
+
contextFields: mutation.contextFields.map(makeContextField),
|
|
2235
|
+
entityName: table.getEntityName(),
|
|
2236
|
+
identifyFields: table.getPrimaryKeyColumns().map((it) => it.fieldName()),
|
|
2237
|
+
mutationName: `update${table.getEntityName().name}`,
|
|
2238
|
+
inputName: entity.name.updateInputName(),
|
|
2239
|
+
refetch: !mutation.noReFetch,
|
|
2240
|
+
returnType: {
|
|
2241
|
+
typeName: mutation.noReFetch ? "Boolean" : table.getEntityName().name,
|
|
2242
|
+
dbType: mutation.noReFetch ? "boolean" : void 0,
|
|
2243
|
+
nullable: false,
|
|
2244
|
+
array: false,
|
|
2245
|
+
entity: !mutation.noReFetch
|
|
2246
|
+
},
|
|
2247
|
+
args: [{
|
|
2248
|
+
name: table.getEntityName().lowerCase(),
|
|
2249
|
+
type: {
|
|
2250
|
+
typeName: table.getEntityName().updateInputName(),
|
|
2251
|
+
nullable: false,
|
|
2252
|
+
array: false,
|
|
2253
|
+
entity: true
|
|
2254
|
+
}
|
|
2255
|
+
}],
|
|
2256
|
+
mutationType: "update",
|
|
2257
|
+
subscription: mutation.subscription.enabled,
|
|
2258
|
+
requireIdDecodeMiddleware: entity.updateInput.fields.some((it) => it.hashId),
|
|
2259
|
+
middlewares: mutation.middlewares
|
|
2260
|
+
};
|
|
2261
|
+
};
|
|
2262
|
+
const makeDeleteMutationNode = (table, entity, mutation) => {
|
|
2263
|
+
return {
|
|
2264
|
+
entity,
|
|
2265
|
+
mutationName: `delete${table.getEntityName().name}`,
|
|
2266
|
+
inputName: entity.name.identifyInputName(),
|
|
2267
|
+
contextFields: mutation.contextFields.map(makeContextField),
|
|
2268
|
+
entityName: table.getEntityName(),
|
|
2269
|
+
identifyFields: table.getPrimaryKeyColumns().map((it) => it.fieldName()),
|
|
2270
|
+
refetch: false,
|
|
2271
|
+
returnType: {
|
|
2272
|
+
typeName: "Boolean",
|
|
2273
|
+
dbType: "boolean",
|
|
2274
|
+
nullable: false,
|
|
2275
|
+
array: false,
|
|
2276
|
+
entity: false
|
|
2277
|
+
},
|
|
2278
|
+
args: [{
|
|
2279
|
+
name: table.getEntityName().lowerCase(),
|
|
2280
|
+
type: {
|
|
2281
|
+
typeName: table.getEntityName().identifyInputName(),
|
|
2282
|
+
nullable: false,
|
|
2283
|
+
array: false,
|
|
2284
|
+
entity: true
|
|
2285
|
+
}
|
|
2286
|
+
}],
|
|
2287
|
+
mutationType: "delete",
|
|
2288
|
+
subscription: mutation.subscription.enabled,
|
|
2289
|
+
requireIdDecodeMiddleware: entity.identifyFields().some((it) => it.hashId),
|
|
2290
|
+
middlewares: mutation.middlewares
|
|
2291
|
+
};
|
|
2292
|
+
};
|
|
2293
|
+
//#endregion
|
|
2294
|
+
//#region src/generatorv2/scripts/columnToGqlType.ts
|
|
2295
|
+
const columnTypeToGqlPrimitive = (type) => {
|
|
2296
|
+
switch (type) {
|
|
2297
|
+
case "tinyint":
|
|
2298
|
+
case "smallint":
|
|
2299
|
+
case "mediumint":
|
|
2300
|
+
case "int":
|
|
2301
|
+
case "bigint":
|
|
2302
|
+
case "decimal":
|
|
2303
|
+
case "year": return "Int";
|
|
2304
|
+
case "float":
|
|
2305
|
+
case "double": return "Float";
|
|
2306
|
+
case "char":
|
|
2307
|
+
case "varchar":
|
|
2308
|
+
case "text":
|
|
2309
|
+
case "time":
|
|
2310
|
+
case "date":
|
|
2311
|
+
case "datetime":
|
|
2312
|
+
case "timestamp": return "String";
|
|
2313
|
+
case "boolean": return "Boolean";
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
//#endregion
|
|
2317
|
+
//#region src/generatorv2/nodes/FieldNode.ts
|
|
2318
|
+
const getHashId = (store, entity, column) => {
|
|
2319
|
+
if (!column.isReference()) {
|
|
2320
|
+
if (column.data.option.autoIncrementHashId) return { encoder: entity.IDEncoderName() };
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
const ref = column.data.reference;
|
|
2324
|
+
const parent = store.table(ref.parentTable);
|
|
2325
|
+
if (!parent.column(ref.parentColumn).data.option.autoIncrementHashId) return void 0;
|
|
2326
|
+
return { encoder: parent.getEntityName().IDEncoderName() };
|
|
2327
|
+
};
|
|
2328
|
+
const makeFieldNode = (store, entity, column) => {
|
|
2329
|
+
const hashId = getHashId(store, entity.name, column);
|
|
2330
|
+
return {
|
|
2331
|
+
entity,
|
|
2332
|
+
fieldName: column.fieldName(),
|
|
2333
|
+
columnName: column.columnName(),
|
|
2334
|
+
gqlType: hashId ? "ID" : column.gqlType(),
|
|
2335
|
+
dbType: column.dataType(),
|
|
2336
|
+
isAutoIncrement: column.data.autoIncrement,
|
|
2337
|
+
isArray: false,
|
|
2338
|
+
isPrimary: column.isPrimary(),
|
|
2339
|
+
isNullable: column.isNullable(),
|
|
2340
|
+
isUpdatable: !(column.data.onUpdateCurrentTimeStamp || column.isPrimary()) && column.data.option.updatable,
|
|
2341
|
+
isGQLOpen: true,
|
|
2342
|
+
column: column.data,
|
|
2343
|
+
option: column.data.option,
|
|
2344
|
+
hashId
|
|
2345
|
+
};
|
|
2346
|
+
};
|
|
2347
|
+
const makeCreatableFieldNode = (store, entity, column) => {
|
|
2348
|
+
if (column.data.autoIncrement || column.data.defaultCurrentTimeStamp) return null;
|
|
2349
|
+
const hashId = getHashId(store, entity.name, column);
|
|
2350
|
+
return {
|
|
2351
|
+
entity,
|
|
2352
|
+
fieldName: column.fieldName(),
|
|
2353
|
+
columnName: column.columnName(),
|
|
2354
|
+
gqlType: hashId ? "ID" : column.gqlType(),
|
|
2355
|
+
dbType: column.dataType(),
|
|
2356
|
+
isAutoIncrement: column.data.autoIncrement,
|
|
2357
|
+
isArray: false,
|
|
2358
|
+
isPrimary: column.isPrimary(),
|
|
2359
|
+
isNullable: column.isNullableOnCreate(),
|
|
2360
|
+
isUpdatable: column.isUpdatable(),
|
|
2361
|
+
isGQLOpen: !(column.table.gqlOption.mutations.find((it) => it.type === "create")?.contextFields || []).some((it) => it.column === column.columnName()),
|
|
2362
|
+
column: column.data,
|
|
2363
|
+
option: column.data.option,
|
|
2364
|
+
hashId: getHashId(store, entity.name, column)
|
|
2365
|
+
};
|
|
2366
|
+
};
|
|
2367
|
+
const makeUpdatableFieldNode = (store, entity, column) => {
|
|
2368
|
+
if (!column.isUpdatable() || !column.data.option.updatable) return null;
|
|
2369
|
+
const hashId = getHashId(store, entity.name, column);
|
|
2370
|
+
return {
|
|
2371
|
+
entity,
|
|
2372
|
+
fieldName: column.fieldName(),
|
|
2373
|
+
columnName: column.columnName(),
|
|
2374
|
+
gqlType: hashId ? "ID" : column.gqlType(),
|
|
2375
|
+
dbType: column.dataType(),
|
|
2376
|
+
isAutoIncrement: column.data.autoIncrement,
|
|
2377
|
+
isArray: false,
|
|
2378
|
+
isNullable: true,
|
|
2379
|
+
isPrimary: false,
|
|
2380
|
+
isUpdatable: true,
|
|
2381
|
+
isGQLOpen: !(column.table.gqlOption.mutations.find((it) => it.type === "update")?.contextFields || []).some((it) => it.column === column.columnName()),
|
|
2382
|
+
column: column.data,
|
|
2383
|
+
option: column.data.option,
|
|
2384
|
+
hashId: getHashId(store, entity.name, column)
|
|
2385
|
+
};
|
|
2386
|
+
};
|
|
2387
|
+
//#endregion
|
|
2388
|
+
//#region src/migration/makeCondition.ts
|
|
2389
|
+
const parent = (field) => ({
|
|
2390
|
+
kind: "parent",
|
|
2391
|
+
field
|
|
2392
|
+
});
|
|
2393
|
+
const child = (field) => ({
|
|
2394
|
+
kind: "child",
|
|
2395
|
+
field
|
|
2396
|
+
});
|
|
2397
|
+
const contextOrError = (field, errorMessage) => ({
|
|
2398
|
+
kind: "context",
|
|
2399
|
+
field,
|
|
2400
|
+
onNotDefined: {
|
|
2401
|
+
action: "error",
|
|
2402
|
+
message: errorMessage
|
|
2403
|
+
}
|
|
2404
|
+
});
|
|
2405
|
+
const contextOrDefault = (field, defaultValue) => ({
|
|
2406
|
+
kind: "context",
|
|
2407
|
+
field,
|
|
2408
|
+
onNotDefined: {
|
|
2409
|
+
action: "defaultValue",
|
|
2410
|
+
value: defaultValue
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2413
|
+
const fixed = (value) => ({
|
|
2414
|
+
kind: "fixed",
|
|
2415
|
+
value
|
|
2416
|
+
});
|
|
2417
|
+
const today = (thresholdHour, date) => ({
|
|
2418
|
+
kind: "today",
|
|
2419
|
+
type: date ? "date" : "datetime",
|
|
2420
|
+
thresholdHour
|
|
2421
|
+
});
|
|
2422
|
+
const now = () => ({ kind: "now" });
|
|
2423
|
+
const values = (begin, end) => ({
|
|
2424
|
+
kind: "range",
|
|
2425
|
+
begin,
|
|
2426
|
+
end
|
|
2427
|
+
});
|
|
2428
|
+
const betweenToday = (thresholdHour) => ({
|
|
2429
|
+
kind: "date-range",
|
|
2430
|
+
range: "today",
|
|
2431
|
+
thresholdHour
|
|
2432
|
+
});
|
|
2433
|
+
const custom = (conditionName, parentRequiredFields, childRequiredFields) => ({
|
|
2434
|
+
kind: "custom",
|
|
2435
|
+
conditionName,
|
|
2436
|
+
parentRequiredFields,
|
|
2437
|
+
childRequiredFields
|
|
2438
|
+
});
|
|
2439
|
+
const field = (column) => ({
|
|
2440
|
+
kind: "field",
|
|
2441
|
+
column
|
|
2442
|
+
});
|
|
2443
|
+
const arg = (name, type) => ({
|
|
2444
|
+
kind: "arg",
|
|
2445
|
+
name,
|
|
2446
|
+
type
|
|
2447
|
+
});
|
|
2448
|
+
const betweenRel = (left, range) => ({
|
|
2449
|
+
kind: "comparison",
|
|
2450
|
+
left,
|
|
2451
|
+
operator: "BETWEEN",
|
|
2452
|
+
right: range
|
|
2453
|
+
});
|
|
2454
|
+
const betweenQuery = (left, begin, end) => ({
|
|
2455
|
+
kind: "between",
|
|
2456
|
+
operator: "BETWEEN",
|
|
2457
|
+
left,
|
|
2458
|
+
begin,
|
|
2459
|
+
end
|
|
2460
|
+
});
|
|
2461
|
+
const comparisonRel = (left, operator, right) => ({
|
|
2462
|
+
kind: "comparison",
|
|
2463
|
+
left,
|
|
2464
|
+
right,
|
|
2465
|
+
operator
|
|
2466
|
+
});
|
|
2467
|
+
const inRel = (left, right) => ({
|
|
2468
|
+
kind: "comparison",
|
|
2469
|
+
left,
|
|
2470
|
+
right,
|
|
2471
|
+
operator: "IN"
|
|
2472
|
+
});
|
|
2473
|
+
const isNullRel = (value) => ({
|
|
2474
|
+
kind: "isNull",
|
|
2475
|
+
value,
|
|
2476
|
+
not: false
|
|
2477
|
+
});
|
|
2478
|
+
const isNotNullRel = (value) => ({
|
|
2479
|
+
kind: "isNull",
|
|
2480
|
+
value,
|
|
2481
|
+
not: true
|
|
2482
|
+
});
|
|
2483
|
+
const comparisonQuery = (left, operator, right) => ({
|
|
2484
|
+
kind: "comparison",
|
|
2485
|
+
left,
|
|
2486
|
+
right,
|
|
2487
|
+
operator
|
|
2488
|
+
});
|
|
2489
|
+
const Conditions = {
|
|
2490
|
+
betweenRel,
|
|
2491
|
+
betweenQuery,
|
|
2492
|
+
custom,
|
|
2493
|
+
rel: {
|
|
2494
|
+
between: betweenRel,
|
|
2495
|
+
comparison: comparisonRel,
|
|
2496
|
+
in: inRel,
|
|
2497
|
+
isNull: isNullRel,
|
|
2498
|
+
isNotNull: isNotNullRel
|
|
2499
|
+
},
|
|
2500
|
+
query: {
|
|
2501
|
+
between: betweenQuery,
|
|
2502
|
+
comparison: comparisonQuery
|
|
2503
|
+
},
|
|
2504
|
+
value: {
|
|
2505
|
+
parent,
|
|
2506
|
+
child,
|
|
2507
|
+
contextOrError,
|
|
2508
|
+
contextOrDefault,
|
|
2509
|
+
fixed,
|
|
2510
|
+
today,
|
|
2511
|
+
now,
|
|
2512
|
+
field,
|
|
2513
|
+
arg
|
|
2514
|
+
},
|
|
2515
|
+
range: {
|
|
2516
|
+
values,
|
|
2517
|
+
today: betweenToday
|
|
2518
|
+
}
|
|
2519
|
+
};
|
|
2520
|
+
//#endregion
|
|
2521
|
+
//#region src/generatorv2/nodes/ReferencedNode.ts
|
|
2522
|
+
var ReferenceNode = class ReferenceNode {
|
|
2523
|
+
static fromReference(entity, column, parentTable) {
|
|
2524
|
+
const ref = column.data.reference;
|
|
2525
|
+
if (!ref.fieldName) return null;
|
|
2526
|
+
return new ReferenceNode(entity, ref.fieldName, column.table.tableName, ref.parentTable, makeJoinCondition(ref.parentColumn, column.columnName()), false, column.isNullable(), column.isPrimary(), column.table.gqlOption.enabled && parentTable.gqlOption.enabled);
|
|
2527
|
+
}
|
|
2528
|
+
static formVirtualRelation(ds, entity, rel) {
|
|
2529
|
+
if (!rel.childFieldName) return null;
|
|
2530
|
+
return new ReferenceNode(entity, rel.childFieldName, rel.childTable, rel.parentTable, rel.conditions, rel.childType === void 0 || rel.childType === "array", rel.childType === "nullable", false, ds.table(rel.parentTable).gqlOption.enabled && ds.table(rel.childTable).gqlOption.enabled);
|
|
2531
|
+
}
|
|
2532
|
+
constructor(entity, fieldName, tableName, parentTableName, joinCondition, isArray, isNullable, isPrimary, isGQLOpen) {
|
|
2533
|
+
this.entity = entity;
|
|
2534
|
+
this.fieldName = fieldName;
|
|
2535
|
+
this.tableName = tableName;
|
|
2536
|
+
this.parentTableName = parentTableName;
|
|
2537
|
+
this.joinCondition = joinCondition;
|
|
2538
|
+
this.isArray = isArray;
|
|
2539
|
+
this.isNullable = isNullable;
|
|
2540
|
+
this.isPrimary = isPrimary;
|
|
2541
|
+
this.isGQLOpen = isGQLOpen;
|
|
2542
|
+
}
|
|
2543
|
+
};
|
|
2544
|
+
var ReferencedNode = class ReferencedNode {
|
|
2545
|
+
static fromReference(entity, parentTable, column) {
|
|
2546
|
+
const ref = column.data.reference;
|
|
2547
|
+
if (!ref.parentFieldName) return null;
|
|
2548
|
+
return new ReferencedNode(entity, ref.parentFieldName, column.table.tableName, makeJoinCondition(column.columnName(), ref.parentColumn), ref.relation === "Many", ref.relation === "OneOrZero", column.isPrimary(), parentTable.gqlOption.enabled && column.table.gqlOption.enabled);
|
|
2549
|
+
}
|
|
2550
|
+
static fromVirtualRelation(ds, entity, rel) {
|
|
2551
|
+
if (!rel.parentFieldName) return null;
|
|
2552
|
+
return new ReferencedNode(entity, rel.parentFieldName, rel.childTable, rel.conditions.map(reverseConditionNode), rel.parentType === void 0 || rel.parentType === "array", rel.parentType === "nullable", false, ds.table(rel.parentTable).gqlOption.enabled && ds.table(rel.childTable).gqlOption.enabled);
|
|
2553
|
+
}
|
|
2554
|
+
constructor(entity, fieldName, childTable, joinCondition, isArray, isNullable, isPrimary, isGQLOpen) {
|
|
2555
|
+
this.entity = entity;
|
|
2556
|
+
this.fieldName = fieldName;
|
|
2557
|
+
this.childTable = childTable;
|
|
2558
|
+
this.joinCondition = joinCondition;
|
|
2559
|
+
this.isArray = isArray;
|
|
2560
|
+
this.isNullable = isNullable;
|
|
2561
|
+
this.isPrimary = isPrimary;
|
|
2562
|
+
this.isGQLOpen = isGQLOpen;
|
|
2563
|
+
}
|
|
2564
|
+
};
|
|
2565
|
+
const reverseConditionValue = (cv) => {
|
|
2566
|
+
if (cv.kind === "parent") return {
|
|
2567
|
+
...cv,
|
|
2568
|
+
kind: "child"
|
|
2569
|
+
};
|
|
2570
|
+
else if (cv.kind === "child") return {
|
|
2571
|
+
...cv,
|
|
2572
|
+
kind: "parent"
|
|
2573
|
+
};
|
|
2574
|
+
return cv;
|
|
2575
|
+
};
|
|
2576
|
+
const reverseRangeCondition = (condition) => {
|
|
2577
|
+
if (condition.kind === "range") return {
|
|
2578
|
+
kind: condition.kind,
|
|
2579
|
+
begin: reverseConditionValue(condition.begin),
|
|
2580
|
+
end: reverseConditionValue(condition.end)
|
|
2581
|
+
};
|
|
2582
|
+
return condition;
|
|
2583
|
+
};
|
|
2584
|
+
const reverseConditionNode = (condition) => {
|
|
2585
|
+
if (condition.kind === "custom") return {
|
|
2586
|
+
...condition,
|
|
2587
|
+
parentRequiredFields: condition.childRequiredFields,
|
|
2588
|
+
childRequiredFields: condition.parentRequiredFields
|
|
2589
|
+
};
|
|
2590
|
+
if (condition.kind === "isNull") {
|
|
2591
|
+
if (condition.not) return Conditions.rel.isNotNull(reverseConditionValue(condition.value));
|
|
2592
|
+
return Conditions.rel.isNull(reverseConditionValue(condition.value));
|
|
2593
|
+
}
|
|
2594
|
+
if (condition.operator === "BETWEEN") return Conditions.rel.between(reverseConditionValue(condition.left), reverseRangeCondition(condition.right));
|
|
2595
|
+
if (condition.operator === "IN") return Conditions.rel.in(reverseConditionValue(condition.left), condition.right.map(reverseConditionValue));
|
|
2596
|
+
return Conditions.rel.comparison(reverseConditionValue(condition.right), condition.operator, reverseConditionValue(condition.left));
|
|
2597
|
+
};
|
|
2598
|
+
const makeJoinCondition = (parentColumn, childColumn) => {
|
|
2599
|
+
return [Conditions.rel.comparison(Conditions.value.parent(parentColumn), "=", Conditions.value.child(childColumn))];
|
|
2600
|
+
};
|
|
2601
|
+
//#endregion
|
|
2602
|
+
//#region src/generatorv2/nodes/entityNode.ts
|
|
2603
|
+
var EntityNode = class {
|
|
2604
|
+
constructor(store, table) {
|
|
2605
|
+
this.name = EntityName.fromTableName(table.tableName);
|
|
2606
|
+
this.fields = table.columns.map((it) => makeFieldNode(store, this, it));
|
|
2607
|
+
this.tableName = table.tableName;
|
|
2608
|
+
this.gqlEnabled = table.gqlOption.enabled;
|
|
2609
|
+
this.identifyKeys = table.primaryKey;
|
|
2610
|
+
this.queries = table.gqlOption.queries;
|
|
2611
|
+
this.creatable = {
|
|
2612
|
+
gqlEnabled: table.gqlOption.enabled && table.gqlOption.mutations.find((it) => it.type === "create") !== void 0,
|
|
2613
|
+
fields: table.columns.map((it) => makeCreatableFieldNode(store, this, it)).filter(nonNullable)
|
|
2614
|
+
};
|
|
2615
|
+
this.updateInput = {
|
|
2616
|
+
gqlEnabled: table.gqlOption.enabled && table.gqlOption.mutations.find((it) => it.type === "update") !== void 0,
|
|
2617
|
+
fields: [...this.fields.filter((it) => it.isPrimary), ...table.columns.map((it) => makeUpdatableFieldNode(store, this, it)).filter(nonNullable)]
|
|
2618
|
+
};
|
|
2619
|
+
this.references = table.getReferenceColumns().map((column) => ReferenceNode.fromReference(this, column, store.table(column.data.reference.parentTable))).concat(table.virtualRelations.map((it) => ReferenceNode.formVirtualRelation(store, this, it))).filter(nonNullable);
|
|
2620
|
+
this.referencedBy = store.referencedBy(table.tableName).map((column) => ReferencedNode.fromReference(this, table, column)).concat(store.virtualReferencedBy(table.tableName).map((rel) => ReferencedNode.fromVirtualRelation(store, this, rel))).filter(nonNullable);
|
|
2621
|
+
const makeFindMethodNode = (columns, isArray) => {
|
|
2622
|
+
const fields = columns.map((column) => this.fields.find((it) => it.columnName === column));
|
|
2623
|
+
return {
|
|
2624
|
+
name: makeFindQueryName(fields.map((it) => it.fieldName)),
|
|
2625
|
+
params: fields.map((it) => makePrimitiveParameterNode(it.fieldName, it.columnName, it.dbType)),
|
|
2626
|
+
isArray
|
|
2627
|
+
};
|
|
2628
|
+
};
|
|
2629
|
+
this.findMethods = [makeFindMethodNode(table.primaryKey, false)];
|
|
2630
|
+
this.mutations = makeEntityMutationNodes(table, this);
|
|
2631
|
+
}
|
|
2632
|
+
identifyFields() {
|
|
2633
|
+
return this.fields.filter((it) => it.isPrimary);
|
|
2634
|
+
}
|
|
2635
|
+
primaryQueryName() {
|
|
2636
|
+
return makeFindQueryName(this.identifyFields().map((it) => it.fieldName));
|
|
2637
|
+
}
|
|
2638
|
+
};
|
|
2639
|
+
const makePrimitiveParameterNode = (fieldName, columnName, dbtype) => ({
|
|
2640
|
+
entity: false,
|
|
2641
|
+
fieldName,
|
|
2642
|
+
columnName,
|
|
2643
|
+
dbtype,
|
|
2644
|
+
gqltype: columnTypeToGqlPrimitive(dbtype)
|
|
2645
|
+
});
|
|
2646
|
+
//#endregion
|
|
2647
|
+
//#region src/generatorv2/parser/makeEntityNodes.ts
|
|
2648
|
+
const makeEntityNodes = (store) => {
|
|
2649
|
+
const make = makeEntityNode(store);
|
|
2650
|
+
return store.tables.map(make);
|
|
2651
|
+
};
|
|
2652
|
+
const makeEntityNode = (store) => (table) => {
|
|
2653
|
+
return new EntityNode(store, table);
|
|
2654
|
+
};
|
|
2655
|
+
//#endregion
|
|
2656
|
+
//#region src/generatorv2/parser/makeSubscriptionNode.ts
|
|
2657
|
+
const makeSubscriptionNodes = (store) => {
|
|
2658
|
+
return store.tables.flatMap((table) => {
|
|
2659
|
+
return table.gqlOption.mutations.map((it) => {
|
|
2660
|
+
return makeSubscriptionNode(table, it);
|
|
2661
|
+
});
|
|
2662
|
+
}).filter(nonNullable);
|
|
2663
|
+
};
|
|
2664
|
+
const subscriptionNamePostfix = {
|
|
2665
|
+
create: "Created",
|
|
2666
|
+
update: "Updated",
|
|
2667
|
+
delete: "Deleted"
|
|
2668
|
+
};
|
|
2669
|
+
const makeSubscriptionNode = (table, mutation) => {
|
|
2670
|
+
if (!mutation.subscription.enabled) return null;
|
|
2671
|
+
const subscriptionName = table.getEntityName().name + subscriptionNamePostfix[mutation.type];
|
|
2672
|
+
return {
|
|
2673
|
+
subscriptionName,
|
|
2674
|
+
entity: table.getEntityName(),
|
|
2675
|
+
publishFunctionName: "publish" + subscriptionName,
|
|
2676
|
+
returnType: {
|
|
2677
|
+
typeName: table.getEntityName().name,
|
|
2678
|
+
nullable: false,
|
|
2679
|
+
array: false,
|
|
2680
|
+
entity: true
|
|
2681
|
+
},
|
|
2682
|
+
args: mutation.subscription.subscriptionFilter.map((it) => {
|
|
2683
|
+
const column = table.column(it);
|
|
2684
|
+
return {
|
|
2685
|
+
name: it,
|
|
2686
|
+
type: {
|
|
2687
|
+
typeName: column.gqlType(),
|
|
2688
|
+
dbType: column.dataType(),
|
|
2689
|
+
nullable: false,
|
|
2690
|
+
array: false,
|
|
2691
|
+
entity: false
|
|
2692
|
+
}
|
|
2693
|
+
};
|
|
2694
|
+
}),
|
|
2695
|
+
filters: (mutation.subscription?.subscriptionFilter || []).map((it) => {
|
|
2696
|
+
const column = table.column(it);
|
|
2697
|
+
return {
|
|
2698
|
+
field: column.fieldName(),
|
|
2699
|
+
gqlType: column.gqlType()
|
|
2700
|
+
};
|
|
2701
|
+
}),
|
|
2702
|
+
mutationType: mutation.type,
|
|
2703
|
+
gqlEnabled: table.gqlOption.enabled && mutation.subscription.enabled
|
|
2704
|
+
};
|
|
2705
|
+
};
|
|
2706
|
+
//#endregion
|
|
2707
|
+
//#region src/generatorv2/parse.ts
|
|
2708
|
+
const parse = (store) => {
|
|
2709
|
+
store.tables.forEach((it) => {
|
|
2710
|
+
if (it.primaryKey.length === 0) throw new Error(`Table: ${it.tableName} has no primary key.`);
|
|
2711
|
+
});
|
|
2712
|
+
return {
|
|
2713
|
+
entities: makeEntityNodes(store),
|
|
2714
|
+
subscriptions: makeSubscriptionNodes(store),
|
|
2715
|
+
contexts: makeContextNodes(store)
|
|
2716
|
+
};
|
|
2717
|
+
};
|
|
2718
|
+
//#endregion
|
|
2719
|
+
//#region src/generatorv2/codegen_v2.ts
|
|
2720
|
+
var CodeGen_v2 = class {
|
|
2721
|
+
constructor(store) {
|
|
2722
|
+
this.codeGen = new TsCodegen_v2();
|
|
2723
|
+
this.outDir = config().migration.out;
|
|
2724
|
+
this.dbDataSourceDir = node_path.join(this.outDir, Directory.paths.DATA_SOURCES);
|
|
2725
|
+
this.generateDir = node_path.join(this.outDir, Directory.paths.GENERATED);
|
|
2726
|
+
this.generateEntityDir = node_path.join(this.outDir, Directory.paths.ENTITIES);
|
|
2727
|
+
this.generateDbDataSourceDir = node_path.join(this.outDir, Directory.paths.GENERATED_DS);
|
|
2728
|
+
this.root = parse(store);
|
|
2729
|
+
}
|
|
2730
|
+
async generate() {
|
|
2731
|
+
await this.prepareDirs();
|
|
2732
|
+
await Promise.all([
|
|
2733
|
+
...this.root.entities.map((it) => this.generateEntity(it)),
|
|
2734
|
+
...this.root.entities.map((it) => this.generateDatasource(it)),
|
|
2735
|
+
...this.root.entities.map((it) => this.generateGeneratedDatasource(it)),
|
|
2736
|
+
this.generateGql(this.root),
|
|
2737
|
+
this.generateFiles(this.root),
|
|
2738
|
+
...this.generateOnceFiles(),
|
|
2739
|
+
this.generateCondition(this.root),
|
|
2740
|
+
this.generateIDEncoders(this.root),
|
|
2741
|
+
this.generateMiddleware(this.root)
|
|
2742
|
+
]);
|
|
2743
|
+
}
|
|
2744
|
+
async prepareDirs() {
|
|
2745
|
+
mkDirIfNotExist(this.generateDir);
|
|
2746
|
+
await emptyDir(this.generateDir);
|
|
2747
|
+
mkDirIfNotExist(this.generateEntityDir);
|
|
2748
|
+
mkDirIfNotExist(this.generateDbDataSourceDir);
|
|
2749
|
+
mkDirIfNotExist(this.dbDataSourceDir);
|
|
2750
|
+
}
|
|
2751
|
+
getFullPath(basePath, entityName) {
|
|
2752
|
+
return node_path.join(basePath, `${entityName}.${this.codeGen.fileExtension}`);
|
|
2753
|
+
}
|
|
2754
|
+
async generateEntity(node) {
|
|
2755
|
+
return (0, node_fs_promises.writeFile)(this.getFullPath(this.generateEntityDir, node.name.name), await this.codeGen.generateEntity(node));
|
|
2756
|
+
}
|
|
2757
|
+
async generateDatasource(node) {
|
|
2758
|
+
return writeFileIfNotExist(this.getFullPath(this.dbDataSourceDir, node.name.name), await this.codeGen.generateDatasource(node));
|
|
2759
|
+
}
|
|
2760
|
+
async generateGeneratedDatasource(node) {
|
|
2761
|
+
return (0, node_fs_promises.writeFile)(this.getFullPath(this.generateDbDataSourceDir, node.name.name), await this.codeGen.generateGeneratedDatasource(node));
|
|
2762
|
+
}
|
|
2763
|
+
async generateGql(rootNode) {
|
|
2764
|
+
return Promise.all([
|
|
2765
|
+
(0, node_fs_promises.writeFile)(this.getFullPath(this.generateDir, "typeDefs"), await this.codeGen.generateGqlTypeDefs(rootNode)),
|
|
2766
|
+
(0, node_fs_promises.writeFile)(this.getFullPath(this.generateDir, "resolver"), await this.codeGen.generateGqlResolver(rootNode)),
|
|
2767
|
+
(0, node_fs_promises.writeFile)(this.getFullPath(this.generateDir, "query"), await this.codeGen.generateGqlQuery(rootNode)),
|
|
2768
|
+
(0, node_fs_promises.writeFile)(this.getFullPath(this.generateDir, "mutation"), await this.codeGen.generateGqlMutation(rootNode)),
|
|
2769
|
+
(0, node_fs_promises.writeFile)(this.getFullPath(this.generateDir, "subscription"), await this.codeGen.generateGqlSubscription(rootNode)),
|
|
2770
|
+
(0, node_fs_promises.writeFile)(this.getFullPath(this.generateDir, "context"), await this.codeGen.generateGQLContext(rootNode))
|
|
2771
|
+
]);
|
|
2772
|
+
}
|
|
2773
|
+
async generateFiles(rootNode) {
|
|
2774
|
+
const files = await this.codeGen.generateFiles(rootNode);
|
|
2775
|
+
return Promise.all(files.map((it) => writeFileIfNotExist(this.getFullPath(this.generateDir, it.name), it.body)));
|
|
2776
|
+
}
|
|
2777
|
+
generateOnceFiles() {
|
|
2778
|
+
return this.codeGen.generateOnceFiles().map((it) => writeFileIfNotExist(this.getFullPath(this.outDir, it.name), it.body));
|
|
2779
|
+
}
|
|
2780
|
+
async generateCondition(rootNode) {
|
|
2781
|
+
const filePath = this.getFullPath(this.outDir, tsFileNames.conditions);
|
|
2782
|
+
const content = (0, node_fs.existsSync)(filePath) ? (0, node_fs.readFileSync)(filePath).toString() : "";
|
|
2783
|
+
const nextContent = this.codeGen.generateConditions(rootNode, content);
|
|
2784
|
+
if (nextContent) (0, node_fs.writeFileSync)(filePath, nextContent);
|
|
2785
|
+
}
|
|
2786
|
+
async generateIDEncoders(rootNode) {
|
|
2787
|
+
const filePath = this.getFullPath(this.outDir, tsFileNames.encoder);
|
|
2788
|
+
const content = (0, node_fs.existsSync)(filePath) ? (0, node_fs.readFileSync)(filePath).toString() : "";
|
|
2789
|
+
const nextContent = this.codeGen.generateIDEncoders(rootNode, content);
|
|
2790
|
+
if (nextContent) (0, node_fs.writeFileSync)(filePath, nextContent);
|
|
2791
|
+
}
|
|
2792
|
+
async generateMiddleware(rootNode) {
|
|
2793
|
+
const filePath = this.getFullPath(this.outDir, tsFileNames.middleware);
|
|
2794
|
+
const content = (0, node_fs.existsSync)(filePath) ? (0, node_fs.readFileSync)(filePath).toString() : "";
|
|
2795
|
+
const nextContent = this.codeGen.generateMiddlewares(rootNode, content);
|
|
2796
|
+
if (nextContent) (0, node_fs.writeFileSync)(filePath, nextContent);
|
|
2797
|
+
}
|
|
2798
|
+
};
|
|
2799
|
+
//#endregion
|
|
2800
|
+
//#region src/migration/exec/getMigrationFiles.ts
|
|
2801
|
+
const getMigrationFileDir = () => {
|
|
2802
|
+
return node_path.default.join(process.cwd(), config().migration.dir);
|
|
2803
|
+
};
|
|
2804
|
+
const getMigrationFileNames = () => {
|
|
2805
|
+
return node_fs.default.readdirSync(getMigrationFileDir()).filter((it) => it.split(".").pop() === "ts");
|
|
2806
|
+
};
|
|
2807
|
+
//#endregion
|
|
2808
|
+
//#region src/error.ts
|
|
2809
|
+
var SasatError = class extends Error {
|
|
2810
|
+
constructor(message) {
|
|
2811
|
+
super(message);
|
|
2812
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
2813
|
+
this.name = "SasatError";
|
|
2814
|
+
}
|
|
2815
|
+
};
|
|
2816
|
+
//#endregion
|
|
2817
|
+
//#region src/runtime/sql/sqlString.ts
|
|
2818
|
+
const { escape, escapeId } = sqlstring.default;
|
|
2819
|
+
const SqlString = {
|
|
2820
|
+
escape: (value) => escape(value, true),
|
|
2821
|
+
escapeId: (name) => escapeId(name)
|
|
2822
|
+
};
|
|
2823
|
+
//#endregion
|
|
2824
|
+
//#region src/db/sql/columnToSql.ts
|
|
2825
|
+
const columnToSql = (column) => {
|
|
2826
|
+
const words = [SqlString.escapeId(column.columnName), column.type];
|
|
2827
|
+
if (column.length) words.push(`(${[column.length, column.scale].filter((it) => it !== void 0).join(",")})`);
|
|
2828
|
+
if (column.signed === true) words.push("SIGNED");
|
|
2829
|
+
else if (column.signed === false) words.push("UNSIGNED");
|
|
2830
|
+
if (column.zerofill) words.push("ZEROFILL");
|
|
2831
|
+
if (column.autoIncrement) words.push("AUTO_INCREMENT");
|
|
2832
|
+
if (column.notNull) words.push("NOT NULL");
|
|
2833
|
+
else if (!column.notNull) words.push("NULL");
|
|
2834
|
+
if ((column.type === "timestamp" || column.type === "datetime") && column.default === "CURRENT_TIMESTAMP") words.push("DEFAULT CURRENT_TIMESTAMP");
|
|
2835
|
+
else if (column.default !== void 0) words.push("DEFAULT " + SqlString.escape(column.default));
|
|
2836
|
+
if (column.onUpdateCurrentTimeStamp) words.push("ON UPDATE CURRENT_TIMESTAMP");
|
|
2837
|
+
return words.join(" ");
|
|
2838
|
+
};
|
|
2839
|
+
//#endregion
|
|
2840
|
+
//#region src/migration/serializable/column.ts
|
|
2841
|
+
var BaseColumn = class {
|
|
2842
|
+
constructor(data, table) {
|
|
2843
|
+
this.data = data;
|
|
2844
|
+
this.table = table;
|
|
2845
|
+
}
|
|
2846
|
+
fieldName() {
|
|
2847
|
+
return this.data.fieldName;
|
|
2848
|
+
}
|
|
2849
|
+
columnName() {
|
|
2850
|
+
return this.data.columnName;
|
|
2851
|
+
}
|
|
2852
|
+
dataType() {
|
|
2853
|
+
return this.data.type;
|
|
2854
|
+
}
|
|
2855
|
+
tsType() {
|
|
2856
|
+
return columnTypeToTsType(this.dataType());
|
|
2857
|
+
}
|
|
2858
|
+
gqlType() {
|
|
2859
|
+
return columnTypeToGqlPrimitive(this.dataType());
|
|
2860
|
+
}
|
|
2861
|
+
isNullable() {
|
|
2862
|
+
return !this.data.notNull;
|
|
2863
|
+
}
|
|
2864
|
+
isNullableOnCreate() {
|
|
2865
|
+
return !this.data.notNull || this.data.default !== void 0 || this.data.autoIncrement;
|
|
2866
|
+
}
|
|
2867
|
+
isReference() {
|
|
2868
|
+
return this.data.hasReference;
|
|
2869
|
+
}
|
|
2870
|
+
serialize() {
|
|
2871
|
+
return JSON.parse(JSON.stringify(this.data));
|
|
2872
|
+
}
|
|
2873
|
+
toSql() {
|
|
2874
|
+
return columnToSql(this.data);
|
|
2875
|
+
}
|
|
2876
|
+
isPrimary() {
|
|
2877
|
+
return this.table.primaryKey.includes(this.columnName());
|
|
2878
|
+
}
|
|
2879
|
+
isUpdatable() {
|
|
2880
|
+
return !(this.isPrimary() || this.data.onUpdateCurrentTimeStamp);
|
|
2881
|
+
}
|
|
2882
|
+
};
|
|
2883
|
+
var NormalColumn = class extends BaseColumn {
|
|
2884
|
+
constructor(data, table) {
|
|
2885
|
+
super(data, table);
|
|
2886
|
+
this.data = data;
|
|
2887
|
+
}
|
|
2888
|
+
addReference(reference) {
|
|
2889
|
+
return new ReferenceColumn({
|
|
2890
|
+
...this.data,
|
|
2891
|
+
hasReference: true,
|
|
2892
|
+
reference
|
|
2893
|
+
}, this.table);
|
|
2894
|
+
}
|
|
2895
|
+
};
|
|
2896
|
+
var ReferenceColumn = class extends BaseColumn {
|
|
2897
|
+
constructor(data, table) {
|
|
2898
|
+
super(data, table);
|
|
2899
|
+
this.data = data;
|
|
2900
|
+
}
|
|
2901
|
+
getConstraintName() {
|
|
2902
|
+
return `ref_${this.table.tableName}_${this.fieldName()}__${this.data.reference.parentTable}_${this.data.reference.parentColumn}`;
|
|
2903
|
+
}
|
|
2904
|
+
};
|
|
2905
|
+
//#endregion
|
|
2906
|
+
//#region src/migration/data/index.ts
|
|
2907
|
+
var DBIndex = class {
|
|
2908
|
+
constructor(tableName, columns) {
|
|
2909
|
+
this.tableName = tableName;
|
|
2910
|
+
this.columns = columns;
|
|
2911
|
+
this.constraintName = this.toConstraintName(columns);
|
|
2912
|
+
}
|
|
2913
|
+
toConstraintName(columns) {
|
|
2914
|
+
return `index_${this.tableName}__${columns.join("_")}`;
|
|
2915
|
+
}
|
|
2916
|
+
addSql() {
|
|
2917
|
+
return `ALTER TABLE ${this.tableName} ADD INDEX ${this.constraintName}(${this.columns.join(",")})`;
|
|
2918
|
+
}
|
|
2919
|
+
dropSql() {
|
|
2920
|
+
return `DROP INDEX ${this.constraintName} ON ${this.tableName}`;
|
|
2921
|
+
}
|
|
2922
|
+
serialize() {
|
|
2923
|
+
return {
|
|
2924
|
+
constraintName: this.constraintName,
|
|
2925
|
+
columns: this.columns
|
|
2926
|
+
};
|
|
2927
|
+
}
|
|
2928
|
+
};
|
|
2929
|
+
//#endregion
|
|
2930
|
+
//#region src/migration/functions/assembleColumn.ts
|
|
2931
|
+
const assembleColumn = (data, table) => {
|
|
2932
|
+
if (data.hasReference) return new ReferenceColumn(data, table);
|
|
2933
|
+
return new NormalColumn(data, table);
|
|
2934
|
+
};
|
|
2935
|
+
//#endregion
|
|
2936
|
+
//#region src/migration/serialized/serializedColumn.ts
|
|
2937
|
+
const defaultColumnOption = {
|
|
2938
|
+
updatable: true,
|
|
2939
|
+
autoIncrementHashId: false
|
|
2940
|
+
};
|
|
2941
|
+
const referenceToSql = (constraintName, ref) => {
|
|
2942
|
+
const onUpdate = ref.onUpdate ? ` ON UPDATE ${ref.onUpdate}` : "";
|
|
2943
|
+
const onDelete = ref.onDelete ? ` ON DELETE ${ref.onDelete}` : "";
|
|
2944
|
+
return `CONSTRAINT ${constraintName} FOREIGN KEY(${ref.columnName}) REFERENCES ${SqlString.escapeId(ref.parentTable)}(${SqlString.escapeId(ref.parentColumn)})` + onUpdate + onDelete;
|
|
2945
|
+
};
|
|
2946
|
+
//#endregion
|
|
2947
|
+
//#region src/migration/serializable/table.ts
|
|
2948
|
+
var TableHandler = class {
|
|
2949
|
+
get index() {
|
|
2950
|
+
return this.indexes;
|
|
2951
|
+
}
|
|
2952
|
+
get columns() {
|
|
2953
|
+
return this._columns;
|
|
2954
|
+
}
|
|
2955
|
+
get virtualRelations() {
|
|
2956
|
+
return this._virtualRelations;
|
|
2957
|
+
}
|
|
2958
|
+
addVirtualRelation(relation) {
|
|
2959
|
+
this._virtualRelations.push({
|
|
2960
|
+
...relation,
|
|
2961
|
+
childTable: this.tableName
|
|
2962
|
+
});
|
|
2963
|
+
}
|
|
2964
|
+
get gqlOption() {
|
|
2965
|
+
return this._gqlOption;
|
|
2966
|
+
}
|
|
2967
|
+
constructor(table, store) {
|
|
2968
|
+
this.store = store;
|
|
2969
|
+
this._gqlOption = defaultGQLOption();
|
|
2970
|
+
this.tableName = table.tableName;
|
|
2971
|
+
this.primaryKey = table.primaryKey || [];
|
|
2972
|
+
this.uniqueKeys = table.uniqueKeys || [];
|
|
2973
|
+
this.indexes = table.indexes?.map((it) => new DBIndex(this.tableName, it.columns)) || [];
|
|
2974
|
+
this._gqlOption = table.gqlOption || defaultGQLOption();
|
|
2975
|
+
this._columns = (table.columns || []).map((it) => assembleColumn(it, this));
|
|
2976
|
+
this._virtualRelations = table.virtualRelations || [];
|
|
2977
|
+
}
|
|
2978
|
+
column(columnName) {
|
|
2979
|
+
const column = this.columns.find((it) => it.columnName() === columnName);
|
|
2980
|
+
if (!column) throw new Error(`${this.tableName}.${columnName} is Not Found`);
|
|
2981
|
+
return column;
|
|
2982
|
+
}
|
|
2983
|
+
addColumn(column, isPrimary = false, isUnique = false) {
|
|
2984
|
+
this.columns.push(column);
|
|
2985
|
+
if (isPrimary) this.setPrimaryKey(column.columnName());
|
|
2986
|
+
if (isUnique) this.addUniqueKey(column.columnName());
|
|
2987
|
+
}
|
|
2988
|
+
dropColumn(columnName) {
|
|
2989
|
+
this._columns = this._columns.filter((it) => it.fieldName() !== columnName);
|
|
2990
|
+
}
|
|
2991
|
+
serialize() {
|
|
2992
|
+
return {
|
|
2993
|
+
columns: this.columns.map((it) => it.serialize()),
|
|
2994
|
+
primaryKey: this.primaryKey,
|
|
2995
|
+
uniqueKeys: this.uniqueKeys,
|
|
2996
|
+
indexes: this.indexes,
|
|
2997
|
+
tableName: this.tableName,
|
|
2998
|
+
gqlOption: JSON.parse(JSON.stringify(this.gqlOption)),
|
|
2999
|
+
virtualRelations: this._virtualRelations
|
|
3000
|
+
};
|
|
3001
|
+
}
|
|
3002
|
+
addReferences(ref, fieldName, notNull = true) {
|
|
3003
|
+
const data = {
|
|
3004
|
+
...this.store.table(ref.parentTable).column(ref.parentColumn).serialize(),
|
|
3005
|
+
hasReference: true,
|
|
3006
|
+
fieldName: fieldName || ref.columnName,
|
|
3007
|
+
columnName: ref.columnName,
|
|
3008
|
+
notNull,
|
|
3009
|
+
default: void 0,
|
|
3010
|
+
zerofill: false,
|
|
3011
|
+
autoIncrement: false,
|
|
3012
|
+
defaultCurrentTimeStamp: false,
|
|
3013
|
+
onUpdateCurrentTimeStamp: false,
|
|
3014
|
+
reference: ref
|
|
3015
|
+
};
|
|
3016
|
+
this.columns.push(new ReferenceColumn(data, this));
|
|
3017
|
+
return this;
|
|
3018
|
+
}
|
|
3019
|
+
getIndexConstraintName(columns) {
|
|
3020
|
+
return `index_${this.tableName}__${columns.join("_")}`;
|
|
3021
|
+
}
|
|
3022
|
+
addIndex(...columns) {
|
|
3023
|
+
this.indexes.push(new DBIndex(this.tableName, columns));
|
|
3024
|
+
return this;
|
|
3025
|
+
}
|
|
3026
|
+
removeIndex(...columns) {
|
|
3027
|
+
const constraint = this.getIndexConstraintName(columns);
|
|
3028
|
+
this.indexes = this.indexes.filter((it) => it.constraintName !== constraint);
|
|
3029
|
+
return this;
|
|
3030
|
+
}
|
|
3031
|
+
addUniqueKey(...columnNames) {
|
|
3032
|
+
if (columnNames.length === 0) throw new SasatError("No column name specified");
|
|
3033
|
+
this.uniqueKeys.push(columnNames);
|
|
3034
|
+
return this;
|
|
3035
|
+
}
|
|
3036
|
+
setPrimaryKey(...columnNames) {
|
|
3037
|
+
if (columnNames.length === 0) throw new Error("Primary key is required");
|
|
3038
|
+
this.primaryKey = columnNames;
|
|
3039
|
+
return this;
|
|
3040
|
+
}
|
|
3041
|
+
showCreateTable() {
|
|
3042
|
+
const rows = [...this.columns.map((it) => it.toSql())];
|
|
3043
|
+
if (this.primaryKey.length !== 0) rows.push(`PRIMARY KEY (${this.primaryKey.map(SqlString.escapeId).join(",")})`);
|
|
3044
|
+
this.uniqueKeys.forEach((it) => {
|
|
3045
|
+
if (this.uniqueKeys.length !== 0) rows.push(`UNIQUE KEY (${it.join(",")})`);
|
|
3046
|
+
});
|
|
3047
|
+
rows.push(...this._columns.filter((it) => it.isReference() && !it.data.reference.noFKey).map((it) => {
|
|
3048
|
+
const ref = it;
|
|
3049
|
+
return referenceToSql(ref.getConstraintName(), ref.data.reference);
|
|
3050
|
+
}));
|
|
3051
|
+
return `CREATE TABLE ${SqlString.escapeId(this.tableName)}
|
|
3052
|
+
(
|
|
3053
|
+
${rows.join(", ")}
|
|
3054
|
+
)`;
|
|
3055
|
+
}
|
|
3056
|
+
hasColumn(columnName) {
|
|
3057
|
+
return !!this.columns.find((it) => it.columnName() === columnName);
|
|
3058
|
+
}
|
|
3059
|
+
isColumnPrimary(columnName) {
|
|
3060
|
+
return this.primaryKey.includes(columnName);
|
|
3061
|
+
}
|
|
3062
|
+
getEntityName() {
|
|
3063
|
+
return EntityName.fromTableName(this.tableName);
|
|
3064
|
+
}
|
|
3065
|
+
setGQLOption(option) {
|
|
3066
|
+
this._gqlOption = {
|
|
3067
|
+
...this.gqlOption,
|
|
3068
|
+
...option
|
|
3069
|
+
};
|
|
3070
|
+
}
|
|
3071
|
+
getReferenceColumns() {
|
|
3072
|
+
return this.columns.filter((it) => it.isReference());
|
|
3073
|
+
}
|
|
3074
|
+
addForeignKey(reference) {
|
|
3075
|
+
const columnName = reference.columnName;
|
|
3076
|
+
const column1 = this.column(columnName);
|
|
3077
|
+
if (!column1) throw new Error("Column: `" + columnName + "` Not Found");
|
|
3078
|
+
if (column1.isReference()) throw new Error("Column: `" + columnName + "`already has reference, multiple reference is not supported");
|
|
3079
|
+
const ref = column1.addReference(reference);
|
|
3080
|
+
this._columns = this.columns.map((it) => it.columnName() === columnName ? ref : it);
|
|
3081
|
+
}
|
|
3082
|
+
changeType(columnName, type) {
|
|
3083
|
+
this.updateColumn(columnName, { type });
|
|
3084
|
+
}
|
|
3085
|
+
setDefault(columnName, value) {
|
|
3086
|
+
this.updateColumn(columnName, { default: value });
|
|
3087
|
+
}
|
|
3088
|
+
updateColumn(columnName, diff) {
|
|
3089
|
+
const update = (column) => {
|
|
3090
|
+
if (column.isReference()) return new ReferenceColumn({
|
|
3091
|
+
...column.serialize(),
|
|
3092
|
+
...diff
|
|
3093
|
+
}, this);
|
|
3094
|
+
return new NormalColumn({
|
|
3095
|
+
...column.serialize(),
|
|
3096
|
+
...diff
|
|
3097
|
+
}, this);
|
|
3098
|
+
};
|
|
3099
|
+
if (!this.column(columnName)) throw new Error(this.tableName + "." + columnName + " Not Found");
|
|
3100
|
+
this._columns = this.columns.map((it) => it.columnName() === columnName ? update(it) : it);
|
|
3101
|
+
}
|
|
3102
|
+
getPrimaryKeyColumns() {
|
|
3103
|
+
return this.columns.filter((it) => this.primaryKey.includes(it.columnName()));
|
|
3104
|
+
}
|
|
3105
|
+
};
|
|
3106
|
+
//#endregion
|
|
3107
|
+
//#region src/migration/creators/columnBuilder.ts
|
|
3108
|
+
var ColumnBuilderBase = class {
|
|
3109
|
+
constructor(columnName) {
|
|
3110
|
+
this.columnName = columnName;
|
|
3111
|
+
this._primary = false;
|
|
3112
|
+
this._notNull = true;
|
|
3113
|
+
this._unique = false;
|
|
3114
|
+
this._option = defaultColumnOption;
|
|
3115
|
+
this._fieldName = columnName;
|
|
3116
|
+
}
|
|
3117
|
+
fieldName(fieldName) {
|
|
3118
|
+
this._fieldName = fieldName;
|
|
3119
|
+
return this;
|
|
3120
|
+
}
|
|
3121
|
+
notNull() {
|
|
3122
|
+
this._notNull = true;
|
|
3123
|
+
return this;
|
|
3124
|
+
}
|
|
3125
|
+
nullable() {
|
|
3126
|
+
this._notNull = false;
|
|
3127
|
+
return this;
|
|
3128
|
+
}
|
|
3129
|
+
primary() {
|
|
3130
|
+
this._primary = true;
|
|
3131
|
+
return this;
|
|
3132
|
+
}
|
|
3133
|
+
unique() {
|
|
3134
|
+
this._unique = true;
|
|
3135
|
+
return this;
|
|
3136
|
+
}
|
|
3137
|
+
updatable(updatable) {
|
|
3138
|
+
this._option = {
|
|
3139
|
+
...this._option,
|
|
3140
|
+
updatable
|
|
3141
|
+
};
|
|
3142
|
+
return this;
|
|
3143
|
+
}
|
|
3144
|
+
};
|
|
3145
|
+
var ColumnBuilder = class extends ColumnBuilderBase {
|
|
3146
|
+
constructor(name, type, length, scale) {
|
|
3147
|
+
super(name);
|
|
3148
|
+
this.type = type;
|
|
3149
|
+
this.length = length;
|
|
3150
|
+
this.scale = scale;
|
|
3151
|
+
this._zerofill = false;
|
|
3152
|
+
this._autoIncrement = false;
|
|
3153
|
+
this._defaultCurrentTimeStamp = false;
|
|
3154
|
+
this._onUpdateCurrentTimeStamp = false;
|
|
3155
|
+
this._fieldName = name;
|
|
3156
|
+
}
|
|
3157
|
+
default(value) {
|
|
3158
|
+
this._default = value;
|
|
3159
|
+
return this;
|
|
3160
|
+
}
|
|
3161
|
+
build() {
|
|
3162
|
+
return {
|
|
3163
|
+
data: {
|
|
3164
|
+
hasReference: false,
|
|
3165
|
+
columnName: this.columnName,
|
|
3166
|
+
fieldName: this._fieldName,
|
|
3167
|
+
type: this.type,
|
|
3168
|
+
length: this.length,
|
|
3169
|
+
scale: this.scale,
|
|
3170
|
+
notNull: this._notNull,
|
|
3171
|
+
zerofill: this._zerofill,
|
|
3172
|
+
signed: this._signed,
|
|
3173
|
+
autoIncrement: this._autoIncrement,
|
|
3174
|
+
default: this._default,
|
|
3175
|
+
defaultCurrentTimeStamp: this._defaultCurrentTimeStamp,
|
|
3176
|
+
onUpdateCurrentTimeStamp: this._onUpdateCurrentTimeStamp,
|
|
3177
|
+
option: this._option
|
|
3178
|
+
},
|
|
3179
|
+
isPrimary: this._primary,
|
|
3180
|
+
isUnique: this._unique
|
|
3181
|
+
};
|
|
3182
|
+
}
|
|
3183
|
+
};
|
|
3184
|
+
var StringColumnBuilder = class extends ColumnBuilder {
|
|
3185
|
+
constructor(name, type, length) {
|
|
3186
|
+
super(name, type);
|
|
3187
|
+
this.name = name;
|
|
3188
|
+
this.type = type;
|
|
3189
|
+
this.length = length;
|
|
3190
|
+
}
|
|
3191
|
+
default(value) {
|
|
3192
|
+
this._default = value;
|
|
3193
|
+
return this;
|
|
3194
|
+
}
|
|
3195
|
+
};
|
|
3196
|
+
var TextColumnBuilder = class extends ColumnBuilder {
|
|
3197
|
+
constructor(name, type) {
|
|
3198
|
+
super(name, type);
|
|
3199
|
+
this.name = name;
|
|
3200
|
+
this.type = type;
|
|
3201
|
+
}
|
|
3202
|
+
default(value) {
|
|
3203
|
+
this._default = value;
|
|
3204
|
+
return this;
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
var NumberColumnBuilder = class extends ColumnBuilder {
|
|
3208
|
+
signed() {
|
|
3209
|
+
this._signed = true;
|
|
3210
|
+
return this;
|
|
3211
|
+
}
|
|
3212
|
+
unsigned() {
|
|
3213
|
+
this._signed = false;
|
|
3214
|
+
return this;
|
|
3215
|
+
}
|
|
3216
|
+
zerofill() {
|
|
3217
|
+
this._zerofill = true;
|
|
3218
|
+
return this;
|
|
3219
|
+
}
|
|
3220
|
+
default(value) {
|
|
3221
|
+
this._default = value;
|
|
3222
|
+
return this;
|
|
3223
|
+
}
|
|
3224
|
+
};
|
|
3225
|
+
var IntegerColumnBuilder = class extends NumberColumnBuilder {
|
|
3226
|
+
constructor(name, type, length) {
|
|
3227
|
+
super(name, type, length);
|
|
3228
|
+
this.name = name;
|
|
3229
|
+
this.type = type;
|
|
3230
|
+
this.length = length;
|
|
3231
|
+
}
|
|
3232
|
+
autoIncrement() {
|
|
3233
|
+
this._autoIncrement = true;
|
|
3234
|
+
return this;
|
|
3235
|
+
}
|
|
3236
|
+
};
|
|
3237
|
+
var FloatColumnBuilder = class extends NumberColumnBuilder {
|
|
3238
|
+
constructor(name, type, length, scale) {
|
|
3239
|
+
super(name, type, length, scale);
|
|
3240
|
+
this.name = name;
|
|
3241
|
+
this.type = type;
|
|
3242
|
+
this.length = length;
|
|
3243
|
+
this.scale = scale;
|
|
3244
|
+
}
|
|
3245
|
+
autoIncrement() {
|
|
3246
|
+
this._autoIncrement = true;
|
|
3247
|
+
return this;
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
var DecimalColumnBuilder = class extends NumberColumnBuilder {
|
|
3251
|
+
constructor(name, type, length, scale) {
|
|
3252
|
+
super(name, type, length, scale);
|
|
3253
|
+
this.name = name;
|
|
3254
|
+
this.type = type;
|
|
3255
|
+
this.length = length;
|
|
3256
|
+
this.scale = scale;
|
|
3257
|
+
}
|
|
3258
|
+
};
|
|
3259
|
+
var DateColumnBuilder = class extends ColumnBuilder {
|
|
3260
|
+
constructor(name, type) {
|
|
3261
|
+
super(name, type);
|
|
3262
|
+
this.name = name;
|
|
3263
|
+
this.type = type;
|
|
3264
|
+
}
|
|
3265
|
+
default(value) {
|
|
3266
|
+
this._default = value;
|
|
3267
|
+
return this;
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
var TimeStampColumnBuilder = class extends ColumnBuilder {
|
|
3271
|
+
constructor(name, type) {
|
|
3272
|
+
super(name, type);
|
|
3273
|
+
this.name = name;
|
|
3274
|
+
this.type = type;
|
|
3275
|
+
}
|
|
3276
|
+
default(value) {
|
|
3277
|
+
this._default = value;
|
|
3278
|
+
return this;
|
|
3279
|
+
}
|
|
3280
|
+
defaultCurrentTimeStamp() {
|
|
3281
|
+
this._defaultCurrentTimeStamp = true;
|
|
3282
|
+
return this.default("CURRENT_TIMESTAMP");
|
|
3283
|
+
}
|
|
3284
|
+
onUpdateCurrentTimeStamp() {
|
|
3285
|
+
this._onUpdateCurrentTimeStamp = true;
|
|
3286
|
+
return this;
|
|
3287
|
+
}
|
|
3288
|
+
};
|
|
3289
|
+
var ReferenceColumnBuilder = class extends ColumnBuilderBase {
|
|
3290
|
+
constructor(ref, parent) {
|
|
3291
|
+
super(ref.columnName);
|
|
3292
|
+
this.ref = ref;
|
|
3293
|
+
this.parent = parent;
|
|
3294
|
+
this._option = {
|
|
3295
|
+
...this._option,
|
|
3296
|
+
updatable: false
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
notNull() {
|
|
3300
|
+
this._notNull = true;
|
|
3301
|
+
return this;
|
|
3302
|
+
}
|
|
3303
|
+
nullable() {
|
|
3304
|
+
this._notNull = false;
|
|
3305
|
+
return this;
|
|
3306
|
+
}
|
|
3307
|
+
primary() {
|
|
3308
|
+
this._primary = true;
|
|
3309
|
+
return this;
|
|
3310
|
+
}
|
|
3311
|
+
unique() {
|
|
3312
|
+
this._unique = true;
|
|
3313
|
+
return this;
|
|
3314
|
+
}
|
|
3315
|
+
build() {
|
|
3316
|
+
return {
|
|
3317
|
+
data: {
|
|
3318
|
+
...this.parent.serialize(),
|
|
3319
|
+
hasReference: true,
|
|
3320
|
+
fieldName: this._fieldName,
|
|
3321
|
+
columnName: this.columnName,
|
|
3322
|
+
notNull: this._notNull,
|
|
3323
|
+
default: void 0,
|
|
3324
|
+
autoIncrement: false,
|
|
3325
|
+
defaultCurrentTimeStamp: false,
|
|
3326
|
+
onUpdateCurrentTimeStamp: false,
|
|
3327
|
+
reference: this.ref,
|
|
3328
|
+
option: this._option
|
|
3329
|
+
},
|
|
3330
|
+
isPrimary: this._primary,
|
|
3331
|
+
isUnique: this._unique
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
};
|
|
3335
|
+
var AutoIncrementIDColumnBuilder = class extends ColumnBuilderBase {
|
|
3336
|
+
constructor(columnName, option) {
|
|
3337
|
+
super(columnName);
|
|
3338
|
+
this.option = option;
|
|
3339
|
+
this._option = {
|
|
3340
|
+
...this._option,
|
|
3341
|
+
updatable: false,
|
|
3342
|
+
autoIncrementHashId: true,
|
|
3343
|
+
hashSalt: option?.salt
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3346
|
+
build() {
|
|
3347
|
+
return {
|
|
3348
|
+
data: {
|
|
3349
|
+
hasReference: false,
|
|
3350
|
+
fieldName: this._fieldName,
|
|
3351
|
+
columnName: this.columnName,
|
|
3352
|
+
type: this.option?.bigint ? "bigint" : "int",
|
|
3353
|
+
notNull: true,
|
|
3354
|
+
default: void 0,
|
|
3355
|
+
zerofill: false,
|
|
3356
|
+
signed: false,
|
|
3357
|
+
autoIncrement: true,
|
|
3358
|
+
length: void 0,
|
|
3359
|
+
scale: void 0,
|
|
3360
|
+
defaultCurrentTimeStamp: false,
|
|
3361
|
+
onUpdateCurrentTimeStamp: false,
|
|
3362
|
+
option: this._option
|
|
3363
|
+
},
|
|
3364
|
+
isPrimary: true,
|
|
3365
|
+
isUnique: false
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
};
|
|
3369
|
+
//#endregion
|
|
3370
|
+
//#region src/migration/creators/columnCreator.ts
|
|
3371
|
+
var ColumnCreator = class {
|
|
3372
|
+
constructor(table, name) {
|
|
3373
|
+
this.table = table;
|
|
3374
|
+
this.name = name;
|
|
3375
|
+
this.char = (length) => this.create(new StringColumnBuilder(this.name, "char", length));
|
|
3376
|
+
this.varchar = (length) => this.create(new StringColumnBuilder(this.name, "varchar", length));
|
|
3377
|
+
this.text = () => this.create(new TextColumnBuilder(this.name, "text"));
|
|
3378
|
+
this.tinyInt = (length) => this.create(new IntegerColumnBuilder(this.name, "tinyint", length));
|
|
3379
|
+
this.smallInt = (length) => this.create(new IntegerColumnBuilder(this.name, "smallint", length));
|
|
3380
|
+
this.mediumInt = (length) => this.create(new IntegerColumnBuilder(this.name, "mediumint", length));
|
|
3381
|
+
this.int = (length) => this.create(new IntegerColumnBuilder(this.name, "int", length));
|
|
3382
|
+
this.bigInt = (length) => this.create(new IntegerColumnBuilder(this.name, "bigint", length));
|
|
3383
|
+
this.float = (length, scale) => this.create(new FloatColumnBuilder(this.name, "float", length, scale));
|
|
3384
|
+
this.double = (length, scale) => this.create(new FloatColumnBuilder(this.name, "double", length, scale));
|
|
3385
|
+
this.decimal = (length, scale) => this.create(new DecimalColumnBuilder(this.name, "decimal", length, scale));
|
|
3386
|
+
this.year = () => this.create(new DateColumnBuilder(this.name, "year"));
|
|
3387
|
+
this.date = () => this.create(new DateColumnBuilder(this.name, "date"));
|
|
3388
|
+
this.time = () => this.create(new DateColumnBuilder(this.name, "time"));
|
|
3389
|
+
this.dateTime = () => this.create(new TimeStampColumnBuilder(this.name, "datetime"));
|
|
3390
|
+
this.timestamp = () => this.create(new TimeStampColumnBuilder(this.name, "timestamp"));
|
|
3391
|
+
}
|
|
3392
|
+
create(column) {
|
|
3393
|
+
this.table.addColumn(column);
|
|
3394
|
+
return column;
|
|
3395
|
+
}
|
|
3396
|
+
};
|
|
3397
|
+
//#endregion
|
|
3398
|
+
//#region src/migration/creators/tableCreator.ts
|
|
3399
|
+
var TableCreator = class {
|
|
3400
|
+
constructor(tableName, store) {
|
|
3401
|
+
this.tableName = tableName;
|
|
3402
|
+
this.store = store;
|
|
3403
|
+
this.columns = [];
|
|
3404
|
+
this.table = new TableHandler({ tableName }, store);
|
|
3405
|
+
}
|
|
3406
|
+
autoIncrementHashId(columnName, option) {
|
|
3407
|
+
this.addColumn(new AutoIncrementIDColumnBuilder(columnName, option));
|
|
3408
|
+
return this;
|
|
3409
|
+
}
|
|
3410
|
+
column(name) {
|
|
3411
|
+
return new ColumnCreator(this, name);
|
|
3412
|
+
}
|
|
3413
|
+
addVirtualRelation(relation) {
|
|
3414
|
+
this.table.addVirtualRelation(relation);
|
|
3415
|
+
return this;
|
|
3416
|
+
}
|
|
3417
|
+
addColumn(column) {
|
|
3418
|
+
if (this.table.hasColumn(column.columnName)) throw new Error(`${this.tableName}.${column.columnName} already exists`);
|
|
3419
|
+
this.columns.push(column);
|
|
3420
|
+
}
|
|
3421
|
+
addUniqueKey(...columnNames) {
|
|
3422
|
+
this.table.addUniqueKey(...columnNames);
|
|
3423
|
+
return this;
|
|
3424
|
+
}
|
|
3425
|
+
references(ref) {
|
|
3426
|
+
const column = new ReferenceColumnBuilder(ref, this.store.table(ref.parentTable).column(ref.parentColumn));
|
|
3427
|
+
this.addColumn(column);
|
|
3428
|
+
return column;
|
|
3429
|
+
}
|
|
3430
|
+
setPrimaryKey(...columnNames) {
|
|
3431
|
+
this.table.setPrimaryKey(...columnNames);
|
|
3432
|
+
return this;
|
|
3433
|
+
}
|
|
3434
|
+
create() {
|
|
3435
|
+
this.columns.forEach((column) => {
|
|
3436
|
+
const { data, isPrimary, isUnique } = column.build();
|
|
3437
|
+
this.table.addColumn(data.hasReference ? new ReferenceColumn(data, this.table) : new NormalColumn(data, this.table), isPrimary, isUnique);
|
|
3438
|
+
});
|
|
3439
|
+
return this.table;
|
|
3440
|
+
}
|
|
3441
|
+
createdAt() {
|
|
3442
|
+
this.column("createdAt").timestamp().defaultCurrentTimeStamp().notNull().updatable(false);
|
|
3443
|
+
return this;
|
|
3444
|
+
}
|
|
3445
|
+
updatedAt() {
|
|
3446
|
+
this.column("updatedAt").timestamp().defaultCurrentTimeStamp().onUpdateCurrentTimeStamp().notNull().updatable(false);
|
|
3447
|
+
return this;
|
|
3448
|
+
}
|
|
3449
|
+
addIndex(...columns) {
|
|
3450
|
+
this.table.addIndex(`index_${this.tableName}__${columns.join("_")}`, ...columns);
|
|
3451
|
+
return this;
|
|
3452
|
+
}
|
|
3453
|
+
enableGQL() {
|
|
3454
|
+
this.table.setGQLOption({
|
|
3455
|
+
...this.table.gqlOption,
|
|
3456
|
+
enabled: true
|
|
3457
|
+
});
|
|
3458
|
+
return this;
|
|
3459
|
+
}
|
|
3460
|
+
setGQLOption(option) {
|
|
3461
|
+
this.table.setGQLOption(option);
|
|
3462
|
+
return this;
|
|
3463
|
+
}
|
|
3464
|
+
addGQLQuery(...query) {
|
|
3465
|
+
this.table.setGQLOption({ queries: [...this.table.gqlOption.queries, ...query] });
|
|
3466
|
+
return this;
|
|
3467
|
+
}
|
|
3468
|
+
addGQLMutation(...mutation) {
|
|
3469
|
+
this.table.setGQLOption({ mutations: [...this.table.gqlOption.mutations, ...mutation] });
|
|
3470
|
+
return this;
|
|
3471
|
+
}
|
|
3472
|
+
};
|
|
3473
|
+
//#endregion
|
|
3474
|
+
//#region src/db/sql/sqlCreater.ts
|
|
3475
|
+
const SqlCreator = {
|
|
3476
|
+
addColumn: (tableName, column) => `ALTER TABLE ${tableName} ADD COLUMN ${columnToSql(column)}`,
|
|
3477
|
+
dropColumn: (tableName, columnName) => `ALTER TABLE ${tableName} DROP COLUMN ${columnName}`,
|
|
3478
|
+
addUniqueKey: (tableName, columns) => `ALTER TABLE ${tableName} ADD UNIQUE ${columns.join("__")}(${columns.join(",")})`,
|
|
3479
|
+
addPrimaryKey: (tableName, columns) => `ALTER TABLE ${tableName} ADD PRIMARY KEY ${columns.join("__")}(${columns.join(",")})`,
|
|
3480
|
+
addForeignKey: (tableName, constraintName, reference) => {
|
|
3481
|
+
const onUpdate = reference.onUpdate ? " ON UPDATE " + reference.onUpdate : "";
|
|
3482
|
+
const onDelete = reference.onDelete ? " ON DELETE " + reference.onDelete : "";
|
|
3483
|
+
return `ALTER TABLE ${tableName} ADD CONSTRAINT '${constraintName}' FOREIGN KEY (${reference.columnName}) REFERENCES ${reference.parentTable}(${reference.parentColumn})${onUpdate}${onDelete}`;
|
|
3484
|
+
}
|
|
3485
|
+
};
|
|
3486
|
+
//#endregion
|
|
3487
|
+
//#region src/migration/creators/createColumn.ts
|
|
3488
|
+
const createColumn = (name) => ({
|
|
3489
|
+
char: (length) => new StringColumnBuilder(name, "char", length),
|
|
3490
|
+
varchar: (length) => new StringColumnBuilder(name, "varchar", length),
|
|
3491
|
+
text: () => new TextColumnBuilder(name, "text"),
|
|
3492
|
+
tinyInt: (length) => new IntegerColumnBuilder(name, "tinyint", length),
|
|
3493
|
+
smallInt: (length) => new IntegerColumnBuilder(name, "smallint", length),
|
|
3494
|
+
mediumInt: (length) => new IntegerColumnBuilder(name, "mediumint", length),
|
|
3495
|
+
int: (length) => new IntegerColumnBuilder(name, "int", length),
|
|
3496
|
+
bigInt: (length) => new IntegerColumnBuilder(name, "bigint", length),
|
|
3497
|
+
float: (length, scale) => new FloatColumnBuilder(name, "float", length, scale),
|
|
3498
|
+
double: (length, scale) => new FloatColumnBuilder(name, "double", length, scale),
|
|
3499
|
+
decimal: (length, scale) => new DecimalColumnBuilder(name, "decimal", length, scale),
|
|
3500
|
+
year: () => new DateColumnBuilder(name, "year"),
|
|
3501
|
+
date: () => new DateColumnBuilder(name, "date"),
|
|
3502
|
+
time: () => new DateColumnBuilder(name, "time"),
|
|
3503
|
+
dateTime: () => new TimeStampColumnBuilder(name, "datetime"),
|
|
3504
|
+
timestamp: () => new TimeStampColumnBuilder(name, "timestamp")
|
|
3505
|
+
});
|
|
3506
|
+
//#endregion
|
|
3507
|
+
//#region src/migration/front/tableMigrator.ts
|
|
3508
|
+
var TableMigrator = class TableMigrator {
|
|
3509
|
+
constructor(table, store) {
|
|
3510
|
+
this.table = table;
|
|
3511
|
+
this.store = store;
|
|
3512
|
+
}
|
|
3513
|
+
get primaryKey() {
|
|
3514
|
+
return this.table.primaryKey;
|
|
3515
|
+
}
|
|
3516
|
+
static deserialize(data, store) {
|
|
3517
|
+
return new TableMigrator(new TableHandler(data, store), store);
|
|
3518
|
+
}
|
|
3519
|
+
get tableName() {
|
|
3520
|
+
return this.table.tableName;
|
|
3521
|
+
}
|
|
3522
|
+
column(columnName) {
|
|
3523
|
+
return this.table.column(columnName);
|
|
3524
|
+
}
|
|
3525
|
+
showCreateTable() {
|
|
3526
|
+
return this.table.showCreateTable();
|
|
3527
|
+
}
|
|
3528
|
+
getIndexes() {
|
|
3529
|
+
return this.table.index;
|
|
3530
|
+
}
|
|
3531
|
+
serialize() {
|
|
3532
|
+
return this.table.serialize();
|
|
3533
|
+
}
|
|
3534
|
+
addIndex(...columns) {
|
|
3535
|
+
this.table.addIndex(...columns);
|
|
3536
|
+
const index = new DBIndex(this.tableName, columns);
|
|
3537
|
+
this.store.addQuery(index.addSql());
|
|
3538
|
+
return this;
|
|
3539
|
+
}
|
|
3540
|
+
removeIndex(...columns) {
|
|
3541
|
+
this.table.removeIndex(...columns);
|
|
3542
|
+
this.store.addQuery(new DBIndex(this.tableName, columns).dropSql());
|
|
3543
|
+
return this;
|
|
3544
|
+
}
|
|
3545
|
+
_addColumn(column) {
|
|
3546
|
+
this.table.addColumn(new NormalColumn(column, this.table));
|
|
3547
|
+
this.store.addQuery(SqlCreator.addColumn(this.tableName, column));
|
|
3548
|
+
return this;
|
|
3549
|
+
}
|
|
3550
|
+
addColumn(name, create) {
|
|
3551
|
+
const column = create(createColumn(name)).build();
|
|
3552
|
+
return this._addColumn(column.data);
|
|
3553
|
+
}
|
|
3554
|
+
dropColumn(columnName) {
|
|
3555
|
+
this.table.dropColumn(columnName);
|
|
3556
|
+
this.store.addQuery(SqlCreator.dropColumn(this.tableName, columnName));
|
|
3557
|
+
return this;
|
|
3558
|
+
}
|
|
3559
|
+
enableGQL() {
|
|
3560
|
+
this.table.setGQLOption({
|
|
3561
|
+
...this.table.gqlOption,
|
|
3562
|
+
enabled: true
|
|
3563
|
+
});
|
|
3564
|
+
return this;
|
|
3565
|
+
}
|
|
3566
|
+
setGQLOption(option) {
|
|
3567
|
+
this.table.setGQLOption(option);
|
|
3568
|
+
return this;
|
|
3569
|
+
}
|
|
3570
|
+
addForeignKey(reference) {
|
|
3571
|
+
this.tableExists(reference.parentTable);
|
|
3572
|
+
this.table.addForeignKey(reference);
|
|
3573
|
+
const column = this.table.column(reference.columnName);
|
|
3574
|
+
const targetColumn = this.store.table(reference.parentTable).column(reference.parentColumn);
|
|
3575
|
+
if (!targetColumn) throw new Error("Column: " + reference.parentTable + "." + reference.parentColumn + " Not Exists");
|
|
3576
|
+
if (column.dataType() !== targetColumn.dataType()) throw new Error(`${this.tableName}.${reference.columnName} AND ${reference.parentTable}.${reference.parentColumn} is different Type( ${column.dataType()} != ${targetColumn.dataType()} )`);
|
|
3577
|
+
this.store.addQuery(SqlCreator.addForeignKey(this.tableName, column.getConstraintName(), reference));
|
|
3578
|
+
return this;
|
|
3579
|
+
}
|
|
3580
|
+
changeColumnType(columnName, type) {
|
|
3581
|
+
this.table.changeType(columnName, type);
|
|
3582
|
+
this.store.addQuery(`ALTER TABLE ${this.tableName} MODIFY ${columnName} ${type}`);
|
|
3583
|
+
return this;
|
|
3584
|
+
}
|
|
3585
|
+
tableExists(tableName) {
|
|
3586
|
+
if (!this.store.table(tableName)) throw new Error("QueryTable: " + tableName + " Not Exists");
|
|
3587
|
+
return true;
|
|
3588
|
+
}
|
|
3589
|
+
setDefault(columnName, value) {
|
|
3590
|
+
this.table.setDefault(columnName, value);
|
|
3591
|
+
this.store.addQuery(`ALTER TABLE ${this.tableName} ALTER ${columnName} SET DEFAULT ${SqlString.escape(value)}`);
|
|
3592
|
+
return this;
|
|
3593
|
+
}
|
|
3594
|
+
get gqlOption() {
|
|
3595
|
+
return this.table.gqlOption;
|
|
3596
|
+
}
|
|
3597
|
+
addGQLQuery(...queries) {
|
|
3598
|
+
this.table.setGQLOption({
|
|
3599
|
+
...this.table.gqlOption,
|
|
3600
|
+
queries: [...this.table.gqlOption.queries, ...queries]
|
|
3601
|
+
});
|
|
3602
|
+
return this;
|
|
3603
|
+
}
|
|
3604
|
+
addGQLMutation(...mutations) {
|
|
3605
|
+
this.table.setGQLOption({
|
|
3606
|
+
...this.table.gqlOption,
|
|
3607
|
+
mutations: [...this.table.gqlOption.mutations, ...mutations]
|
|
3608
|
+
});
|
|
3609
|
+
return this;
|
|
3610
|
+
}
|
|
3611
|
+
};
|
|
3612
|
+
//#endregion
|
|
3613
|
+
//#region src/migration/front/storeMigrator.ts
|
|
3614
|
+
var StoreMigrator = class StoreMigrator {
|
|
3615
|
+
constructor() {
|
|
3616
|
+
this.tables = [];
|
|
3617
|
+
this.migrationQueue = [];
|
|
3618
|
+
}
|
|
3619
|
+
static new() {
|
|
3620
|
+
if (node_fs.default.existsSync(node_path.default.join(config().migration.dir, "initialSchema.yml"))) return StoreMigrator.deserialize(readInitialSchema());
|
|
3621
|
+
return new StoreMigrator();
|
|
3622
|
+
}
|
|
3623
|
+
static deserialize(data) {
|
|
3624
|
+
const store = new StoreMigrator();
|
|
3625
|
+
store.tables = data.tables.map((it) => TableMigrator.deserialize(it, store));
|
|
3626
|
+
store.resetQueue();
|
|
3627
|
+
return store;
|
|
3628
|
+
}
|
|
3629
|
+
table(tableName) {
|
|
3630
|
+
const table = this.tables.find((it) => it.tableName === tableName);
|
|
3631
|
+
if (!table) throw new Error("QueryTable: " + tableName + " Not Found");
|
|
3632
|
+
return table;
|
|
3633
|
+
}
|
|
3634
|
+
addQuery(...query) {
|
|
3635
|
+
this.migrationQueue.push(...query);
|
|
3636
|
+
}
|
|
3637
|
+
createTable(tableName, tableCreator) {
|
|
3638
|
+
if (this.tables.find((it) => it.tableName === tableName)) throw new SasatError(`${tableName} is already exist`);
|
|
3639
|
+
const creator = new TableCreator(tableName, this);
|
|
3640
|
+
tableCreator(creator);
|
|
3641
|
+
const table = new TableMigrator(creator.create(), this);
|
|
3642
|
+
this.tables.push(table);
|
|
3643
|
+
this.addQuery(table.showCreateTable());
|
|
3644
|
+
this.addQuery(...table.getIndexes().map((it) => it.addSql()));
|
|
3645
|
+
return this;
|
|
3646
|
+
}
|
|
3647
|
+
dropTable(tableName) {
|
|
3648
|
+
this.addQuery(`DROP TABLE ${tableName}`);
|
|
3649
|
+
this.tables = this.tables.filter((it) => it.tableName !== tableName);
|
|
3650
|
+
return this;
|
|
3651
|
+
}
|
|
3652
|
+
sql(...sql) {
|
|
3653
|
+
this.addQuery(...sql);
|
|
3654
|
+
return this;
|
|
3655
|
+
}
|
|
3656
|
+
getSql() {
|
|
3657
|
+
return this.migrationQueue;
|
|
3658
|
+
}
|
|
3659
|
+
resetQueue() {
|
|
3660
|
+
this.migrationQueue = [];
|
|
3661
|
+
}
|
|
3662
|
+
serialize() {
|
|
3663
|
+
return { tables: this.tables.map((it) => it.serialize()) };
|
|
3664
|
+
}
|
|
3665
|
+
setConfig(conf) {
|
|
3666
|
+
this.conf = conf;
|
|
3667
|
+
return this;
|
|
3668
|
+
}
|
|
3669
|
+
getUpdateConfig() {
|
|
3670
|
+
return this.conf;
|
|
3671
|
+
}
|
|
3672
|
+
};
|
|
3673
|
+
//#endregion
|
|
3674
|
+
//#region src/db/formatQuery.ts
|
|
3675
|
+
const formatQuery = (str, ...params) => {
|
|
3676
|
+
let ret = str[0];
|
|
3677
|
+
for (let i = 0; i < params.length; i++) {
|
|
3678
|
+
if (typeof params[i] === "function") ret += params[i]();
|
|
3679
|
+
else if (Array.isArray(params[i])) ret += params[i].map((it) => SqlString.escape(it)).join(", ");
|
|
3680
|
+
else ret += SqlString.escape(params[i]);
|
|
3681
|
+
ret += str[i + 1];
|
|
3682
|
+
}
|
|
3683
|
+
return ret;
|
|
3684
|
+
};
|
|
3685
|
+
//#endregion
|
|
3686
|
+
//#region src/db/connectors/dbClient.ts
|
|
3687
|
+
const noop = () => {};
|
|
3688
|
+
var SQLClient = class {
|
|
3689
|
+
constructor() {
|
|
3690
|
+
this.logger = noop;
|
|
3691
|
+
}
|
|
3692
|
+
rawQuery(sql) {
|
|
3693
|
+
this.logger(sql);
|
|
3694
|
+
return this.execSql(sql);
|
|
3695
|
+
}
|
|
3696
|
+
rawCommand(sql) {
|
|
3697
|
+
this.logger(sql);
|
|
3698
|
+
return this.execSql(sql);
|
|
3699
|
+
}
|
|
3700
|
+
query(templateString, ...params) {
|
|
3701
|
+
return this.rawQuery(formatQuery(templateString, ...params));
|
|
3702
|
+
}
|
|
3703
|
+
command(templateString, ...params) {
|
|
3704
|
+
return this.rawCommand(formatQuery(templateString, ...params));
|
|
3705
|
+
}
|
|
3706
|
+
};
|
|
3707
|
+
var SQLTransaction = class extends SQLClient {};
|
|
3708
|
+
var DBClient = class extends SQLClient {
|
|
3709
|
+
constructor(logger = noop) {
|
|
3710
|
+
super();
|
|
3711
|
+
this._released = false;
|
|
3712
|
+
this.logger = logger;
|
|
3713
|
+
}
|
|
3714
|
+
isReleased() {
|
|
3715
|
+
return this._released;
|
|
3716
|
+
}
|
|
3717
|
+
};
|
|
3718
|
+
//#endregion
|
|
3719
|
+
//#region src/db/connectors/mysql/transaction.ts
|
|
3720
|
+
var MySqlTransaction = class extends SQLTransaction {
|
|
3721
|
+
constructor(connection) {
|
|
3722
|
+
super();
|
|
3723
|
+
this.connection = connection;
|
|
3724
|
+
}
|
|
3725
|
+
async commit() {
|
|
3726
|
+
const result = await this.connection.commit();
|
|
3727
|
+
await this.connection.end();
|
|
3728
|
+
return result;
|
|
3729
|
+
}
|
|
3730
|
+
async rollback() {
|
|
3731
|
+
await this.connection.rollback();
|
|
3732
|
+
await this.connection.end();
|
|
3733
|
+
}
|
|
3734
|
+
async execSql(sql) {
|
|
3735
|
+
return (await this.connection.query(sql))[0];
|
|
3736
|
+
}
|
|
3737
|
+
};
|
|
3738
|
+
//#endregion
|
|
3739
|
+
//#region src/db/connectors/mysql/poolClient.ts
|
|
3740
|
+
var MysqlPoolClient = class extends DBClient {
|
|
3741
|
+
constructor(poolOption, logger) {
|
|
3742
|
+
super(logger);
|
|
3743
|
+
this.poolOption = poolOption;
|
|
3744
|
+
this.pool = (0, mysql2_promise.createPool)({
|
|
3745
|
+
dateStrings: true,
|
|
3746
|
+
...poolOption
|
|
3747
|
+
});
|
|
3748
|
+
this.release = this.release.bind(this);
|
|
3749
|
+
}
|
|
3750
|
+
async transaction() {
|
|
3751
|
+
const connection = await (0, mysql2_promise.createConnection)({
|
|
3752
|
+
...config().db,
|
|
3753
|
+
dateStrings: true,
|
|
3754
|
+
...this.poolOption
|
|
3755
|
+
});
|
|
3756
|
+
await connection.beginTransaction();
|
|
3757
|
+
return new MySqlTransaction(connection);
|
|
3758
|
+
}
|
|
3759
|
+
async release() {
|
|
3760
|
+
await this.pool.end();
|
|
3761
|
+
this._released = true;
|
|
3762
|
+
}
|
|
3763
|
+
async execSql(sql) {
|
|
3764
|
+
return (await this.pool.query(sql))[0];
|
|
3765
|
+
}
|
|
3766
|
+
};
|
|
3767
|
+
//#endregion
|
|
3768
|
+
//#region src/db/getDbClient.ts
|
|
3769
|
+
let client;
|
|
3770
|
+
const getDbClient = (option, logger) => {
|
|
3771
|
+
if (client && !client.isReleased()) return client;
|
|
3772
|
+
client = new MysqlPoolClient({
|
|
3773
|
+
...config().db,
|
|
3774
|
+
...option
|
|
3775
|
+
}, logger);
|
|
3776
|
+
return client;
|
|
3777
|
+
};
|
|
3778
|
+
//#endregion
|
|
3779
|
+
//#region src/migration/exec/getCurrentMigration.ts
|
|
3780
|
+
const calcRunMigrationFileNames = (records) => {
|
|
3781
|
+
const result = [];
|
|
3782
|
+
records.forEach((it) => {
|
|
3783
|
+
if (it.direction === "down") {
|
|
3784
|
+
if (result[result.length] !== it.name) throw new Error("Invalid migration history: `down` migration must be the same migration as the last `up` migration ");
|
|
3785
|
+
result.pop();
|
|
3786
|
+
return;
|
|
3787
|
+
}
|
|
3788
|
+
result.push(it.name);
|
|
3789
|
+
});
|
|
3790
|
+
return result;
|
|
3791
|
+
};
|
|
3792
|
+
const getCurrentMigration = async (options) => {
|
|
3793
|
+
const migrationTable = SqlString.escapeId(config().migration.table);
|
|
3794
|
+
const files = getMigrationFileNames();
|
|
3795
|
+
const client = getDbClient();
|
|
3796
|
+
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)`;
|
|
3797
|
+
if (!options.silent) {
|
|
3798
|
+
Console.log(`creating migration table: ${migrationTable} :: ${Buffer.from(migrationTable).toString("base64")}`);
|
|
3799
|
+
Console.log(query);
|
|
3800
|
+
}
|
|
3801
|
+
await client.rawQuery(query);
|
|
3802
|
+
const q = `SELECT name, direction FROM ${migrationTable} ORDER BY id ASC`;
|
|
3803
|
+
if (!options.silent) Console.debug(q);
|
|
3804
|
+
const result = await client.rawQuery(q);
|
|
3805
|
+
console.debug(result);
|
|
3806
|
+
if (!result.length) return;
|
|
3807
|
+
const runs = calcRunMigrationFileNames(result);
|
|
3808
|
+
if (runs.length === 0) return;
|
|
3809
|
+
runs.forEach((run, i) => {
|
|
3810
|
+
if (files[i] !== run) throw new Error(`\
|
|
3811
|
+
Invalid migration order: Migration must be performed in the same order
|
|
3812
|
+
Found : ${files[i]}
|
|
3813
|
+
in migration history: ${run}`);
|
|
3814
|
+
});
|
|
3815
|
+
return runs[runs.length - 1];
|
|
3816
|
+
};
|
|
3817
|
+
//#endregion
|
|
3818
|
+
//#region src/migration/exec/migrationFileCompiler.ts
|
|
3819
|
+
const changeExtTsToJs = (fileName) => fileName.slice(0, -3) + ".mjs";
|
|
3820
|
+
const compileMigrationFiles = () => {
|
|
3821
|
+
const compiles = getMigrationFileNames().map(async (fileName) => {
|
|
3822
|
+
const filePath = node_path.default.join(getMigrationFileDir(), fileName);
|
|
3823
|
+
const r = await (0, esbuild.build)({
|
|
3824
|
+
entryPoints: [filePath],
|
|
3825
|
+
bundle: true,
|
|
3826
|
+
outfile: changeExtTsToJs(filePath),
|
|
3827
|
+
platform: "node",
|
|
3828
|
+
format: "esm",
|
|
3829
|
+
outExtension: { ".js": ".mjs" },
|
|
3830
|
+
banner: { js: `import { createRequire as topLevelCreateRequire } from 'module';
|
|
3831
|
+
const require = topLevelCreateRequire(import.meta.url);
|
|
3832
|
+
import { fileURLToPath as __topLevelFileURLToPath } from 'url';
|
|
3833
|
+
import { dirname as __topLevelDirname } from 'path';
|
|
3834
|
+
const __filename = __topLevelFileURLToPath(import.meta.url);
|
|
3835
|
+
const __dirname = __topLevelDirname(__filename);
|
|
3836
|
+
` }
|
|
3837
|
+
});
|
|
3838
|
+
if (r.errors.length !== 0) throw r.errors;
|
|
3839
|
+
return fileName;
|
|
3840
|
+
});
|
|
3841
|
+
return Promise.all(compiles);
|
|
3842
|
+
};
|
|
3843
|
+
//#endregion
|
|
3844
|
+
//#region src/migration/exec/readMigrationFile.ts
|
|
3845
|
+
const readMigration = async (store, tsFileName, direction) => {
|
|
3846
|
+
const instance = new (await (import(node_path.default.join(process.cwd(), config().migration.dir, changeExtTsToJs(tsFileName))))).default();
|
|
3847
|
+
if (direction === "up") {
|
|
3848
|
+
if (instance.beforeUp) await instance.beforeUp();
|
|
3849
|
+
await instance.up(store);
|
|
3850
|
+
if (instance.afterUp) await instance.afterUp();
|
|
3851
|
+
} else {
|
|
3852
|
+
if (instance.beforeDown) await instance.beforeDown();
|
|
3853
|
+
await instance.down(store);
|
|
3854
|
+
if (instance.afterDown) await instance.afterDown();
|
|
3855
|
+
}
|
|
3856
|
+
return store;
|
|
3857
|
+
};
|
|
3858
|
+
//#endregion
|
|
3859
|
+
//#region src/migration/exec/createCurrentMigrationDataStore.ts
|
|
3860
|
+
const createCurrentMigrationDataStore = async (targetMigrationName) => {
|
|
3861
|
+
const allFiles = getMigrationFileNames();
|
|
3862
|
+
let store = StoreMigrator.new();
|
|
3863
|
+
if (!targetMigrationName) return store;
|
|
3864
|
+
const files = allFiles.slice(0, allFiles.indexOf(targetMigrationName) + 1);
|
|
3865
|
+
for (const tsFileName of files) store = await readMigration(store, tsFileName, "up");
|
|
3866
|
+
store.resetQueue();
|
|
3867
|
+
return store;
|
|
3868
|
+
};
|
|
3869
|
+
//#endregion
|
|
3870
|
+
//#region src/migration/exec/getMigrationTarget.ts
|
|
3871
|
+
const getMigrationTargets = (files, current) => {
|
|
3872
|
+
const currentIndex = current ? files.indexOf(current) + 1 : 0;
|
|
3873
|
+
const targetIndex = files.indexOf(config().migration.target || files[files.length - 1]) + 1;
|
|
3874
|
+
if (currentIndex === -1 || targetIndex === -1) throw new Error("migration target not found");
|
|
3875
|
+
if (targetIndex >= currentIndex) return {
|
|
3876
|
+
direction: "up",
|
|
3877
|
+
files: files.slice(currentIndex, targetIndex)
|
|
3878
|
+
};
|
|
3879
|
+
return {
|
|
3880
|
+
direction: "down",
|
|
3881
|
+
files: files.slice(targetIndex, currentIndex).reverse()
|
|
3882
|
+
};
|
|
3883
|
+
};
|
|
3884
|
+
//#endregion
|
|
3885
|
+
//#region src/migration/exec/runMigration.ts
|
|
3886
|
+
const runMigration = async (client, store, migrationName, direction, options) => {
|
|
3887
|
+
const sqls = store.getSql();
|
|
3888
|
+
const conf = store.getUpdateConfig();
|
|
3889
|
+
if (conf) setConfig(conf);
|
|
3890
|
+
store.resetQueue();
|
|
3891
|
+
if (!options.silent) sqls.forEach(Console.log);
|
|
3892
|
+
if (options.dry) return;
|
|
3893
|
+
const transaction = await client.transaction();
|
|
3894
|
+
try {
|
|
3895
|
+
for (const sql of sqls) await transaction.rawQuery(sql).catch((e) => {
|
|
3896
|
+
Console.error(`ERROR ON ${migrationName}`);
|
|
3897
|
+
Console.error(`SQL: ${sql}`);
|
|
3898
|
+
Console.error(`MESSAGE: ${e.message}`);
|
|
3899
|
+
process.exit(1);
|
|
3900
|
+
});
|
|
3901
|
+
await transaction.query`insert into ${() => config().migration.table} (name, direction) values (${[migrationName, direction]})`;
|
|
3902
|
+
return await transaction.commit();
|
|
3903
|
+
} catch (e) {
|
|
3904
|
+
await transaction.rollback();
|
|
3905
|
+
throw e;
|
|
3906
|
+
}
|
|
3907
|
+
};
|
|
3908
|
+
//#endregion
|
|
3909
|
+
//#region src/migration/controller.ts
|
|
3910
|
+
var MigrationController = class {
|
|
3911
|
+
async migrate(client, options) {
|
|
3912
|
+
const fileNames = getMigrationFileNames();
|
|
3913
|
+
const currentMigration = await getCurrentMigration(options);
|
|
3914
|
+
if (!options.silent) Console.log("--current migration--: " + currentMigration);
|
|
3915
|
+
let store = await createCurrentMigrationDataStore(currentMigration);
|
|
3916
|
+
if (store.getUpdateConfig()) setConfig(store.getUpdateConfig());
|
|
3917
|
+
const target = getMigrationTargets(fileNames, currentMigration);
|
|
3918
|
+
for (const tsFileName of target.files) {
|
|
3919
|
+
if (!options.silent) Console.log("---------\n" + tsFileName);
|
|
3920
|
+
store = await readMigration(store, tsFileName, target.direction);
|
|
3921
|
+
await runMigration(client, store, tsFileName, target.direction, options);
|
|
3922
|
+
store.resetQueue();
|
|
3923
|
+
}
|
|
3924
|
+
return {
|
|
3925
|
+
store: store.serialize(),
|
|
3926
|
+
currentMigration: config().migration.target || fileNames[fileNames.length - 1]
|
|
3927
|
+
};
|
|
3928
|
+
}
|
|
3929
|
+
};
|
|
3930
|
+
//#endregion
|
|
3931
|
+
//#region src/migration/dataStore.ts
|
|
3932
|
+
var DataStoreHandler = class {
|
|
3933
|
+
constructor(store) {
|
|
3934
|
+
this.tables = store.tables.map((it) => new TableHandler(it, this));
|
|
3935
|
+
}
|
|
3936
|
+
table(tableName) {
|
|
3937
|
+
const table = this.tables.find((it) => it.tableName === tableName);
|
|
3938
|
+
if (!table) throw new Error(`Table: ${tableName} is Not Found`);
|
|
3939
|
+
return table;
|
|
3940
|
+
}
|
|
3941
|
+
referencedBy(tableName) {
|
|
3942
|
+
return this.tables.flatMap((it) => it.columns.filter((it) => it.isReference() && it.data.reference.parentTable === tableName));
|
|
3943
|
+
}
|
|
3944
|
+
virtualReferencedBy(tableName) {
|
|
3945
|
+
return this.tables.flatMap((it) => it.virtualRelations.filter((it) => it.parentTable === tableName));
|
|
3946
|
+
}
|
|
3947
|
+
};
|
|
3948
|
+
//#endregion
|
|
3949
|
+
//#region src/cli/commands/migrate.ts
|
|
3950
|
+
const migrate = async (client, options) => {
|
|
3951
|
+
let current;
|
|
3952
|
+
if (!options.silent) Console.log("--migration started--");
|
|
3953
|
+
try {
|
|
3954
|
+
if (!options.skipBuild) await compileMigrationFiles();
|
|
3955
|
+
const conf = config();
|
|
3956
|
+
if (conf.migration.db) setConfig({ db: conf.migration.db });
|
|
3957
|
+
const result = await new MigrationController().migrate(client, options);
|
|
3958
|
+
current = result.currentMigration;
|
|
3959
|
+
if (options.generateFiles) {
|
|
3960
|
+
const storeHandler = new DataStoreHandler(result.store);
|
|
3961
|
+
writeCurrentSchema(result.store);
|
|
3962
|
+
await new CodeGen_v2(storeHandler).generate();
|
|
3963
|
+
}
|
|
3964
|
+
if (!options.silent) Console.success(`current migration is ${current}`);
|
|
3965
|
+
} catch (e) {
|
|
3966
|
+
Console.error(e.message);
|
|
3967
|
+
throw e;
|
|
3968
|
+
}
|
|
3969
|
+
};
|
|
3970
|
+
//#endregion
|
|
3971
|
+
Object.defineProperty(exports, "CodeGen_v2", {
|
|
3972
|
+
enumerable: true,
|
|
3973
|
+
get: function() {
|
|
3974
|
+
return CodeGen_v2;
|
|
3975
|
+
}
|
|
3976
|
+
});
|
|
3977
|
+
Object.defineProperty(exports, "Conditions", {
|
|
3978
|
+
enumerable: true,
|
|
3979
|
+
get: function() {
|
|
3980
|
+
return Conditions;
|
|
3981
|
+
}
|
|
3982
|
+
});
|
|
3983
|
+
Object.defineProperty(exports, "Console", {
|
|
3984
|
+
enumerable: true,
|
|
3985
|
+
get: function() {
|
|
3986
|
+
return Console;
|
|
3987
|
+
}
|
|
3988
|
+
});
|
|
3989
|
+
Object.defineProperty(exports, "DBClient", {
|
|
3990
|
+
enumerable: true,
|
|
3991
|
+
get: function() {
|
|
3992
|
+
return DBClient;
|
|
3993
|
+
}
|
|
3994
|
+
});
|
|
3995
|
+
Object.defineProperty(exports, "DBColumnTypes", {
|
|
3996
|
+
enumerable: true,
|
|
3997
|
+
get: function() {
|
|
3998
|
+
return DBColumnTypes;
|
|
3999
|
+
}
|
|
4000
|
+
});
|
|
4001
|
+
Object.defineProperty(exports, "DataStoreHandler", {
|
|
4002
|
+
enumerable: true,
|
|
4003
|
+
get: function() {
|
|
4004
|
+
return DataStoreHandler;
|
|
4005
|
+
}
|
|
4006
|
+
});
|
|
4007
|
+
Object.defineProperty(exports, "Directory", {
|
|
4008
|
+
enumerable: true,
|
|
4009
|
+
get: function() {
|
|
4010
|
+
return Directory;
|
|
4011
|
+
}
|
|
4012
|
+
});
|
|
4013
|
+
Object.defineProperty(exports, "MySqlTransaction", {
|
|
4014
|
+
enumerable: true,
|
|
4015
|
+
get: function() {
|
|
4016
|
+
return MySqlTransaction;
|
|
4017
|
+
}
|
|
4018
|
+
});
|
|
4019
|
+
Object.defineProperty(exports, "SasatError", {
|
|
4020
|
+
enumerable: true,
|
|
4021
|
+
get: function() {
|
|
4022
|
+
return SasatError;
|
|
4023
|
+
}
|
|
4024
|
+
});
|
|
4025
|
+
Object.defineProperty(exports, "SqlString", {
|
|
4026
|
+
enumerable: true,
|
|
4027
|
+
get: function() {
|
|
4028
|
+
return SqlString;
|
|
4029
|
+
}
|
|
4030
|
+
});
|
|
4031
|
+
Object.defineProperty(exports, "__toESM", {
|
|
4032
|
+
enumerable: true,
|
|
4033
|
+
get: function() {
|
|
4034
|
+
return __toESM;
|
|
4035
|
+
}
|
|
4036
|
+
});
|
|
4037
|
+
Object.defineProperty(exports, "assignDeep", {
|
|
4038
|
+
enumerable: true,
|
|
4039
|
+
get: function() {
|
|
4040
|
+
return assignDeep;
|
|
4041
|
+
}
|
|
4042
|
+
});
|
|
4043
|
+
Object.defineProperty(exports, "camelize", {
|
|
4044
|
+
enumerable: true,
|
|
4045
|
+
get: function() {
|
|
4046
|
+
return camelize;
|
|
4047
|
+
}
|
|
4048
|
+
});
|
|
4049
|
+
Object.defineProperty(exports, "capitalizeFirstLetter", {
|
|
4050
|
+
enumerable: true,
|
|
4051
|
+
get: function() {
|
|
4052
|
+
return capitalizeFirstLetter;
|
|
4053
|
+
}
|
|
4054
|
+
});
|
|
4055
|
+
Object.defineProperty(exports, "columnTypeToGqlPrimitive", {
|
|
4056
|
+
enumerable: true,
|
|
4057
|
+
get: function() {
|
|
4058
|
+
return columnTypeToGqlPrimitive;
|
|
4059
|
+
}
|
|
4060
|
+
});
|
|
4061
|
+
Object.defineProperty(exports, "compileMigrationFiles", {
|
|
4062
|
+
enumerable: true,
|
|
4063
|
+
get: function() {
|
|
4064
|
+
return compileMigrationFiles;
|
|
4065
|
+
}
|
|
4066
|
+
});
|
|
4067
|
+
Object.defineProperty(exports, "config", {
|
|
4068
|
+
enumerable: true,
|
|
4069
|
+
get: function() {
|
|
4070
|
+
return config;
|
|
4071
|
+
}
|
|
4072
|
+
});
|
|
4073
|
+
Object.defineProperty(exports, "createCurrentMigrationDataStore", {
|
|
4074
|
+
enumerable: true,
|
|
4075
|
+
get: function() {
|
|
4076
|
+
return createCurrentMigrationDataStore;
|
|
4077
|
+
}
|
|
4078
|
+
});
|
|
4079
|
+
Object.defineProperty(exports, "defaultColumnOption", {
|
|
4080
|
+
enumerable: true,
|
|
4081
|
+
get: function() {
|
|
4082
|
+
return defaultColumnOption;
|
|
4083
|
+
}
|
|
4084
|
+
});
|
|
4085
|
+
Object.defineProperty(exports, "defaultConf", {
|
|
4086
|
+
enumerable: true,
|
|
4087
|
+
get: function() {
|
|
4088
|
+
return defaultConf;
|
|
4089
|
+
}
|
|
4090
|
+
});
|
|
4091
|
+
Object.defineProperty(exports, "defaultGQLOption", {
|
|
4092
|
+
enumerable: true,
|
|
4093
|
+
get: function() {
|
|
4094
|
+
return defaultGQLOption;
|
|
4095
|
+
}
|
|
4096
|
+
});
|
|
4097
|
+
Object.defineProperty(exports, "formatQuery", {
|
|
4098
|
+
enumerable: true,
|
|
4099
|
+
get: function() {
|
|
4100
|
+
return formatQuery;
|
|
4101
|
+
}
|
|
4102
|
+
});
|
|
4103
|
+
Object.defineProperty(exports, "getDbClient", {
|
|
4104
|
+
enumerable: true,
|
|
4105
|
+
get: function() {
|
|
4106
|
+
return getDbClient;
|
|
4107
|
+
}
|
|
4108
|
+
});
|
|
4109
|
+
Object.defineProperty(exports, "getMigrationFileNames", {
|
|
4110
|
+
enumerable: true,
|
|
4111
|
+
get: function() {
|
|
4112
|
+
return getMigrationFileNames;
|
|
4113
|
+
}
|
|
4114
|
+
});
|
|
4115
|
+
Object.defineProperty(exports, "migrate", {
|
|
4116
|
+
enumerable: true,
|
|
4117
|
+
get: function() {
|
|
4118
|
+
return migrate;
|
|
4119
|
+
}
|
|
4120
|
+
});
|
|
4121
|
+
Object.defineProperty(exports, "mkDirIfNotExist", {
|
|
4122
|
+
enumerable: true,
|
|
4123
|
+
get: function() {
|
|
4124
|
+
return mkDirIfNotExist;
|
|
4125
|
+
}
|
|
4126
|
+
});
|
|
4127
|
+
Object.defineProperty(exports, "nonNullable", {
|
|
4128
|
+
enumerable: true,
|
|
4129
|
+
get: function() {
|
|
4130
|
+
return nonNullable;
|
|
4131
|
+
}
|
|
4132
|
+
});
|
|
4133
|
+
Object.defineProperty(exports, "pick", {
|
|
4134
|
+
enumerable: true,
|
|
4135
|
+
get: function() {
|
|
4136
|
+
return pick;
|
|
4137
|
+
}
|
|
4138
|
+
});
|
|
4139
|
+
Object.defineProperty(exports, "setConfig", {
|
|
4140
|
+
enumerable: true,
|
|
4141
|
+
get: function() {
|
|
4142
|
+
return setConfig;
|
|
4143
|
+
}
|
|
4144
|
+
});
|
|
4145
|
+
Object.defineProperty(exports, "unique", {
|
|
4146
|
+
enumerable: true,
|
|
4147
|
+
get: function() {
|
|
4148
|
+
return unique;
|
|
4149
|
+
}
|
|
4150
|
+
});
|
|
4151
|
+
Object.defineProperty(exports, "writeCurrentSchema", {
|
|
4152
|
+
enumerable: true,
|
|
4153
|
+
get: function() {
|
|
4154
|
+
return writeCurrentSchema;
|
|
4155
|
+
}
|
|
4156
|
+
});
|
|
4157
|
+
Object.defineProperty(exports, "writeYmlFile", {
|
|
4158
|
+
enumerable: true,
|
|
4159
|
+
get: function() {
|
|
4160
|
+
return writeYmlFile;
|
|
4161
|
+
}
|
|
4162
|
+
});
|