@openfn/language-mysql 2.2.2 → 3.0.1

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
@@ -1,18 +1,17 @@
1
1
  {
2
2
  "operations": [
3
3
  {
4
- "name": "insert",
4
+ "name": "sql",
5
5
  "params": [
6
- "table",
7
- "fields"
6
+ "sqlQuery",
7
+ "options"
8
8
  ],
9
9
  "docs": {
10
- "description": "Insert a record",
10
+ "description": "Execute a SQL statement. Take care when inserting values from state directly into a query,\nas this can be a vector for injection attacks. See [OWASP SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html)\nfor guidelines",
11
11
  "tags": [
12
12
  {
13
13
  "title": "example",
14
- "description": "insert(\"users\", { name: (state) => state.data.name });",
15
- "caption": "Insert a record into the `users` table"
14
+ "description": "sql(state => `select * from ${state.data.tableName};`, { writeSql: true })"
16
15
  },
17
16
  {
18
17
  "title": "function",
@@ -26,21 +25,59 @@
26
25
  },
27
26
  {
28
27
  "title": "param",
29
- "description": "The target table",
28
+ "description": "The SQL query as a string or a function that returns a string using state.",
30
29
  "type": {
31
- "type": "NameExpression",
32
- "name": "string"
30
+ "type": "UnionType",
31
+ "elements": [
32
+ {
33
+ "type": "NameExpression",
34
+ "name": "string"
35
+ },
36
+ {
37
+ "type": "NameExpression",
38
+ "name": "function"
39
+ }
40
+ ]
33
41
  },
34
- "name": "table"
42
+ "name": "sqlQuery"
35
43
  },
36
44
  {
37
45
  "title": "param",
38
- "description": "A fields object",
46
+ "description": "Optional options argument.",
39
47
  "type": {
40
- "type": "NameExpression",
41
- "name": "object"
48
+ "type": "OptionalType",
49
+ "expression": {
50
+ "type": "NameExpression",
51
+ "name": "object"
52
+ }
42
53
  },
43
- "name": "fields"
54
+ "name": "options"
55
+ },
56
+ {
57
+ "title": "param",
58
+ "description": "If true, logs the generated SQL statement. Defaults to false.",
59
+ "type": {
60
+ "type": "OptionalType",
61
+ "expression": {
62
+ "type": "NameExpression",
63
+ "name": "boolean"
64
+ }
65
+ },
66
+ "name": "options.writeSql",
67
+ "default": "false"
68
+ },
69
+ {
70
+ "title": "param",
71
+ "description": "If false, does not execute the SQL, just logs it and adds to state.queries. Defaults to true.",
72
+ "type": {
73
+ "type": "OptionalType",
74
+ "expression": {
75
+ "type": "NameExpression",
76
+ "name": "boolean"
77
+ }
78
+ },
79
+ "name": "options.execute",
80
+ "default": "true"
44
81
  },
45
82
  {
46
83
  "title": "returns",
@@ -52,21 +89,21 @@
52
89
  }
53
90
  ]
54
91
  },
55
- "valid": true
92
+ "valid": false
56
93
  },
57
94
  {
58
- "name": "upsert",
95
+ "name": "insert",
59
96
  "params": [
60
97
  "table",
61
98
  "fields"
62
99
  ],
63
100
  "docs": {
64
- "description": "Insert or Update a record if matched",
101
+ "description": "Insert a record",
65
102
  "tags": [
66
103
  {
67
104
  "title": "example",
68
- "description": "upsert(\"table\", { name: (state) => state.data.name });",
69
- "caption": "Upsert a record"
105
+ "description": "insert(\"users\", { name: (state) => state.data.name });",
106
+ "caption": "Insert a record into the `users` table"
70
107
  },
71
108
  {
72
109
  "title": "function",
@@ -109,23 +146,18 @@
109
146
  "valid": true
110
147
  },
111
148
  {
112
- "name": "upsertMany",
149
+ "name": "upsert",
113
150
  "params": [
114
151
  "table",
115
- "data"
152
+ "fields"
116
153
  ],
117
154
  "docs": {
118
- "description": "Insert or update multiple records using ON DUPLICATE KEY",
155
+ "description": "Insert or Update a record if matched",
119
156
  "tags": [
120
- {
121
- "title": "public",
122
- "description": null,
123
- "type": null
124
- },
125
157
  {
126
158
  "title": "example",
127
- "description": "upsertMany(\n 'users', // the DB table\n [\n { name: 'one', email: 'one@openfn.org' },\n { name: 'two', email: 'two@openfn.org' },\n ]\n)",
128
- "caption": "Upsert multiple records"
159
+ "description": "upsert(\"table\", { name: (state) => state.data.name });",
160
+ "caption": "Upsert a record"
129
161
  },
130
162
  {
131
163
  "title": "function",
@@ -148,12 +180,12 @@
148
180
  },
149
181
  {
150
182
  "title": "param",
151
- "description": "An array of objects or a function that returns an array",
183
+ "description": "A fields object",
152
184
  "type": {
153
185
  "type": "NameExpression",
154
- "name": "array"
186
+ "name": "object"
155
187
  },
156
- "name": "data"
188
+ "name": "fields"
157
189
  },
158
190
  {
159
191
  "title": "returns",
@@ -168,17 +200,23 @@
168
200
  "valid": true
169
201
  },
170
202
  {
171
- "name": "query",
203
+ "name": "upsertMany",
172
204
  "params": [
173
- "options"
205
+ "table",
206
+ "data"
174
207
  ],
175
208
  "docs": {
176
- "description": "Execute a SQL statement",
209
+ "description": "Insert or update multiple records using ON DUPLICATE KEY",
177
210
  "tags": [
211
+ {
212
+ "title": "public",
213
+ "description": null,
214
+ "type": null
215
+ },
178
216
  {
179
217
  "title": "example",
180
- "description": "query({ sql: 'select * from users;' })",
181
- "caption": "Execute a SQL statement"
218
+ "description": "upsertMany(\n 'users', // the DB table\n [\n { name: 'one', email: 'one@openfn.org' },\n { name: 'two', email: 'two@openfn.org' },\n ]\n)",
219
+ "caption": "Upsert multiple records"
182
220
  },
183
221
  {
184
222
  "title": "function",
@@ -192,56 +230,21 @@
192
230
  },
193
231
  {
194
232
  "title": "param",
195
- "description": "Payload data for the message",
233
+ "description": "The target table",
196
234
  "type": {
197
235
  "type": "NameExpression",
198
- "name": "object"
236
+ "name": "string"
199
237
  },
200
- "name": "options"
201
- },
202
- {
203
- "title": "returns",
204
- "description": null,
205
- "type": {
206
- "type": "NameExpression",
207
- "name": "Operation"
208
- }
209
- }
210
- ]
211
- },
212
- "valid": true
213
- },
214
- {
215
- "name": "sqlString",
216
- "params": [
217
- "queryString"
218
- ],
219
- "docs": {
220
- "description": "Execute a SQL statement",
221
- "tags": [
222
- {
223
- "title": "example",
224
- "description": "sqlString(state => \"select * from items;\")",
225
- "caption": "Execute a SQL statement"
226
- },
227
- {
228
- "title": "function",
229
- "description": null,
230
- "name": null
231
- },
232
- {
233
- "title": "public",
234
- "description": null,
235
- "type": null
238
+ "name": "table"
236
239
  },
237
240
  {
238
241
  "title": "param",
239
- "description": "A query string (or function which takes state and returns a string)",
242
+ "description": "An array of objects or a function that returns an array",
240
243
  "type": {
241
244
  "type": "NameExpression",
242
- "name": "String"
245
+ "name": "array"
243
246
  },
244
- "name": "queryString"
247
+ "name": "data"
245
248
  },
246
249
  {
247
250
  "title": "returns",
@@ -308,7 +311,7 @@
308
311
  "operation"
309
312
  ],
310
313
  "docs": {
311
- "description": "A custom operation that will only execute the function if the condition returns true",
314
+ "description": "Execute a function only when the condition returns true",
312
315
  "tags": [
313
316
  {
314
317
  "title": "public",
package/dist/index.cjs CHANGED
@@ -40,13 +40,11 @@ __export(src_exports, {
40
40
  fields: () => import_language_common2.fields,
41
41
  fn: () => import_language_common2.fn,
42
42
  fnIf: () => import_language_common2.fnIf,
43
- http: () => import_language_common2.http,
44
43
  insert: () => insert,
45
44
  lastReferenceValue: () => import_language_common2.lastReferenceValue,
46
45
  merge: () => import_language_common2.merge,
47
- query: () => query,
48
46
  sourceValue: () => import_language_common2.sourceValue,
49
- sqlString: () => sqlString,
47
+ sql: () => sql,
50
48
  upsert: () => upsert,
51
49
  upsertMany: () => upsertMany
52
50
  });
@@ -69,13 +67,11 @@ __export(Adaptor_exports, {
69
67
  fields: () => import_language_common2.fields,
70
68
  fn: () => import_language_common2.fn,
71
69
  fnIf: () => import_language_common2.fnIf,
72
- http: () => import_language_common2.http,
73
70
  insert: () => insert,
74
71
  lastReferenceValue: () => import_language_common2.lastReferenceValue,
75
72
  merge: () => import_language_common2.merge,
76
- query: () => query,
77
73
  sourceValue: () => import_language_common2.sourceValue,
78
- sqlString: () => sqlString,
74
+ sql: () => sql,
79
75
  upsert: () => upsert,
80
76
  upsertMany: () => upsertMany
81
77
  });
@@ -84,6 +80,36 @@ var import_util = require("@openfn/language-common/util");
84
80
  var import_mysql = __toESM(require("mysql"), 1);
85
81
  var import_squel = __toESM(require("squel"), 1);
86
82
  var import_language_common2 = require("@openfn/language-common");
83
+ function sql(sqlQuery, options = {}) {
84
+ return (state) => {
85
+ const { connection } = state;
86
+ const [resolvedSqlQuery, resolvedOptions] = (0, import_util.expandReferences)(
87
+ state,
88
+ sqlQuery,
89
+ options
90
+ );
91
+ const { writeSql = false, execute: execute2 = true } = resolvedOptions;
92
+ if (writeSql) {
93
+ console.log("Prepared SQL:", resolvedSqlQuery);
94
+ }
95
+ if (!execute2) {
96
+ return {
97
+ ...state,
98
+ queries: [...state.queries || [], resolvedSqlQuery]
99
+ };
100
+ }
101
+ return new Promise((resolve, reject) => {
102
+ connection.query(resolvedSqlQuery, (err, results, fields2) => {
103
+ if (err) {
104
+ console.log("Error executing query. Disconnecting from database.");
105
+ connection.end();
106
+ return reject(err);
107
+ }
108
+ resolve({ ...state, response: { body: results, fields: fields2 } });
109
+ });
110
+ });
111
+ };
112
+ }
87
113
  function execute(...operations) {
88
114
  const initialState = {
89
115
  references: [],
@@ -127,9 +153,9 @@ function insert(table, fields2) {
127
153
  var sqlParams = squelMysql.insert({
128
154
  autoQuoteFieldNames: true
129
155
  }).into(table).setFields(valuesObj).toParam();
130
- var sql = sqlParams.text;
131
- var inserts = sqlParams.values;
132
- sqlString = import_mysql.default.format(sql, inserts);
156
+ const sql2 = sqlParams.text;
157
+ const inserts = sqlParams.values;
158
+ const sqlString = import_mysql.default.format(sql2, inserts);
133
159
  console.log(`Executing MySQL query: ${sqlString}`);
134
160
  return new Promise((resolve, reject) => {
135
161
  connection.query(sqlString, function(err, results, fields3) {
@@ -158,15 +184,15 @@ function upsert(table, fields2) {
158
184
  var insertParams = squelMysql.insert({
159
185
  autoQuoteFieldNames: true
160
186
  }).into(table).setFields(valuesObj).toParam();
161
- var sql = insertParams.text;
187
+ var sql2 = insertParams.text;
162
188
  var inserts = insertParams.values;
163
- const insertString = import_mysql.default.format(sql, inserts);
189
+ const insertString = import_mysql.default.format(sql2, inserts);
164
190
  var updateParams = squelMysql.update({
165
191
  autoQuoteFieldNames: true
166
192
  }).table("").setFields(valuesObj).toParam();
167
- var sql = updateParams.text;
193
+ var sql2 = updateParams.text;
168
194
  var inserts = updateParams.values;
169
- const updateString = import_mysql.default.format(sql, inserts);
195
+ const updateString = import_mysql.default.format(sql2, inserts);
170
196
  const upsertString = insertString + ` ON DUPLICATE KEY UPDATE ` + updateString.slice(10);
171
197
  console.log("Executing MySQL query: " + upsertString);
172
198
  return new Promise((resolve, reject) => {
@@ -222,36 +248,6 @@ function upsertMany(table, data) {
222
248
  });
223
249
  };
224
250
  }
225
- function query(options) {
226
- return (state) => {
227
- let { connection } = state;
228
- const [opts] = (0, import_util.expandReferences)(state, options);
229
- console.log(
230
- "Executing MySQL statement with options: " + JSON.stringify(opts, 2, null)
231
- );
232
- return new Promise((resolve, reject) => {
233
- connection.query(opts, function(err, results, fields2) {
234
- if (err) {
235
- reject(err);
236
- console.log("That's an error. Disconnecting from database.");
237
- connection.end();
238
- } else {
239
- console.log("Success...");
240
- resolve(JSON.parse(JSON.stringify(results)));
241
- }
242
- });
243
- }).then((data) => {
244
- console.log(data);
245
- const nextState = { ...state, response: { body: data } };
246
- return nextState;
247
- });
248
- };
249
- }
250
- function sqlString(queryString) {
251
- return (state) => {
252
- return query({ sql: queryString })(state);
253
- };
254
- }
255
251
 
256
252
  // src/index.js
257
253
  var src_default = Adaptor_exports;
@@ -271,13 +267,11 @@ var src_default = Adaptor_exports;
271
267
  fields,
272
268
  fn,
273
269
  fnIf,
274
- http,
275
270
  insert,
276
271
  lastReferenceValue,
277
272
  merge,
278
- query,
279
273
  sourceValue,
280
- sqlString,
274
+ sql,
281
275
  upsert,
282
276
  upsertMany
283
277
  });
package/dist/index.js CHANGED
@@ -21,13 +21,11 @@ __export(Adaptor_exports, {
21
21
  fields: () => fields,
22
22
  fn: () => fn,
23
23
  fnIf: () => fnIf,
24
- http: () => http,
25
24
  insert: () => insert,
26
25
  lastReferenceValue: () => lastReferenceValue,
27
26
  merge: () => merge,
28
- query: () => query,
29
27
  sourceValue: () => sourceValue,
30
- sqlString: () => sqlString,
28
+ sql: () => sql,
31
29
  upsert: () => upsert,
32
30
  upsertMany: () => upsertMany
33
31
  });
@@ -39,7 +37,6 @@ import {
39
37
  fn,
40
38
  fnIf,
41
39
  each,
42
- http,
43
40
  merge,
44
41
  field,
45
42
  fields,
@@ -54,6 +51,36 @@ import {
54
51
  lastReferenceValue,
55
52
  as
56
53
  } from "@openfn/language-common";
54
+ function sql(sqlQuery, options = {}) {
55
+ return (state) => {
56
+ const { connection } = state;
57
+ const [resolvedSqlQuery, resolvedOptions] = expandReferences(
58
+ state,
59
+ sqlQuery,
60
+ options
61
+ );
62
+ const { writeSql = false, execute: execute2 = true } = resolvedOptions;
63
+ if (writeSql) {
64
+ console.log("Prepared SQL:", resolvedSqlQuery);
65
+ }
66
+ if (!execute2) {
67
+ return {
68
+ ...state,
69
+ queries: [...state.queries || [], resolvedSqlQuery]
70
+ };
71
+ }
72
+ return new Promise((resolve, reject) => {
73
+ connection.query(resolvedSqlQuery, (err, results, fields2) => {
74
+ if (err) {
75
+ console.log("Error executing query. Disconnecting from database.");
76
+ connection.end();
77
+ return reject(err);
78
+ }
79
+ resolve({ ...state, response: { body: results, fields: fields2 } });
80
+ });
81
+ });
82
+ };
83
+ }
57
84
  function execute(...operations) {
58
85
  const initialState = {
59
86
  references: [],
@@ -97,9 +124,9 @@ function insert(table, fields2) {
97
124
  var sqlParams = squelMysql.insert({
98
125
  autoQuoteFieldNames: true
99
126
  }).into(table).setFields(valuesObj).toParam();
100
- var sql = sqlParams.text;
101
- var inserts = sqlParams.values;
102
- sqlString = mysql.format(sql, inserts);
127
+ const sql2 = sqlParams.text;
128
+ const inserts = sqlParams.values;
129
+ const sqlString = mysql.format(sql2, inserts);
103
130
  console.log(`Executing MySQL query: ${sqlString}`);
104
131
  return new Promise((resolve, reject) => {
105
132
  connection.query(sqlString, function(err, results, fields3) {
@@ -128,15 +155,15 @@ function upsert(table, fields2) {
128
155
  var insertParams = squelMysql.insert({
129
156
  autoQuoteFieldNames: true
130
157
  }).into(table).setFields(valuesObj).toParam();
131
- var sql = insertParams.text;
158
+ var sql2 = insertParams.text;
132
159
  var inserts = insertParams.values;
133
- const insertString = mysql.format(sql, inserts);
160
+ const insertString = mysql.format(sql2, inserts);
134
161
  var updateParams = squelMysql.update({
135
162
  autoQuoteFieldNames: true
136
163
  }).table("").setFields(valuesObj).toParam();
137
- var sql = updateParams.text;
164
+ var sql2 = updateParams.text;
138
165
  var inserts = updateParams.values;
139
- const updateString = mysql.format(sql, inserts);
166
+ const updateString = mysql.format(sql2, inserts);
140
167
  const upsertString = insertString + ` ON DUPLICATE KEY UPDATE ` + updateString.slice(10);
141
168
  console.log("Executing MySQL query: " + upsertString);
142
169
  return new Promise((resolve, reject) => {
@@ -192,36 +219,6 @@ function upsertMany(table, data) {
192
219
  });
193
220
  };
194
221
  }
195
- function query(options) {
196
- return (state) => {
197
- let { connection } = state;
198
- const [opts] = expandReferences(state, options);
199
- console.log(
200
- "Executing MySQL statement with options: " + JSON.stringify(opts, 2, null)
201
- );
202
- return new Promise((resolve, reject) => {
203
- connection.query(opts, function(err, results, fields2) {
204
- if (err) {
205
- reject(err);
206
- console.log("That's an error. Disconnecting from database.");
207
- connection.end();
208
- } else {
209
- console.log("Success...");
210
- resolve(JSON.parse(JSON.stringify(results)));
211
- }
212
- });
213
- }).then((data) => {
214
- console.log(data);
215
- const nextState = { ...state, response: { body: data } };
216
- return nextState;
217
- });
218
- };
219
- }
220
- function sqlString(queryString) {
221
- return (state) => {
222
- return query({ sql: queryString })(state);
223
- };
224
- }
225
222
 
226
223
  // src/index.js
227
224
  var src_default = Adaptor_exports;
@@ -241,13 +238,11 @@ export {
241
238
  fields,
242
239
  fn,
243
240
  fnIf,
244
- http,
245
241
  insert,
246
242
  lastReferenceValue,
247
243
  merge,
248
- query,
249
244
  sourceValue,
250
- sqlString,
245
+ sql,
251
246
  upsert,
252
247
  upsertMany
253
248
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openfn/language-mysql",
3
3
  "label": "MySQL",
4
- "version": "2.2.2",
4
+ "version": "3.0.1",
5
5
  "description": "A MySQL Language Pack for OpenFn",
6
6
  "homepage": "https://docs.openfn.org",
7
7
  "main": "dist/index.cjs",
@@ -22,15 +22,13 @@
22
22
  "mysql": "^2.13.0",
23
23
  "squel": "^5.8.0",
24
24
  "string-escape": "^0.3.0",
25
- "@openfn/language-common": "3.0.2"
25
+ "@openfn/language-common": "3.0.3"
26
26
  },
27
27
  "devDependencies": {
28
28
  "assertion-error": "^1.0.1",
29
- "chai": "^3.4.0",
29
+ "chai": "^5.2.0",
30
30
  "deep-eql": "^0.1.3",
31
- "nock": "^12.0.3",
32
- "rimraf": "^3.0.2",
33
- "sinon": "^1.17.2"
31
+ "rimraf": "^3.0.2"
34
32
  },
35
33
  "type": "module",
36
34
  "exports": {
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Execute a SQL statement. Take care when inserting values from state directly into a query,
3
+ * as this can be a vector for injection attacks. See [OWASP SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html)
4
+ * for guidelines
5
+ * @example
6
+ * sql(state => `select * from ${state.data.tableName};`, { writeSql: true })
7
+ * @function
8
+ * @public
9
+ * @param {string|function} sqlQuery - The SQL query as a string or a function that returns a string using state.
10
+ * @param {object} [options] - Optional options argument.
11
+ * @param {boolean} [options.writeSql = false] - If true, logs the generated SQL statement. Defaults to false.
12
+ * @param {boolean} [options.execute = true] - If false, does not execute the SQL, just logs it and adds to state.queries. Defaults to true.
13
+ * @returns {Operation}
14
+ */
15
+ export function sql(sqlQuery: string | Function, options?: {
16
+ writeSql?: boolean;
17
+ execute?: boolean;
18
+ }): Operation;
1
19
  /**
2
20
  * Execute a sequence of operations.
3
21
  * Wraps `language-common/execute`, and prepends initial state for mysql.
@@ -46,24 +64,4 @@ export function upsert(table: string, fields: object): Operation;
46
64
  * @returns {Operation}
47
65
  */
48
66
  export function upsertMany(table: string, data: any[]): Operation;
49
- /**
50
- * Execute a SQL statement
51
- * @example <caption>Execute a SQL statement</caption>
52
- * query({ sql: 'select * from users;' })
53
- * @function
54
- * @public
55
- * @param {object} options - Payload data for the message
56
- * @returns {Operation}
57
- */
58
- export function query(options: object): Operation;
59
- /**
60
- * Execute a SQL statement
61
- * @example <caption>Execute a SQL statement</caption>
62
- * sqlString(state => "select * from items;")
63
- * @function
64
- * @public
65
- * @param {String} queryString - A query string (or function which takes state and returns a string)
66
- * @returns {Operation}
67
- */
68
- export function sqlString(queryString: string): Operation;
69
- export { fn, fnIf, each, http, merge, field, fields, cursor, dateFns, combine, dataPath, dataValue, alterState, sourceValue, arrayToString, lastReferenceValue, as } from "@openfn/language-common";
67
+ export { fn, fnIf, each, merge, field, fields, cursor, dateFns, combine, dataPath, dataValue, alterState, sourceValue, arrayToString, lastReferenceValue, as } from "@openfn/language-common";