@graf-research/adf-codegen-model-typeorm 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/exec.js +60 -0
- package/dist/index.js +275 -0
- package/package.json +33 -0
package/dist/exec.js
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
"use strict";
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
10
|
+
});
|
11
|
+
};
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
14
|
+
};
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
17
|
+
const adf_core_1 = require("@graf-research/adf-core");
|
18
|
+
const axios_1 = __importDefault(require("axios"));
|
19
|
+
const _1 = require(".");
|
20
|
+
const url_regex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
|
21
|
+
if (!process.argv[2]) {
|
22
|
+
throw new Error(`argv[2] cannot be empty`);
|
23
|
+
}
|
24
|
+
if (!process.argv[3]) {
|
25
|
+
throw new Error(`argv[3] cannot be empty`);
|
26
|
+
}
|
27
|
+
exec(process.argv[2], process.argv[3]);
|
28
|
+
function exec(input_file_or_url, out_folder) {
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
30
|
+
let code = '';
|
31
|
+
if (url_regex.test(input_file_or_url)) {
|
32
|
+
console.log(`downloading file '${input_file_or_url}'...`);
|
33
|
+
const response = yield axios_1.default.get(input_file_or_url, { responseType: 'text' });
|
34
|
+
code = response.data;
|
35
|
+
console.log(`download complete.`);
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
const readFromFile = (f) => new Promise((resolve, reject) => fs_1.default.readFile(f, 'utf-8', (err, data) => err ? reject(err) : resolve(data)));
|
39
|
+
code = yield readFromFile(input_file_or_url);
|
40
|
+
}
|
41
|
+
const result = (0, adf_core_1.parse)(code);
|
42
|
+
const typeorm_model = _1.TypeORMModel.compile([...result.list_table, ...result.list_enum]);
|
43
|
+
for (const f of typeorm_model.enum.files) {
|
44
|
+
writeFiles(f, out_folder);
|
45
|
+
}
|
46
|
+
for (const f of typeorm_model.table.files) {
|
47
|
+
writeFiles(f, out_folder);
|
48
|
+
}
|
49
|
+
});
|
50
|
+
}
|
51
|
+
function writeFiles(output_1) {
|
52
|
+
return __awaiter(this, arguments, void 0, function* (output, main_project_location = 'project') {
|
53
|
+
const folder = main_project_location + '/' + output.filename.split('/').slice(0, -1).join('/');
|
54
|
+
if (!fs_1.default.existsSync(folder)) {
|
55
|
+
fs_1.default.mkdirSync(folder, { recursive: true });
|
56
|
+
}
|
57
|
+
const filename = main_project_location + '/' + output.filename;
|
58
|
+
fs_1.default.writeFileSync(filename, output.content);
|
59
|
+
});
|
60
|
+
}
|
package/dist/index.js
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.TypeORMModel = void 0;
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
8
|
+
var TypeORMModel;
|
9
|
+
(function (TypeORMModel) {
|
10
|
+
function compile(list_model) {
|
11
|
+
const list_table_output = list_model.filter(i => i.type === 'table').map((t) => buildFromTable(t, list_model));
|
12
|
+
const list_enume_output = list_model.filter(i => i.type === 'enum').map((t) => buildFromEnum(t));
|
13
|
+
return {
|
14
|
+
table: {
|
15
|
+
files: list_table_output.reduce((accumulator, o) => [...accumulator, ...o.files], []),
|
16
|
+
map: list_table_output.reduce((accumulator, o) => (Object.assign(Object.assign({}, accumulator), o.map)), {})
|
17
|
+
},
|
18
|
+
enum: {
|
19
|
+
files: list_enume_output.reduce((accumulator, o) => [...accumulator, ...o.files], []),
|
20
|
+
map: list_enume_output.reduce((accumulator, o) => (Object.assign(Object.assign({}, accumulator), o.map)), {})
|
21
|
+
}
|
22
|
+
};
|
23
|
+
}
|
24
|
+
TypeORMModel.compile = compile;
|
25
|
+
function sqlTypeToJSType(type) {
|
26
|
+
switch (type.kind) {
|
27
|
+
case "common":
|
28
|
+
switch (type.type) {
|
29
|
+
case 'text':
|
30
|
+
case "varchar":
|
31
|
+
return 'string';
|
32
|
+
case 'int':
|
33
|
+
case 'float':
|
34
|
+
case 'bigint':
|
35
|
+
case "tinyint":
|
36
|
+
case "smallint":
|
37
|
+
case "real":
|
38
|
+
case "decimal":
|
39
|
+
return 'number';
|
40
|
+
case 'boolean':
|
41
|
+
return 'boolean';
|
42
|
+
case 'timestamp':
|
43
|
+
case "date":
|
44
|
+
return 'Date';
|
45
|
+
}
|
46
|
+
case "decimal":
|
47
|
+
switch (type.type) {
|
48
|
+
case 'decimal':
|
49
|
+
return 'number';
|
50
|
+
}
|
51
|
+
case "chars":
|
52
|
+
switch (type.type) {
|
53
|
+
case 'varchar':
|
54
|
+
return 'string';
|
55
|
+
}
|
56
|
+
case "enum":
|
57
|
+
switch (type.type) {
|
58
|
+
case 'enum':
|
59
|
+
return type.enum_name;
|
60
|
+
}
|
61
|
+
case "relation":
|
62
|
+
switch (type.type) {
|
63
|
+
case 'relation':
|
64
|
+
return type.table_name;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
TypeORMModel.sqlTypeToJSType = sqlTypeToJSType;
|
69
|
+
function getModelFileName(item, extension) {
|
70
|
+
switch (item.type) {
|
71
|
+
case "table": return `./model/table/${item.name}${extension !== null && extension !== void 0 ? extension : ''}`;
|
72
|
+
case "enum": return `./model/enum/${item.name}${extension !== null && extension !== void 0 ? extension : ''}`;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
function buildTableDependency(table, list_model) {
|
76
|
+
return table.columns
|
77
|
+
.filter((tc) => tc.type.type === 'relation' || tc.type.type === 'enum')
|
78
|
+
.map((tc) => {
|
79
|
+
const type = tc.type;
|
80
|
+
switch (type.type) {
|
81
|
+
case 'enum':
|
82
|
+
const enum_item = list_model.find((m) => m.type === 'enum' && m.name === type.enum_name);
|
83
|
+
if (!enum_item) {
|
84
|
+
throw new Error(`Enum "${tc.name}" is not available on models`);
|
85
|
+
}
|
86
|
+
return `import { ${enum_item.name} } from '../.${getModelFileName(enum_item)}'`;
|
87
|
+
case 'relation':
|
88
|
+
const table_item = list_model.find((m) => m.type === 'table' && m.name === type.table_name);
|
89
|
+
if (!table_item) {
|
90
|
+
throw new Error(`Table "${tc.name}" is not available on models`);
|
91
|
+
}
|
92
|
+
return `import { ${table_item.name} } from '../.${getModelFileName(table_item)}'`;
|
93
|
+
}
|
94
|
+
});
|
95
|
+
}
|
96
|
+
function isIsoDate(str) {
|
97
|
+
if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str))
|
98
|
+
return false;
|
99
|
+
const d = new Date(str);
|
100
|
+
return !isNaN(d.getTime()) && d.toISOString() === str;
|
101
|
+
}
|
102
|
+
function getDefaultValue(default_value) {
|
103
|
+
switch (default_value.type) {
|
104
|
+
case "string":
|
105
|
+
return `'${default_value.data}'`;
|
106
|
+
case "number":
|
107
|
+
return String(default_value.data);
|
108
|
+
case "boolean":
|
109
|
+
return `'${String(default_value.data)}'`;
|
110
|
+
case "enum":
|
111
|
+
return `'${default_value.enum_value}'`;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
function buildColumnCommon(type, column, list_model) {
|
115
|
+
var _a, _b;
|
116
|
+
const null_attr = ((_a = column.attributes) !== null && _a !== void 0 ? _a : []).find((attr) => attr.type === 'null');
|
117
|
+
const default_value_attr = ((_b = column.attributes) !== null && _b !== void 0 ? _b : []).find((attr) => attr.type === 'default');
|
118
|
+
const is_required = null_attr ? !null_attr.value : false;
|
119
|
+
const has_default_value = Boolean(default_value_attr);
|
120
|
+
const typeorm_decorator = [
|
121
|
+
`@Column({`,
|
122
|
+
...[
|
123
|
+
`type: '${type.type}',`,
|
124
|
+
`nullable: ${is_required ? 'false' : 'true'},`,
|
125
|
+
has_default_value ? `default: ${getDefaultValue(default_value_attr.value)},` : ''
|
126
|
+
].filter(Boolean).map(line => ' ' + line),
|
127
|
+
`})`,
|
128
|
+
];
|
129
|
+
return [
|
130
|
+
...typeorm_decorator,
|
131
|
+
`${column.name}${is_required ? '!' : '?'}: ${sqlTypeToJSType(type)};`
|
132
|
+
];
|
133
|
+
}
|
134
|
+
function buildColumnDecimal(type, column) {
|
135
|
+
var _a, _b;
|
136
|
+
const null_attr = ((_a = column.attributes) !== null && _a !== void 0 ? _a : []).find((attr) => attr.type === 'null');
|
137
|
+
const default_value_attr = ((_b = column.attributes) !== null && _b !== void 0 ? _b : []).find((attr) => attr.type === 'default');
|
138
|
+
const is_required = null_attr ? !null_attr.value : false;
|
139
|
+
const has_default_value = Boolean(default_value_attr);
|
140
|
+
const typeorm_decorator = [
|
141
|
+
`@Column({`,
|
142
|
+
...[
|
143
|
+
`type: '${type.type}',`,
|
144
|
+
type.precision ? `precision: ${type.precision},` : '',
|
145
|
+
type.scale ? `scale: ${type.scale},` : '',
|
146
|
+
`nullable: ${is_required ? 'false' : 'true'},`,
|
147
|
+
has_default_value ? `default: ${getDefaultValue(default_value_attr.value)},` : ''
|
148
|
+
].filter(Boolean).map(line => ' ' + line),
|
149
|
+
`})`,
|
150
|
+
];
|
151
|
+
return [
|
152
|
+
...typeorm_decorator,
|
153
|
+
`${column.name}${is_required ? '!' : '?'}: ${sqlTypeToJSType(type)};`
|
154
|
+
];
|
155
|
+
}
|
156
|
+
function buildColumnChars(type, column) {
|
157
|
+
var _a, _b;
|
158
|
+
const null_attr = ((_a = column.attributes) !== null && _a !== void 0 ? _a : []).find((attr) => attr.type === 'null');
|
159
|
+
const default_value_attr = ((_b = column.attributes) !== null && _b !== void 0 ? _b : []).find((attr) => attr.type === 'default');
|
160
|
+
const is_required = null_attr ? !null_attr.value : false;
|
161
|
+
const has_default_value = Boolean(default_value_attr);
|
162
|
+
const typeorm_decorator = [
|
163
|
+
`@Column({`,
|
164
|
+
...[
|
165
|
+
`type: '${type.type}',`,
|
166
|
+
type.size ? `length: ${type.size},` : '',
|
167
|
+
`nullable: ${is_required ? 'false' : 'true'},`,
|
168
|
+
has_default_value ? `default: ${getDefaultValue(default_value_attr.value)},` : ''
|
169
|
+
].filter(Boolean).map(line => ' ' + line),
|
170
|
+
`})`,
|
171
|
+
];
|
172
|
+
return [
|
173
|
+
...typeorm_decorator,
|
174
|
+
`${column.name}${is_required ? '!' : '?'}: ${sqlTypeToJSType(type)};`
|
175
|
+
];
|
176
|
+
}
|
177
|
+
function buildColumnEnum(type, column) {
|
178
|
+
var _a, _b;
|
179
|
+
const null_attr = ((_a = column.attributes) !== null && _a !== void 0 ? _a : []).find((attr) => attr.type === 'null');
|
180
|
+
const default_value_attr = ((_b = column.attributes) !== null && _b !== void 0 ? _b : []).find((attr) => attr.type === 'default');
|
181
|
+
const is_required = null_attr ? !null_attr.value : false;
|
182
|
+
const has_default_value = Boolean(default_value_attr);
|
183
|
+
const typeorm_decorator = [
|
184
|
+
`@Column({`,
|
185
|
+
...[
|
186
|
+
`type: 'enum',`,
|
187
|
+
`enum: ${type.enum_name},`,
|
188
|
+
`nullable: ${is_required ? 'false' : 'true'},`,
|
189
|
+
has_default_value ? `default: ${getDefaultValue(default_value_attr.value)},` : ''
|
190
|
+
].filter(Boolean).map(line => ' ' + line),
|
191
|
+
`})`,
|
192
|
+
];
|
193
|
+
return [
|
194
|
+
...typeorm_decorator,
|
195
|
+
`${column.name}${is_required ? '!' : '?'}: ${sqlTypeToJSType(type)};`
|
196
|
+
];
|
197
|
+
}
|
198
|
+
function buildColumnRelation(type, column, table, list_model) {
|
199
|
+
var _a;
|
200
|
+
const null_attr = ((_a = column.attributes) !== null && _a !== void 0 ? _a : []).find((attr) => attr.type === 'null');
|
201
|
+
const is_required = null_attr ? !null_attr.value : false;
|
202
|
+
const foreign_table = list_model.find((item) => item.type === 'table' && item.name === type.table_name);
|
203
|
+
if (!foreign_table) {
|
204
|
+
throw new Error(`Table "${type.table_name}" not found on relation "${table.name}.${column.name}"`);
|
205
|
+
}
|
206
|
+
const foreign_column = foreign_table.columns.find((fc) => fc.name === type.foreign_key);
|
207
|
+
if (!foreign_column) {
|
208
|
+
throw new Error(`Column "${type.foreign_key}" on foreight table "${type.table_name}" not found on relation "${table.name}.${column.name}"`);
|
209
|
+
}
|
210
|
+
const one_to_many_field_name = `otm_${column.name}`;
|
211
|
+
const typeorm_decorator = [
|
212
|
+
`@ManyToOne(() => ${foreign_table.name}, x => x.${foreign_column.name}, { nullable: ${is_required ? 'false' : 'true'} })`,
|
213
|
+
`@JoinColumn({ name: '${column.name}' })`,
|
214
|
+
`${one_to_many_field_name}${is_required ? '!' : '?'}: ${foreign_table.name};`,
|
215
|
+
`@Column({`,
|
216
|
+
...[
|
217
|
+
`name: '${column.name}',`,
|
218
|
+
`type: '${foreign_column.type.type}',`,
|
219
|
+
`nullable: ${is_required ? 'false' : 'true'},`,
|
220
|
+
].filter(Boolean).map(line => ' ' + line),
|
221
|
+
`})`,
|
222
|
+
];
|
223
|
+
return [
|
224
|
+
...typeorm_decorator,
|
225
|
+
`${column.name}${is_required ? '!' : '?'}: ${sqlTypeToJSType(foreign_column.type)};`
|
226
|
+
];
|
227
|
+
}
|
228
|
+
function buildColumn(column, table, list_model) {
|
229
|
+
switch (column.type.kind) {
|
230
|
+
case "common": return buildColumnCommon(column.type, column, list_model);
|
231
|
+
case "decimal": return buildColumnDecimal(column.type, column);
|
232
|
+
case "chars": return buildColumnChars(column.type, column);
|
233
|
+
case "enum": return buildColumnEnum(column.type, column);
|
234
|
+
case "relation": return buildColumnRelation(column.type, column, table, list_model);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
function buildFromTable(table, list_model) {
|
238
|
+
return {
|
239
|
+
files: [{
|
240
|
+
filename: getModelFileName(table, '.ts'),
|
241
|
+
content: [
|
242
|
+
'import { Column, CreateDateColumn, DeleteDateColumn, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn, BaseEntity } from "typeorm";',
|
243
|
+
...lodash_1.default.uniq(buildTableDependency(table, list_model)),
|
244
|
+
'',
|
245
|
+
`@Entity('${table.name}')`,
|
246
|
+
`export class ${table.name} extends BaseEntity {`,
|
247
|
+
...table.columns
|
248
|
+
.reduce((acc, c) => [...acc, ...buildColumn(c, table, list_model)], [])
|
249
|
+
.map(line => ' ' + line),
|
250
|
+
`}`
|
251
|
+
].join('\n')
|
252
|
+
}],
|
253
|
+
map: {
|
254
|
+
[table.name]: getModelFileName(table)
|
255
|
+
}
|
256
|
+
};
|
257
|
+
}
|
258
|
+
function buildFromEnum(enume) {
|
259
|
+
return {
|
260
|
+
files: [{
|
261
|
+
filename: getModelFileName(enume, '.ts'),
|
262
|
+
content: [
|
263
|
+
`export enum ${enume.name} {`,
|
264
|
+
...enume.items
|
265
|
+
.map(s => `'${s}' = '${s}',`)
|
266
|
+
.map(line => ' ' + line),
|
267
|
+
`};`
|
268
|
+
].join('\n')
|
269
|
+
}],
|
270
|
+
map: {
|
271
|
+
[enume.name]: getModelFileName(enume)
|
272
|
+
}
|
273
|
+
};
|
274
|
+
}
|
275
|
+
})(TypeORMModel || (exports.TypeORMModel = TypeORMModel = {}));
|
package/package.json
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
{
|
2
|
+
"name": "@graf-research/adf-codegen-model-typeorm",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"main": "index.js",
|
5
|
+
"scripts": {
|
6
|
+
"build": "rm -rf dist && tsc",
|
7
|
+
"start": "node dist",
|
8
|
+
"dev": "npm run build && npm start",
|
9
|
+
"test": "npm run dev"
|
10
|
+
},
|
11
|
+
"bin": {
|
12
|
+
"adf-codegen-model-typeorm": "dist/exec.js"
|
13
|
+
},
|
14
|
+
"files": [
|
15
|
+
"dist/**/*.js",
|
16
|
+
"package.json"
|
17
|
+
],
|
18
|
+
"keywords": [],
|
19
|
+
"author": "",
|
20
|
+
"license": "ISC",
|
21
|
+
"description": "",
|
22
|
+
"devDependencies": {
|
23
|
+
"@types/axios": "^0.9.36",
|
24
|
+
"@types/lodash": "^4.17.13",
|
25
|
+
"@types/node": "^22.8.1",
|
26
|
+
"typescript": "^5.6.3"
|
27
|
+
},
|
28
|
+
"dependencies": {
|
29
|
+
"@graf-research/adf-core": "^0.0.4",
|
30
|
+
"axios": "^1.7.7",
|
31
|
+
"lodash": "^4.17.21"
|
32
|
+
}
|
33
|
+
}
|