@graf-research/adf-codegen-model-typeorm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. package/dist/exec.js +60 -0
  2. package/dist/index.js +275 -0
  3. 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
+ }