@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,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
C6RestfulModel,
|
|
3
|
+
C6Constants
|
|
4
|
+
} from "@carbonorm/carbonnode";
|
|
5
|
+
|
|
6
|
+
export type RestTableNames = {{{RestTableNames}}};
|
|
7
|
+
|
|
8
|
+
export type RestShortTableNames = {{{RestShortTableNames}}};
|
|
9
|
+
|
|
10
|
+
{{#TABLES}}
|
|
11
|
+
|
|
12
|
+
export interface i{{TABLE_NAME_SHORT_PASCAL_CASE}} {
|
|
13
|
+
{{#each TYPE_VALIDATION}}
|
|
14
|
+
'{{this.COLUMN_NAME}}'?: {{this.TYPESCRIPT_TYPE}};
|
|
15
|
+
{{/each}}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface iDefine{{TABLE_NAME_SHORT_PASCAL_CASE}} {
|
|
19
|
+
{{#each COLUMNS_UPPERCASE}}
|
|
20
|
+
'{{@key}}': string;
|
|
21
|
+
{{/each}}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const {{TABLE_NAME_SHORT}}: C6RestfulModel & iDefine{{TABLE_NAME_SHORT_PASCAL_CASE}} = {
|
|
25
|
+
TABLE_NAME: '{{TABLE_NAME}}',
|
|
26
|
+
{{#each COLUMNS_UPPERCASE}}
|
|
27
|
+
{{@key}}: '{{this}}',
|
|
28
|
+
{{/each}}
|
|
29
|
+
PRIMARY: [
|
|
30
|
+
{{#PRIMARY}}
|
|
31
|
+
'{{this}}',
|
|
32
|
+
{{/PRIMARY}}
|
|
33
|
+
],
|
|
34
|
+
PRIMARY_SHORT: [
|
|
35
|
+
{{#each PRIMARY_SHORT}}
|
|
36
|
+
'{{this}}',
|
|
37
|
+
{{/each}}
|
|
38
|
+
],
|
|
39
|
+
COLUMNS: {
|
|
40
|
+
{{#each COLUMNS}}
|
|
41
|
+
'{{@key}}': '{{this}}',
|
|
42
|
+
{{/each}}
|
|
43
|
+
},
|
|
44
|
+
TYPE_VALIDATION: {
|
|
45
|
+
{{#each TYPE_VALIDATION}}
|
|
46
|
+
'{{@key}}': {
|
|
47
|
+
MYSQL_TYPE: '{{this.MYSQL_TYPE}}',
|
|
48
|
+
MAX_LENGTH: '{{this.MAX_LENGTH}}',
|
|
49
|
+
AUTO_INCREMENT: {{this.AUTO_INCREMENT}},
|
|
50
|
+
SKIP_COLUMN_IN_POST: {{this.SKIP_COLUMN_IN_POST}}
|
|
51
|
+
},
|
|
52
|
+
{{/each}}
|
|
53
|
+
},
|
|
54
|
+
REGEX_VALIDATION: {
|
|
55
|
+
{{#each REGEX_VALIDATION}}
|
|
56
|
+
'{{@key}}': '{{this}}',
|
|
57
|
+
{{/each}}
|
|
58
|
+
},
|
|
59
|
+
TABLE_REFERENCES: {
|
|
60
|
+
{{#each TABLE_REFERENCES}}'{{@key}}': [{{#this}}{
|
|
61
|
+
TABLE: '{{TABLE}}',
|
|
62
|
+
COLUMN: '{{COLUMN}}',
|
|
63
|
+
CONSTRAINT: '{{CONSTRAINT}}',
|
|
64
|
+
},{{/this}}],{{/each}}
|
|
65
|
+
},
|
|
66
|
+
TABLE_REFERENCED_BY: {
|
|
67
|
+
{{#each TABLE_REFERENCED_BY}}'{{@key}}': [{{#this}}{
|
|
68
|
+
TABLE: '{{TABLE}}',
|
|
69
|
+
COLUMN: '{{COLUMN}}',
|
|
70
|
+
CONSTRAINT: '{{CONSTRAINT}}',
|
|
71
|
+
},{{/this}}],{{/each}}
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
{{/TABLES}}
|
|
75
|
+
|
|
76
|
+
export const TABLES = {
|
|
77
|
+
{{#TABLES}}
|
|
78
|
+
{{TABLE_NAME_SHORT}}: {{TABLE_NAME_SHORT}},
|
|
79
|
+
{{/TABLES}}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const C6 : { TABLES: { [key: string]: (C6RestfulModel & { [key: string]: any }) } }
|
|
83
|
+
& { [key: string]: any } = {
|
|
84
|
+
...C6Constants,
|
|
85
|
+
TABLES: TABLES,
|
|
86
|
+
...TABLES
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const COLUMNS = {
|
|
90
|
+
{{#TABLES}}{{#each TYPE_VALIDATION}}'{{@key}}': '{{this.COLUMN_NAME}}',{{/each}}
|
|
91
|
+
{{/TABLES}}
|
|
92
|
+
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
export type RestTableInterfaces = {{{RestTableInterfaces}}};
|
|
97
|
+
|
|
98
|
+
export type tStatefulApiData<T> = T[] | undefined | null;
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
// this refers to the value types of the keys above, aka values in the state
|
|
102
|
+
export interface iRestfulObjectArrayTypes {
|
|
103
|
+
{{#TABLES}}
|
|
104
|
+
{{TABLE_NAME_SHORT}}: tStatefulApiData<i{{TABLE_NAME_SHORT_PASCAL_CASE}}>,
|
|
105
|
+
{{/TABLES}}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const initialRestfulObjectsState: iRestfulObjectArrayTypes = {
|
|
109
|
+
{{#TABLES}}
|
|
110
|
+
{{TABLE_NAME_SHORT}}: undefined,
|
|
111
|
+
{{/TABLES}}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export type tRestfulObjectArrayValues = iRestfulObjectArrayTypes[keyof iRestfulObjectArrayTypes];
|
|
115
|
+
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {xdescribe, expect, test} from '@jest/globals';
|
|
2
|
+
import {CarbonReact} from "@carbonorm/carbonreact";
|
|
3
|
+
import {checkAllRequestsComplete} from "@carbonorm/carbonnode";
|
|
4
|
+
import {act, waitFor} from '@testing-library/react';
|
|
5
|
+
import {C6, iRestfulObjectArrayTypes, i{{TABLE_NAME_SHORT_PASCAL_CASE}}, {{TABLE_NAME_SHORT}} } from "{{RELATIVE_OUTPUT_DIR}}/C6";
|
|
6
|
+
|
|
7
|
+
const randomString = Math.random().toString(36).substring(7);
|
|
8
|
+
const randomInt = Math.floor(Math.random() * 1000000);
|
|
9
|
+
const fillString = 'string' + randomString + randomInt;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
{{{TABLE_DEFINITION}}}
|
|
13
|
+
**/
|
|
14
|
+
|
|
15
|
+
const Test_Data: i{{TABLE_NAME_SHORT_PASCAL_CASE}} = {
|
|
16
|
+
{{#each TYPE_VALIDATION}}
|
|
17
|
+
{{#SKIP_COLUMN_IN_POST}}{{COLUMN_NAME}}: {{#TYPESCRIPT_TYPE_IS_STRING}}fillString.substring(0, {{MAX_LENGTH}}){{/TYPESCRIPT_TYPE_IS_STRING}}{{#TYPESCRIPT_TYPE_IS_NUMBER}}randomInt,{{/TYPESCRIPT_TYPE_IS_NUMBER}}{{/SKIP_COLUMN_IN_POST}}
|
|
18
|
+
{{/each}}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default Test_Data;
|
|
22
|
+
|
|
23
|
+
xdescribe('REST {{TABLE_NAME_SHORT_PASCAL_CASE}} api', () => {
|
|
24
|
+
|
|
25
|
+
let testData = Test_Data;
|
|
26
|
+
|
|
27
|
+
test('GET POST PUT DELETE', async () => {
|
|
28
|
+
|
|
29
|
+
await act(async () => {
|
|
30
|
+
|
|
31
|
+
let selectAllResponse = await {{TABLE_NAME_SHORT}}.Get({})
|
|
32
|
+
|
|
33
|
+
if ('function' === typeof selectAllResponse) {
|
|
34
|
+
throw Error('selectAllResponse is a promise, this typically means this specific get request has already run during test setup.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// We don't care if it is filled or not, just that the request can be made.
|
|
38
|
+
expect(selectAllResponse?.data?.rest).not.toBeUndefined();
|
|
39
|
+
|
|
40
|
+
const postResponse = await {{TABLE_NAME_SHORT}}.Post(testData);
|
|
41
|
+
|
|
42
|
+
console.log('postResponse', postResponse?.data)
|
|
43
|
+
|
|
44
|
+
expect(postResponse?.data?.created).not.toBeUndefined();
|
|
45
|
+
|
|
46
|
+
const primaryKey = {{TABLE_NAME_SHORT}}.PRIMARY_SHORT[0];
|
|
47
|
+
|
|
48
|
+
const postID = postResponse?.data?.created
|
|
49
|
+
|
|
50
|
+
const singleRowSelect = await {{TABLE_NAME_SHORT}}.Get({
|
|
51
|
+
[C6.WHERE]: {
|
|
52
|
+
[{{TABLE_NAME_SHORT}}[primaryKey.toUpperCase()]]: postID,
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
if ('function' === typeof singleRowSelect) {
|
|
57
|
+
throw Error('singleRowSelect is a promise, this is unexpected.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('singleRowSelect', singleRowSelect?.data)
|
|
61
|
+
|
|
62
|
+
// Ensure the expected response datastructure is returned
|
|
63
|
+
expect(singleRowSelect?.data?.rest).not.toBeUndefined();
|
|
64
|
+
|
|
65
|
+
// Make sure the previously created post is now returned
|
|
66
|
+
expect(typeof singleRowSelect?.data?.rest).toEqual('object');
|
|
67
|
+
|
|
68
|
+
// todo - make this work correctly with multiple primary keys
|
|
69
|
+
const selectedPostId = singleRowSelect?.data?.rest[0][primaryKey]
|
|
70
|
+
|
|
71
|
+
expect(selectedPostId).toEqual(postID);
|
|
72
|
+
|
|
73
|
+
const multipleRowSelect = await {{TABLE_NAME_SHORT}}.Get({
|
|
74
|
+
[C6.WHERE]: {
|
|
75
|
+
[{{TABLE_NAME_SHORT}}[primaryKey.toUpperCase()]]: [C6.IN, [0, postID]],
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
if ('function' === typeof multipleRowSelect) {
|
|
80
|
+
throw Error('singleRowSelect is a promise, this is unexpected.');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log('singleRowSelect', multipleRowSelect?.data)
|
|
84
|
+
|
|
85
|
+
// Ensure the expected response datastructure is returned
|
|
86
|
+
expect(multipleRowSelect?.data?.rest).not.toBeUndefined();
|
|
87
|
+
|
|
88
|
+
// Make sure the previously created post is now returned
|
|
89
|
+
expect(typeof multipleRowSelect?.data?.rest).toEqual('object');
|
|
90
|
+
|
|
91
|
+
testData[primaryKey] = postID
|
|
92
|
+
|
|
93
|
+
{{#each TYPE_VALIDATION}}
|
|
94
|
+
testData.{{@key}} = {{#TYPESCRIPT_TYPE_IS_STRING}}fillString.substring(0, {{TYPE_VALIDATION.MAX_LENGTH}}){{/TYPESCRIPT_TYPE_IS_STRING}}{{#TYPESCRIPT_TYPE_IS_NUMBER}}randomInt{{/TYPESCRIPT_TYPE_IS_NUMBER}};
|
|
95
|
+
{{/each}}
|
|
96
|
+
|
|
97
|
+
// wait for the global state to be updated
|
|
98
|
+
expect(CarbonReact.getState<iRestfulObjectArrayTypes>().{{TABLE_NAME_SHORT}}).not.toBeUndefined();
|
|
99
|
+
|
|
100
|
+
const updateResponse = await {{TABLE_NAME_SHORT}}.Put(testData)
|
|
101
|
+
|
|
102
|
+
expect(updateResponse?.data?.updated).not.toBeUndefined();
|
|
103
|
+
|
|
104
|
+
const deleteResponse = await {{TABLE_NAME_SHORT}}.Delete({
|
|
105
|
+
[primaryKey]: postID
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
console.log('deleteResponse', deleteResponse?.data)
|
|
109
|
+
|
|
110
|
+
expect(deleteResponse?.data?.deleted).not.toBeUndefined();
|
|
111
|
+
|
|
112
|
+
await waitFor(async () => {
|
|
113
|
+
expect(checkAllRequestsComplete()).toEqual(true);
|
|
114
|
+
}, {timeout: 10000, interval: 1000});
|
|
115
|
+
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
}, 100000);
|
|
119
|
+
|
|
120
|
+
})
|
|
121
|
+
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
var __values = (this && this.__values) || function(o) {
|
|
2
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
3
|
+
if (m) return m.call(o);
|
|
4
|
+
if (o && typeof o.length === "number") return {
|
|
5
|
+
next: function () {
|
|
6
|
+
if (o && i >= o.length) o = void 0;
|
|
7
|
+
return { value: o && o[i++], done: !o };
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
11
|
+
};
|
|
12
|
+
var execSync = require('child_process').execSync;
|
|
13
|
+
var fs = require('fs');
|
|
14
|
+
var path = require('path');
|
|
15
|
+
var Handlebars = require('handlebars');
|
|
16
|
+
var args = process.argv.slice(2); // Slice the first two elements
|
|
17
|
+
var argMap = {};
|
|
18
|
+
for (var i = 0; i < args.length; i += 2) {
|
|
19
|
+
argMap[args[i]] = args[i + 1];
|
|
20
|
+
}
|
|
21
|
+
var createDirIfNotExists = function (dir) {
|
|
22
|
+
return !fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined;
|
|
23
|
+
};
|
|
24
|
+
var MySQLDump = /** @class */ (function () {
|
|
25
|
+
function MySQLDump() {
|
|
26
|
+
}
|
|
27
|
+
MySQLDump.buildCNF = function (cnfFile) {
|
|
28
|
+
if (cnfFile === void 0) { cnfFile = null; }
|
|
29
|
+
if (this.mysqlcnf !== '') {
|
|
30
|
+
return this.mysqlcnf;
|
|
31
|
+
}
|
|
32
|
+
var cnf = [
|
|
33
|
+
'[client]',
|
|
34
|
+
"user = ".concat(this.DB_USER),
|
|
35
|
+
"password = ".concat(this.DB_PASS),
|
|
36
|
+
"host = ".concat(this.DB_HOST),
|
|
37
|
+
"port = ".concat(this.DB_PORT),
|
|
38
|
+
'',
|
|
39
|
+
];
|
|
40
|
+
cnf.push("");
|
|
41
|
+
cnfFile !== null && cnfFile !== void 0 ? cnfFile : (cnfFile = path.join(process.cwd(), '/mysql.cnf'));
|
|
42
|
+
try {
|
|
43
|
+
fs.writeFileSync(cnfFile, cnf.join('\n'));
|
|
44
|
+
fs.chmodSync(cnfFile, 488);
|
|
45
|
+
console.log("Successfully created mysql.cnf file in (".concat(cnfFile, ")"));
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.error("Failed to store file contents of mysql.cnf in (".concat(process.cwd(), ")"), error);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
return (this.mysqlcnf = cnfFile);
|
|
52
|
+
};
|
|
53
|
+
MySQLDump.MySQLDump = function (mysqldump, data, schemas, outputFile, otherOption, specificTable) {
|
|
54
|
+
if (mysqldump === void 0) { mysqldump = null; }
|
|
55
|
+
if (data === void 0) { data = false; }
|
|
56
|
+
if (schemas === void 0) { schemas = true; }
|
|
57
|
+
if (outputFile === void 0) { outputFile = null; }
|
|
58
|
+
if (otherOption === void 0) { otherOption = ''; }
|
|
59
|
+
if (specificTable === void 0) { specificTable = null; }
|
|
60
|
+
specificTable = specificTable || '';
|
|
61
|
+
if (outputFile === null) {
|
|
62
|
+
outputFile = path.join(process.cwd(), 'mysqldump.sql');
|
|
63
|
+
}
|
|
64
|
+
if (!data && !schemas) {
|
|
65
|
+
console.warn("MysqlDump is running with --no-create-info and --no-data. Why?");
|
|
66
|
+
}
|
|
67
|
+
var defaultsExtraFile = this.buildCNF();
|
|
68
|
+
var hexBlobOption = data ? '--hex-blob ' : '--no-data ';
|
|
69
|
+
var createInfoOption = schemas ? '' : ' --no-create-info ';
|
|
70
|
+
var cmd = "".concat(mysqldump || 'mysqldump', " --defaults-extra-file=\"").concat(defaultsExtraFile, "\" ").concat(otherOption, " --skip-add-locks --single-transaction --quick ").concat(createInfoOption).concat(hexBlobOption).concat(this.DB_NAME, " ").concat(specificTable, " > '").concat(outputFile, "'");
|
|
71
|
+
this.executeAndCheckStatus(cmd);
|
|
72
|
+
return (this.mysqldump = outputFile);
|
|
73
|
+
};
|
|
74
|
+
MySQLDump.executeAndCheckStatus = function (command, exitOnFailure, output) {
|
|
75
|
+
if (exitOnFailure === void 0) { exitOnFailure = true; }
|
|
76
|
+
if (output === void 0) { output = []; }
|
|
77
|
+
try {
|
|
78
|
+
var stdout = execSync(command, { encoding: 'utf-8' });
|
|
79
|
+
output.push(stdout);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.log("The command >> ".concat(command, " \n\t returned with a status code (").concat(error.status, "). Expecting 0 for success."));
|
|
83
|
+
console.log("Command output::\t ".concat(error.stdout));
|
|
84
|
+
if (exitOnFailure) {
|
|
85
|
+
process.exit(error.status);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
MySQLDump.mysqlcnf = '';
|
|
90
|
+
MySQLDump.mysqldump = '';
|
|
91
|
+
MySQLDump.DB_USER = argMap['--user'] || 'root';
|
|
92
|
+
MySQLDump.DB_PASS = argMap['--pass'] || 'password';
|
|
93
|
+
MySQLDump.DB_HOST = argMap['--host'] || '127.0.0.1';
|
|
94
|
+
MySQLDump.DB_PORT = argMap['--port'] || '3306';
|
|
95
|
+
MySQLDump.DB_NAME = argMap['--dbname'] || 'carbonPHP';
|
|
96
|
+
MySQLDump.DB_PREFIX = argMap['--prefix'] || 'carbon_';
|
|
97
|
+
MySQLDump.RELATIVE_OUTPUT_DIR = argMap['--output'] || '/src/api/rest';
|
|
98
|
+
MySQLDump.OUTPUT_DIR = path.join(process.cwd(), MySQLDump.RELATIVE_OUTPUT_DIR);
|
|
99
|
+
return MySQLDump;
|
|
100
|
+
}());
|
|
101
|
+
createDirIfNotExists(MySQLDump.OUTPUT_DIR);
|
|
102
|
+
var pathRuntimeReference = MySQLDump.RELATIVE_OUTPUT_DIR.replace(/(^\/(src\/)?)|(\/+$)/g, '');
|
|
103
|
+
// Usage example
|
|
104
|
+
var dumpFileLocation = MySQLDump.MySQLDump();
|
|
105
|
+
function capitalizeFirstLetter(string) {
|
|
106
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
107
|
+
}
|
|
108
|
+
function determineTypeScriptType(mysqlType) {
|
|
109
|
+
switch (mysqlType.toLowerCase()) {
|
|
110
|
+
case 'varchar':
|
|
111
|
+
case 'text':
|
|
112
|
+
case 'char':
|
|
113
|
+
case 'datetime':
|
|
114
|
+
case 'timestamp':
|
|
115
|
+
case 'date':
|
|
116
|
+
return 'string';
|
|
117
|
+
case 'int':
|
|
118
|
+
case 'bigint':
|
|
119
|
+
case 'smallint':
|
|
120
|
+
case 'decimal':
|
|
121
|
+
case 'float':
|
|
122
|
+
case 'double':
|
|
123
|
+
return 'number';
|
|
124
|
+
case 'boolean':
|
|
125
|
+
case 'tinyint(1)':
|
|
126
|
+
return 'boolean';
|
|
127
|
+
case 'json':
|
|
128
|
+
return 'any'; // or 'object' based on usage
|
|
129
|
+
default:
|
|
130
|
+
return 'string';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
var parseSQLToTypeScript = function (sql) {
|
|
134
|
+
var e_1, _a, e_2, _b;
|
|
135
|
+
var tableMatches = sql.matchAll(/CREATE\s+TABLE\s+`?(\w+)`?\s+\(((.|\n)+?)\)\s*(ENGINE=.+?);/gm);
|
|
136
|
+
var tableData = {};
|
|
137
|
+
var references = [];
|
|
138
|
+
var _loop_1 = function (tableMatch) {
|
|
139
|
+
var tableName = tableMatch[1];
|
|
140
|
+
var columnDefinitions = tableMatch[2];
|
|
141
|
+
var columns = {};
|
|
142
|
+
var columnRegex = /^\s*`(\w+)` (\w+)(?:\((\d+)\))?( NOT NULL)?( AUTO_INCREMENT)?(?: DEFAULT '(\w+)')?/g;
|
|
143
|
+
var columnMatch = void 0;
|
|
144
|
+
while ((columnMatch = columnRegex.exec(columnDefinitions))) {
|
|
145
|
+
columns[columnMatch[1]] = {
|
|
146
|
+
type: columnMatch[2],
|
|
147
|
+
length: columnMatch[3] || '',
|
|
148
|
+
notNull: !!columnMatch[4],
|
|
149
|
+
autoIncrement: !!columnMatch[5],
|
|
150
|
+
defaultValue: columnMatch[6] || '',
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// Extract primary keys
|
|
154
|
+
var primaryKeyMatch = columnDefinitions.match(/PRIMARY KEY \(([^)]+)\)/i);
|
|
155
|
+
var primaryKeys = primaryKeyMatch
|
|
156
|
+
? primaryKeyMatch[1].split(',').map(function (key) { return key.trim().replace(/`/g, ''); })
|
|
157
|
+
: [];
|
|
158
|
+
// Extract foreign keys
|
|
159
|
+
var foreignKeyRegex = /CONSTRAINT `([^`]+)` FOREIGN KEY \(`([^`]+)`\) REFERENCES `([^`]+)` \(`([^`]+)`\)( ON DELETE (\w+))?( ON UPDATE (\w+))?/g;
|
|
160
|
+
var foreignKeyMatch = void 0;
|
|
161
|
+
while ((foreignKeyMatch = foreignKeyRegex.exec(columnDefinitions))) {
|
|
162
|
+
var constraintName = foreignKeyMatch[1];
|
|
163
|
+
var localColumn = foreignKeyMatch[2];
|
|
164
|
+
var foreignTable = foreignKeyMatch[3];
|
|
165
|
+
var foreignColumn = foreignKeyMatch[4];
|
|
166
|
+
var onDeleteAction = foreignKeyMatch[6] || null;
|
|
167
|
+
var onUpdateAction = foreignKeyMatch[8] || null;
|
|
168
|
+
references.push({
|
|
169
|
+
TABLE: tableName,
|
|
170
|
+
CONSTRAINT: constraintName,
|
|
171
|
+
FOREIGN_KEY: localColumn,
|
|
172
|
+
REFERENCES: "".concat(foreignTable, ".").concat(foreignColumn),
|
|
173
|
+
ON_DELETE: onDeleteAction,
|
|
174
|
+
ON_UPDATE: onUpdateAction
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
var tsModel = {
|
|
178
|
+
RELATIVE_OUTPUT_DIR: pathRuntimeReference,
|
|
179
|
+
TABLE_NAME: tableName,
|
|
180
|
+
TABLE_DEFINITION: tableMatch[0],
|
|
181
|
+
TABLE_CONSTRAINT: references,
|
|
182
|
+
TABLE_NAME_SHORT: tableName.replace(MySQLDump.DB_PREFIX, ''),
|
|
183
|
+
TABLE_NAME_LOWER: tableName.toLowerCase(),
|
|
184
|
+
TABLE_NAME_UPPER: tableName.toUpperCase(),
|
|
185
|
+
TABLE_NAME_PASCAL_CASE: tableName.split('_').map(capitalizeFirstLetter).join('_'),
|
|
186
|
+
TABLE_NAME_SHORT_PASCAL_CASE: tableName.replace(MySQLDump.DB_PREFIX, '').split('_').map(capitalizeFirstLetter).join('_'),
|
|
187
|
+
PRIMARY: primaryKeys.map(function (pk) { return "".concat(tableName, ".").concat(pk); }),
|
|
188
|
+
PRIMARY_SHORT: primaryKeys,
|
|
189
|
+
COLUMNS: {},
|
|
190
|
+
COLUMNS_UPPERCASE: {},
|
|
191
|
+
TYPE_VALIDATION: {},
|
|
192
|
+
REGEX_VALIDATION: {},
|
|
193
|
+
TABLE_REFERENCES: {},
|
|
194
|
+
TABLE_REFERENCED_BY: {},
|
|
195
|
+
};
|
|
196
|
+
for (var colName in columns) {
|
|
197
|
+
tsModel.COLUMNS["".concat(tableName, ".").concat(colName)] = colName;
|
|
198
|
+
tsModel.COLUMNS_UPPERCASE[colName.toUpperCase()] = tableName + '.' + colName;
|
|
199
|
+
var typescript_type = determineTypeScriptType(columns[colName].type.toLowerCase()) === "number" ? "number" : "string";
|
|
200
|
+
tsModel.TYPE_VALIDATION["".concat(tableName, ".").concat(colName)] = {
|
|
201
|
+
COLUMN_NAME: colName,
|
|
202
|
+
MYSQL_TYPE: columns[colName].type.toLowerCase(),
|
|
203
|
+
TYPESCRIPT_TYPE: typescript_type,
|
|
204
|
+
TYPESCRIPT_TYPE_IS_STRING: 'string' === typescript_type,
|
|
205
|
+
TYPESCRIPT_TYPE_IS_NUMBER: 'number' === typescript_type,
|
|
206
|
+
MAX_LENGTH: columns[colName].length,
|
|
207
|
+
AUTO_INCREMENT: columns[colName].autoIncrement,
|
|
208
|
+
SKIP_COLUMN_IN_POST: !columns[colName].notNull && !columns[colName].defaultValue,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
tableData[tableName] = tsModel;
|
|
212
|
+
};
|
|
213
|
+
try {
|
|
214
|
+
// @ts-ignore
|
|
215
|
+
for (var tableMatches_1 = __values(tableMatches), tableMatches_1_1 = tableMatches_1.next(); !tableMatches_1_1.done; tableMatches_1_1 = tableMatches_1.next()) {
|
|
216
|
+
var tableMatch = tableMatches_1_1.value;
|
|
217
|
+
_loop_1(tableMatch);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
221
|
+
finally {
|
|
222
|
+
try {
|
|
223
|
+
if (tableMatches_1_1 && !tableMatches_1_1.done && (_a = tableMatches_1.return)) _a.call(tableMatches_1);
|
|
224
|
+
}
|
|
225
|
+
finally { if (e_1) throw e_1.error; }
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
for (var references_1 = __values(references), references_1_1 = references_1.next(); !references_1_1.done; references_1_1 = references_1.next()) {
|
|
229
|
+
var ref = references_1_1.value;
|
|
230
|
+
var foreignTable = ref.REFERENCES.split('.')[0];
|
|
231
|
+
var foreignColumn = ref.REFERENCES.split('.')[1];
|
|
232
|
+
var tableName = ref.TABLE;
|
|
233
|
+
var columnName = ref.FOREIGN_KEY;
|
|
234
|
+
var constraintName = ref.CONSTRAINT;
|
|
235
|
+
if (!tableData[foreignTable]) {
|
|
236
|
+
console.log("Foreign table ".concat(foreignTable, " not found for ").concat(ref.TABLE, ".").concat(ref.CONSTRAINT));
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (!tableData[foreignTable].TABLE_REFERENCED_BY) {
|
|
240
|
+
tableData[foreignTable].TABLE_REFERENCED_BY = {};
|
|
241
|
+
}
|
|
242
|
+
if (!tableData[foreignTable].TABLE_REFERENCED_BY[foreignColumn]) {
|
|
243
|
+
tableData[foreignTable].TABLE_REFERENCED_BY[foreignColumn] = [];
|
|
244
|
+
}
|
|
245
|
+
tableData[foreignTable].TABLE_REFERENCED_BY[foreignColumn].push({
|
|
246
|
+
TABLE: tableName,
|
|
247
|
+
COLUMN: columnName,
|
|
248
|
+
CONSTRAINT: constraintName
|
|
249
|
+
});
|
|
250
|
+
if (!tableData[tableName].TABLE_REFERENCES) {
|
|
251
|
+
tableData[tableName].TABLE_REFERENCES = {};
|
|
252
|
+
}
|
|
253
|
+
if (!tableData[tableName].TABLE_REFERENCES[columnName]) {
|
|
254
|
+
tableData[tableName].TABLE_REFERENCES[columnName] = [];
|
|
255
|
+
}
|
|
256
|
+
tableData[tableName].TABLE_REFERENCES[columnName].push({
|
|
257
|
+
TABLE: foreignTable,
|
|
258
|
+
COLUMN: foreignColumn,
|
|
259
|
+
CONSTRAINT: constraintName
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
264
|
+
finally {
|
|
265
|
+
try {
|
|
266
|
+
if (references_1_1 && !references_1_1.done && (_b = references_1.return)) _b.call(references_1);
|
|
267
|
+
}
|
|
268
|
+
finally { if (e_2) throw e_2.error; }
|
|
269
|
+
}
|
|
270
|
+
var tables = Object.values(tableData);
|
|
271
|
+
return {
|
|
272
|
+
TABLES: tables,
|
|
273
|
+
RestTableNames: tables.map(function (table) { return "'" + table.TABLE_NAME + "'"; }).join('\n | '),
|
|
274
|
+
RestShortTableNames: tables.map(function (table) { return "'" + table.TABLE_NAME_SHORT + "'"; }).join('\n | '),
|
|
275
|
+
RestTableInterfaces: tables.map(function (table) { return 'i' + table.TABLE_NAME_SHORT_PASCAL_CASE; }).join('\n | '),
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
// use dumpFileLocation to get sql
|
|
279
|
+
var sql = fs.readFileSync(dumpFileLocation, 'utf-8');
|
|
280
|
+
var tableData = parseSQLToTypeScript(sql);
|
|
281
|
+
// write to file
|
|
282
|
+
fs.writeFileSync(path.join(process.cwd(), 'C6MySqlDump.json'), JSON.stringify(tableData));
|
|
283
|
+
// import this file src/assets/handlebars/C6.tsx.handlebars for a mustache template
|
|
284
|
+
var template = fs.readFileSync(path.resolve(__dirname, 'assets/handlebars/C6.tsx.handlebars'), 'utf-8');
|
|
285
|
+
fs.writeFileSync(path.join(MySQLDump.OUTPUT_DIR, 'C6.tsx'), Handlebars.compile(template)(tableData));
|
|
286
|
+
var testTemplate = fs.readFileSync(path.resolve(__dirname, 'assets/handlebars/Tests.tsx.handlebars'), 'utf-8');
|
|
287
|
+
Object.values(tableData.TABLES).map(function (tableData, key) {
|
|
288
|
+
var tableName = tableData.TABLE_NAME_SHORT;
|
|
289
|
+
fs.writeFileSync(path.join(MySQLDump.OUTPUT_DIR, tableName + '.tsx'), Handlebars.compile(testTemplate)(tableData));
|
|
290
|
+
});
|
|
291
|
+
console.log('Successfully created CarbonORM bindings!');
|