@openfn/language-mssql 5.0.14 → 5.2.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 +91 -1
- package/dist/index.cjs +55 -37
- package/dist/index.js +55 -41
- package/package.json +7 -6
- package/types/Adaptor.d.ts +11 -2
- package/types/index.d.ts +1 -0
- package/types/util.d.ts +13 -0
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":
|
|
123
|
+
"valid": false
|
|
88
124
|
},
|
|
89
125
|
{
|
|
90
126
|
"name": "insert",
|
|
@@ -1237,6 +1273,60 @@
|
|
|
1237
1273
|
]
|
|
1238
1274
|
},
|
|
1239
1275
|
"valid": false
|
|
1276
|
+
},
|
|
1277
|
+
{
|
|
1278
|
+
"name": "as",
|
|
1279
|
+
"params": [
|
|
1280
|
+
"key",
|
|
1281
|
+
"operation"
|
|
1282
|
+
],
|
|
1283
|
+
"docs": {
|
|
1284
|
+
"description": "Run an operation and save the result to a custom key in state instead of overwriting state.data.",
|
|
1285
|
+
"tags": [
|
|
1286
|
+
{
|
|
1287
|
+
"title": "public",
|
|
1288
|
+
"description": null,
|
|
1289
|
+
"type": null
|
|
1290
|
+
},
|
|
1291
|
+
{
|
|
1292
|
+
"title": "function",
|
|
1293
|
+
"description": null,
|
|
1294
|
+
"name": null
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
"title": "example",
|
|
1298
|
+
"description": "as('cceData', collections.get('cce-data-dhis2', { key: `*:*:${$.syncedAt}*` }));",
|
|
1299
|
+
"caption": "Fetch cce-data from collections and store them under state.cceData"
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
"title": "param",
|
|
1303
|
+
"description": "The state key to assign the result of the operation to.",
|
|
1304
|
+
"type": {
|
|
1305
|
+
"type": "NameExpression",
|
|
1306
|
+
"name": "string"
|
|
1307
|
+
},
|
|
1308
|
+
"name": "key"
|
|
1309
|
+
},
|
|
1310
|
+
{
|
|
1311
|
+
"title": "param",
|
|
1312
|
+
"description": " An operation that returns a new state object with a `data` property",
|
|
1313
|
+
"type": {
|
|
1314
|
+
"type": "NameExpression",
|
|
1315
|
+
"name": "function"
|
|
1316
|
+
},
|
|
1317
|
+
"name": "operation"
|
|
1318
|
+
},
|
|
1319
|
+
{
|
|
1320
|
+
"title": "returns",
|
|
1321
|
+
"description": null,
|
|
1322
|
+
"type": {
|
|
1323
|
+
"type": "NameExpression",
|
|
1324
|
+
"name": "Operation"
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
]
|
|
1328
|
+
},
|
|
1329
|
+
"valid": true
|
|
1240
1330
|
}
|
|
1241
1331
|
]
|
|
1242
1332
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var src_exports = {};
|
|
21
21
|
__export(src_exports, {
|
|
22
22
|
alterState: () => import_language_common2.alterState,
|
|
23
|
+
as: () => import_language_common2.as,
|
|
23
24
|
combine: () => import_language_common2.combine,
|
|
24
25
|
cursor: () => import_language_common2.cursor,
|
|
25
26
|
dataPath: () => import_language_common2.dataPath,
|
|
@@ -45,7 +46,8 @@ __export(src_exports, {
|
|
|
45
46
|
sql: () => sql,
|
|
46
47
|
upsert: () => upsert,
|
|
47
48
|
upsertIf: () => upsertIf,
|
|
48
|
-
upsertMany: () => upsertMany
|
|
49
|
+
upsertMany: () => upsertMany,
|
|
50
|
+
util: () => util_exports
|
|
49
51
|
});
|
|
50
52
|
module.exports = __toCommonJS(src_exports);
|
|
51
53
|
|
|
@@ -53,6 +55,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
53
55
|
var Adaptor_exports = {};
|
|
54
56
|
__export(Adaptor_exports, {
|
|
55
57
|
alterState: () => import_language_common2.alterState,
|
|
58
|
+
as: () => import_language_common2.as,
|
|
56
59
|
combine: () => import_language_common2.combine,
|
|
57
60
|
cursor: () => import_language_common2.cursor,
|
|
58
61
|
dataPath: () => import_language_common2.dataPath,
|
|
@@ -80,6 +83,23 @@ __export(Adaptor_exports, {
|
|
|
80
83
|
upsertMany: () => upsertMany
|
|
81
84
|
});
|
|
82
85
|
var import_language_common = require("@openfn/language-common");
|
|
86
|
+
var import_util = require("@openfn/language-common/util");
|
|
87
|
+
|
|
88
|
+
// src/util.js
|
|
89
|
+
var util_exports = {};
|
|
90
|
+
__export(util_exports, {
|
|
91
|
+
escape: () => escape
|
|
92
|
+
});
|
|
93
|
+
function escape(stringExp) {
|
|
94
|
+
if (typeof stringExp === "object" && stringExp !== null) {
|
|
95
|
+
return Object.values(stringExp).map((x) => escape(x));
|
|
96
|
+
} else if (typeof stringExp !== "string") {
|
|
97
|
+
return stringExp;
|
|
98
|
+
}
|
|
99
|
+
return stringExp.replace(/\'/g, "''");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/Adaptor.js
|
|
83
103
|
var import_tedious = require("tedious");
|
|
84
104
|
var import_language_common2 = require("@openfn/language-common");
|
|
85
105
|
function createConnection(state) {
|
|
@@ -138,10 +158,9 @@ function execute(...operations) {
|
|
|
138
158
|
};
|
|
139
159
|
}
|
|
140
160
|
function cleanupState(state) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
delete state.connection;
|
|
161
|
+
var _a;
|
|
162
|
+
(_a = state == null ? void 0 : state.connection) == null ? void 0 : _a.close();
|
|
163
|
+
state == null ? true : delete state.connection;
|
|
145
164
|
return state;
|
|
146
165
|
}
|
|
147
166
|
function addRowsToRefs(state, rows) {
|
|
@@ -198,7 +217,8 @@ function sql(params) {
|
|
|
198
217
|
return (state) => {
|
|
199
218
|
const { connection } = state;
|
|
200
219
|
try {
|
|
201
|
-
const
|
|
220
|
+
const [resolvedParams] = (0, import_util.expandReferences)(state, params);
|
|
221
|
+
const { query, options } = resolvedParams;
|
|
202
222
|
console.log(`Preparing to execute sql statement: ${query}`);
|
|
203
223
|
return queryHandler(state, query, composeNextState, options);
|
|
204
224
|
} catch (e) {
|
|
@@ -232,25 +252,19 @@ function handleOptions(options) {
|
|
|
232
252
|
}
|
|
233
253
|
return options && options.setNull || "'undefined'";
|
|
234
254
|
}
|
|
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
255
|
function findValue(filter) {
|
|
244
256
|
return (state) => {
|
|
245
257
|
const { connection } = state;
|
|
246
258
|
const { uuid, relation, where, operator } = filter;
|
|
247
|
-
const whereData = (0,
|
|
248
|
-
const operatorData = (0,
|
|
259
|
+
const [whereData] = (0, import_util.expandReferences)(state, where);
|
|
260
|
+
const [operatorData] = (0, import_util.expandReferences)(state, operator);
|
|
249
261
|
let conditionsArray = [];
|
|
250
|
-
for (let key in whereData)
|
|
262
|
+
for (let key in whereData) {
|
|
263
|
+
const escapedValue = escape(whereData[key]);
|
|
251
264
|
conditionsArray.push(
|
|
252
|
-
`${key} ${operatorData ? operatorData[key] : "="} '${
|
|
265
|
+
`${key} ${operatorData ? operatorData[key] : "="} '${escapedValue}'`
|
|
253
266
|
);
|
|
267
|
+
}
|
|
254
268
|
const condition = conditionsArray.length > 0 ? `where ${conditionsArray.join(" and ")}` : "";
|
|
255
269
|
try {
|
|
256
270
|
const body = `select ${uuid} from ${relation} ${condition}`;
|
|
@@ -261,13 +275,15 @@ function findValue(filter) {
|
|
|
261
275
|
const request = new import_tedious.Request(body, (err, rowCount, rows) => {
|
|
262
276
|
if (err) {
|
|
263
277
|
console.error(err.message);
|
|
264
|
-
|
|
278
|
+
reject(err);
|
|
265
279
|
} else {
|
|
266
280
|
if (rows.length > 0) {
|
|
267
281
|
returnValue = rows[0][0].value;
|
|
268
282
|
}
|
|
269
|
-
if (returnValue === null)
|
|
283
|
+
if (returnValue === null) {
|
|
284
|
+
console.log("No value found");
|
|
270
285
|
resolve(void 0);
|
|
286
|
+
}
|
|
271
287
|
resolve(returnValue);
|
|
272
288
|
}
|
|
273
289
|
});
|
|
@@ -283,9 +299,9 @@ function insert(table, record, options) {
|
|
|
283
299
|
return (state) => {
|
|
284
300
|
const { connection } = state;
|
|
285
301
|
try {
|
|
286
|
-
const recordData = (0,
|
|
302
|
+
const [recordData] = (0, import_util.expandReferences)(state, record);
|
|
287
303
|
const columns = Object.keys(recordData).sort();
|
|
288
|
-
const values = columns.map((key) =>
|
|
304
|
+
const values = columns.map((key) => escape(recordData[key])).join("', '");
|
|
289
305
|
const query = handleValues(
|
|
290
306
|
`INSERT INTO ${table} (${columns.join(", ")}) VALUES ('${values}');`,
|
|
291
307
|
handleOptions(options)
|
|
@@ -308,10 +324,10 @@ function insertMany(table, records, options) {
|
|
|
308
324
|
return (state) => {
|
|
309
325
|
const { connection } = state;
|
|
310
326
|
try {
|
|
311
|
-
const recordData = (0,
|
|
327
|
+
const [recordData] = (0, import_util.expandReferences)(state, records);
|
|
312
328
|
const columns = Object.keys(recordData[0]);
|
|
313
329
|
const valueSets = recordData.map(
|
|
314
|
-
(x) => `('${
|
|
330
|
+
(x) => `('${escape(Object.values(x)).join("', '")}')`
|
|
315
331
|
);
|
|
316
332
|
const query = handleValues(
|
|
317
333
|
`INSERT INTO ${table} (${columns.join(", ")}) VALUES ${valueSets.join(
|
|
@@ -337,10 +353,10 @@ function upsert(table, uuid, record, options) {
|
|
|
337
353
|
return (state) => {
|
|
338
354
|
const { connection } = state;
|
|
339
355
|
try {
|
|
340
|
-
const recordData = (0,
|
|
356
|
+
const [recordData] = (0, import_util.expandReferences)(state, record);
|
|
341
357
|
const columns = Object.keys(recordData).sort();
|
|
342
|
-
const selectValues = columns.map((key) => `'${
|
|
343
|
-
const updateValues = columns.map((key) => `[Target].${key}='${
|
|
358
|
+
const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
|
|
359
|
+
const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
|
|
344
360
|
const insertColumns = columns.join(", ");
|
|
345
361
|
const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
|
|
346
362
|
const constraint = [];
|
|
@@ -383,17 +399,17 @@ function upsertIf(logical, table, uuid, record, options) {
|
|
|
383
399
|
return (state) => {
|
|
384
400
|
const { connection } = state;
|
|
385
401
|
try {
|
|
386
|
-
const recordData = (0,
|
|
402
|
+
const [recordData] = (0, import_util.expandReferences)(state, record);
|
|
387
403
|
const columns = Object.keys(recordData).sort();
|
|
388
|
-
const logicalData = (0,
|
|
404
|
+
const [logicalData] = (0, import_util.expandReferences)(state, logical);
|
|
389
405
|
return new Promise((resolve, reject) => {
|
|
390
406
|
if (!logicalData) {
|
|
391
407
|
console.log(`Skipping upsert for ${uuid}.`);
|
|
392
408
|
resolve(state);
|
|
393
409
|
return state;
|
|
394
410
|
}
|
|
395
|
-
const selectValues = columns.map((key) => `'${
|
|
396
|
-
const updateValues = columns.map((key) => `[Target].${key}='${
|
|
411
|
+
const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
|
|
412
|
+
const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
|
|
397
413
|
const insertColumns = columns.join(", ");
|
|
398
414
|
const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
|
|
399
415
|
const constraint = [];
|
|
@@ -435,7 +451,7 @@ function upsertMany(table, uuid, records, options) {
|
|
|
435
451
|
return (state) => {
|
|
436
452
|
const { connection } = state;
|
|
437
453
|
try {
|
|
438
|
-
const recordData = (0,
|
|
454
|
+
const [recordData] = (0, import_util.expandReferences)(state, records);
|
|
439
455
|
return new Promise((resolve, reject) => {
|
|
440
456
|
if (!recordData || recordData.length === 0) {
|
|
441
457
|
console.log("No records provided; skipping upsert.");
|
|
@@ -443,7 +459,7 @@ function upsertMany(table, uuid, records, options) {
|
|
|
443
459
|
}
|
|
444
460
|
const columns = Object.keys(recordData[0]);
|
|
445
461
|
const valueSets = recordData.map(
|
|
446
|
-
(x) => `('${
|
|
462
|
+
(x) => `('${escape(Object.values(x)).join("', '")}')`
|
|
447
463
|
);
|
|
448
464
|
const insertColumns = columns.join(", ");
|
|
449
465
|
const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
|
|
@@ -486,7 +502,7 @@ function upsertMany(table, uuid, records, options) {
|
|
|
486
502
|
function describeTable(tableName, options) {
|
|
487
503
|
return (state) => {
|
|
488
504
|
const { connection } = state;
|
|
489
|
-
const name = (0,
|
|
505
|
+
const [name] = (0, import_util.expandReferences)(state, tableName);
|
|
490
506
|
try {
|
|
491
507
|
const query = `SELECT column_name
|
|
492
508
|
FROM information_schema.columns
|
|
@@ -504,7 +520,7 @@ function insertTable(tableName, columns, options) {
|
|
|
504
520
|
return (state) => {
|
|
505
521
|
const { connection } = state;
|
|
506
522
|
try {
|
|
507
|
-
const data = (0,
|
|
523
|
+
const [data] = (0, import_util.expandReferences)(state, columns);
|
|
508
524
|
return new Promise((resolve, reject) => {
|
|
509
525
|
if (!data || data.length === 0) {
|
|
510
526
|
console.log("No columns provided; skipping table creation.");
|
|
@@ -530,7 +546,7 @@ function modifyTable(tableName, columns, options) {
|
|
|
530
546
|
return (state) => {
|
|
531
547
|
const { connection } = state;
|
|
532
548
|
try {
|
|
533
|
-
const data = (0,
|
|
549
|
+
const [data] = (0, import_util.expandReferences)(state, columns);
|
|
534
550
|
return new Promise((resolve, reject) => {
|
|
535
551
|
if (!data || data.length === 0) {
|
|
536
552
|
console.log("No columns provided; skipping table modification.");
|
|
@@ -556,6 +572,7 @@ var src_default = Adaptor_exports;
|
|
|
556
572
|
// Annotate the CommonJS export names for ESM import in node:
|
|
557
573
|
0 && (module.exports = {
|
|
558
574
|
alterState,
|
|
575
|
+
as,
|
|
559
576
|
combine,
|
|
560
577
|
cursor,
|
|
561
578
|
dataPath,
|
|
@@ -580,5 +597,6 @@ var src_default = Adaptor_exports;
|
|
|
580
597
|
sql,
|
|
581
598
|
upsert,
|
|
582
599
|
upsertIf,
|
|
583
|
-
upsertMany
|
|
600
|
+
upsertMany,
|
|
601
|
+
util
|
|
584
602
|
});
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ var __export = (target, all) => {
|
|
|
8
8
|
var Adaptor_exports = {};
|
|
9
9
|
__export(Adaptor_exports, {
|
|
10
10
|
alterState: () => alterState,
|
|
11
|
+
as: () => as,
|
|
11
12
|
combine: () => combine,
|
|
12
13
|
cursor: () => cursor,
|
|
13
14
|
dataPath: () => dataPath,
|
|
@@ -34,10 +35,24 @@ __export(Adaptor_exports, {
|
|
|
34
35
|
upsertIf: () => upsertIf,
|
|
35
36
|
upsertMany: () => upsertMany
|
|
36
37
|
});
|
|
37
|
-
import {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
import { execute as commonExecute } from "@openfn/language-common";
|
|
39
|
+
import { expandReferences } from "@openfn/language-common/util";
|
|
40
|
+
|
|
41
|
+
// src/util.js
|
|
42
|
+
var util_exports = {};
|
|
43
|
+
__export(util_exports, {
|
|
44
|
+
escape: () => escape
|
|
45
|
+
});
|
|
46
|
+
function escape(stringExp) {
|
|
47
|
+
if (typeof stringExp === "object" && stringExp !== null) {
|
|
48
|
+
return Object.values(stringExp).map((x) => escape(x));
|
|
49
|
+
} else if (typeof stringExp !== "string") {
|
|
50
|
+
return stringExp;
|
|
51
|
+
}
|
|
52
|
+
return stringExp.replace(/\'/g, "''");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/Adaptor.js
|
|
41
56
|
import { Connection, Request } from "tedious";
|
|
42
57
|
import {
|
|
43
58
|
alterState,
|
|
@@ -54,7 +69,8 @@ import {
|
|
|
54
69
|
lastReferenceValue,
|
|
55
70
|
cursor,
|
|
56
71
|
merge,
|
|
57
|
-
sourceValue
|
|
72
|
+
sourceValue,
|
|
73
|
+
as
|
|
58
74
|
} from "@openfn/language-common";
|
|
59
75
|
function createConnection(state) {
|
|
60
76
|
const {
|
|
@@ -112,10 +128,9 @@ function execute(...operations) {
|
|
|
112
128
|
};
|
|
113
129
|
}
|
|
114
130
|
function cleanupState(state) {
|
|
115
|
-
|
|
116
|
-
|
|
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) {
|
|
@@ -172,7 +187,8 @@ function sql(params) {
|
|
|
172
187
|
return (state) => {
|
|
173
188
|
const { connection } = state;
|
|
174
189
|
try {
|
|
175
|
-
const
|
|
190
|
+
const [resolvedParams] = expandReferences(state, params);
|
|
191
|
+
const { query, options } = resolvedParams;
|
|
176
192
|
console.log(`Preparing to execute sql statement: ${query}`);
|
|
177
193
|
return queryHandler(state, query, composeNextState, options);
|
|
178
194
|
} catch (e) {
|
|
@@ -206,25 +222,19 @@ function handleOptions(options) {
|
|
|
206
222
|
}
|
|
207
223
|
return options && options.setNull || "'undefined'";
|
|
208
224
|
}
|
|
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
225
|
function findValue(filter) {
|
|
218
226
|
return (state) => {
|
|
219
227
|
const { connection } = state;
|
|
220
228
|
const { uuid, relation, where, operator } = filter;
|
|
221
|
-
const whereData = expandReferences(where)
|
|
222
|
-
const operatorData = expandReferences(operator)
|
|
229
|
+
const [whereData] = expandReferences(state, where);
|
|
230
|
+
const [operatorData] = expandReferences(state, operator);
|
|
223
231
|
let conditionsArray = [];
|
|
224
|
-
for (let key in whereData)
|
|
232
|
+
for (let key in whereData) {
|
|
233
|
+
const escapedValue = escape(whereData[key]);
|
|
225
234
|
conditionsArray.push(
|
|
226
|
-
`${key} ${operatorData ? operatorData[key] : "="} '${
|
|
235
|
+
`${key} ${operatorData ? operatorData[key] : "="} '${escapedValue}'`
|
|
227
236
|
);
|
|
237
|
+
}
|
|
228
238
|
const condition = conditionsArray.length > 0 ? `where ${conditionsArray.join(" and ")}` : "";
|
|
229
239
|
try {
|
|
230
240
|
const body = `select ${uuid} from ${relation} ${condition}`;
|
|
@@ -235,13 +245,15 @@ function findValue(filter) {
|
|
|
235
245
|
const request = new Request(body, (err, rowCount, rows) => {
|
|
236
246
|
if (err) {
|
|
237
247
|
console.error(err.message);
|
|
238
|
-
|
|
248
|
+
reject(err);
|
|
239
249
|
} else {
|
|
240
250
|
if (rows.length > 0) {
|
|
241
251
|
returnValue = rows[0][0].value;
|
|
242
252
|
}
|
|
243
|
-
if (returnValue === null)
|
|
253
|
+
if (returnValue === null) {
|
|
254
|
+
console.log("No value found");
|
|
244
255
|
resolve(void 0);
|
|
256
|
+
}
|
|
245
257
|
resolve(returnValue);
|
|
246
258
|
}
|
|
247
259
|
});
|
|
@@ -257,9 +269,9 @@ function insert(table, record, options) {
|
|
|
257
269
|
return (state) => {
|
|
258
270
|
const { connection } = state;
|
|
259
271
|
try {
|
|
260
|
-
const recordData = expandReferences(record)
|
|
272
|
+
const [recordData] = expandReferences(state, record);
|
|
261
273
|
const columns = Object.keys(recordData).sort();
|
|
262
|
-
const values = columns.map((key) =>
|
|
274
|
+
const values = columns.map((key) => escape(recordData[key])).join("', '");
|
|
263
275
|
const query = handleValues(
|
|
264
276
|
`INSERT INTO ${table} (${columns.join(", ")}) VALUES ('${values}');`,
|
|
265
277
|
handleOptions(options)
|
|
@@ -282,10 +294,10 @@ function insertMany(table, records, options) {
|
|
|
282
294
|
return (state) => {
|
|
283
295
|
const { connection } = state;
|
|
284
296
|
try {
|
|
285
|
-
const recordData = expandReferences(records)
|
|
297
|
+
const [recordData] = expandReferences(state, records);
|
|
286
298
|
const columns = Object.keys(recordData[0]);
|
|
287
299
|
const valueSets = recordData.map(
|
|
288
|
-
(x) => `('${
|
|
300
|
+
(x) => `('${escape(Object.values(x)).join("', '")}')`
|
|
289
301
|
);
|
|
290
302
|
const query = handleValues(
|
|
291
303
|
`INSERT INTO ${table} (${columns.join(", ")}) VALUES ${valueSets.join(
|
|
@@ -311,10 +323,10 @@ function upsert(table, uuid, record, options) {
|
|
|
311
323
|
return (state) => {
|
|
312
324
|
const { connection } = state;
|
|
313
325
|
try {
|
|
314
|
-
const recordData = expandReferences(record)
|
|
326
|
+
const [recordData] = expandReferences(state, record);
|
|
315
327
|
const columns = Object.keys(recordData).sort();
|
|
316
|
-
const selectValues = columns.map((key) => `'${
|
|
317
|
-
const updateValues = columns.map((key) => `[Target].${key}='${
|
|
328
|
+
const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
|
|
329
|
+
const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
|
|
318
330
|
const insertColumns = columns.join(", ");
|
|
319
331
|
const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
|
|
320
332
|
const constraint = [];
|
|
@@ -357,17 +369,17 @@ function upsertIf(logical, table, uuid, record, options) {
|
|
|
357
369
|
return (state) => {
|
|
358
370
|
const { connection } = state;
|
|
359
371
|
try {
|
|
360
|
-
const recordData = expandReferences(record)
|
|
372
|
+
const [recordData] = expandReferences(state, record);
|
|
361
373
|
const columns = Object.keys(recordData).sort();
|
|
362
|
-
const logicalData = expandReferences(logical)
|
|
374
|
+
const [logicalData] = expandReferences(state, logical);
|
|
363
375
|
return new Promise((resolve, reject) => {
|
|
364
376
|
if (!logicalData) {
|
|
365
377
|
console.log(`Skipping upsert for ${uuid}.`);
|
|
366
378
|
resolve(state);
|
|
367
379
|
return state;
|
|
368
380
|
}
|
|
369
|
-
const selectValues = columns.map((key) => `'${
|
|
370
|
-
const updateValues = columns.map((key) => `[Target].${key}='${
|
|
381
|
+
const selectValues = columns.map((key) => `'${escape(recordData[key])}' AS ${key}`).join(", ");
|
|
382
|
+
const updateValues = columns.map((key) => `[Target].${key}='${escape(recordData[key])}'`).join(", ");
|
|
371
383
|
const insertColumns = columns.join(", ");
|
|
372
384
|
const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
|
|
373
385
|
const constraint = [];
|
|
@@ -409,7 +421,7 @@ function upsertMany(table, uuid, records, options) {
|
|
|
409
421
|
return (state) => {
|
|
410
422
|
const { connection } = state;
|
|
411
423
|
try {
|
|
412
|
-
const recordData = expandReferences(records)
|
|
424
|
+
const [recordData] = expandReferences(state, records);
|
|
413
425
|
return new Promise((resolve, reject) => {
|
|
414
426
|
if (!recordData || recordData.length === 0) {
|
|
415
427
|
console.log("No records provided; skipping upsert.");
|
|
@@ -417,7 +429,7 @@ function upsertMany(table, uuid, records, options) {
|
|
|
417
429
|
}
|
|
418
430
|
const columns = Object.keys(recordData[0]);
|
|
419
431
|
const valueSets = recordData.map(
|
|
420
|
-
(x) => `('${
|
|
432
|
+
(x) => `('${escape(Object.values(x)).join("', '")}')`
|
|
421
433
|
);
|
|
422
434
|
const insertColumns = columns.join(", ");
|
|
423
435
|
const insertValues = columns.map((key) => `[Source].${key}`).join(", ");
|
|
@@ -460,7 +472,7 @@ function upsertMany(table, uuid, records, options) {
|
|
|
460
472
|
function describeTable(tableName, options) {
|
|
461
473
|
return (state) => {
|
|
462
474
|
const { connection } = state;
|
|
463
|
-
const name = expandReferences(tableName)
|
|
475
|
+
const [name] = expandReferences(state, tableName);
|
|
464
476
|
try {
|
|
465
477
|
const query = `SELECT column_name
|
|
466
478
|
FROM information_schema.columns
|
|
@@ -478,7 +490,7 @@ function insertTable(tableName, columns, options) {
|
|
|
478
490
|
return (state) => {
|
|
479
491
|
const { connection } = state;
|
|
480
492
|
try {
|
|
481
|
-
const data = expandReferences(columns)
|
|
493
|
+
const [data] = expandReferences(state, columns);
|
|
482
494
|
return new Promise((resolve, reject) => {
|
|
483
495
|
if (!data || data.length === 0) {
|
|
484
496
|
console.log("No columns provided; skipping table creation.");
|
|
@@ -504,7 +516,7 @@ function modifyTable(tableName, columns, options) {
|
|
|
504
516
|
return (state) => {
|
|
505
517
|
const { connection } = state;
|
|
506
518
|
try {
|
|
507
|
-
const data = expandReferences(columns)
|
|
519
|
+
const [data] = expandReferences(state, columns);
|
|
508
520
|
return new Promise((resolve, reject) => {
|
|
509
521
|
if (!data || data.length === 0) {
|
|
510
522
|
console.log("No columns provided; skipping table modification.");
|
|
@@ -529,6 +541,7 @@ function modifyTable(tableName, columns, options) {
|
|
|
529
541
|
var src_default = Adaptor_exports;
|
|
530
542
|
export {
|
|
531
543
|
alterState,
|
|
544
|
+
as,
|
|
532
545
|
combine,
|
|
533
546
|
cursor,
|
|
534
547
|
dataPath,
|
|
@@ -554,5 +567,6 @@ export {
|
|
|
554
567
|
sql,
|
|
555
568
|
upsert,
|
|
556
569
|
upsertIf,
|
|
557
|
-
upsertMany
|
|
570
|
+
upsertMany,
|
|
571
|
+
util_exports as util
|
|
558
572
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/language-mssql",
|
|
3
|
-
"
|
|
3
|
+
"label": "MSSQL",
|
|
4
|
+
"version": "5.2.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": "
|
|
29
|
+
"@openfn/language-common": "3.0.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"assertion-error": "2.0.0",
|
|
32
|
-
"chai": "
|
|
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"
|
package/types/Adaptor.d.ts
CHANGED
|
@@ -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:
|
|
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
|
|
@@ -161,4 +170,4 @@ export function insertTable(tableName: string, columns: any[], options: object):
|
|
|
161
170
|
* @returns {Operation}
|
|
162
171
|
*/
|
|
163
172
|
export function modifyTable(tableName: string, columns: any[], options: object): Operation;
|
|
164
|
-
export { alterState, combine, dataPath, dataValue, dateFns, each, field, fields, fn, fnIf, http, lastReferenceValue, cursor, merge, sourceValue } from "@openfn/language-common";
|
|
173
|
+
export { alterState, combine, dataPath, dataValue, dateFns, each, field, fields, fn, fnIf, http, lastReferenceValue, cursor, merge, sourceValue, as } from "@openfn/language-common";
|
package/types/index.d.ts
CHANGED
package/types/util.d.ts
ADDED
|
@@ -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;
|