@carbonorm/carbonnode 2.0.34 → 3.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/api/builders/sqlBuilder.d.ts +3 -0
- package/dist/api/carbonSqlExecutor.d.ts +17 -0
- package/dist/api/convertForRequestBody.d.ts +1 -1
- package/dist/api/executors/Executor.d.ts +18 -0
- package/dist/api/executors/HttpExecutor.d.ts +15 -0
- package/dist/api/executors/SqlExecutor.d.ts +11 -0
- package/dist/api/interfaces/ormInterfaces.d.ts +22 -1
- package/dist/api/rest/Blog_Categories.d.ts +37 -0
- package/dist/api/rest/Blog_Categories.test.d.ts +11 -0
- package/dist/api/rest/Blog_Images.d.ts +37 -0
- package/dist/api/rest/Blog_Images.test.d.ts +15 -0
- package/dist/api/rest/Blog_Post_Categories.d.ts +37 -0
- package/dist/api/rest/Blog_Post_Categories.test.d.ts +13 -0
- package/dist/api/rest/Blog_Post_Tags.d.ts +37 -0
- package/dist/api/rest/Blog_Post_Tags.test.d.ts +13 -0
- package/dist/api/rest/Blog_Posts.d.ts +37 -0
- package/dist/api/rest/Blog_Posts.test.d.ts +21 -0
- package/dist/api/rest/Blog_Tags.d.ts +37 -0
- package/dist/api/rest/Blog_Tags.test.d.ts +11 -0
- package/dist/api/rest/C6.d.ts +1000 -0
- package/dist/api/rest/Cache.d.ts +37 -0
- package/dist/api/rest/Cache.test.d.ts +12 -0
- package/dist/api/rest/Cities.d.ts +37 -0
- package/dist/api/rest/Cities.test.d.ts +17 -0
- package/dist/api/rest/Counties.d.ts +37 -0
- package/dist/api/rest/Counties.test.d.ts +18 -0
- package/dist/api/rest/Countries.d.ts +37 -0
- package/dist/api/rest/Countries.test.d.ts +24 -0
- package/dist/api/rest/Geometries.d.ts +37 -0
- package/dist/api/rest/Geometries.test.d.ts +16 -0
- package/dist/api/rest/Images.d.ts +37 -0
- package/dist/api/rest/Images.test.d.ts +16 -0
- package/dist/api/rest/Land_Section_Info.d.ts +37 -0
- package/dist/api/rest/Land_Section_Info.test.d.ts +15 -0
- package/dist/api/rest/Neighborhoods.d.ts +37 -0
- package/dist/api/rest/Neighborhoods.test.d.ts +12 -0
- package/dist/api/rest/Parcel_Building_Details.d.ts +37 -0
- package/dist/api/rest/Parcel_Building_Details.test.d.ts +40 -0
- package/dist/api/rest/Parcel_Neighborhoods.d.ts +37 -0
- package/dist/api/rest/Parcel_Neighborhoods.test.d.ts +15 -0
- package/dist/api/rest/Parcel_Owners.d.ts +37 -0
- package/dist/api/rest/Parcel_Owners.test.d.ts +23 -0
- package/dist/api/rest/Parcel_Sales.d.ts +37 -0
- package/dist/api/rest/Parcel_Sales.test.d.ts +19 -0
- package/dist/api/rest/Parcel_Tax_History.d.ts +37 -0
- package/dist/api/rest/Parcel_Tax_History.test.d.ts +24 -0
- package/dist/api/rest/Parcels.d.ts +37 -0
- package/dist/api/rest/Parcels.test.d.ts +42 -0
- package/dist/api/rest/Payment_Charge_Logs.d.ts +37 -0
- package/dist/api/rest/Payment_Charge_Logs.test.d.ts +17 -0
- package/dist/api/rest/Payment_Subscriptions.d.ts +37 -0
- package/dist/api/rest/Payment_Subscriptions.test.d.ts +20 -0
- package/dist/api/rest/Property_Units.d.ts +37 -0
- package/dist/api/rest/Property_Units.test.d.ts +55 -0
- package/dist/api/rest/Sources.d.ts +37 -0
- package/dist/api/rest/Sources.test.d.ts +17 -0
- package/dist/api/rest/States.d.ts +37 -0
- package/dist/api/rest/States.test.d.ts +20 -0
- package/dist/api/rest/Tax_Districts.d.ts +37 -0
- package/dist/api/rest/Tax_Districts.test.d.ts +12 -0
- package/dist/api/rest/Users.d.ts +37 -0
- package/dist/api/rest/Users.test.d.ts +14 -0
- package/dist/api/rest/Valuation_Reports.d.ts +37 -0
- package/dist/api/rest/Valuation_Reports.test.d.ts +36 -0
- package/dist/api/rest/Zip_Codes.d.ts +37 -0
- package/dist/api/rest/Zip_Codes.test.d.ts +15 -0
- package/dist/api/restRequest.d.ts +5 -141
- package/dist/api/types/dynamicFetching.d.ts +10 -0
- package/dist/api/types/modifyTypes.d.ts +9 -0
- package/dist/api/types/mysqlTypes.d.ts +4 -0
- package/dist/api/types/ormInterfaces.d.ts +223 -0
- package/dist/api/utils/apiHelpers.d.ts +9 -0
- package/dist/api/utils/cacheManager.d.ts +10 -0
- package/dist/api/utils/logger.d.ts +7 -0
- package/dist/api/utils/sortAndSerializeQueryObject.d.ts +1 -0
- package/dist/api/utils/testHelpers.d.ts +1 -0
- package/dist/api/utils/toastNotifier.d.ts +2 -0
- package/dist/index.cjs.js +973 -537
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.esm.js +958 -537
- package/dist/index.esm.js.map +1 -1
- package/dist/variables/isNode.d.ts +2 -0
- package/package.json +32 -6
- package/scripts/assets/handlebars/C6.ts.handlebars +5 -1
- package/scripts/generateRestBindings.cjs +89 -23
- package/scripts/generateRestBindings.ts +100 -27
- package/src/api/builders/sqlBuilder.ts +173 -0
- package/src/api/convertForRequestBody.ts +1 -2
- package/src/api/executors/Executor.ts +26 -0
- package/src/api/executors/HttpExecutor.ts +790 -0
- package/src/api/executors/SqlExecutor.ts +90 -0
- package/src/api/restRequest.ts +20 -1128
- package/src/api/types/dynamicFetching.ts +10 -0
- package/src/api/types/modifyTypes.ts +25 -0
- package/src/api/types/mysqlTypes.ts +33 -0
- package/src/api/types/ormInterfaces.ts +287 -0
- package/src/api/utils/apiHelpers.ts +83 -0
- package/src/api/utils/cacheManager.ts +67 -0
- package/src/api/utils/logger.ts +24 -0
- package/src/api/utils/sortAndSerializeQueryObject.ts +12 -0
- package/src/api/utils/testHelpers.ts +24 -0
- package/src/api/utils/toastNotifier.ts +11 -0
- package/src/index.ts +16 -1
- package/src/variables/isNode.ts +3 -0
- package/src/api/interfaces/ormInterfaces.ts +0 -79
|
@@ -24,7 +24,7 @@ class MySQLDump {
|
|
|
24
24
|
static DB_PASS = argMap['--pass'] || 'password';
|
|
25
25
|
static DB_HOST = argMap['--host'] || '127.0.0.1';
|
|
26
26
|
static DB_PORT = argMap['--port'] || '3306';
|
|
27
|
-
static DB_NAME = argMap['--dbname'] || '
|
|
27
|
+
static DB_NAME = argMap['--dbname'] || 'assessorly';
|
|
28
28
|
static DB_PREFIX = argMap['--prefix'] || 'carbon_';
|
|
29
29
|
static RELATIVE_OUTPUT_DIR = argMap['--output'] || '/src/api/rest';
|
|
30
30
|
static OUTPUT_DIR = path.join(process.cwd(), MySQLDump.RELATIVE_OUTPUT_DIR);
|
|
@@ -151,34 +151,91 @@ function capitalizeFirstLetter(string) {
|
|
|
151
151
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
function determineTypeScriptType(mysqlType) {
|
|
154
|
+
function determineTypeScriptType(mysqlType: string, enumValues?: string[]): string {
|
|
155
|
+
const baseType = mysqlType.toLowerCase().replace(/\(.+?\)/, '').split(' ')[0];
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
if (baseType === 'enum' && Array.isArray(enumValues)) {
|
|
158
|
+
return enumValues.map(val => `'${val}'`).join(' | ');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
switch (mysqlType) {
|
|
162
|
+
case 'enum':
|
|
163
|
+
throw Error('An unexpected error occurred. Please report this issue to the maintainers of this script.');
|
|
164
|
+
|
|
165
|
+
// Date & Time
|
|
166
|
+
case 'time':
|
|
167
|
+
case 'year':
|
|
168
|
+
case 'date':
|
|
160
169
|
case 'datetime':
|
|
161
170
|
case 'timestamp':
|
|
162
|
-
|
|
171
|
+
return 'Date | string';
|
|
172
|
+
|
|
173
|
+
// String & Temporal
|
|
174
|
+
case 'char':
|
|
175
|
+
case 'varchar':
|
|
176
|
+
case 'text':
|
|
177
|
+
case 'tinytext':
|
|
178
|
+
case 'mediumtext':
|
|
179
|
+
case 'longtext':
|
|
180
|
+
case 'set':
|
|
163
181
|
return 'string';
|
|
182
|
+
|
|
183
|
+
// Numeric
|
|
184
|
+
case 'tinyint':
|
|
185
|
+
case 'smallint':
|
|
186
|
+
case 'mediumint':
|
|
164
187
|
case 'int':
|
|
188
|
+
case 'integer':
|
|
165
189
|
case 'bigint':
|
|
166
|
-
case 'smallint':
|
|
167
190
|
case 'decimal':
|
|
191
|
+
case 'dec':
|
|
192
|
+
case 'numeric':
|
|
168
193
|
case 'float':
|
|
169
194
|
case 'double':
|
|
170
|
-
case '
|
|
195
|
+
case 'real':
|
|
171
196
|
return 'number';
|
|
197
|
+
|
|
198
|
+
// Boolean
|
|
172
199
|
case 'boolean':
|
|
200
|
+
case 'bool':
|
|
173
201
|
return 'boolean';
|
|
202
|
+
|
|
203
|
+
// JSON
|
|
174
204
|
case 'json':
|
|
175
|
-
return 'any';
|
|
205
|
+
return 'any';
|
|
206
|
+
|
|
207
|
+
// GeoJSON
|
|
208
|
+
case 'geometry':
|
|
209
|
+
return 'GeoJSON.Geometry';
|
|
210
|
+
case 'point':
|
|
211
|
+
return '{ x: number; y: number }';
|
|
212
|
+
case 'linestring':
|
|
213
|
+
return 'GeoJSON.LineString';
|
|
214
|
+
case 'polygon':
|
|
215
|
+
return 'GeoJSON.Polygon';
|
|
216
|
+
case 'multipoint':
|
|
217
|
+
return 'GeoJSON.MultiPoint';
|
|
218
|
+
case 'multilinestring':
|
|
219
|
+
return 'GeoJSON.MultiLineString';
|
|
220
|
+
case 'multipolygon':
|
|
221
|
+
return 'GeoJSON.MultiPolygon';
|
|
222
|
+
case 'geometrycollection':
|
|
223
|
+
return 'GeoJSON.GeometryCollection';
|
|
224
|
+
|
|
225
|
+
// Binary
|
|
226
|
+
case 'binary':
|
|
227
|
+
case 'varbinary':
|
|
228
|
+
case 'blob':
|
|
229
|
+
case 'tinyblob':
|
|
230
|
+
case 'mediumblob':
|
|
231
|
+
case 'longblob':
|
|
232
|
+
return 'Buffer | string';
|
|
233
|
+
|
|
176
234
|
default:
|
|
177
235
|
return 'string';
|
|
178
236
|
}
|
|
179
237
|
}
|
|
180
238
|
|
|
181
|
-
|
|
182
239
|
const parseSQLToTypeScript = (sql: string) => {
|
|
183
240
|
|
|
184
241
|
const tableMatches = sql.matchAll(/CREATE\s+TABLE\s+`?(\w+)`?\s+\(((.|\n)+?)\)\s*(ENGINE=.+?);/gm);
|
|
@@ -216,22 +273,37 @@ const parseSQLToTypeScript = (sql: string) => {
|
|
|
216
273
|
let columns = {};
|
|
217
274
|
|
|
218
275
|
// Improved regular expression to match column definitions
|
|
219
|
-
const columnRegex =
|
|
220
|
-
|
|
221
|
-
let columnMatch;
|
|
222
|
-
|
|
276
|
+
const columnRegex = /^\s*`([^`]+)`\s+((?:enum|set)\((?:'(?:[^']|\\')*'(?:,\s*'(?:[^']|\\')*')*)\)|[a-zA-Z0-9_]+(?:\s+unsigned)?(?:\(\d+(?:,\d+)?\))?)\s*(NOT NULL|NULL)?\s*(DEFAULT\s+(?:'[^']*'|[^\s,]+))?\s*(AUTO_INCREMENT)?/i;
|
|
223
277
|
|
|
224
278
|
const columnDefinitionsLines = columnDefinitions.split('\n');
|
|
225
279
|
|
|
226
280
|
columnDefinitionsLines.forEach(line => {
|
|
227
281
|
if (!line.match(/(PRIMARY KEY|UNIQUE KEY|CONSTRAINT)/)) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
282
|
+
const match = columnRegex.exec(line.trim());
|
|
283
|
+
if (match) {
|
|
284
|
+
const [, name, fullTypeRaw, nullability, defaultRaw, autoInc] = match;
|
|
285
|
+
|
|
286
|
+
const fullType = fullTypeRaw.trim();
|
|
287
|
+
const enumMatch = /^enum\((.+)\)$/i.exec(fullType);
|
|
288
|
+
const enumValues = enumMatch
|
|
289
|
+
? enumMatch[1]
|
|
290
|
+
.split(/,(?=(?:[^']*'[^']*')*[^']*$)/) // split only top-level commas
|
|
291
|
+
.map(s => s.trim().replace(/^'(.*)'$/, '$1'))
|
|
292
|
+
: null;
|
|
293
|
+
const type = fullType.replace(/\(.+?\)/, '').split(' ')[0].toLowerCase(); const lengthMatch = fullType.match(/\(([^)]+)\)/);
|
|
294
|
+
const length = lengthMatch ? lengthMatch[1] : '';
|
|
295
|
+
|
|
296
|
+
const sridMatch = line.match(/SRID\s+(\d+)/i);
|
|
297
|
+
const srid = sridMatch ? parseInt(sridMatch[1], 10) : null;
|
|
298
|
+
|
|
299
|
+
columns[name] = {
|
|
300
|
+
type,
|
|
301
|
+
length,
|
|
302
|
+
srid,
|
|
303
|
+
enumValues,
|
|
304
|
+
notNull: nullability?.toUpperCase() === 'NOT NULL',
|
|
305
|
+
autoIncrement: !!autoInc,
|
|
306
|
+
defaultValue: defaultRaw ? defaultRaw.replace(/^DEFAULT\s+/i, '') : ''
|
|
235
307
|
};
|
|
236
308
|
}
|
|
237
309
|
}
|
|
@@ -269,7 +341,7 @@ const parseSQLToTypeScript = (sql: string) => {
|
|
|
269
341
|
|
|
270
342
|
let REACT_IMPORT: false|string = false, CARBON_REACT_INSTANCE : false|string = false;
|
|
271
343
|
|
|
272
|
-
if (argMap['--react']
|
|
344
|
+
if (argMap['--react']) {
|
|
273
345
|
|
|
274
346
|
const reactArgSplit = argMap['--react'].split(';')
|
|
275
347
|
|
|
@@ -282,11 +354,12 @@ const parseSQLToTypeScript = (sql: string) => {
|
|
|
282
354
|
|
|
283
355
|
}
|
|
284
356
|
|
|
285
|
-
|
|
286
357
|
const tsModel = {
|
|
287
358
|
RELATIVE_OUTPUT_DIR: pathRuntimeReference,
|
|
288
359
|
TABLE_NAME: tableName,
|
|
289
|
-
TABLE_DEFINITION: tableMatch[0],
|
|
360
|
+
TABLE_DEFINITION: tableMatch[0].replace(/\/\*!([0-9]{5}) ([^*]+)\*\//g, (_match, _version, body) => {
|
|
361
|
+
return `/!* ${body.trim()} *!/`;
|
|
362
|
+
}),
|
|
290
363
|
TABLE_CONSTRAINT: references,
|
|
291
364
|
REST_URL_EXPRESSION: argMap['--restUrlExpression'] || '"/rest/"',
|
|
292
365
|
TABLE_NAME_SHORT: tableName.replace(MySQLDump.DB_PREFIX, ''),
|
|
@@ -312,13 +385,13 @@ const parseSQLToTypeScript = (sql: string) => {
|
|
|
312
385
|
|
|
313
386
|
tsModel.COLUMNS_UPPERCASE[colName.toUpperCase()] = tableName + '.' + colName;
|
|
314
387
|
|
|
315
|
-
const typescript_type = determineTypeScriptType(columns[colName].type.toLowerCase())
|
|
388
|
+
const typescript_type = determineTypeScriptType(columns[colName].type.toLowerCase(), columns[colName].enumValues)
|
|
316
389
|
|
|
317
390
|
tsModel.TYPE_VALIDATION[`${tableName}.${colName}`] = {
|
|
318
391
|
COLUMN_NAME: colName,
|
|
319
392
|
MYSQL_TYPE: columns[colName].type.toLowerCase(),
|
|
320
393
|
TYPESCRIPT_TYPE: typescript_type,
|
|
321
|
-
TYPESCRIPT_TYPE_IS_STRING: 'string'
|
|
394
|
+
TYPESCRIPT_TYPE_IS_STRING: typescript_type === 'string' || typescript_type.includes("'"),
|
|
322
395
|
TYPESCRIPT_TYPE_IS_NUMBER: 'number' === typescript_type,
|
|
323
396
|
MAX_LENGTH: columns[colName].length,
|
|
324
397
|
AUTO_INCREMENT: columns[colName].autoIncrement,
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { C6Constants } from "api/C6Constants";
|
|
2
|
+
|
|
3
|
+
export function buildBooleanJoinedConditions(set: any, andMode = true): string {
|
|
4
|
+
const booleanOperator = andMode ? 'AND' : 'OR';
|
|
5
|
+
let sql = '';
|
|
6
|
+
|
|
7
|
+
const OPERATORS = ['=', '!=', '<', '<=', '>', '>=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'IS', 'IS NOT'];
|
|
8
|
+
|
|
9
|
+
const isAggregateArray = (value: any) => Array.isArray(value) && typeof value[0] === 'string' && OPERATORS.includes(value[0]);
|
|
10
|
+
|
|
11
|
+
const isNumericKeyed = (obj: any) => Array.isArray(obj) && Object.keys(obj).every(k => /^\d+$/.test(k));
|
|
12
|
+
|
|
13
|
+
// todo - we should be doing something with value no????
|
|
14
|
+
const addCondition = (column: string, op: string, _value: any): string => {
|
|
15
|
+
const paramName = column.replace(/\W+/g, '_');
|
|
16
|
+
return `(${column} ${op} :${paramName})`;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
if (isNumericKeyed(set)) {
|
|
20
|
+
switch (set.length) {
|
|
21
|
+
case 2:
|
|
22
|
+
sql += addCondition(set[0], '=', set[1]);
|
|
23
|
+
break;
|
|
24
|
+
case 3:
|
|
25
|
+
if (!OPERATORS.includes(set[1])) {
|
|
26
|
+
throw new Error(`Invalid operator: ${set[1]}`);
|
|
27
|
+
}
|
|
28
|
+
sql += addCondition(set[0], set[1], set[2]);
|
|
29
|
+
break;
|
|
30
|
+
default:
|
|
31
|
+
throw new Error(`Invalid array condition: ${JSON.stringify(set)}`);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
const parts: string[] = [];
|
|
35
|
+
for (const [key, value] of Object.entries(set)) {
|
|
36
|
+
if (/^\d+$/.test(key)) {
|
|
37
|
+
parts.push(buildBooleanJoinedConditions(value, !andMode));
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!Array.isArray(value) || isAggregateArray(value)) {
|
|
42
|
+
parts.push(addCondition(key, '=', value));
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (value.length === 2 && OPERATORS.includes(value[0])) {
|
|
47
|
+
parts.push(addCondition(key, value[0], value[1]));
|
|
48
|
+
} else if (value.length === 1 && isAggregateArray(value[0])) {
|
|
49
|
+
parts.push(addCondition(key, '=', value[0]));
|
|
50
|
+
} else {
|
|
51
|
+
throw new Error(`Invalid condition for ${key}: ${JSON.stringify(value)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
sql = parts.join(` ${booleanOperator} `);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return `(${sql})`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function buildAggregateField(field: string | any[]): string {
|
|
62
|
+
if (typeof field === 'string') return field;
|
|
63
|
+
|
|
64
|
+
if (!Array.isArray(field)) throw new Error('Invalid SELECT entry: must be string or array');
|
|
65
|
+
|
|
66
|
+
const [agg, ...args] = field;
|
|
67
|
+
|
|
68
|
+
switch (agg) {
|
|
69
|
+
case 'COUNT':
|
|
70
|
+
return `COUNT(${args[0] || '*'})`;
|
|
71
|
+
case 'SUM':
|
|
72
|
+
case 'AVG':
|
|
73
|
+
case 'MIN':
|
|
74
|
+
case 'MAX':
|
|
75
|
+
return `${agg}(${args[0]})${args[1] ? ` AS ${args[1]}` : ''}`;
|
|
76
|
+
case 'DISTINCT':
|
|
77
|
+
return `DISTINCT(${args[0]})${args[1] ? ` AS ${args[1]}` : ''}`;
|
|
78
|
+
case 'GROUP_CONCAT': {
|
|
79
|
+
const [col, alias, sortCol, sortType] = args;
|
|
80
|
+
const order = sortCol ? ` ORDER BY ${sortCol} ${sortType || 'ASC'}` : '';
|
|
81
|
+
return `GROUP_CONCAT(DISTINCT ${col}${order} SEPARATOR ',')${alias ? ` AS ${alias}` : ''}`;
|
|
82
|
+
}
|
|
83
|
+
case 'AS': {
|
|
84
|
+
const [col, alias] = args;
|
|
85
|
+
return `${col} AS ${alias}`;
|
|
86
|
+
}
|
|
87
|
+
case 'CONVERT_TZ': {
|
|
88
|
+
const [ts, fromTz, toTz] = args;
|
|
89
|
+
return `CONVERT_TZ(${ts}, ${fromTz}, ${toTz})`;
|
|
90
|
+
}
|
|
91
|
+
case 'NOW':
|
|
92
|
+
return 'NOW()';
|
|
93
|
+
default:
|
|
94
|
+
throw new Error(`Unsupported aggregate: ${agg}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function buildSelectQuery<RestShortTableNames>(table: RestShortTableNames, primary: string | undefined, args: any, isSubSelect = false): string {
|
|
99
|
+
const selectList = args?.[C6Constants.SELECT] ?? ['*'];
|
|
100
|
+
const selectFields = Array.isArray(selectList)
|
|
101
|
+
? selectList.map(f => buildAggregateField(f)).join(', ')
|
|
102
|
+
: '*';
|
|
103
|
+
|
|
104
|
+
let sql = `SELECT ${selectFields} FROM \`${table}\``;
|
|
105
|
+
|
|
106
|
+
if (args?.[C6Constants.JOIN]) {
|
|
107
|
+
const joins = args[C6Constants.JOIN];
|
|
108
|
+
for (const joinType in joins) {
|
|
109
|
+
const joinKeyword = joinType.replace('_', ' ').toUpperCase();
|
|
110
|
+
for (const joinTable in joins[joinType]) {
|
|
111
|
+
const onClause = buildBooleanJoinedConditions(joins[joinType][joinTable]);
|
|
112
|
+
sql += ` ${joinKeyword} JOIN \`${joinTable}\` ON ${onClause}`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (args?.[C6Constants.WHERE]) {
|
|
118
|
+
sql += ` WHERE ${buildBooleanJoinedConditions(args[C6Constants.WHERE])}`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (args?.[C6Constants.GROUP_BY]) {
|
|
122
|
+
const groupByFields = Array.isArray(args[C6Constants.GROUP_BY]) ? args[C6Constants.GROUP_BY].join(', ') : args[C6Constants.GROUP_BY];
|
|
123
|
+
sql += ` GROUP BY ${groupByFields}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (args?.[C6Constants.HAVING]) {
|
|
127
|
+
sql += ` HAVING ${buildBooleanJoinedConditions(args[C6Constants.HAVING])}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (args?.[C6Constants.PAGINATION]) {
|
|
131
|
+
const p = args[C6Constants.PAGINATION];
|
|
132
|
+
let limitClause = '';
|
|
133
|
+
|
|
134
|
+
if (p[C6Constants.ORDER]) {
|
|
135
|
+
const orderArray = Object.entries(p[C6Constants.ORDER]).map(([col, dir]) => {
|
|
136
|
+
if (!['ASC', 'DESC'].includes(String(dir).toUpperCase())) {
|
|
137
|
+
throw new Error(`Invalid order direction: ${dir}`);
|
|
138
|
+
}
|
|
139
|
+
return `${col} ${String(dir).toUpperCase()}`;
|
|
140
|
+
});
|
|
141
|
+
sql += ` ORDER BY ${orderArray.join(', ')}`;
|
|
142
|
+
} else if (primary) {
|
|
143
|
+
sql += ` ORDER BY ${primary} DESC`;
|
|
144
|
+
} /*else {
|
|
145
|
+
// todo - this is wrong
|
|
146
|
+
const primaryKey = C6Constants.TABLES['users'].PRIMARY_SHORT?.[0] ?? 'user_id';
|
|
147
|
+
sql += ` ORDER BY ${primaryKey} DESC`;
|
|
148
|
+
}*/
|
|
149
|
+
|
|
150
|
+
if (p[C6Constants.LIMIT] != null) {
|
|
151
|
+
const limit = parseInt(p[C6Constants.LIMIT], 10);
|
|
152
|
+
if (isNaN(limit) || limit < 0) {
|
|
153
|
+
throw new Error(`Invalid LIMIT: ${p[C6Constants.LIMIT]}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const page = parseInt(p[C6Constants.PAGE] ?? 1, 10);
|
|
157
|
+
if (isNaN(page) || page < 1) {
|
|
158
|
+
throw new Error(`PAGE must be >= 1 (got ${p[C6Constants.PAGE]})`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const offset = (page - 1) * limit;
|
|
162
|
+
limitClause += ` LIMIT ${offset}, ${limit}`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
sql += limitClause;
|
|
166
|
+
} else if (!isSubSelect && primary) {
|
|
167
|
+
sql += ` ORDER BY ${primary} ASC LIMIT 1`;
|
|
168
|
+
} else if (!isSubSelect && !primary) {
|
|
169
|
+
sql += ` ORDER BY id ASC LIMIT 100`; // fallback default limit
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return sql;
|
|
173
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {C6Constants} from "api/C6Constants";
|
|
2
|
-
import {iC6RestfulModel} from "
|
|
3
|
-
import {iC6Object} from "api/restRequest";
|
|
2
|
+
import {iC6Object, iC6RestfulModel} from "./types/ormInterfaces";
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
export default function <RestTableInterfaces extends { [key:string] : any }>(restfulObject: RestTableInterfaces, tableName: string | string[], C6: iC6Object, regexErrorHandler: (message:string) => void = alert) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {apiReturn, iAPI, iRest} from "@carbonorm/carbonnode";
|
|
2
|
+
import {Modify} from "../types/modifyTypes";
|
|
3
|
+
|
|
4
|
+
export abstract class Executor<
|
|
5
|
+
CustomAndRequiredFields extends { [key: string]: any }, // CustomAndRequiredFields
|
|
6
|
+
RestTableInterfaces extends { [key: string]: any }, // RestTableInterfaces
|
|
7
|
+
RequestTableOverrides = { [key in keyof RestTableInterfaces]: any }, // RequestTableOverrides
|
|
8
|
+
ResponseDataType = any, // ResponseDataType
|
|
9
|
+
RestShortTableNames extends string = "" // RestShortTableNames
|
|
10
|
+
> {
|
|
11
|
+
|
|
12
|
+
public constructor(
|
|
13
|
+
protected config: iRest<
|
|
14
|
+
CustomAndRequiredFields,
|
|
15
|
+
RestTableInterfaces,
|
|
16
|
+
RequestTableOverrides,
|
|
17
|
+
ResponseDataType,
|
|
18
|
+
RestShortTableNames
|
|
19
|
+
>,
|
|
20
|
+
protected request: iAPI<Modify<RestTableInterfaces, RequestTableOverrides>> & CustomAndRequiredFields = {} as iAPI<Modify<RestTableInterfaces, RequestTableOverrides>> & CustomAndRequiredFields
|
|
21
|
+
) {
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
abstract execute(): Promise<apiReturn<ResponseDataType>>
|
|
25
|
+
|
|
26
|
+
}
|