@bdkinc/knex-ibmi 0.0.6 → 0.0.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/index.js CHANGED
@@ -183,7 +183,57 @@ var import_querycompiler = __toESM(require("knex/lib/query/querycompiler"));
183
183
  var import_isObject2 = __toESM(require("lodash/isObject"));
184
184
  var import_wrappingFormatter = require("knex/lib/formatter/wrappingFormatter");
185
185
  var import_date_fns = require("date-fns");
186
+ var import_isEmpty = __toESM(require("lodash/isEmpty"));
186
187
  var IBMiQueryCompiler = class extends import_querycompiler.default {
188
+ insert() {
189
+ const insertValues = this.single.insert || [];
190
+ let sql = `SELECT ${// @ts-ignore
191
+ this.single.returning ? (
192
+ // @ts-ignore
193
+ this.formatter.columnize(this.single.returning)
194
+ ) : "IDENTITY_VAL_LOCAL()"} FROM FINAL TABLE(`;
195
+ sql += this.with() + `insert into ${this.tableName} `;
196
+ const { returning } = this.single;
197
+ const returningSql = returning ? (
198
+ // @ts-ignore
199
+ this._returning("insert", returning) + " "
200
+ ) : "";
201
+ if (Array.isArray(insertValues)) {
202
+ if (insertValues.length === 0) {
203
+ return "";
204
+ }
205
+ } else if (typeof insertValues === "object" && (0, import_isEmpty.default)(insertValues)) {
206
+ return {
207
+ // @ts-ignore
208
+ sql: sql + returningSql + this._emptyInsertValue,
209
+ returning
210
+ };
211
+ }
212
+ sql += this._buildInsertData(insertValues, returningSql);
213
+ sql += ")";
214
+ return {
215
+ sql,
216
+ returning
217
+ };
218
+ }
219
+ _buildInsertData(insertValues, returningSql) {
220
+ let sql = "";
221
+ const insertData = this._prepInsert(insertValues);
222
+ if (typeof insertData === "string") {
223
+ sql += insertData;
224
+ } else {
225
+ if (insertData.columns.length) {
226
+ sql += `(${this.formatter.columnize(insertData.columns)}`;
227
+ sql += `) ${returningSql}values (` + // @ts-ignore
228
+ this._buildInsertValues(insertData) + ")";
229
+ } else if (insertValues.length === 1 && insertValues[0]) {
230
+ sql += returningSql + this._emptyInsertValue;
231
+ } else {
232
+ return "";
233
+ }
234
+ }
235
+ return sql;
236
+ }
187
237
  _prepInsert(data) {
188
238
  if ((0, import_isObject2.default)(data)) {
189
239
  if (data.hasOwnProperty("migration_time")) {
@@ -237,6 +287,33 @@ var IBMiQueryCompiler = class extends import_querycompiler.default {
237
287
  values
238
288
  };
239
289
  }
290
+ _returning(method, value, withTrigger) {
291
+ switch (method) {
292
+ case "update":
293
+ case "insert":
294
+ return value ? (
295
+ // @ts-ignore
296
+ `${withTrigger ? " into #out" : ""}`
297
+ ) : "";
298
+ case "del":
299
+ return value ? (
300
+ // @ts-ignore
301
+ `${withTrigger ? " into #out" : ""}`
302
+ ) : "";
303
+ case "rowcount":
304
+ return value ? ";select @@rowcount" : "";
305
+ }
306
+ }
307
+ columnizeWithPrefix(prefix, target) {
308
+ const columns = typeof target === "string" ? [target] : target;
309
+ let str = "", i = -1;
310
+ while (++i < columns.length) {
311
+ if (i > 0)
312
+ str += ", ";
313
+ str += prefix + this.wrap(columns[i]);
314
+ }
315
+ return str;
316
+ }
240
317
  };
241
318
  var ibmi_querycompiler_default = IBMiQueryCompiler;
242
319
 
@@ -319,11 +396,35 @@ var DB2Client = class extends import_knex.default.Client {
319
396
  const connection = await pool.connect();
320
397
  const statement = await connection.createStatement();
321
398
  await statement.prepare(obj.sql);
399
+ console.log({ obj });
322
400
  if (obj.bindings) {
323
401
  await statement.bind(obj.bindings);
324
402
  }
325
403
  const result = await statement.execute();
326
- obj.response = { rows: [result.count], rowCount: result.count };
404
+ if (result.statement.includes("IDENTITY_VAL_LOCAL()")) {
405
+ obj.response = {
406
+ rows: result.map(
407
+ (row) => result.columns.length > 0 ? row[result.columns[0].name] : row
408
+ ),
409
+ rowCount: result.length
410
+ };
411
+ } else if (method === "update") {
412
+ console.log(this.queryCompiler);
413
+ let returningSelect = obj.sql.replace("update", "select * from ");
414
+ returningSelect = returningSelect.replace("where", "and");
415
+ returningSelect = returningSelect.replace("set", "where");
416
+ returningSelect = returningSelect.replace(this.tableName, "where");
417
+ const selectStatement = await connection.createStatement();
418
+ await selectStatement.prepare(returningSelect);
419
+ if (obj.bindings) {
420
+ await selectStatement.bind(obj.bindings);
421
+ }
422
+ const selected = await selectStatement.execute();
423
+ console.log(selected.columns);
424
+ obj.response = { rows: selected, rowCount: selected.length };
425
+ } else {
426
+ obj.response = { rows: result, rowCount: result.length };
427
+ }
327
428
  } catch (err) {
328
429
  console.error(err);
329
430
  throw new Error(err);
@@ -331,6 +432,18 @@ var DB2Client = class extends import_knex.default.Client {
331
432
  }
332
433
  return obj;
333
434
  }
435
+ _selectAfterUpdate() {
436
+ const returnSelect = `; SELECT ${this.single.returning ? (
437
+ // @ts-ignore
438
+ this.formatter.columnize(this.single.returning)
439
+ ) : "*"} from ${this.tableName} `;
440
+ let whereStatement = [this.where()];
441
+ console.log({ whereStatement });
442
+ for (const [key, value] of Object.entries(this.single.update)) {
443
+ whereStatement.push(`WHERE ${key} = ${value}`);
444
+ }
445
+ return returnSelect + whereStatement.join(" and ");
446
+ }
334
447
  transaction(container, config, outerTx) {
335
448
  return new ibmi_transaction_default(this, ...arguments);
336
449
  }
@@ -366,6 +479,7 @@ var DB2Client = class extends import_knex.default.Client {
366
479
  case "del":
367
480
  case "delete":
368
481
  case "update":
482
+ return rows;
369
483
  case "counter":
370
484
  return resp.rowCount;
371
485
  default:
package/dist/index.mjs CHANGED
@@ -148,7 +148,57 @@ import QueryCompiler from "knex/lib/query/querycompiler";
148
148
  import isObject2 from "lodash/isObject";
149
149
  import { rawOrFn as rawOrFn_ } from "knex/lib/formatter/wrappingFormatter";
150
150
  import { format } from "date-fns";
151
+ import isEmpty from "lodash/isEmpty";
151
152
  var IBMiQueryCompiler = class extends QueryCompiler {
153
+ insert() {
154
+ const insertValues = this.single.insert || [];
155
+ let sql = `SELECT ${// @ts-ignore
156
+ this.single.returning ? (
157
+ // @ts-ignore
158
+ this.formatter.columnize(this.single.returning)
159
+ ) : "IDENTITY_VAL_LOCAL()"} FROM FINAL TABLE(`;
160
+ sql += this.with() + `insert into ${this.tableName} `;
161
+ const { returning } = this.single;
162
+ const returningSql = returning ? (
163
+ // @ts-ignore
164
+ this._returning("insert", returning) + " "
165
+ ) : "";
166
+ if (Array.isArray(insertValues)) {
167
+ if (insertValues.length === 0) {
168
+ return "";
169
+ }
170
+ } else if (typeof insertValues === "object" && isEmpty(insertValues)) {
171
+ return {
172
+ // @ts-ignore
173
+ sql: sql + returningSql + this._emptyInsertValue,
174
+ returning
175
+ };
176
+ }
177
+ sql += this._buildInsertData(insertValues, returningSql);
178
+ sql += ")";
179
+ return {
180
+ sql,
181
+ returning
182
+ };
183
+ }
184
+ _buildInsertData(insertValues, returningSql) {
185
+ let sql = "";
186
+ const insertData = this._prepInsert(insertValues);
187
+ if (typeof insertData === "string") {
188
+ sql += insertData;
189
+ } else {
190
+ if (insertData.columns.length) {
191
+ sql += `(${this.formatter.columnize(insertData.columns)}`;
192
+ sql += `) ${returningSql}values (` + // @ts-ignore
193
+ this._buildInsertValues(insertData) + ")";
194
+ } else if (insertValues.length === 1 && insertValues[0]) {
195
+ sql += returningSql + this._emptyInsertValue;
196
+ } else {
197
+ return "";
198
+ }
199
+ }
200
+ return sql;
201
+ }
152
202
  _prepInsert(data) {
153
203
  if (isObject2(data)) {
154
204
  if (data.hasOwnProperty("migration_time")) {
@@ -202,6 +252,33 @@ var IBMiQueryCompiler = class extends QueryCompiler {
202
252
  values
203
253
  };
204
254
  }
255
+ _returning(method, value, withTrigger) {
256
+ switch (method) {
257
+ case "update":
258
+ case "insert":
259
+ return value ? (
260
+ // @ts-ignore
261
+ `${withTrigger ? " into #out" : ""}`
262
+ ) : "";
263
+ case "del":
264
+ return value ? (
265
+ // @ts-ignore
266
+ `${withTrigger ? " into #out" : ""}`
267
+ ) : "";
268
+ case "rowcount":
269
+ return value ? ";select @@rowcount" : "";
270
+ }
271
+ }
272
+ columnizeWithPrefix(prefix, target) {
273
+ const columns = typeof target === "string" ? [target] : target;
274
+ let str = "", i = -1;
275
+ while (++i < columns.length) {
276
+ if (i > 0)
277
+ str += ", ";
278
+ str += prefix + this.wrap(columns[i]);
279
+ }
280
+ return str;
281
+ }
205
282
  };
206
283
  var ibmi_querycompiler_default = IBMiQueryCompiler;
207
284
 
@@ -284,11 +361,35 @@ var DB2Client = class extends knex.Client {
284
361
  const connection = await pool.connect();
285
362
  const statement = await connection.createStatement();
286
363
  await statement.prepare(obj.sql);
364
+ console.log({ obj });
287
365
  if (obj.bindings) {
288
366
  await statement.bind(obj.bindings);
289
367
  }
290
368
  const result = await statement.execute();
291
- obj.response = { rows: [result.count], rowCount: result.count };
369
+ if (result.statement.includes("IDENTITY_VAL_LOCAL()")) {
370
+ obj.response = {
371
+ rows: result.map(
372
+ (row) => result.columns.length > 0 ? row[result.columns[0].name] : row
373
+ ),
374
+ rowCount: result.length
375
+ };
376
+ } else if (method === "update") {
377
+ console.log(this.queryCompiler);
378
+ let returningSelect = obj.sql.replace("update", "select * from ");
379
+ returningSelect = returningSelect.replace("where", "and");
380
+ returningSelect = returningSelect.replace("set", "where");
381
+ returningSelect = returningSelect.replace(this.tableName, "where");
382
+ const selectStatement = await connection.createStatement();
383
+ await selectStatement.prepare(returningSelect);
384
+ if (obj.bindings) {
385
+ await selectStatement.bind(obj.bindings);
386
+ }
387
+ const selected = await selectStatement.execute();
388
+ console.log(selected.columns);
389
+ obj.response = { rows: selected, rowCount: selected.length };
390
+ } else {
391
+ obj.response = { rows: result, rowCount: result.length };
392
+ }
292
393
  } catch (err) {
293
394
  console.error(err);
294
395
  throw new Error(err);
@@ -296,6 +397,18 @@ var DB2Client = class extends knex.Client {
296
397
  }
297
398
  return obj;
298
399
  }
400
+ _selectAfterUpdate() {
401
+ const returnSelect = `; SELECT ${this.single.returning ? (
402
+ // @ts-ignore
403
+ this.formatter.columnize(this.single.returning)
404
+ ) : "*"} from ${this.tableName} `;
405
+ let whereStatement = [this.where()];
406
+ console.log({ whereStatement });
407
+ for (const [key, value] of Object.entries(this.single.update)) {
408
+ whereStatement.push(`WHERE ${key} = ${value}`);
409
+ }
410
+ return returnSelect + whereStatement.join(" and ");
411
+ }
299
412
  transaction(container, config, outerTx) {
300
413
  return new ibmi_transaction_default(this, ...arguments);
301
414
  }
@@ -331,6 +444,7 @@ var DB2Client = class extends knex.Client {
331
444
  case "del":
332
445
  case "delete":
333
446
  case "update":
447
+ return rows;
334
448
  case "counter":
335
449
  return resp.rowCount;
336
450
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bdkinc/knex-ibmi",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Knex dialect for IBMi",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/index.ts CHANGED
@@ -114,11 +114,45 @@ class DB2Client extends knex.Client {
114
114
  const connection = await pool.connect();
115
115
  const statement = await connection.createStatement();
116
116
  await statement.prepare(obj.sql);
117
+ console.log({ obj });
117
118
  if (obj.bindings) {
118
119
  await statement.bind(obj.bindings);
119
120
  }
120
121
  const result = await statement.execute();
121
- obj.response = { rows: [result.count], rowCount: result.count };
122
+ // this is hacky we check the SQL for the ID column
123
+ // most dialects return the ID of the inserted
124
+ // we check for the IDENTITY scalar function
125
+ // if that function is present, then we just return the value of the
126
+ // IDENTITY column
127
+ if (result.statement.includes("IDENTITY_VAL_LOCAL()")) {
128
+ obj.response = {
129
+ rows: result.map((row) =>
130
+ result.columns.length > 0 ? row[result.columns[0].name] : row,
131
+ ),
132
+ rowCount: result.length,
133
+ };
134
+ } else if (method === "update") {
135
+ // if is in update we need to run a separate select query
136
+ // this also feels hacky and should be cleaned up
137
+ // it would be a lot easier if the table-reference function
138
+ // worked the same for updates as it does inserts
139
+ // on DB2 LUW it does work so if they ever add it we need to fix
140
+ console.log(this.queryCompiler)
141
+ let returningSelect = obj.sql.replace("update", "select * from ");
142
+ returningSelect = returningSelect.replace("where", "and");
143
+ returningSelect = returningSelect.replace("set", "where");
144
+ returningSelect = returningSelect.replace(this.tableName, "where");
145
+ const selectStatement = await connection.createStatement();
146
+ await selectStatement.prepare(returningSelect);
147
+ if (obj.bindings) {
148
+ await selectStatement.bind(obj.bindings);
149
+ }
150
+ const selected = await selectStatement.execute();
151
+ console.log(selected.columns)
152
+ obj.response = {rows: selected, rowCount: selected.length}
153
+ } else {
154
+ obj.response = { rows: result, rowCount: result.length };
155
+ }
122
156
  } catch (err: any) {
123
157
  console.error(err);
124
158
  throw new Error(err);
@@ -128,6 +162,21 @@ class DB2Client extends knex.Client {
128
162
  return obj;
129
163
  }
130
164
 
165
+ _selectAfterUpdate() {
166
+ const returnSelect = `; SELECT ${
167
+ this.single.returning
168
+ ? // @ts-ignore
169
+ this.formatter.columnize(this.single.returning)
170
+ : "*"
171
+ } from ${this.tableName} `;
172
+ let whereStatement = [this.where()];
173
+ console.log({ whereStatement });
174
+ for (const [key, value] of Object.entries(this.single.update)) {
175
+ whereStatement.push(`WHERE ${key} = ${value}`);
176
+ }
177
+ return returnSelect + whereStatement.join(" and ");
178
+ }
179
+
131
180
  transaction(container: any, config: any, outerTx: any): Knex.Transaction {
132
181
  // @ts-ignore
133
182
  return new Transaction(this, ...arguments);
@@ -174,6 +223,7 @@ class DB2Client extends knex.Client {
174
223
  case "del":
175
224
  case "delete":
176
225
  case "update":
226
+ return rows;
177
227
  case "counter":
178
228
  return resp.rowCount;
179
229
  default:
@@ -2,8 +2,80 @@ import QueryCompiler from "knex/lib/query/querycompiler";
2
2
  import isObject from "lodash/isObject";
3
3
  import { rawOrFn as rawOrFn_ } from "knex/lib/formatter/wrappingFormatter";
4
4
  import { format } from "date-fns";
5
+ import * as console from "console";
6
+ import isEmpty from "lodash/isEmpty";
5
7
 
6
8
  class IBMiQueryCompiler extends QueryCompiler {
9
+ insert() {
10
+ // @ts-ignore
11
+ const insertValues = this.single.insert || [];
12
+ // we need to return a value
13
+ // we need to wrap the insert statement in a select statement
14
+ // we use the "IDENTITY_VAL_LOCAL()" function to return the IDENTITY
15
+ // unless specified in a return
16
+ // @ts-ignore
17
+ let sql = `SELECT ${
18
+ // @ts-ignore
19
+ this.single.returning
20
+ ? // @ts-ignore
21
+ this.formatter.columnize(this.single.returning)
22
+ : "IDENTITY_VAL_LOCAL()"
23
+ } FROM FINAL TABLE(`;
24
+ // @ts-ignore
25
+ sql += this.with() + `insert into ${this.tableName} `;
26
+ // @ts-ignore
27
+ const { returning } = this.single;
28
+ const returningSql = returning
29
+ ? // @ts-ignore
30
+ this._returning("insert", returning) + " "
31
+ : "";
32
+
33
+ if (Array.isArray(insertValues)) {
34
+ if (insertValues.length === 0) {
35
+ return "";
36
+ }
37
+ } else if (typeof insertValues === "object" && isEmpty(insertValues)) {
38
+ return {
39
+ // @ts-ignore
40
+ sql: sql + returningSql + this._emptyInsertValue,
41
+ returning,
42
+ };
43
+ }
44
+
45
+ // @ts-ignore
46
+ sql += this._buildInsertData(insertValues, returningSql);
47
+ sql += ")";
48
+
49
+ return {
50
+ sql,
51
+ returning,
52
+ };
53
+ }
54
+
55
+ _buildInsertData(insertValues, returningSql) {
56
+ let sql = "";
57
+ const insertData = this._prepInsert(insertValues);
58
+ if (typeof insertData === "string") {
59
+ sql += insertData;
60
+ } else {
61
+ if (insertData.columns.length) {
62
+ // @ts-ignore
63
+ sql += `(${this.formatter.columnize(insertData.columns)}`;
64
+ sql +=
65
+ `) ${returningSql}values (` +
66
+ // @ts-ignore
67
+ this._buildInsertValues(insertData) +
68
+ ")";
69
+ } else if (insertValues.length === 1 && insertValues[0]) {
70
+ // @ts-ignore
71
+ sql += returningSql + this._emptyInsertValue;
72
+ } else {
73
+ return "";
74
+ }
75
+ }
76
+ return sql;
77
+ }
78
+
7
79
  _prepInsert(data) {
8
80
  if (isObject(data)) {
9
81
  if (data.hasOwnProperty("migration_time")) {
@@ -54,6 +126,36 @@ class IBMiQueryCompiler extends QueryCompiler {
54
126
  values,
55
127
  };
56
128
  }
129
+
130
+ _returning(method, value, withTrigger) {
131
+ // currently a placeholder in case I need to update return values
132
+ switch (method) {
133
+ case "update":
134
+ case "insert":
135
+ return value
136
+ ? // @ts-ignore
137
+ `${withTrigger ? " into #out" : ""}`
138
+ : "";
139
+ case "del":
140
+ return value
141
+ ? // @ts-ignore
142
+ `${withTrigger ? " into #out" : ""}`
143
+ : "";
144
+ case "rowcount":
145
+ return value ? ";select @@rowcount" : "";
146
+ }
147
+ }
148
+
149
+ columnizeWithPrefix(prefix, target) {
150
+ const columns = typeof target === "string" ? [target] : target;
151
+ let str = "",
152
+ i = -1;
153
+ while (++i < columns.length) {
154
+ if (i > 0) str += ", ";
155
+ str += prefix + this.wrap(columns[i]);
156
+ }
157
+ return str;
158
+ }
57
159
  }
58
160
 
59
161
  export default IBMiQueryCompiler;