@carbonorm/carbonnode 1.1.2 → 1.1.7
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/api/interfaces/ormInterfaces.d.ts +1 -0
- package/dist/index.cjs.js +8 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +8 -2
- package/dist/index.esm.js.map +1 -1
- package/package.json +11 -4
- package/scripts/assets/handlebars/C6.tsx.handlebars +115 -0
- package/scripts/assets/handlebars/Tests.tsx.handlebars +121 -0
- package/scripts/generateRestBindings.cjs +291 -0
- package/scripts/generateRestBindings.ts +381 -0
- package/src/api/axiosInstance.ts +8 -2
- package/src/api/interfaces/ormInterfaces.ts +9 -0
- package/src/api/restRequest.ts +2 -1
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
const {execSync} = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const Handlebars = require('handlebars');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const args = process.argv.slice(2); // Slice the first two elements
|
|
8
|
+
const argMap = {};
|
|
9
|
+
|
|
10
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
11
|
+
argMap[args[i]] = args[i + 1];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const createDirIfNotExists = dir =>
|
|
15
|
+
!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined;
|
|
16
|
+
|
|
17
|
+
class MySQLDump {
|
|
18
|
+
|
|
19
|
+
static mysqlcnf: string = '';
|
|
20
|
+
static mysqldump: string = '';
|
|
21
|
+
static DB_USER = argMap['--user'] || 'root';
|
|
22
|
+
static DB_PASS = argMap['--pass'] || 'password';
|
|
23
|
+
static DB_HOST = argMap['--host'] || '127.0.0.1';
|
|
24
|
+
static DB_PORT = argMap['--port'] || '3306';
|
|
25
|
+
static DB_NAME = argMap['--dbname'] || 'carbonPHP';
|
|
26
|
+
static DB_PREFIX = argMap['--prefix'] || 'carbon_';
|
|
27
|
+
static RELATIVE_OUTPUT_DIR = argMap['--output'] || '/src/api/rest';
|
|
28
|
+
static OUTPUT_DIR = path.join(process.cwd(), MySQLDump.RELATIVE_OUTPUT_DIR);
|
|
29
|
+
|
|
30
|
+
static buildCNF(cnfFile = null) {
|
|
31
|
+
|
|
32
|
+
if (this.mysqlcnf !== '') {
|
|
33
|
+
|
|
34
|
+
return this.mysqlcnf;
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const cnf = [
|
|
39
|
+
'[client]',
|
|
40
|
+
`user = ${this.DB_USER}`,
|
|
41
|
+
`password = ${this.DB_PASS}`,
|
|
42
|
+
`host = ${this.DB_HOST}`,
|
|
43
|
+
`port = ${this.DB_PORT}`,
|
|
44
|
+
'',
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
cnf.push(``);
|
|
49
|
+
|
|
50
|
+
cnfFile ??= path.join(process.cwd(), '/mysql.cnf');
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
|
|
54
|
+
fs.writeFileSync(cnfFile, cnf.join('\n'));
|
|
55
|
+
|
|
56
|
+
fs.chmodSync(cnfFile, 0o750);
|
|
57
|
+
|
|
58
|
+
console.log(`Successfully created mysql.cnf file in (${cnfFile})`);
|
|
59
|
+
|
|
60
|
+
} catch (error) {
|
|
61
|
+
|
|
62
|
+
console.error(`Failed to store file contents of mysql.cnf in (${process.cwd()})`, error);
|
|
63
|
+
|
|
64
|
+
process.exit(1);
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return (this.mysqlcnf = cnfFile);
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static MySQLDump(mysqldump = null, data = false, schemas = true, outputFile = null, otherOption = '', specificTable = null) {
|
|
73
|
+
specificTable = specificTable || '';
|
|
74
|
+
|
|
75
|
+
if (outputFile === null) {
|
|
76
|
+
outputFile = path.join(process.cwd(), 'mysqldump.sql');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!data && !schemas) {
|
|
80
|
+
console.warn("MysqlDump is running with --no-create-info and --no-data. Why?");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const defaultsExtraFile = this.buildCNF();
|
|
84
|
+
|
|
85
|
+
const hexBlobOption = data ? '--hex-blob ' : '--no-data ';
|
|
86
|
+
|
|
87
|
+
const createInfoOption = schemas ? '' : ' --no-create-info ';
|
|
88
|
+
|
|
89
|
+
const cmd = `${mysqldump || 'mysqldump'} --defaults-extra-file="${defaultsExtraFile}" ${otherOption} --skip-add-locks --single-transaction --quick ${createInfoOption}${hexBlobOption}${this.DB_NAME} ${specificTable} > '${outputFile}'`;
|
|
90
|
+
|
|
91
|
+
this.executeAndCheckStatus(cmd);
|
|
92
|
+
|
|
93
|
+
return (this.mysqldump = outputFile);
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static executeAndCheckStatus(command, exitOnFailure = true, output = []) {
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
|
|
101
|
+
const stdout = execSync(command, {encoding: 'utf-8'});
|
|
102
|
+
|
|
103
|
+
output.push(stdout);
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
|
|
107
|
+
console.log(`The command >> ${command} \n\t returned with a status code (${error.status}). Expecting 0 for success.`);
|
|
108
|
+
|
|
109
|
+
console.log(`Command output::\t ${error.stdout}`);
|
|
110
|
+
|
|
111
|
+
if (exitOnFailure) {
|
|
112
|
+
|
|
113
|
+
process.exit(error.status);
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
createDirIfNotExists(MySQLDump.OUTPUT_DIR)
|
|
124
|
+
|
|
125
|
+
const pathRuntimeReference = MySQLDump.RELATIVE_OUTPUT_DIR.replace(/(^\/(src\/)?)|(\/+$)/g, '')
|
|
126
|
+
|
|
127
|
+
// Usage example
|
|
128
|
+
const dumpFileLocation = MySQLDump.MySQLDump();
|
|
129
|
+
|
|
130
|
+
type ColumnInfo = {
|
|
131
|
+
type: string;
|
|
132
|
+
length?: string;
|
|
133
|
+
autoIncrement: boolean;
|
|
134
|
+
notNull: boolean;
|
|
135
|
+
defaultValue?: string;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
type foreignKeyInfo = {
|
|
139
|
+
TABLE: string,
|
|
140
|
+
CONSTRAINT: string,
|
|
141
|
+
FOREIGN_KEY: string,
|
|
142
|
+
REFERENCES: string,
|
|
143
|
+
ON_DELETE: string,
|
|
144
|
+
ON_UPDATE: string
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function capitalizeFirstLetter(string) {
|
|
148
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function determineTypeScriptType(mysqlType) {
|
|
152
|
+
switch (mysqlType.toLowerCase()) {
|
|
153
|
+
case 'varchar':
|
|
154
|
+
case 'text':
|
|
155
|
+
case 'char':
|
|
156
|
+
case 'datetime':
|
|
157
|
+
case 'timestamp':
|
|
158
|
+
case 'date':
|
|
159
|
+
return 'string';
|
|
160
|
+
case 'int':
|
|
161
|
+
case 'bigint':
|
|
162
|
+
case 'smallint':
|
|
163
|
+
case 'decimal':
|
|
164
|
+
case 'float':
|
|
165
|
+
case 'double':
|
|
166
|
+
return 'number';
|
|
167
|
+
case 'boolean':
|
|
168
|
+
case 'tinyint(1)':
|
|
169
|
+
return 'boolean';
|
|
170
|
+
case 'json':
|
|
171
|
+
return 'any'; // or 'object' based on usage
|
|
172
|
+
default:
|
|
173
|
+
return 'string';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
const parseSQLToTypeScript = (sql: string) => {
|
|
179
|
+
|
|
180
|
+
const tableMatches = sql.matchAll(/CREATE\s+TABLE\s+`?(\w+)`?\s+\(((.|\n)+?)\)\s*(ENGINE=.+?);/gm);
|
|
181
|
+
|
|
182
|
+
let tableData: {
|
|
183
|
+
[TableName: string]: {
|
|
184
|
+
RELATIVE_OUTPUT_DIR: string,
|
|
185
|
+
TABLE_NAME: string,
|
|
186
|
+
TABLE_DEFINITION: string,
|
|
187
|
+
TABLE_CONSTRAINT: {},
|
|
188
|
+
TABLE_NAME_SHORT: string,
|
|
189
|
+
TABLE_NAME_LOWER: string,
|
|
190
|
+
TABLE_NAME_UPPER: string,
|
|
191
|
+
TABLE_NAME_PASCAL_CASE: string,
|
|
192
|
+
TABLE_NAME_SHORT_PASCAL_CASE: string,
|
|
193
|
+
TABLE_REFERENCED_BY?: {},
|
|
194
|
+
TABLE_REFERENCES?: {},
|
|
195
|
+
PRIMARY: string[],
|
|
196
|
+
PRIMARY_SHORT: string[],
|
|
197
|
+
COLUMNS: {},
|
|
198
|
+
COLUMNS_UPPERCASE: {},
|
|
199
|
+
TYPE_VALIDATION: {},
|
|
200
|
+
REGEX_VALIDATION: {},
|
|
201
|
+
}
|
|
202
|
+
} = {};
|
|
203
|
+
|
|
204
|
+
let references: foreignKeyInfo[] = [];
|
|
205
|
+
|
|
206
|
+
// @ts-ignore
|
|
207
|
+
for (const tableMatch of tableMatches) {
|
|
208
|
+
|
|
209
|
+
const tableName = tableMatch[1];
|
|
210
|
+
const columnDefinitions = tableMatch[2];
|
|
211
|
+
|
|
212
|
+
let columns: any = {};
|
|
213
|
+
const columnRegex: RegExp = /^\s*`(\w+)` (\w+)(?:\((\d+)\))?( NOT NULL)?( AUTO_INCREMENT)?(?: DEFAULT '(\w+)')?/g;
|
|
214
|
+
let columnMatch: RegExpExecArray | null;
|
|
215
|
+
|
|
216
|
+
while ((columnMatch = columnRegex.exec(columnDefinitions))) {
|
|
217
|
+
columns[columnMatch[1]] = {
|
|
218
|
+
type: columnMatch[2],
|
|
219
|
+
length: columnMatch[3] || '',
|
|
220
|
+
notNull: !!columnMatch[4],
|
|
221
|
+
autoIncrement: !!columnMatch[5],
|
|
222
|
+
defaultValue: columnMatch[6] || '',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Extract primary keys
|
|
227
|
+
const primaryKeyMatch = columnDefinitions.match(/PRIMARY KEY \(([^)]+)\)/i);
|
|
228
|
+
const primaryKeys = primaryKeyMatch
|
|
229
|
+
? primaryKeyMatch[1].split(',').map(key => key.trim().replace(/`/g, ''))
|
|
230
|
+
: [];
|
|
231
|
+
|
|
232
|
+
// Extract foreign keys
|
|
233
|
+
const foreignKeyRegex: RegExp = /CONSTRAINT `([^`]+)` FOREIGN KEY \(`([^`]+)`\) REFERENCES `([^`]+)` \(`([^`]+)`\)( ON DELETE (\w+))?( ON UPDATE (\w+))?/g;
|
|
234
|
+
let foreignKeyMatch: RegExpExecArray | null;
|
|
235
|
+
|
|
236
|
+
while ((foreignKeyMatch = foreignKeyRegex.exec(columnDefinitions))) {
|
|
237
|
+
const constraintName = foreignKeyMatch[1];
|
|
238
|
+
const localColumn = foreignKeyMatch[2];
|
|
239
|
+
const foreignTable = foreignKeyMatch[3];
|
|
240
|
+
const foreignColumn = foreignKeyMatch[4];
|
|
241
|
+
const onDeleteAction = foreignKeyMatch[6] || null;
|
|
242
|
+
const onUpdateAction = foreignKeyMatch[8] || null;
|
|
243
|
+
|
|
244
|
+
references.push({
|
|
245
|
+
TABLE: tableName,
|
|
246
|
+
CONSTRAINT: constraintName,
|
|
247
|
+
FOREIGN_KEY: localColumn,
|
|
248
|
+
REFERENCES: `${foreignTable}.${foreignColumn}`,
|
|
249
|
+
ON_DELETE: onDeleteAction,
|
|
250
|
+
ON_UPDATE: onUpdateAction
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const tsModel = {
|
|
256
|
+
RELATIVE_OUTPUT_DIR: pathRuntimeReference,
|
|
257
|
+
TABLE_NAME: tableName,
|
|
258
|
+
TABLE_DEFINITION: tableMatch[0],
|
|
259
|
+
TABLE_CONSTRAINT: references,
|
|
260
|
+
TABLE_NAME_SHORT: tableName.replace(MySQLDump.DB_PREFIX, ''),
|
|
261
|
+
TABLE_NAME_LOWER: tableName.toLowerCase(),
|
|
262
|
+
TABLE_NAME_UPPER: tableName.toUpperCase(),
|
|
263
|
+
TABLE_NAME_PASCAL_CASE: tableName.split('_').map(capitalizeFirstLetter).join('_'),
|
|
264
|
+
TABLE_NAME_SHORT_PASCAL_CASE: tableName.replace(MySQLDump.DB_PREFIX, '').split('_').map(capitalizeFirstLetter).join('_'),
|
|
265
|
+
PRIMARY: primaryKeys.map(pk => `${tableName}.${pk}`),
|
|
266
|
+
PRIMARY_SHORT: primaryKeys,
|
|
267
|
+
COLUMNS: {},
|
|
268
|
+
COLUMNS_UPPERCASE: {},
|
|
269
|
+
TYPE_VALIDATION: {},
|
|
270
|
+
REGEX_VALIDATION: {},
|
|
271
|
+
TABLE_REFERENCES: {},
|
|
272
|
+
TABLE_REFERENCED_BY:{},
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
for (const colName in columns) {
|
|
276
|
+
|
|
277
|
+
tsModel.COLUMNS[`${tableName}.${colName}`] = colName;
|
|
278
|
+
|
|
279
|
+
tsModel.COLUMNS_UPPERCASE[colName.toUpperCase()] = tableName + '.' + colName;
|
|
280
|
+
|
|
281
|
+
const typescript_type = determineTypeScriptType(columns[colName].type.toLowerCase()) === "number" ? "number" : "string"
|
|
282
|
+
|
|
283
|
+
tsModel.TYPE_VALIDATION[`${tableName}.${colName}`] = {
|
|
284
|
+
COLUMN_NAME: colName,
|
|
285
|
+
MYSQL_TYPE: columns[colName].type.toLowerCase(),
|
|
286
|
+
TYPESCRIPT_TYPE: typescript_type,
|
|
287
|
+
TYPESCRIPT_TYPE_IS_STRING: 'string' === typescript_type,
|
|
288
|
+
TYPESCRIPT_TYPE_IS_NUMBER: 'number' === typescript_type,
|
|
289
|
+
MAX_LENGTH: columns[colName].length,
|
|
290
|
+
AUTO_INCREMENT: columns[colName].autoIncrement,
|
|
291
|
+
SKIP_COLUMN_IN_POST: !columns[colName].notNull && !columns[colName].defaultValue,
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
tableData[tableName] = tsModel;
|
|
297
|
+
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
for (const ref of references) {
|
|
301
|
+
|
|
302
|
+
const foreignTable = ref.REFERENCES.split('.')[0];
|
|
303
|
+
const foreignColumn = ref.REFERENCES.split('.')[1];
|
|
304
|
+
const tableName = ref.TABLE;
|
|
305
|
+
const columnName = ref.FOREIGN_KEY;
|
|
306
|
+
const constraintName = ref.CONSTRAINT;
|
|
307
|
+
|
|
308
|
+
if (!tableData[foreignTable]) {
|
|
309
|
+
console.log(`Foreign table ${foreignTable} not found for ${ref.TABLE}.${ref.CONSTRAINT}`);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (!tableData[foreignTable].TABLE_REFERENCED_BY) {
|
|
314
|
+
tableData[foreignTable].TABLE_REFERENCED_BY = {};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (!tableData[foreignTable].TABLE_REFERENCED_BY[foreignColumn]) {
|
|
318
|
+
tableData[foreignTable].TABLE_REFERENCED_BY[foreignColumn] = [];
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
tableData[foreignTable].TABLE_REFERENCED_BY[foreignColumn].push({
|
|
322
|
+
TABLE: tableName,
|
|
323
|
+
COLUMN: columnName,
|
|
324
|
+
CONSTRAINT: constraintName
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
if (!tableData[tableName].TABLE_REFERENCES) {
|
|
328
|
+
tableData[tableName].TABLE_REFERENCES = {};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (!tableData[tableName].TABLE_REFERENCES[columnName]) {
|
|
332
|
+
tableData[tableName].TABLE_REFERENCES[columnName] = [];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
tableData[tableName].TABLE_REFERENCES[columnName].push({
|
|
336
|
+
TABLE: foreignTable,
|
|
337
|
+
COLUMN: foreignColumn,
|
|
338
|
+
CONSTRAINT: constraintName
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const tables = Object.values(tableData);
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
TABLES: tables,
|
|
348
|
+
RestTableNames: tables.map(table => "'" + table.TABLE_NAME + "'").join('\n | '),
|
|
349
|
+
RestShortTableNames: tables.map(table => "'" + table.TABLE_NAME_SHORT + "'").join('\n | '),
|
|
350
|
+
RestTableInterfaces: tables.map(table => 'i' + table.TABLE_NAME_SHORT_PASCAL_CASE).join('\n | '),
|
|
351
|
+
};
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
// use dumpFileLocation to get sql
|
|
356
|
+
const sql = fs.readFileSync(dumpFileLocation, 'utf-8');
|
|
357
|
+
|
|
358
|
+
const tableData = parseSQLToTypeScript(sql);
|
|
359
|
+
|
|
360
|
+
// write to file
|
|
361
|
+
fs.writeFileSync(path.join(process.cwd(), 'C6MySqlDump.json'), JSON.stringify(tableData));
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
// import this file src/assets/handlebars/C6.tsx.handlebars for a mustache template
|
|
365
|
+
|
|
366
|
+
const template = fs.readFileSync(path.resolve(__dirname, 'assets/handlebars/C6.tsx.handlebars'), 'utf-8');
|
|
367
|
+
|
|
368
|
+
fs.writeFileSync(path.join(MySQLDump.OUTPUT_DIR, 'C6.tsx'), Handlebars.compile(template)(tableData));
|
|
369
|
+
|
|
370
|
+
const testTemplate = fs.readFileSync(path.resolve(__dirname, 'assets/handlebars/Tests.tsx.handlebars'), 'utf-8');
|
|
371
|
+
|
|
372
|
+
Object.values(tableData.TABLES).map((tableData, key) => {
|
|
373
|
+
|
|
374
|
+
const tableName = tableData.TABLE_NAME_SHORT
|
|
375
|
+
|
|
376
|
+
fs.writeFileSync(path.join(MySQLDump.OUTPUT_DIR, tableName + '.tsx'), Handlebars.compile(testTemplate)(tableData));
|
|
377
|
+
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
console.log('Successfully created CarbonORM bindings!')
|
|
381
|
+
|
package/src/api/axiosInstance.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
// @link https://www.npmjs.com/package/axios-cache-adapter
|
|
2
2
|
import axios from "axios";
|
|
3
3
|
import Qs from "qs";
|
|
4
|
-
//import axiosInterceptors from "api/hoc/axiosInterceptors";
|
|
5
4
|
|
|
6
|
-
// noinspection SpellCheckingInspection
|
|
7
5
|
|
|
6
|
+
// updating these values
|
|
7
|
+
// @link https://github.com/axios/axios/issues/209
|
|
8
|
+
//
|
|
9
|
+
// only affects the global instance and instances created afterwards
|
|
10
|
+
// axios.defaults.headers.common['Auth-Token'] = 'foo bar';
|
|
11
|
+
//
|
|
12
|
+
// immediately affects this instance
|
|
13
|
+
// axiosInstance.defaults.headers['Auth-Token'] = 'foo bar';
|
|
8
14
|
export default (axios.create({
|
|
9
15
|
|
|
10
16
|
// `baseURL` will be prepended to `url` unless `url` is absolute.
|
|
@@ -22,10 +22,19 @@ export interface iTypeValidation {
|
|
|
22
22
|
SKIP_COLUMN_IN_POST: boolean
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
export interface iConstraint {
|
|
26
|
+
TABLE: string,
|
|
27
|
+
COLUMN: string,
|
|
28
|
+
CONSTRAINT: string
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
export interface C6RestfulModel<RestShortTableNames extends string = string> {
|
|
26
32
|
TABLE_NAME: RestShortTableNames,
|
|
27
33
|
PRIMARY: string[],
|
|
34
|
+
PRIMARY_SHORT: string[],
|
|
28
35
|
COLUMNS: stringMap,
|
|
29
36
|
REGEX_VALIDATION: RegExpMap,
|
|
30
37
|
TYPE_VALIDATION: {[key: string]: iTypeValidation},
|
|
38
|
+
TABLE_REFERENCES: {[columnName: string]: iConstraint[]},
|
|
39
|
+
TABLE_REFERENCED_BY: {[columnName: string]: iConstraint[]}
|
|
31
40
|
}
|
package/src/api/restRequest.ts
CHANGED