@openfn/language-mssql 5.0.14 → 5.1.0

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/ast.json CHANGED
@@ -74,6 +74,42 @@
74
74
  },
75
75
  "name": "filter"
76
76
  },
77
+ {
78
+ "title": "param",
79
+ "description": "The uuid column to determine a matching/existing record",
80
+ "type": {
81
+ "type": "NameExpression",
82
+ "name": "string"
83
+ },
84
+ "name": "filter.uuid"
85
+ },
86
+ {
87
+ "title": "param",
88
+ "description": "The table to lookup the value in",
89
+ "type": {
90
+ "type": "NameExpression",
91
+ "name": "string"
92
+ },
93
+ "name": "filter.relation"
94
+ },
95
+ {
96
+ "title": "param",
97
+ "description": "The condition to use for the lookup. Values are automatically escaped for security.",
98
+ "type": {
99
+ "type": "NameExpression",
100
+ "name": "object"
101
+ },
102
+ "name": "filter.where"
103
+ },
104
+ {
105
+ "title": "param",
106
+ "description": "The operator to use for the lookup",
107
+ "type": {
108
+ "type": "NameExpression",
109
+ "name": "object"
110
+ },
111
+ "name": "filter.operator"
112
+ },
77
113
  {
78
114
  "title": "returns",
79
115
  "description": null,
@@ -84,7 +120,7 @@
84
120
  }
85
121
  ]
86
122
  },
87
- "valid": true
123
+ "valid": false
88
124
  },
89
125
  {
90
126
  "name": "insert",
package/dist/index.cjs CHANGED
@@ -45,7 +45,8 @@ __export(src_exports, {
45
45
  sql: () => sql,
46
46
  upsert: () => upsert,
47
47
  upsertIf: () => upsertIf,
48
- upsertMany: () => upsertMany
48
+ upsertMany: () => upsertMany,
49
+ util: () => util_exports
49
50
  });
50
51
  module.exports = __toCommonJS(src_exports);
51
52
 
@@ -80,6 +81,22 @@ __export(Adaptor_exports, {
80
81
  upsertMany: () => upsertMany
81
82
  });
82
83
  var import_language_common = require("@openfn/language-common");
84
+
85
+ // src/util.js
86
+ var util_exports = {};
87
+ __export(util_exports, {
88
+ escape: () => escape
89
+ });
90
+ function escape(stringExp) {
91
+ if (typeof stringExp === "object" && stringExp !== null) {
92
+ return Object.values(stringExp).map((x) => escape(x));
93
+ } else if (typeof stringExp !== "string") {
94
+ return stringExp;
95
+ }
96
+ return stringExp.replace(/\'/g, "''");
97
+ }
98
+
99
+ // src/Adaptor.js
83
100
  var import_tedious = require("tedious");
84
101
  var import_language_common2 = require("@openfn/language-common");
85
102
  function createConnection(state) {
@@ -138,10 +155,9 @@ function execute(...operations) {
138
155
  };
139
156
  }
140
157
  function cleanupState(state) {
141
- if (state.connection) {
142
- state.connection.close();
143
- }
144
- delete state.connection;
158
+ var _a;
159
+ (_a = state == null ? void 0 : state.connection) == null ? void 0 : _a.close();
160
+ state == null ? true : delete state.connection;
145
161
  return state;
146
162
  }
147
163
  function addRowsToRefs(state, rows) {
@@ -232,14 +248,6 @@ function handleOptions(options) {
232
248
  }
233
249
  return options && options.setNull || "'undefined'";
234
250
  }
235
- function escapeQuote(stringExp) {
236
- if (typeof stringExp === "object" && stringExp !== null) {
237
- return Object.values(stringExp).map((x) => escapeQuote(x));
238
- } else if (typeof stringExp !== "string") {
239
- return stringExp;
240
- }
241
- return stringExp.replace(/\'/g, "''");
242
- }
243
251
  function findValue(filter) {
244
252
  return (state) => {
245
253
  const { connection } = state;
@@ -247,10 +255,12 @@ function findValue(filter) {
247
255
  const whereData = (0, import_language_common.expandReferences)(where)(state);
248
256
  const operatorData = (0, import_language_common.expandReferences)(operator)(state);
249
257
  let conditionsArray = [];
250
- for (let key in whereData)
258
+ for (let key in whereData) {
259
+ const escapedValue = escape(whereData[key]);
251
260
  conditionsArray.push(
252
- `${key} ${operatorData ? operatorData[key] : "="} '${whereData[key]}'`
261
+ `${key} ${operatorData ? operatorData[key] : "="} '${escapedValue}'`
253
262
  );
263
+ }
254
264
  const condition = conditionsArray.length > 0 ? `where ${conditionsArray.join(" and ")}` : "";
255
265
  try {
256
266
  const body = `select ${uuid} from ${relation} ${condition}`;
@@ -261,13 +271,15 @@ function findValue(filter) {
261
271
  const request = new import_tedious.Request(body, (err, rowCount, rows) => {
262
272
  if (err) {
263
273
  console.error(err.message);
264
- throw err;
274
+ reject(err);
265
275
  } else {
266
276
  if (rows.length > 0) {
267
277
  returnValue = rows[0][0].value;
268
278
  }
269
- if (returnValue === null)
279
+ if (returnValue === null) {
280
+ console.log("No value found");
270
281
  resolve(void 0);
282
+ }
271
283
  resolve(returnValue);
272
284
  }
273
285
  });
@@ -285,7 +297,7 @@ function insert(table, record, options) {
285
297
  try {
286
298
  const recordData = (0, import_language_common.expandReferences)(record)(state);
287
299
  const columns = Object.keys(recordData).sort();
288
- const values = columns.map((key) => escapeQuote(recordData[key])).join("', '");
300
+ const values = columns.map((key) => escape(recordData[key])).join("', '");
289
301
  const query = handleValues(
290
302
  `INSERT INTO ${table} (${columns.join(", ")}) VALUES ('${values}');`,
291
303
  handleOptions(options)
@@ -311,7 +323,7 @@ function insertMany(table, records, options) {
311
323
  const recordData = (0, import_language_common.expandReferences)(records)(state);
312
324
  const columns = Object.keys(recordData[0]);
313
325
  const valueSets = recordData.map(
314
- (x) => `('${escapeQuote(Object.values(x)).join("', '")}')`
326
+ (x) => `('${escape(Object.values(x)).join("', '")}')`
315
327
  );
316
328
  const query = handleValues(
317
329
  `INSERT INTO ${table} (${columns.join(", ")}) VALUES ${valueSets.join(
@@ -339,8 +351,8 @@ function upsert(table, uuid, record, options) {
339
351
  try {
340
352
  const recordData = (0, import_language_common.expandReferences)(record)(state);
341
353
  const columns = Object.keys(recordData).sort();
342
- const selectValues = columns.map((key) => `'${escapeQuote(recordData[key])}' AS ${key}`).join(", ");
343
- const updateValues = columns.map((key) => `[Target].${key}='${escapeQuote(recordData[key])}'`).join(", ");
354
+ const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
355
+ const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
344
356
  const insertColumns = columns.join(", ");
345
357
  const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
346
358
  const constraint = [];
@@ -392,8 +404,8 @@ function upsertIf(logical, table, uuid, record, options) {
392
404
  resolve(state);
393
405
  return state;
394
406
  }
395
- const selectValues = columns.map((key) => `'${escapeQuote(recordData[key])}' AS ${key}`).join(", ");
396
- const updateValues = columns.map((key) => `[Target].${key}='${escapeQuote(recordData[key])}'`).join(", ");
407
+ const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
408
+ const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
397
409
  const insertColumns = columns.join(", ");
398
410
  const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
399
411
  const constraint = [];
@@ -443,7 +455,7 @@ function upsertMany(table, uuid, records, options) {
443
455
  }
444
456
  const columns = Object.keys(recordData[0]);
445
457
  const valueSets = recordData.map(
446
- (x) => `('${escapeQuote(Object.values(x)).join("', '")}')`
458
+ (x) => `('${escape(Object.values(x)).join("', '")}')`
447
459
  );
448
460
  const insertColumns = columns.join(", ");
449
461
  const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
@@ -580,5 +592,6 @@ var src_default = Adaptor_exports;
580
592
  sql,
581
593
  upsert,
582
594
  upsertIf,
583
- upsertMany
595
+ upsertMany,
596
+ util
584
597
  });
package/dist/index.js CHANGED
@@ -38,6 +38,22 @@ import {
38
38
  execute as commonExecute,
39
39
  expandReferences
40
40
  } from "@openfn/language-common";
41
+
42
+ // src/util.js
43
+ var util_exports = {};
44
+ __export(util_exports, {
45
+ escape: () => escape
46
+ });
47
+ function escape(stringExp) {
48
+ if (typeof stringExp === "object" && stringExp !== null) {
49
+ return Object.values(stringExp).map((x) => escape(x));
50
+ } else if (typeof stringExp !== "string") {
51
+ return stringExp;
52
+ }
53
+ return stringExp.replace(/\'/g, "''");
54
+ }
55
+
56
+ // src/Adaptor.js
41
57
  import { Connection, Request } from "tedious";
42
58
  import {
43
59
  alterState,
@@ -112,10 +128,9 @@ function execute(...operations) {
112
128
  };
113
129
  }
114
130
  function cleanupState(state) {
115
- if (state.connection) {
116
- state.connection.close();
117
- }
118
- delete state.connection;
131
+ var _a;
132
+ (_a = state == null ? void 0 : state.connection) == null ? void 0 : _a.close();
133
+ state == null ? true : delete state.connection;
119
134
  return state;
120
135
  }
121
136
  function addRowsToRefs(state, rows) {
@@ -206,14 +221,6 @@ function handleOptions(options) {
206
221
  }
207
222
  return options && options.setNull || "'undefined'";
208
223
  }
209
- function escapeQuote(stringExp) {
210
- if (typeof stringExp === "object" && stringExp !== null) {
211
- return Object.values(stringExp).map((x) => escapeQuote(x));
212
- } else if (typeof stringExp !== "string") {
213
- return stringExp;
214
- }
215
- return stringExp.replace(/\'/g, "''");
216
- }
217
224
  function findValue(filter) {
218
225
  return (state) => {
219
226
  const { connection } = state;
@@ -221,10 +228,12 @@ function findValue(filter) {
221
228
  const whereData = expandReferences(where)(state);
222
229
  const operatorData = expandReferences(operator)(state);
223
230
  let conditionsArray = [];
224
- for (let key in whereData)
231
+ for (let key in whereData) {
232
+ const escapedValue = escape(whereData[key]);
225
233
  conditionsArray.push(
226
- `${key} ${operatorData ? operatorData[key] : "="} '${whereData[key]}'`
234
+ `${key} ${operatorData ? operatorData[key] : "="} '${escapedValue}'`
227
235
  );
236
+ }
228
237
  const condition = conditionsArray.length > 0 ? `where ${conditionsArray.join(" and ")}` : "";
229
238
  try {
230
239
  const body = `select ${uuid} from ${relation} ${condition}`;
@@ -235,13 +244,15 @@ function findValue(filter) {
235
244
  const request = new Request(body, (err, rowCount, rows) => {
236
245
  if (err) {
237
246
  console.error(err.message);
238
- throw err;
247
+ reject(err);
239
248
  } else {
240
249
  if (rows.length > 0) {
241
250
  returnValue = rows[0][0].value;
242
251
  }
243
- if (returnValue === null)
252
+ if (returnValue === null) {
253
+ console.log("No value found");
244
254
  resolve(void 0);
255
+ }
245
256
  resolve(returnValue);
246
257
  }
247
258
  });
@@ -259,7 +270,7 @@ function insert(table, record, options) {
259
270
  try {
260
271
  const recordData = expandReferences(record)(state);
261
272
  const columns = Object.keys(recordData).sort();
262
- const values = columns.map((key) => escapeQuote(recordData[key])).join("', '");
273
+ const values = columns.map((key) => escape(recordData[key])).join("', '");
263
274
  const query = handleValues(
264
275
  `INSERT INTO ${table} (${columns.join(", ")}) VALUES ('${values}');`,
265
276
  handleOptions(options)
@@ -285,7 +296,7 @@ function insertMany(table, records, options) {
285
296
  const recordData = expandReferences(records)(state);
286
297
  const columns = Object.keys(recordData[0]);
287
298
  const valueSets = recordData.map(
288
- (x) => `('${escapeQuote(Object.values(x)).join("', '")}')`
299
+ (x) => `('${escape(Object.values(x)).join("', '")}')`
289
300
  );
290
301
  const query = handleValues(
291
302
  `INSERT INTO ${table} (${columns.join(", ")}) VALUES ${valueSets.join(
@@ -313,8 +324,8 @@ function upsert(table, uuid, record, options) {
313
324
  try {
314
325
  const recordData = expandReferences(record)(state);
315
326
  const columns = Object.keys(recordData).sort();
316
- const selectValues = columns.map((key) => `'${escapeQuote(recordData[key])}' AS ${key}`).join(", ");
317
- const updateValues = columns.map((key) => `[Target].${key}='${escapeQuote(recordData[key])}'`).join(", ");
327
+ const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
328
+ const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
318
329
  const insertColumns = columns.join(", ");
319
330
  const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
320
331
  const constraint = [];
@@ -366,8 +377,8 @@ function upsertIf(logical, table, uuid, record, options) {
366
377
  resolve(state);
367
378
  return state;
368
379
  }
369
- const selectValues = columns.map((key) => `'${escapeQuote(recordData[key])}' AS ${key}`).join(", ");
370
- const updateValues = columns.map((key) => `[Target].${key}='${escapeQuote(recordData[key])}'`).join(", ");
380
+ const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
381
+ const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
371
382
  const insertColumns = columns.join(", ");
372
383
  const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
373
384
  const constraint = [];
@@ -417,7 +428,7 @@ function upsertMany(table, uuid, records, options) {
417
428
  }
418
429
  const columns = Object.keys(recordData[0]);
419
430
  const valueSets = recordData.map(
420
- (x) => `('${escapeQuote(Object.values(x)).join("', '")}')`
431
+ (x) => `('${escape(Object.values(x)).join("', '")}')`
421
432
  );
422
433
  const insertColumns = columns.join(", ");
423
434
  const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
@@ -554,5 +565,6 @@ export {
554
565
  sql,
555
566
  upsert,
556
567
  upsertIf,
557
- upsertMany
568
+ upsertMany,
569
+ util_exports as util
558
570
  };
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@openfn/language-mssql",
3
- "version": "5.0.14",
3
+ "label": "MSSQL",
4
+ "version": "5.1.0",
4
5
  "description": "A Microsoft SQL language pack for OpenFn",
5
6
  "exports": {
6
7
  ".": {
@@ -25,13 +26,12 @@
25
26
  ],
26
27
  "dependencies": {
27
28
  "tedious": "18.6.1",
28
- "@openfn/language-common": "2.4.0"
29
+ "@openfn/language-common": "2.5.0"
29
30
  },
30
31
  "devDependencies": {
31
32
  "assertion-error": "2.0.0",
32
- "chai": "4.3.6",
33
+ "chai": "^5.2.0",
33
34
  "deep-eql": "4.1.1",
34
- "esno": "^0.16.3",
35
35
  "rimraf": "3.0.2"
36
36
  },
37
37
  "type": "module",
@@ -39,8 +39,9 @@
39
39
  "main": "dist/index.cjs",
40
40
  "scripts": {
41
41
  "build": "pnpm clean && build-adaptor mssql",
42
- "test": "mocha --experimental-specifier-resolution=node --no-warnings",
43
- "test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings",
42
+ "test": "mocha --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
43
+ "test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
44
+ "test:integration": "mocha --experimental-specifier-resolution=node --no-warnings test/integration.js",
44
45
  "clean": "rimraf dist types docs",
45
46
  "pack": "pnpm pack --pack-destination ../../dist",
46
47
  "lint": "eslint src"
@@ -33,9 +33,18 @@ export function sql(params: object): Operation;
33
33
  * })
34
34
  * @function
35
35
  * @param {object} filter - A filter object with the lookup table, a uuid and the condition
36
+ * @param {string} filter.uuid - The uuid column to determine a matching/existing record
37
+ * @param {string} filter.relation - The table to lookup the value in
38
+ * @param {object} filter.where - The condition to use for the lookup. Values are automatically escaped for security.
39
+ * @param {object} filter.operator - The operator to use for the lookup
36
40
  * @returns {Operation}
37
41
  */
38
- export function findValue(filter: object): Operation;
42
+ export function findValue(filter: {
43
+ uuid: string;
44
+ relation: string;
45
+ where: object;
46
+ operator: object;
47
+ }): Operation;
39
48
  /**
40
49
  * Insert a record
41
50
  * @public
package/types/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export default Adaptor;
2
2
  export * from "./Adaptor";
3
+ export * as util from "./util";
3
4
  import * as Adaptor from "./Adaptor";
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Escapes a string for use in an SQL query.
3
+ * @example <caption>Examples</caption>
4
+ * util.escape('test string') // 'test string'
5
+ * util.escape("O'Connor") // "O''Connor"
6
+ * util.escape('string with "quotes"') // 'string with "quotes"'
7
+ * util.escape('') // ''
8
+ * util.escape(null) // null
9
+ * util.escape("'; DROP TABLE users; --") // "''; DROP TABLE users; --"
10
+ * @param {string} stringExp - The string to escape.
11
+ * @returns {string} The escaped string.
12
+ */
13
+ export function escape(stringExp: string): string;