@carbonorm/carbonnode 3.0.13 → 3.1.2
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/C6Constants.d.ts +184 -0
- package/dist/api/builders/queryHelpers.d.ts +4 -0
- package/dist/api/builders/sqlBuilder.d.ts +17 -5
- package/dist/api/executors/Executor.d.ts +9 -15
- package/dist/api/executors/HttpExecutor.d.ts +7 -14
- package/dist/api/executors/SqlExecutor.d.ts +43 -14
- package/dist/api/orm/SqlBuilder.d.ts +17 -0
- package/dist/api/orm/builders/AggregateBuilder.d.ts +5 -0
- package/dist/api/orm/builders/ConditionBuilder.d.ts +11 -0
- package/dist/api/orm/builders/JoinBuilder.d.ts +5 -0
- package/dist/api/orm/builders/PaginationBuilder.d.ts +5 -0
- package/dist/api/orm/queries/DeleteQueryBuilder.d.ts +6 -0
- package/dist/api/orm/queries/SelectQueryBuilder.d.ts +6 -0
- package/dist/api/orm/queries/UpdateQueryBuilder.d.ts +6 -0
- package/dist/api/orm/queryHelpers.d.ts +4 -0
- package/dist/api/orm/utils/sqlUtils.d.ts +7 -0
- package/dist/api/restOrm.d.ts +3 -10
- package/dist/api/restRequest.d.ts +3 -10
- package/dist/api/types/ormGenerics.d.ts +13 -0
- package/dist/api/types/ormInterfaces.d.ts +23 -40
- package/dist/index.cjs.js +444 -249
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.esm.js +432 -249
- package/dist/index.esm.js.map +1 -1
- package/package.json +7 -2
- package/scripts/assets/handlebars/C6.ts.handlebars +2 -4
- package/scripts/generateRestBindings.cjs +1 -1
- package/scripts/generateRestBindings.ts +1 -1
- package/src/api/C6Constants.ts +38 -2
- package/src/api/executors/Executor.ts +18 -36
- package/src/api/executors/HttpExecutor.ts +46 -59
- package/src/api/executors/SqlExecutor.ts +89 -58
- package/src/api/handlers/ExpressHandler.ts +3 -2
- package/src/api/orm/builders/AggregateBuilder.ts +38 -0
- package/src/api/orm/builders/ConditionBuilder.ts +113 -0
- package/src/api/orm/builders/JoinBuilder.ts +25 -0
- package/src/api/orm/builders/PaginationBuilder.ts +28 -0
- package/src/api/orm/queries/DeleteQueryBuilder.ts +28 -0
- package/src/api/orm/queries/SelectQueryBuilder.ts +49 -0
- package/src/api/orm/queries/UpdateQueryBuilder.ts +42 -0
- package/src/api/orm/queryHelpers.ts +18 -0
- package/src/api/orm/utils/sqlUtils.ts +24 -0
- package/src/api/restOrm.ts +4 -14
- package/src/api/restRequest.ts +16 -34
- package/src/api/types/ormGenerics.ts +18 -0
- package/src/api/types/ormInterfaces.ts +28 -43
- package/src/index.ts +10 -1
- package/src/api/builders/sqlBuilder.ts +0 -223
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import {C6Constants} from "api/C6Constants";
|
|
2
|
-
import isVerbose from "../../variables/isVerbose";
|
|
3
|
-
import {Executor} from "../executors/Executor";
|
|
4
|
-
import {iRestMethods} from "../types/ormInterfaces";
|
|
5
|
-
|
|
6
|
-
interface QueryResult {
|
|
7
|
-
sql: string;
|
|
8
|
-
params: any[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export abstract class SqlBuilder<
|
|
12
|
-
RequestMethod extends iRestMethods,
|
|
13
|
-
RestShortTableName extends string = any,
|
|
14
|
-
RestTableInterface extends Record<string, any> = any,
|
|
15
|
-
PrimaryKey extends Extract<keyof RestTableInterface, string> = Extract<keyof RestTableInterface, string>,
|
|
16
|
-
CustomAndRequiredFields extends { [key: string]: any } = any,
|
|
17
|
-
RequestTableOverrides extends { [key in keyof RestTableInterface]: any } = { [key in keyof RestTableInterface]: any }
|
|
18
|
-
> extends Executor<
|
|
19
|
-
RequestMethod,
|
|
20
|
-
RestShortTableName,
|
|
21
|
-
RestTableInterface,
|
|
22
|
-
PrimaryKey,
|
|
23
|
-
CustomAndRequiredFields,
|
|
24
|
-
RequestTableOverrides
|
|
25
|
-
> {
|
|
26
|
-
/** Generate nested WHERE/JOIN conditions with parameter binding */
|
|
27
|
-
protected buildBooleanJoinedConditions(
|
|
28
|
-
set: any,
|
|
29
|
-
andMode = true,
|
|
30
|
-
params: any[] = []
|
|
31
|
-
): string {
|
|
32
|
-
const booleanOperator = andMode ? 'AND' : 'OR';
|
|
33
|
-
const OPERATORS = ['=', '!=', '<', '<=', '>', '>=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'IS', 'IS NOT'];
|
|
34
|
-
|
|
35
|
-
const isAggregateArray = (value: any) =>
|
|
36
|
-
Array.isArray(value) && typeof value[0] === 'string' && OPERATORS.includes(value[0]);
|
|
37
|
-
const isNumericKeyed = (obj: any) =>
|
|
38
|
-
Array.isArray(obj) && Object.keys(obj).every(k => /^\d+$/.test(k));
|
|
39
|
-
|
|
40
|
-
const addCondition = (column: string, op: string, value: any): string => {
|
|
41
|
-
let clause: string;
|
|
42
|
-
/*if (Buffer.isBuffer(value)) { // TODO - I want this as a parameterized option, for now default to faster
|
|
43
|
-
params.push(value.toString('hex')); // Or use UNHEX(?) in SQL
|
|
44
|
-
clause = `(${column} = UNHEX(?))`;
|
|
45
|
-
} else {*/
|
|
46
|
-
params.push(value);
|
|
47
|
-
clause = `( ${column} ${op} ? )`;
|
|
48
|
-
//}
|
|
49
|
-
isVerbose() && console.log(`[WHERE] ➕ ${clause} ->`, value);
|
|
50
|
-
return clause;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
let sql: string;
|
|
54
|
-
if (isNumericKeyed(set)) {
|
|
55
|
-
isVerbose() && console.log(`[WHERE] Numeric keyed condition:`, set);
|
|
56
|
-
switch (set.length) {
|
|
57
|
-
case 2:
|
|
58
|
-
sql = addCondition(set[0], '=', set[1]);
|
|
59
|
-
break;
|
|
60
|
-
case 3:
|
|
61
|
-
if (!OPERATORS.includes(set[1])) throw new Error(`Invalid operator: ${set[1]}`);
|
|
62
|
-
sql = addCondition(set[0], set[1], set[2]);
|
|
63
|
-
break;
|
|
64
|
-
default:
|
|
65
|
-
throw new Error(`Invalid array condition: ${JSON.stringify(set)}`);
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
const parts: string[] = [];
|
|
69
|
-
for (const [key, value] of Object.entries(set)) {
|
|
70
|
-
if (/^\d+$/.test(key)) {
|
|
71
|
-
parts.push(this.buildBooleanJoinedConditions(value, !andMode, params));
|
|
72
|
-
} else if (!Array.isArray(value) || isAggregateArray(value)) {
|
|
73
|
-
parts.push(addCondition(key, '=', value));
|
|
74
|
-
} else if (value.length === 2 && OPERATORS.includes(value[0])) {
|
|
75
|
-
parts.push(addCondition(key, value[0], value[1]));
|
|
76
|
-
} else {
|
|
77
|
-
throw new Error(`Invalid condition for ${key}: ${JSON.stringify(value)}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
sql = parts.join(` ${booleanOperator} `);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
isVerbose() && console.log(`[WHERE] Final: (${sql})`);
|
|
84
|
-
return `(${sql})`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** Translate array or function calls into SQL expressions */
|
|
88
|
-
protected buildAggregateField(field: string | any[]): string {
|
|
89
|
-
if (typeof field === 'string') return field;
|
|
90
|
-
if (!Array.isArray(field)) throw new Error('Invalid SELECT entry');
|
|
91
|
-
|
|
92
|
-
let [fn, ...args] = field;
|
|
93
|
-
let alias: string | undefined;
|
|
94
|
-
if (args.length >= 2 && args[args.length - 2] === 'AS') {
|
|
95
|
-
alias = String(args.pop());
|
|
96
|
-
args.pop();
|
|
97
|
-
}
|
|
98
|
-
const F = String(fn).toUpperCase();
|
|
99
|
-
const p = args.join(', ');
|
|
100
|
-
|
|
101
|
-
isVerbose() && console.log(`[SELECT] ${F}(${p})${alias ? ` AS ${alias}` : ''}`);
|
|
102
|
-
switch (F) {
|
|
103
|
-
case 'DATE_ADD':
|
|
104
|
-
return `DATE_ADD(${args[0]}, ${args[1]})${alias ? ` AS ${alias}` : ''}`;
|
|
105
|
-
case 'DATE_SUB':
|
|
106
|
-
return `DATE_SUB(${args[0]}, ${args[1]})${alias ? ` AS ${alias}` : ''}`;
|
|
107
|
-
case 'YEAR':
|
|
108
|
-
return `YEAR(${args[0]})${alias ? ` AS ${alias}` : ''}`;
|
|
109
|
-
case 'MONTH':
|
|
110
|
-
return `MONTH(${args[0]})${alias ? ` AS ${alias}` : ''}`;
|
|
111
|
-
case 'DAY':
|
|
112
|
-
return `DAY(${args[0]})${alias ? ` AS ${alias}` : ''}`;
|
|
113
|
-
case 'ROUND':
|
|
114
|
-
case 'CEIL':
|
|
115
|
-
case 'FLOOR':
|
|
116
|
-
case 'ABS':
|
|
117
|
-
case 'SQRT':
|
|
118
|
-
return `${F}(${p})${alias ? ` AS ${alias}` : ''}`;
|
|
119
|
-
case 'ST_DISTANCE':
|
|
120
|
-
return `ST_Distance(${p})${alias ? ` AS ${alias}` : ''}`;
|
|
121
|
-
default:
|
|
122
|
-
if (/^[A-Z_]+$/.test(F)) return `${F}(${p})${alias ? ` AS ${alias}` : ''}`;
|
|
123
|
-
throw new Error(`Unsupported function: ${F}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** Compose a parameterized SELECT query with optional JOIN/WHERE/GROUP/HAVING/PAGINATION */
|
|
128
|
-
protected buildSelectQuery<RestShortTableNames>(
|
|
129
|
-
table: RestShortTableNames,
|
|
130
|
-
primary: string | undefined,
|
|
131
|
-
args: any,
|
|
132
|
-
isSubSelect = false
|
|
133
|
-
): QueryResult {
|
|
134
|
-
const model = this.config.C6.TABLES[table as string];
|
|
135
|
-
const params: any[] = [];
|
|
136
|
-
|
|
137
|
-
// SELECT
|
|
138
|
-
const selectList = args?.[C6Constants.SELECT] ?? ['*'];
|
|
139
|
-
const selectFields = Array.isArray(selectList)
|
|
140
|
-
? selectList.map(f => this.buildAggregateField(f)).join(', ')
|
|
141
|
-
: '*';
|
|
142
|
-
let sql = `SELECT ${selectFields} FROM ${table}`;
|
|
143
|
-
isVerbose() && console.log(`[SELECT]`, selectFields);
|
|
144
|
-
|
|
145
|
-
// JOIN
|
|
146
|
-
if (args?.[C6Constants.JOIN]) {
|
|
147
|
-
for (const jt in args[C6Constants.JOIN]) {
|
|
148
|
-
const jk = jt.replace('_', ' ').toUpperCase();
|
|
149
|
-
for (const jn in args[C6Constants.JOIN][jt]) {
|
|
150
|
-
const on = this.buildBooleanJoinedConditions(args[C6Constants.JOIN][jt][jn], true, params);
|
|
151
|
-
sql += ` ${jk} JOIN \`${jn}\` ON ${on}`;
|
|
152
|
-
isVerbose() && console.log(`[JOIN]`, jk, jn, on);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// WHERE
|
|
158
|
-
if (args?.[C6Constants.WHERE]) {
|
|
159
|
-
let wc = this.buildBooleanJoinedConditions(args[C6Constants.WHERE], true, params);
|
|
160
|
-
// Trim leading and trailing parentheses if they fully wrap the condition
|
|
161
|
-
while (wc.startsWith('(') && wc.endsWith(')')) {
|
|
162
|
-
wc = wc.slice(1, -1).trim();
|
|
163
|
-
}
|
|
164
|
-
sql += ` WHERE ${wc}`;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// GROUP BY
|
|
168
|
-
if (args?.[C6Constants.GROUP_BY]) {
|
|
169
|
-
const gb = Array.isArray(args[C6Constants.GROUP_BY])
|
|
170
|
-
? args[C6Constants.GROUP_BY].join(', ')
|
|
171
|
-
: args[C6Constants.GROUP_BY];
|
|
172
|
-
sql += ` GROUP BY ${gb}`;
|
|
173
|
-
isVerbose() && console.log(`[GROUP BY]`, gb);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// HAVING
|
|
177
|
-
if (args?.[C6Constants.HAVING]) {
|
|
178
|
-
const hc = this.buildBooleanJoinedConditions(args[C6Constants.HAVING], true, params);
|
|
179
|
-
sql += ` HAVING ${hc}`;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// PAGINATION
|
|
183
|
-
if (args?.[C6Constants.PAGINATION]) {
|
|
184
|
-
const p = args[C6Constants.PAGINATION];
|
|
185
|
-
if (p[C6Constants.ORDER]) {
|
|
186
|
-
const ord = Object.entries(p[C6Constants.ORDER]).map(([c, d]) => `${c} ${String(d).toUpperCase()}`);
|
|
187
|
-
sql += ` ORDER BY ${ord.join(', ')}`;
|
|
188
|
-
isVerbose() && console.log(`[ORDER BY]`, ord);
|
|
189
|
-
}
|
|
190
|
-
if (p[C6Constants.LIMIT] != null) {
|
|
191
|
-
const lim = parseInt(p[C6Constants.LIMIT], 10);
|
|
192
|
-
const pg = parseInt(p[C6Constants.PAGE] ?? 1, 10);
|
|
193
|
-
const off = (pg - 1) * lim;
|
|
194
|
-
sql += ` LIMIT ${off}, ${lim}`;
|
|
195
|
-
isVerbose() && console.log(`[LIMIT]`, off, lim);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Fallback ORDER/LIMIT
|
|
199
|
-
else if (!isSubSelect) {
|
|
200
|
-
let ok: string | undefined;
|
|
201
|
-
if (primary) ok = primary;
|
|
202
|
-
else if (model?.PRIMARY_SHORT?.[0]) ok = model.PRIMARY_SHORT[0];
|
|
203
|
-
else for (const ts of ['created_at', 'updated_at']) {
|
|
204
|
-
if (model?.COLUMNS?.[`${table}.${ts}`]) {
|
|
205
|
-
ok = ts;
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (ok) {
|
|
210
|
-
const dir = primary ? 'ASC' : 'DESC';
|
|
211
|
-
const lim = primary ? 1 : 100;
|
|
212
|
-
sql += ` ORDER BY ${ok} ${dir} LIMIT ${lim}`;
|
|
213
|
-
isVerbose() && console.log(`[ORDER]`, ok, dir, lim);
|
|
214
|
-
} else {
|
|
215
|
-
sql += ` LIMIT 100`;
|
|
216
|
-
isVerbose() && console.warn(`[ORDER] fallback LIMIT 100`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
isVerbose() && console.log(`[SQL]`, sql, params);
|
|
221
|
-
return {sql, params};
|
|
222
|
-
}
|
|
223
|
-
}
|