@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.
@@ -1,4 +1,4 @@
1
- import { SqlBuilder } from "api/builders/sqlBuilder";
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 { PoolConnection, RowDataPacket, ResultSetHeader } from 'mysql2/promise';
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 { TABLE_NAME } = this.config.restModel;
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 { rest } as apiReturn<DetermineResponseDataType<RequestMethod, RestTableInterface>>;
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 = { rest: result, created: true };
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
- rest: result,
56
+ ...result,
54
57
  updated: true,
55
- rowCount: (result as ResultSetHeader).affectedRows
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: (result as ResultSetHeader).affectedRows
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 sql = this.buildSelectQuery<TName>(table, primary, args);
90
- console.log(`[SQL EXECUTOR] 🧠 Generated SELECT SQL:`, sql);
91
- const formatted = this.formatSQLWithParams(sql.sql, sql.params);
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.sql, sql.params);
103
+ const [rows] = await conn.query<RowDataPacket[]>(sql, values);
96
104
  console.log(`[SQL EXECUTOR] 📦 Rows fetched:`, rows);
97
- return rows;
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(', ')}) VALUES (${placeholders})`;
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 result;
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}\` SET ${updates} WHERE \`${primary[0]}\` = ?`;
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 result;
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 FROM \`${table}\` WHERE \`${key}\` = ?`;
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 result;
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
- public formatSQLWithParams(sql: string, params: any[]): string {
149
- let index = 0;
150
-
151
- return sql.replace(/\?/g, () => {
152
- if (index >= params.length) return '?'; // fallback if params are missing
153
- const val = params[index++];
154
- if (val === null || val === undefined) return 'NULL';
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
- RestShortTableName extends string = any,
243
- RestTableInterface extends { [key: string]: any } = any,
244
- PrimaryKey extends Extract<keyof RestTableInterface, string> = Extract<keyof RestTableInterface, string>
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: {