@carbonorm/carbonnode 3.0.13 → 3.0.15
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 +1 -0
- package/dist/api/builders/sqlBuilder.d.ts +17 -5
- package/dist/api/executors/SqlExecutor.d.ts +38 -6
- package/dist/index.cjs.js +392 -153
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +392 -153
- package/dist/index.esm.js.map +1 -1
- package/package.json +7 -2
- package/scripts/generateRestBindings.cjs +1 -1
- package/scripts/generateRestBindings.ts +1 -1
- package/src/api/C6Constants.ts +1 -0
- package/src/api/builders/sqlBuilder.ts +336 -105
- package/src/api/executors/SqlExecutor.ts +76 -33
- package/src/api/handlers/ExpressHandler.ts +3 -2
- package/src/api/types/ormInterfaces.ts +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {SqlBuilder} from "api/builders/sqlBuilder";
|
|
2
2
|
import {
|
|
3
3
|
apiReturn,
|
|
4
4
|
DetermineResponseDataType,
|
|
@@ -7,7 +7,9 @@ import {
|
|
|
7
7
|
iDeleteC6RestResponse,
|
|
8
8
|
iRestMethods
|
|
9
9
|
} from "../types/ormInterfaces";
|
|
10
|
-
import
|
|
10
|
+
import namedPlaceholders from 'named-placeholders';
|
|
11
|
+
import {PoolConnection, RowDataPacket, ResultSetHeader} from 'mysql2/promise';
|
|
12
|
+
import {Buffer} from 'buffer';
|
|
11
13
|
|
|
12
14
|
export class SqlExecutor<
|
|
13
15
|
RequestMethod extends iRestMethods,
|
|
@@ -25,8 +27,9 @@ export class SqlExecutor<
|
|
|
25
27
|
RequestTableOverrides
|
|
26
28
|
> {
|
|
27
29
|
|
|
30
|
+
|
|
28
31
|
async execute(): Promise<apiReturn<DetermineResponseDataType<RequestMethod, RestTableInterface>>> {
|
|
29
|
-
const {
|
|
32
|
+
const {TABLE_NAME} = this.config.restModel;
|
|
30
33
|
const method = this.config.requestMethod;
|
|
31
34
|
|
|
32
35
|
console.log(`[SQL EXECUTOR] ▶️ Executing ${method} on table "${TABLE_NAME}"`);
|
|
@@ -36,13 +39,13 @@ export class SqlExecutor<
|
|
|
36
39
|
case 'GET': {
|
|
37
40
|
const rest = await this.select(TABLE_NAME, undefined, this.request);
|
|
38
41
|
console.log(`[SQL EXECUTOR] ✅ GET result:`, rest);
|
|
39
|
-
return
|
|
42
|
+
return rest as apiReturn<DetermineResponseDataType<RequestMethod, RestTableInterface>>;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
case 'POST': {
|
|
43
46
|
const result = await this.insert(TABLE_NAME, this.request);
|
|
44
47
|
console.log(`[SQL EXECUTOR] ✅ POST result:`, result);
|
|
45
|
-
const created: iPostC6RestResponse = {
|
|
48
|
+
const created: iPostC6RestResponse = {rest: result, created: true};
|
|
46
49
|
return created as apiReturn<DetermineResponseDataType<RequestMethod, RestTableInterface>>;
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -50,9 +53,9 @@ export class SqlExecutor<
|
|
|
50
53
|
const result = await this.update(TABLE_NAME, [], this.request);
|
|
51
54
|
console.log(`[SQL EXECUTOR] ✅ PUT result:`, result);
|
|
52
55
|
const updated: iPutC6RestResponse = {
|
|
53
|
-
|
|
56
|
+
...result,
|
|
54
57
|
updated: true,
|
|
55
|
-
rowCount:
|
|
58
|
+
rowCount: result.rest.affectedRows
|
|
56
59
|
};
|
|
57
60
|
return updated as apiReturn<DetermineResponseDataType<RequestMethod, RestTableInterface>>;
|
|
58
61
|
}
|
|
@@ -63,7 +66,7 @@ export class SqlExecutor<
|
|
|
63
66
|
const deleted: iDeleteC6RestResponse = {
|
|
64
67
|
rest: result,
|
|
65
68
|
deleted: true,
|
|
66
|
-
rowCount:
|
|
69
|
+
rowCount: result.rest.affectedRows
|
|
67
70
|
};
|
|
68
71
|
return deleted as apiReturn<DetermineResponseDataType<RequestMethod, RestTableInterface>>;
|
|
69
72
|
}
|
|
@@ -85,16 +88,26 @@ export class SqlExecutor<
|
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
90
|
|
|
91
|
+
public serialize = (row: any) => Object.fromEntries(Object.entries(row).map(
|
|
92
|
+
([k, v]) => [k, Buffer.isBuffer(v) ? v.toString('hex').toUpperCase() : v]
|
|
93
|
+
));
|
|
94
|
+
|
|
88
95
|
async select<TName extends string>(table: TName, primary: string | undefined, args: any) {
|
|
89
|
-
const
|
|
90
|
-
console.log(`[SQL EXECUTOR] 🧠 Generated SELECT SQL:`,
|
|
91
|
-
const formatted = this.formatSQLWithParams(
|
|
96
|
+
const QueryResult = this.buildSelectQuery<TName>(table, primary, args);
|
|
97
|
+
console.log(`[SQL EXECUTOR] 🧠 Generated SELECT SQL:`, QueryResult);
|
|
98
|
+
const formatted = this.formatSQLWithParams(QueryResult.sql, QueryResult.params);
|
|
92
99
|
console.log(`[SQL EXECUTOR] 🧠 Formatted SELECT SQL:`, formatted);
|
|
93
|
-
|
|
100
|
+
const toUnnamed = namedPlaceholders();
|
|
101
|
+
const [sql, values] = toUnnamed(QueryResult.sql, QueryResult.params);
|
|
94
102
|
return await this.withConnection(async (conn) => {
|
|
95
|
-
const [rows] = await conn.query<RowDataPacket[]>(sql
|
|
103
|
+
const [rows] = await conn.query<RowDataPacket[]>(sql, values);
|
|
96
104
|
console.log(`[SQL EXECUTOR] 📦 Rows fetched:`, rows);
|
|
97
|
-
return
|
|
105
|
+
return {
|
|
106
|
+
rest: rows.map(this.serialize),
|
|
107
|
+
sql: {
|
|
108
|
+
sql, values
|
|
109
|
+
}
|
|
110
|
+
};
|
|
98
111
|
});
|
|
99
112
|
}
|
|
100
113
|
|
|
@@ -102,14 +115,20 @@ export class SqlExecutor<
|
|
|
102
115
|
const keys = Object.keys(data);
|
|
103
116
|
const values = keys.map(k => data[k]);
|
|
104
117
|
const placeholders = keys.map(() => '?').join(', ');
|
|
105
|
-
const sql = `INSERT INTO \`${table}\` (${keys.join(', ')})
|
|
118
|
+
const sql = `INSERT INTO \`${table}\` (${keys.join(', ')})
|
|
119
|
+
VALUES (${placeholders})`;
|
|
106
120
|
|
|
107
121
|
console.log(`[SQL EXECUTOR] 🧠 Generated INSERT SQL:`, sql);
|
|
108
122
|
console.log(`[SQL EXECUTOR] 🔢 Values:`, values);
|
|
109
123
|
|
|
110
124
|
return await this.withConnection(async (conn) => {
|
|
111
125
|
const [result] = await conn.execute<ResultSetHeader>(sql, values);
|
|
112
|
-
return
|
|
126
|
+
return {
|
|
127
|
+
rest: result,
|
|
128
|
+
sql: {
|
|
129
|
+
sql, placeholders
|
|
130
|
+
}
|
|
131
|
+
};
|
|
113
132
|
});
|
|
114
133
|
}
|
|
115
134
|
|
|
@@ -118,7 +137,9 @@ export class SqlExecutor<
|
|
|
118
137
|
const keys = Object.keys(data);
|
|
119
138
|
const values = keys.map(k => data[k]);
|
|
120
139
|
const updates = keys.map(k => `\`${k}\` = ?`).join(', ');
|
|
121
|
-
const sql = `UPDATE \`${table}\`
|
|
140
|
+
const sql = `UPDATE \`${table}\`
|
|
141
|
+
SET ${updates}
|
|
142
|
+
WHERE \`${primary[0]}\` = ?`;
|
|
122
143
|
values.push(data[primary[0]]);
|
|
123
144
|
|
|
124
145
|
console.log(`[SQL EXECUTOR] 🧠 Generated UPDATE SQL:`, sql);
|
|
@@ -126,38 +147,60 @@ export class SqlExecutor<
|
|
|
126
147
|
|
|
127
148
|
return await this.withConnection(async (conn) => {
|
|
128
149
|
const [result] = await conn.execute<ResultSetHeader>(sql, values);
|
|
129
|
-
return
|
|
150
|
+
return {
|
|
151
|
+
rest:result,
|
|
152
|
+
sql: {
|
|
153
|
+
sql, values
|
|
154
|
+
}
|
|
155
|
+
};
|
|
130
156
|
});
|
|
131
157
|
}
|
|
132
158
|
|
|
133
159
|
async delete<TName extends string>(table: TName, primary: string[], args: Record<string, any>) {
|
|
134
160
|
const key = primary?.[0];
|
|
135
161
|
if (!key || !args?.[key]) throw new Error('Primary key and value required for delete');
|
|
136
|
-
const sql = `DELETE
|
|
162
|
+
const sql = `DELETE
|
|
163
|
+
FROM \`${table}\`
|
|
164
|
+
WHERE \`${key}\` = ?`;
|
|
137
165
|
|
|
138
166
|
console.log(`[SQL EXECUTOR] 🧠 Generated DELETE SQL:`, sql);
|
|
139
167
|
console.log(`[SQL EXECUTOR] 🔢 Value:`, args[key]);
|
|
140
168
|
|
|
141
169
|
return await this.withConnection(async (conn) => {
|
|
142
170
|
const [result] = await conn.execute<ResultSetHeader>(sql, [args[key]]);
|
|
143
|
-
return
|
|
171
|
+
return {
|
|
172
|
+
rest: result,
|
|
173
|
+
sql: {
|
|
174
|
+
sql, args
|
|
175
|
+
}
|
|
176
|
+
};
|
|
144
177
|
});
|
|
145
178
|
}
|
|
146
179
|
|
|
180
|
+
public formatSQLWithParams(sql: string, params: any[] | { [key: string]: any }): string {
|
|
181
|
+
if (Array.isArray(params)) {
|
|
182
|
+
let index = 0;
|
|
183
|
+
return sql.replace(/\?/g, () => {
|
|
184
|
+
if (index >= params.length) return '?';
|
|
185
|
+
const val = params[index++];
|
|
186
|
+
return this.formatValue(val);
|
|
187
|
+
});
|
|
188
|
+
} else {
|
|
189
|
+
return sql.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
|
|
190
|
+
const val = params[key];
|
|
191
|
+
return this.formatValue(val);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
147
195
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (Buffer.isBuffer(val)) return `UNHEX('${val.toString('hex')}')`;
|
|
156
|
-
if (typeof val === 'string') return `'${val.replace(/'/g, "''")}'`;
|
|
157
|
-
if (typeof val === 'number') return val.toString();
|
|
158
|
-
if (val instanceof Date) return `'${val.toISOString().slice(0, 19).replace('T', ' ')}'`;
|
|
159
|
-
return `'${JSON.stringify(val)}'`;
|
|
160
|
-
});
|
|
196
|
+
private formatValue(val: any): string {
|
|
197
|
+
if (val === null || val === undefined) return 'NULL';
|
|
198
|
+
if (Buffer.isBuffer(val)) return `UNHEX('${val.toString('hex')}')`;
|
|
199
|
+
if (typeof val === 'string') return `'${val.replace(/'/g, "''")}'`;
|
|
200
|
+
if (typeof val === 'number') return val.toString();
|
|
201
|
+
if (val instanceof Date) return `'${val.toISOString().slice(0, 19).replace('T', ' ')}'`;
|
|
202
|
+
return `'${JSON.stringify(val)}'`;
|
|
161
203
|
}
|
|
162
204
|
|
|
205
|
+
|
|
163
206
|
}
|
|
@@ -38,6 +38,7 @@ export function ExpressHandler({C6, mysqlPool}: { C6: iC6Object, mysqlPool: Pool
|
|
|
38
38
|
res.status(405).json({error: `Method ${method} not allowed`});
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
|
+
|
|
41
42
|
const response = await restRequest({
|
|
42
43
|
C6,
|
|
43
44
|
mysqlPool,
|
|
@@ -45,10 +46,10 @@ export function ExpressHandler({C6, mysqlPool}: { C6: iC6Object, mysqlPool: Pool
|
|
|
45
46
|
restModel: C6.TABLES[table]
|
|
46
47
|
})(payload);
|
|
47
48
|
|
|
48
|
-
console.log('response', JSON.stringify(response));
|
|
49
|
-
|
|
50
49
|
res.status(200).json({success: true, ...response});
|
|
50
|
+
|
|
51
51
|
} catch (err) {
|
|
52
|
+
res.status(500).json({success: false});
|
|
52
53
|
next(err);
|
|
53
54
|
}
|
|
54
55
|
};
|
|
@@ -238,10 +238,10 @@ export interface iRestApiFunctions<RestData extends { [key: string]: any } = any
|
|
|
238
238
|
Put: (request?: RequestQueryBody<'PUT', RestData>) => apiReturn<iPutC6RestResponse<RestData>>;
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
export interface iC6Object<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
241
|
+
export interface iC6Object<
|
|
242
|
+
RestShortTableName extends string = any,
|
|
243
|
+
RestTableInterface extends { [key: string]: any } = any,
|
|
244
|
+
PrimaryKey extends Extract<keyof RestTableInterface, string> = Extract<keyof RestTableInterface, string>
|
|
245
245
|
> {
|
|
246
246
|
C6VERSION: string;
|
|
247
247
|
TABLES: {
|