@openfn/language-mysql 3.0.6 → 4.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 +85 -46
- package/dist/index.cjs +160 -142
- package/dist/index.js +163 -143
- package/package.json +6 -7
- package/types/Adaptor.d.ts +86 -27
package/ast.json
CHANGED
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"title": "example",
|
|
14
14
|
"description": "sql(state => `select * from ${state.data.tableName};`, { writeSql: true })"
|
|
15
15
|
},
|
|
16
|
+
{
|
|
17
|
+
"title": "example",
|
|
18
|
+
"description": "sql(state => `select * from ?? where id = ?;`, {\n values: state => [state.data.tableName, state.data.id],\n});",
|
|
19
|
+
"caption": "Prepared statements"
|
|
20
|
+
},
|
|
16
21
|
{
|
|
17
22
|
"title": "function",
|
|
18
23
|
"description": null,
|
|
@@ -25,59 +30,28 @@
|
|
|
25
30
|
},
|
|
26
31
|
{
|
|
27
32
|
"title": "param",
|
|
28
|
-
"description": "The
|
|
33
|
+
"description": "The sql query string.",
|
|
29
34
|
"type": {
|
|
30
|
-
"type": "
|
|
31
|
-
"
|
|
32
|
-
{
|
|
33
|
-
"type": "NameExpression",
|
|
34
|
-
"name": "string"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
"type": "NameExpression",
|
|
38
|
-
"name": "function"
|
|
39
|
-
}
|
|
40
|
-
]
|
|
35
|
+
"type": "NameExpression",
|
|
36
|
+
"name": "string"
|
|
41
37
|
},
|
|
42
38
|
"name": "sqlQuery"
|
|
43
39
|
},
|
|
44
40
|
{
|
|
45
41
|
"title": "param",
|
|
46
|
-
"description": "
|
|
42
|
+
"description": " The sql query options.",
|
|
47
43
|
"type": {
|
|
48
44
|
"type": "OptionalType",
|
|
49
45
|
"expression": {
|
|
50
46
|
"type": "NameExpression",
|
|
51
|
-
"name": "
|
|
47
|
+
"name": "sqlOptions"
|
|
52
48
|
}
|
|
53
49
|
},
|
|
54
50
|
"name": "options"
|
|
55
51
|
},
|
|
56
52
|
{
|
|
57
|
-
"title": "
|
|
58
|
-
"description": "
|
|
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"
|
|
53
|
+
"title": "state",
|
|
54
|
+
"description": "{MySQLState}"
|
|
81
55
|
},
|
|
82
56
|
{
|
|
83
57
|
"title": "returns",
|
|
@@ -89,7 +63,7 @@
|
|
|
89
63
|
}
|
|
90
64
|
]
|
|
91
65
|
},
|
|
92
|
-
"valid":
|
|
66
|
+
"valid": true
|
|
93
67
|
},
|
|
94
68
|
{
|
|
95
69
|
"name": "insert",
|
|
@@ -102,8 +76,8 @@
|
|
|
102
76
|
"tags": [
|
|
103
77
|
{
|
|
104
78
|
"title": "example",
|
|
105
|
-
"description": "insert(\"users\", { name:
|
|
106
|
-
"caption": "Insert a record into
|
|
79
|
+
"description": "insert(\"users\", { name: \"one\", email: \"one@openfn.org\" });",
|
|
80
|
+
"caption": "Insert a record into a table"
|
|
107
81
|
},
|
|
108
82
|
{
|
|
109
83
|
"title": "function",
|
|
@@ -133,6 +107,10 @@
|
|
|
133
107
|
},
|
|
134
108
|
"name": "fields"
|
|
135
109
|
},
|
|
110
|
+
{
|
|
111
|
+
"title": "state",
|
|
112
|
+
"description": "{MySQLState}"
|
|
113
|
+
},
|
|
136
114
|
{
|
|
137
115
|
"title": "returns",
|
|
138
116
|
"description": null,
|
|
@@ -156,8 +134,8 @@
|
|
|
156
134
|
"tags": [
|
|
157
135
|
{
|
|
158
136
|
"title": "example",
|
|
159
|
-
"description": "upsert(\"
|
|
160
|
-
"caption": "Upsert a record"
|
|
137
|
+
"description": "upsert(\"users\", { name: \"Tuchi Dev\" });",
|
|
138
|
+
"caption": "Upsert a record into a table"
|
|
161
139
|
},
|
|
162
140
|
{
|
|
163
141
|
"title": "function",
|
|
@@ -187,6 +165,10 @@
|
|
|
187
165
|
},
|
|
188
166
|
"name": "fields"
|
|
189
167
|
},
|
|
168
|
+
{
|
|
169
|
+
"title": "state",
|
|
170
|
+
"description": "{MySQLState}"
|
|
171
|
+
},
|
|
190
172
|
{
|
|
191
173
|
"title": "returns",
|
|
192
174
|
"description": null,
|
|
@@ -215,8 +197,8 @@
|
|
|
215
197
|
},
|
|
216
198
|
{
|
|
217
199
|
"title": "example",
|
|
218
|
-
"description": "upsertMany(\n
|
|
219
|
-
"caption": "Upsert multiple records"
|
|
200
|
+
"description": "upsertMany(\n \"users\", // the DB table\n [\n { name: \"one\", email: \"one@openfn.org\" },\n { name: \"two\", email: \"two@openfn.org\" },\n ]\n);",
|
|
201
|
+
"caption": "Upsert multiple records into a table"
|
|
220
202
|
},
|
|
221
203
|
{
|
|
222
204
|
"title": "function",
|
|
@@ -239,13 +221,17 @@
|
|
|
239
221
|
},
|
|
240
222
|
{
|
|
241
223
|
"title": "param",
|
|
242
|
-
"description": "An array of objects
|
|
224
|
+
"description": "An array of objects fields",
|
|
243
225
|
"type": {
|
|
244
226
|
"type": "NameExpression",
|
|
245
227
|
"name": "array"
|
|
246
228
|
},
|
|
247
229
|
"name": "data"
|
|
248
230
|
},
|
|
231
|
+
{
|
|
232
|
+
"title": "state",
|
|
233
|
+
"description": "{MySQLState}"
|
|
234
|
+
},
|
|
249
235
|
{
|
|
250
236
|
"title": "returns",
|
|
251
237
|
"description": null,
|
|
@@ -929,6 +915,59 @@
|
|
|
929
915
|
},
|
|
930
916
|
"valid": false
|
|
931
917
|
},
|
|
918
|
+
{
|
|
919
|
+
"name": "assert",
|
|
920
|
+
"params": [
|
|
921
|
+
"expression",
|
|
922
|
+
"errorMessage"
|
|
923
|
+
],
|
|
924
|
+
"docs": {
|
|
925
|
+
"description": "Asserts the given expression or function resolves to `true`, or else throws an exception. Optionally accepts and error message.",
|
|
926
|
+
"tags": [
|
|
927
|
+
{
|
|
928
|
+
"title": "public",
|
|
929
|
+
"description": null,
|
|
930
|
+
"type": null
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
"title": "function",
|
|
934
|
+
"description": null,
|
|
935
|
+
"name": null
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
"title": "example",
|
|
939
|
+
"description": "assert('a' === 'b', '\"a\" is not equal to \"b\"')"
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
"title": "param",
|
|
943
|
+
"description": "The expression or function to be evaluated.",
|
|
944
|
+
"type": {
|
|
945
|
+
"type": "NameExpression",
|
|
946
|
+
"name": "any"
|
|
947
|
+
},
|
|
948
|
+
"name": "expression"
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
"title": "param",
|
|
952
|
+
"description": "The error message thrown in case of a failed state.",
|
|
953
|
+
"type": {
|
|
954
|
+
"type": "NameExpression",
|
|
955
|
+
"name": "string"
|
|
956
|
+
},
|
|
957
|
+
"name": "errorMessage"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
"title": "returns",
|
|
961
|
+
"description": null,
|
|
962
|
+
"type": {
|
|
963
|
+
"type": "NameExpression",
|
|
964
|
+
"name": "operation"
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
]
|
|
968
|
+
},
|
|
969
|
+
"valid": true
|
|
970
|
+
},
|
|
932
971
|
{
|
|
933
972
|
"name": "as",
|
|
934
973
|
"params": [
|
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ __export(src_exports, {
|
|
|
28
28
|
alterState: () => import_language_common2.alterState,
|
|
29
29
|
arrayToString: () => import_language_common2.arrayToString,
|
|
30
30
|
as: () => import_language_common2.as,
|
|
31
|
+
assert: () => import_language_common2.assert,
|
|
31
32
|
combine: () => import_language_common2.combine,
|
|
32
33
|
cursor: () => import_language_common2.cursor,
|
|
33
34
|
dataPath: () => import_language_common2.dataPath,
|
|
@@ -43,6 +44,7 @@ __export(src_exports, {
|
|
|
43
44
|
insert: () => insert,
|
|
44
45
|
lastReferenceValue: () => import_language_common2.lastReferenceValue,
|
|
45
46
|
merge: () => import_language_common2.merge,
|
|
47
|
+
setMockConnection: () => setMockConnection,
|
|
46
48
|
sourceValue: () => import_language_common2.sourceValue,
|
|
47
49
|
sql: () => sql,
|
|
48
50
|
upsert: () => upsert,
|
|
@@ -56,6 +58,7 @@ __export(Adaptor_exports, {
|
|
|
56
58
|
alterState: () => import_language_common2.alterState,
|
|
57
59
|
arrayToString: () => import_language_common2.arrayToString,
|
|
58
60
|
as: () => import_language_common2.as,
|
|
61
|
+
assert: () => import_language_common2.assert,
|
|
59
62
|
combine: () => import_language_common2.combine,
|
|
60
63
|
cursor: () => import_language_common2.cursor,
|
|
61
64
|
dataPath: () => import_language_common2.dataPath,
|
|
@@ -70,6 +73,7 @@ __export(Adaptor_exports, {
|
|
|
70
73
|
insert: () => insert,
|
|
71
74
|
lastReferenceValue: () => import_language_common2.lastReferenceValue,
|
|
72
75
|
merge: () => import_language_common2.merge,
|
|
76
|
+
setMockConnection: () => setMockConnection,
|
|
73
77
|
sourceValue: () => import_language_common2.sourceValue,
|
|
74
78
|
sql: () => sql,
|
|
75
79
|
upsert: () => upsert,
|
|
@@ -77,175 +81,187 @@ __export(Adaptor_exports, {
|
|
|
77
81
|
});
|
|
78
82
|
var import_language_common = require("@openfn/language-common");
|
|
79
83
|
var import_util = require("@openfn/language-common/util");
|
|
80
|
-
var
|
|
81
|
-
var
|
|
84
|
+
var import_promise = __toESM(require("mysql2/promise"), 1);
|
|
85
|
+
var import_knex = __toESM(require("knex"), 1);
|
|
82
86
|
var import_language_common2 = require("@openfn/language-common");
|
|
83
|
-
|
|
87
|
+
var connection;
|
|
88
|
+
var knexInstance = (0, import_knex.default)({ client: "mysql2" });
|
|
89
|
+
async function connect(state) {
|
|
90
|
+
if (connection) {
|
|
91
|
+
return state;
|
|
92
|
+
}
|
|
93
|
+
const { host, port, database, password, user } = state.configuration || {};
|
|
94
|
+
try {
|
|
95
|
+
connection = await import_promise.default.createConnection({
|
|
96
|
+
host,
|
|
97
|
+
user,
|
|
98
|
+
password,
|
|
99
|
+
database,
|
|
100
|
+
port
|
|
101
|
+
});
|
|
102
|
+
console.log("Connected to database...");
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.log(error);
|
|
105
|
+
throw new Error("Unable to connect to database.");
|
|
106
|
+
}
|
|
107
|
+
return state;
|
|
108
|
+
}
|
|
109
|
+
async function disconnect(state) {
|
|
110
|
+
if (connection) {
|
|
111
|
+
await connection.end();
|
|
112
|
+
console.log("Disconected from database...");
|
|
113
|
+
connection = null;
|
|
114
|
+
}
|
|
115
|
+
knexInstance.destroy();
|
|
116
|
+
return state;
|
|
117
|
+
}
|
|
118
|
+
function formatFields(fields2) {
|
|
119
|
+
if (!fields2)
|
|
120
|
+
return void 0;
|
|
121
|
+
return fields2.map((field2) => ({
|
|
122
|
+
name: field2.name,
|
|
123
|
+
type: field2.type,
|
|
124
|
+
characterSet: field2.characterSet,
|
|
125
|
+
table: field2.orgTable,
|
|
126
|
+
schema: field2.schema,
|
|
127
|
+
length: field2.columnLength,
|
|
128
|
+
decimals: field2.decimals,
|
|
129
|
+
flags: field2.flags,
|
|
130
|
+
encoding: field2.encoding
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
function setMockConnection(mockConnection) {
|
|
134
|
+
connection = mockConnection;
|
|
135
|
+
}
|
|
136
|
+
function execute(...operations) {
|
|
137
|
+
const initialState = {
|
|
138
|
+
queries: []
|
|
139
|
+
};
|
|
84
140
|
return (state) => {
|
|
85
|
-
|
|
141
|
+
return (0, import_language_common.execute)(
|
|
142
|
+
connect,
|
|
143
|
+
...operations,
|
|
144
|
+
disconnect
|
|
145
|
+
)({ ...initialState, ...state });
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function sql(sqlQuery, options = {}) {
|
|
149
|
+
return async (state) => {
|
|
86
150
|
const [resolvedSqlQuery, resolvedOptions] = (0, import_util.expandReferences)(
|
|
87
151
|
state,
|
|
88
152
|
sqlQuery,
|
|
89
153
|
options
|
|
90
154
|
);
|
|
91
|
-
const { writeSql = false, execute: execute2 = true } = resolvedOptions;
|
|
155
|
+
const { writeSql = false, execute: execute2 = true, values } = resolvedOptions;
|
|
92
156
|
if (writeSql) {
|
|
93
157
|
console.log("Prepared SQL:", resolvedSqlQuery);
|
|
158
|
+
if (values) {
|
|
159
|
+
state.queries.push({ sql: resolvedSqlQuery, values });
|
|
160
|
+
} else {
|
|
161
|
+
state.queries.push(resolvedSqlQuery);
|
|
162
|
+
}
|
|
94
163
|
}
|
|
95
164
|
if (!execute2) {
|
|
165
|
+
console.log("Execution skipped, execute is false.");
|
|
96
166
|
return {
|
|
97
167
|
...state,
|
|
98
|
-
queries: [...state.queries
|
|
168
|
+
queries: [...state.queries, resolvedSqlQuery]
|
|
99
169
|
};
|
|
100
170
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
171
|
+
try {
|
|
172
|
+
const [result, fields2] = await connection.execute(
|
|
173
|
+
resolvedSqlQuery,
|
|
174
|
+
values
|
|
175
|
+
);
|
|
176
|
+
console.log("Query executed successfully.");
|
|
177
|
+
return (0, import_language_common.composeNextState)(state, {
|
|
178
|
+
result,
|
|
179
|
+
fields: formatFields(fields2)
|
|
109
180
|
});
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const initialState = {
|
|
115
|
-
references: [],
|
|
116
|
-
data: null
|
|
117
|
-
};
|
|
118
|
-
return (state) => {
|
|
119
|
-
return (0, import_language_common.execute)(
|
|
120
|
-
connect,
|
|
121
|
-
...operations,
|
|
122
|
-
disconnect,
|
|
123
|
-
cleanupState
|
|
124
|
-
)({ ...initialState, ...state });
|
|
181
|
+
} catch (err) {
|
|
182
|
+
console.log("Error executing query.");
|
|
183
|
+
throw err;
|
|
184
|
+
}
|
|
125
185
|
};
|
|
126
186
|
}
|
|
127
|
-
function connect(state) {
|
|
128
|
-
const { host, port, database, password, user } = state.configuration;
|
|
129
|
-
var connection = import_mysql.default.createConnection({
|
|
130
|
-
host,
|
|
131
|
-
user,
|
|
132
|
-
password,
|
|
133
|
-
database,
|
|
134
|
-
port
|
|
135
|
-
});
|
|
136
|
-
connection.connect();
|
|
137
|
-
console.log(`Preparing to query "` + database + `"...`);
|
|
138
|
-
return { ...state, connection };
|
|
139
|
-
}
|
|
140
|
-
function disconnect(state) {
|
|
141
|
-
state.connection.end();
|
|
142
|
-
return state;
|
|
143
|
-
}
|
|
144
|
-
function cleanupState(state) {
|
|
145
|
-
delete state.connection;
|
|
146
|
-
return state;
|
|
147
|
-
}
|
|
148
187
|
function insert(table, fields2) {
|
|
149
|
-
return (state) => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
const sqlString =
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
188
|
+
return async (state) => {
|
|
189
|
+
const [resolvedTable, resolvedFields] = (0, import_util.expandReferences)(
|
|
190
|
+
state,
|
|
191
|
+
table,
|
|
192
|
+
fields2
|
|
193
|
+
);
|
|
194
|
+
const keys = Object.keys(resolvedFields);
|
|
195
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
196
|
+
const columns = keys.map(() => "??").join(", ");
|
|
197
|
+
const sqlString = import_promise.default.format(
|
|
198
|
+
`INSERT INTO ?? (${columns}) VALUES (${placeholders})`,
|
|
199
|
+
[resolvedTable, ...keys]
|
|
200
|
+
);
|
|
201
|
+
try {
|
|
202
|
+
const [result, fields3] = await connection.execute(
|
|
203
|
+
sqlString,
|
|
204
|
+
Object.values(resolvedFields)
|
|
205
|
+
);
|
|
206
|
+
console.log("Success...");
|
|
207
|
+
return (0, import_language_common.composeNextState)(state, {
|
|
208
|
+
result,
|
|
209
|
+
fields: formatFields(fields3)
|
|
172
210
|
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
211
|
+
} catch (err) {
|
|
212
|
+
console.log("Error inserting record.");
|
|
213
|
+
throw err;
|
|
214
|
+
}
|
|
177
215
|
};
|
|
178
216
|
}
|
|
179
217
|
function upsert(table, fields2) {
|
|
180
|
-
return (state) => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
var sql2 = updateParams.text;
|
|
194
|
-
var inserts = updateParams.values;
|
|
195
|
-
const updateString = import_mysql.default.format(sql2, inserts);
|
|
196
|
-
const upsertString = insertString + ` ON DUPLICATE KEY UPDATE ` + updateString.slice(10);
|
|
218
|
+
return async (state) => {
|
|
219
|
+
const [resolvedTable, resolvedFields] = (0, import_util.expandReferences)(
|
|
220
|
+
state,
|
|
221
|
+
table,
|
|
222
|
+
fields2
|
|
223
|
+
);
|
|
224
|
+
const insertQuery = knexInstance(resolvedTable).insert(resolvedFields);
|
|
225
|
+
const insertString = insertQuery.toString();
|
|
226
|
+
const updateParts = Object.keys(resolvedFields).map(
|
|
227
|
+
(key) => `${knexInstance.ref(key)} = VALUES(${knexInstance.ref(key)})`
|
|
228
|
+
);
|
|
229
|
+
const updateClause = updateParts.join(", ");
|
|
230
|
+
const upsertString = `${insertString} ON DUPLICATE KEY UPDATE ${updateClause}`;
|
|
197
231
|
console.log("Executing MySQL query: " + upsertString);
|
|
198
|
-
|
|
199
|
-
connection.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
console.log(results);
|
|
207
|
-
console.log(fields3);
|
|
208
|
-
resolve(results);
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
}).then((data) => {
|
|
212
|
-
const nextState = { ...state, response: { body: data } };
|
|
213
|
-
return nextState;
|
|
214
|
-
});
|
|
232
|
+
try {
|
|
233
|
+
const [result, fields3] = await connection.execute(upsertString);
|
|
234
|
+
console.log("Success...");
|
|
235
|
+
return (0, import_language_common.composeNextState)(state, { result, fields: formatFields(fields3) });
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.log("That's an error.");
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
215
240
|
};
|
|
216
241
|
}
|
|
217
242
|
function upsertMany(table, data) {
|
|
218
|
-
return
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
connection.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
console.log(results);
|
|
241
|
-
console.log(fields2);
|
|
242
|
-
resolve(results);
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
}).then(function(data2) {
|
|
246
|
-
const nextState = { ...state, response: { body: data2 } };
|
|
247
|
-
return nextState;
|
|
248
|
-
});
|
|
243
|
+
return async (state) => {
|
|
244
|
+
const [resolvedTable, resolvedData] = (0, import_util.expandReferences)(state, table, data);
|
|
245
|
+
if (!resolvedData || resolvedData.length === 0) {
|
|
246
|
+
console.log("No records provided; skipping upsert.");
|
|
247
|
+
return state;
|
|
248
|
+
}
|
|
249
|
+
const columns = Object.keys(resolvedData[0]);
|
|
250
|
+
const insertQuery = knexInstance(resolvedTable).insert(resolvedData);
|
|
251
|
+
const insertString = insertQuery.toString();
|
|
252
|
+
const updateParts = columns.map(
|
|
253
|
+
(c) => `${knexInstance.ref(c)} = VALUES(${knexInstance.ref(c)})`
|
|
254
|
+
);
|
|
255
|
+
const updateClause = updateParts.join(", ");
|
|
256
|
+
const upsertString = `${insertString} ON DUPLICATE KEY UPDATE ${updateClause}`;
|
|
257
|
+
try {
|
|
258
|
+
const [result, fields2] = await connection.execute(upsertString);
|
|
259
|
+
console.log("Success...");
|
|
260
|
+
return (0, import_language_common.composeNextState)(state, { result, fields: formatFields(fields2) });
|
|
261
|
+
} catch (err) {
|
|
262
|
+
console.log("That's an error.");
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
249
265
|
};
|
|
250
266
|
}
|
|
251
267
|
|
|
@@ -256,6 +272,7 @@ var src_default = Adaptor_exports;
|
|
|
256
272
|
alterState,
|
|
257
273
|
arrayToString,
|
|
258
274
|
as,
|
|
275
|
+
assert,
|
|
259
276
|
combine,
|
|
260
277
|
cursor,
|
|
261
278
|
dataPath,
|
|
@@ -270,6 +287,7 @@ var src_default = Adaptor_exports;
|
|
|
270
287
|
insert,
|
|
271
288
|
lastReferenceValue,
|
|
272
289
|
merge,
|
|
290
|
+
setMockConnection,
|
|
273
291
|
sourceValue,
|
|
274
292
|
sql,
|
|
275
293
|
upsert,
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ __export(Adaptor_exports, {
|
|
|
10
10
|
alterState: () => alterState,
|
|
11
11
|
arrayToString: () => arrayToString,
|
|
12
12
|
as: () => as,
|
|
13
|
+
assert: () => assert,
|
|
13
14
|
combine: () => combine,
|
|
14
15
|
cursor: () => cursor,
|
|
15
16
|
dataPath: () => dataPath,
|
|
@@ -24,15 +25,19 @@ __export(Adaptor_exports, {
|
|
|
24
25
|
insert: () => insert,
|
|
25
26
|
lastReferenceValue: () => lastReferenceValue,
|
|
26
27
|
merge: () => merge,
|
|
28
|
+
setMockConnection: () => setMockConnection,
|
|
27
29
|
sourceValue: () => sourceValue,
|
|
28
30
|
sql: () => sql,
|
|
29
31
|
upsert: () => upsert,
|
|
30
32
|
upsertMany: () => upsertMany
|
|
31
33
|
});
|
|
32
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
execute as commonExecute,
|
|
36
|
+
composeNextState
|
|
37
|
+
} from "@openfn/language-common";
|
|
33
38
|
import { expandReferences } from "@openfn/language-common/util";
|
|
34
|
-
import mysql from "
|
|
35
|
-
import
|
|
39
|
+
import mysql from "mysql2/promise";
|
|
40
|
+
import knex from "knex";
|
|
36
41
|
import {
|
|
37
42
|
fn,
|
|
38
43
|
fnIf,
|
|
@@ -40,6 +45,7 @@ import {
|
|
|
40
45
|
merge,
|
|
41
46
|
field,
|
|
42
47
|
fields,
|
|
48
|
+
assert,
|
|
43
49
|
cursor,
|
|
44
50
|
dateFns,
|
|
45
51
|
combine,
|
|
@@ -51,172 +57,184 @@ import {
|
|
|
51
57
|
lastReferenceValue,
|
|
52
58
|
as
|
|
53
59
|
} from "@openfn/language-common";
|
|
54
|
-
|
|
60
|
+
var connection;
|
|
61
|
+
var knexInstance = knex({ client: "mysql2" });
|
|
62
|
+
async function connect(state) {
|
|
63
|
+
if (connection) {
|
|
64
|
+
return state;
|
|
65
|
+
}
|
|
66
|
+
const { host, port, database, password, user } = state.configuration || {};
|
|
67
|
+
try {
|
|
68
|
+
connection = await mysql.createConnection({
|
|
69
|
+
host,
|
|
70
|
+
user,
|
|
71
|
+
password,
|
|
72
|
+
database,
|
|
73
|
+
port
|
|
74
|
+
});
|
|
75
|
+
console.log("Connected to database...");
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.log(error);
|
|
78
|
+
throw new Error("Unable to connect to database.");
|
|
79
|
+
}
|
|
80
|
+
return state;
|
|
81
|
+
}
|
|
82
|
+
async function disconnect(state) {
|
|
83
|
+
if (connection) {
|
|
84
|
+
await connection.end();
|
|
85
|
+
console.log("Disconected from database...");
|
|
86
|
+
connection = null;
|
|
87
|
+
}
|
|
88
|
+
knexInstance.destroy();
|
|
89
|
+
return state;
|
|
90
|
+
}
|
|
91
|
+
function formatFields(fields2) {
|
|
92
|
+
if (!fields2)
|
|
93
|
+
return void 0;
|
|
94
|
+
return fields2.map((field2) => ({
|
|
95
|
+
name: field2.name,
|
|
96
|
+
type: field2.type,
|
|
97
|
+
characterSet: field2.characterSet,
|
|
98
|
+
table: field2.orgTable,
|
|
99
|
+
schema: field2.schema,
|
|
100
|
+
length: field2.columnLength,
|
|
101
|
+
decimals: field2.decimals,
|
|
102
|
+
flags: field2.flags,
|
|
103
|
+
encoding: field2.encoding
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
function setMockConnection(mockConnection) {
|
|
107
|
+
connection = mockConnection;
|
|
108
|
+
}
|
|
109
|
+
function execute(...operations) {
|
|
110
|
+
const initialState = {
|
|
111
|
+
queries: []
|
|
112
|
+
};
|
|
55
113
|
return (state) => {
|
|
56
|
-
|
|
114
|
+
return commonExecute(
|
|
115
|
+
connect,
|
|
116
|
+
...operations,
|
|
117
|
+
disconnect
|
|
118
|
+
)({ ...initialState, ...state });
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function sql(sqlQuery, options = {}) {
|
|
122
|
+
return async (state) => {
|
|
57
123
|
const [resolvedSqlQuery, resolvedOptions] = expandReferences(
|
|
58
124
|
state,
|
|
59
125
|
sqlQuery,
|
|
60
126
|
options
|
|
61
127
|
);
|
|
62
|
-
const { writeSql = false, execute: execute2 = true } = resolvedOptions;
|
|
128
|
+
const { writeSql = false, execute: execute2 = true, values } = resolvedOptions;
|
|
63
129
|
if (writeSql) {
|
|
64
130
|
console.log("Prepared SQL:", resolvedSqlQuery);
|
|
131
|
+
if (values) {
|
|
132
|
+
state.queries.push({ sql: resolvedSqlQuery, values });
|
|
133
|
+
} else {
|
|
134
|
+
state.queries.push(resolvedSqlQuery);
|
|
135
|
+
}
|
|
65
136
|
}
|
|
66
137
|
if (!execute2) {
|
|
138
|
+
console.log("Execution skipped, execute is false.");
|
|
67
139
|
return {
|
|
68
140
|
...state,
|
|
69
|
-
queries: [...state.queries
|
|
141
|
+
queries: [...state.queries, resolvedSqlQuery]
|
|
70
142
|
};
|
|
71
143
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
144
|
+
try {
|
|
145
|
+
const [result, fields2] = await connection.execute(
|
|
146
|
+
resolvedSqlQuery,
|
|
147
|
+
values
|
|
148
|
+
);
|
|
149
|
+
console.log("Query executed successfully.");
|
|
150
|
+
return composeNextState(state, {
|
|
151
|
+
result,
|
|
152
|
+
fields: formatFields(fields2)
|
|
80
153
|
});
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const initialState = {
|
|
86
|
-
references: [],
|
|
87
|
-
data: null
|
|
88
|
-
};
|
|
89
|
-
return (state) => {
|
|
90
|
-
return commonExecute(
|
|
91
|
-
connect,
|
|
92
|
-
...operations,
|
|
93
|
-
disconnect,
|
|
94
|
-
cleanupState
|
|
95
|
-
)({ ...initialState, ...state });
|
|
154
|
+
} catch (err) {
|
|
155
|
+
console.log("Error executing query.");
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
96
158
|
};
|
|
97
159
|
}
|
|
98
|
-
function connect(state) {
|
|
99
|
-
const { host, port, database, password, user } = state.configuration;
|
|
100
|
-
var connection = mysql.createConnection({
|
|
101
|
-
host,
|
|
102
|
-
user,
|
|
103
|
-
password,
|
|
104
|
-
database,
|
|
105
|
-
port
|
|
106
|
-
});
|
|
107
|
-
connection.connect();
|
|
108
|
-
console.log(`Preparing to query "` + database + `"...`);
|
|
109
|
-
return { ...state, connection };
|
|
110
|
-
}
|
|
111
|
-
function disconnect(state) {
|
|
112
|
-
state.connection.end();
|
|
113
|
-
return state;
|
|
114
|
-
}
|
|
115
|
-
function cleanupState(state) {
|
|
116
|
-
delete state.connection;
|
|
117
|
-
return state;
|
|
118
|
-
}
|
|
119
160
|
function insert(table, fields2) {
|
|
120
|
-
return (state) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
const sqlString = mysql.format(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
161
|
+
return async (state) => {
|
|
162
|
+
const [resolvedTable, resolvedFields] = expandReferences(
|
|
163
|
+
state,
|
|
164
|
+
table,
|
|
165
|
+
fields2
|
|
166
|
+
);
|
|
167
|
+
const keys = Object.keys(resolvedFields);
|
|
168
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
169
|
+
const columns = keys.map(() => "??").join(", ");
|
|
170
|
+
const sqlString = mysql.format(
|
|
171
|
+
`INSERT INTO ?? (${columns}) VALUES (${placeholders})`,
|
|
172
|
+
[resolvedTable, ...keys]
|
|
173
|
+
);
|
|
174
|
+
try {
|
|
175
|
+
const [result, fields3] = await connection.execute(
|
|
176
|
+
sqlString,
|
|
177
|
+
Object.values(resolvedFields)
|
|
178
|
+
);
|
|
179
|
+
console.log("Success...");
|
|
180
|
+
return composeNextState(state, {
|
|
181
|
+
result,
|
|
182
|
+
fields: formatFields(fields3)
|
|
143
183
|
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
184
|
+
} catch (err) {
|
|
185
|
+
console.log("Error inserting record.");
|
|
186
|
+
throw err;
|
|
187
|
+
}
|
|
148
188
|
};
|
|
149
189
|
}
|
|
150
190
|
function upsert(table, fields2) {
|
|
151
|
-
return (state) => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
var sql2 = updateParams.text;
|
|
165
|
-
var inserts = updateParams.values;
|
|
166
|
-
const updateString = mysql.format(sql2, inserts);
|
|
167
|
-
const upsertString = insertString + ` ON DUPLICATE KEY UPDATE ` + updateString.slice(10);
|
|
191
|
+
return async (state) => {
|
|
192
|
+
const [resolvedTable, resolvedFields] = expandReferences(
|
|
193
|
+
state,
|
|
194
|
+
table,
|
|
195
|
+
fields2
|
|
196
|
+
);
|
|
197
|
+
const insertQuery = knexInstance(resolvedTable).insert(resolvedFields);
|
|
198
|
+
const insertString = insertQuery.toString();
|
|
199
|
+
const updateParts = Object.keys(resolvedFields).map(
|
|
200
|
+
(key) => `${knexInstance.ref(key)} = VALUES(${knexInstance.ref(key)})`
|
|
201
|
+
);
|
|
202
|
+
const updateClause = updateParts.join(", ");
|
|
203
|
+
const upsertString = `${insertString} ON DUPLICATE KEY UPDATE ${updateClause}`;
|
|
168
204
|
console.log("Executing MySQL query: " + upsertString);
|
|
169
|
-
|
|
170
|
-
connection.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
console.log(results);
|
|
178
|
-
console.log(fields3);
|
|
179
|
-
resolve(results);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
}).then((data) => {
|
|
183
|
-
const nextState = { ...state, response: { body: data } };
|
|
184
|
-
return nextState;
|
|
185
|
-
});
|
|
205
|
+
try {
|
|
206
|
+
const [result, fields3] = await connection.execute(upsertString);
|
|
207
|
+
console.log("Success...");
|
|
208
|
+
return composeNextState(state, { result, fields: formatFields(fields3) });
|
|
209
|
+
} catch (err) {
|
|
210
|
+
console.log("That's an error.");
|
|
211
|
+
throw err;
|
|
212
|
+
}
|
|
186
213
|
};
|
|
187
214
|
}
|
|
188
215
|
function upsertMany(table, data) {
|
|
189
|
-
return
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
connection.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
console.log(results);
|
|
212
|
-
console.log(fields2);
|
|
213
|
-
resolve(results);
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
}).then(function(data2) {
|
|
217
|
-
const nextState = { ...state, response: { body: data2 } };
|
|
218
|
-
return nextState;
|
|
219
|
-
});
|
|
216
|
+
return async (state) => {
|
|
217
|
+
const [resolvedTable, resolvedData] = expandReferences(state, table, data);
|
|
218
|
+
if (!resolvedData || resolvedData.length === 0) {
|
|
219
|
+
console.log("No records provided; skipping upsert.");
|
|
220
|
+
return state;
|
|
221
|
+
}
|
|
222
|
+
const columns = Object.keys(resolvedData[0]);
|
|
223
|
+
const insertQuery = knexInstance(resolvedTable).insert(resolvedData);
|
|
224
|
+
const insertString = insertQuery.toString();
|
|
225
|
+
const updateParts = columns.map(
|
|
226
|
+
(c) => `${knexInstance.ref(c)} = VALUES(${knexInstance.ref(c)})`
|
|
227
|
+
);
|
|
228
|
+
const updateClause = updateParts.join(", ");
|
|
229
|
+
const upsertString = `${insertString} ON DUPLICATE KEY UPDATE ${updateClause}`;
|
|
230
|
+
try {
|
|
231
|
+
const [result, fields2] = await connection.execute(upsertString);
|
|
232
|
+
console.log("Success...");
|
|
233
|
+
return composeNextState(state, { result, fields: formatFields(fields2) });
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.log("That's an error.");
|
|
236
|
+
throw err;
|
|
237
|
+
}
|
|
220
238
|
};
|
|
221
239
|
}
|
|
222
240
|
|
|
@@ -226,6 +244,7 @@ export {
|
|
|
226
244
|
alterState,
|
|
227
245
|
arrayToString,
|
|
228
246
|
as,
|
|
247
|
+
assert,
|
|
229
248
|
combine,
|
|
230
249
|
cursor,
|
|
231
250
|
dataPath,
|
|
@@ -241,6 +260,7 @@ export {
|
|
|
241
260
|
insert,
|
|
242
261
|
lastReferenceValue,
|
|
243
262
|
merge,
|
|
263
|
+
setMockConnection,
|
|
244
264
|
sourceValue,
|
|
245
265
|
sql,
|
|
246
266
|
upsert,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/language-mysql",
|
|
3
3
|
"label": "MySQL",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.1",
|
|
5
5
|
"description": "A MySQL Language Pack for OpenFn",
|
|
6
6
|
"homepage": "https://docs.openfn.org",
|
|
7
7
|
"main": "dist/index.cjs",
|
|
@@ -18,10 +18,8 @@
|
|
|
18
18
|
"configuration-schema.json"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"squel": "^5.8.0",
|
|
24
|
-
"string-escape": "^0.3.0",
|
|
21
|
+
"knex": "^3.1.0",
|
|
22
|
+
"mysql2": "^3.15.3",
|
|
25
23
|
"@openfn/language-common": "3.2.1"
|
|
26
24
|
},
|
|
27
25
|
"devDependencies": {
|
|
@@ -42,8 +40,9 @@
|
|
|
42
40
|
"types": "types/index.d.ts",
|
|
43
41
|
"scripts": {
|
|
44
42
|
"build": "pnpm clean && build-adaptor mysql",
|
|
45
|
-
"test": "mocha --experimental-specifier-resolution=node --no-warnings",
|
|
46
|
-
"test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings",
|
|
43
|
+
"test": "mocha --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
|
|
44
|
+
"test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
|
|
45
|
+
"test:integration": "mocha --experimental-specifier-resolution=node --no-warnings test/integration.js",
|
|
47
46
|
"clean": "rimraf dist types docs",
|
|
48
47
|
"pack": "pnpm pack --pack-destination ../../dist",
|
|
49
48
|
"lint": "eslint src"
|
package/types/Adaptor.d.ts
CHANGED
|
@@ -1,67 +1,126 @@
|
|
|
1
|
+
export function setMockConnection(mockConnection: any): void;
|
|
2
|
+
/**
|
|
3
|
+
* State object
|
|
4
|
+
* @typedef {Object} MySQLState
|
|
5
|
+
* @property data - the query results object
|
|
6
|
+
* @property data.result - the query result rows
|
|
7
|
+
* @property data.fields - the query result fields
|
|
8
|
+
* @property queries - an array of queries executed. Queries are added if `options.writeSql` is true.
|
|
9
|
+
* @property references - an array of all previous data objects used in the Job
|
|
10
|
+
* @private
|
|
11
|
+
**/
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} sqlOptions
|
|
14
|
+
* @property {array} [values] - An array of values for prepared statements.
|
|
15
|
+
* @property {boolean} [writeSql = false] - If true, logs the generated SQL statement. Defaults to false.
|
|
16
|
+
* @property {boolean} [execute = true] - If false, does not execute the SQL, just logs it and adds to state.queries. Defaults to true.
|
|
17
|
+
* */
|
|
18
|
+
/**
|
|
19
|
+
* Execute a sequence of operations.
|
|
20
|
+
* Wraps `language-common/execute`, and prepends initial state for mysql.
|
|
21
|
+
* @private
|
|
22
|
+
* @param {Operations} operations - Operations to be performed.
|
|
23
|
+
* @returns {Operation}
|
|
24
|
+
*/
|
|
25
|
+
export function execute(...operations: Operations): Operation;
|
|
1
26
|
/**
|
|
2
27
|
* Execute a SQL statement. Take care when inserting values from state directly into a query,
|
|
3
28
|
* 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
29
|
* for guidelines
|
|
5
30
|
* @example
|
|
6
31
|
* sql(state => `select * from ${state.data.tableName};`, { writeSql: true })
|
|
32
|
+
* @example <caption>Prepared statements</caption>
|
|
33
|
+
* sql(state => `select * from ?? where id = ?;`, {
|
|
34
|
+
* values: state => [state.data.tableName, state.data.id],
|
|
35
|
+
* });
|
|
7
36
|
* @function
|
|
8
37
|
* @public
|
|
9
|
-
* @param {string
|
|
10
|
-
* @param {
|
|
11
|
-
* @
|
|
12
|
-
* @param {boolean} [options.execute = true] - If false, does not execute the SQL, just logs it and adds to state.queries. Defaults to true.
|
|
38
|
+
* @param {string} sqlQuery - The sql query string.
|
|
39
|
+
* @param {sqlOptions} [options] - The sql query options.
|
|
40
|
+
* @state {MySQLState}
|
|
13
41
|
* @returns {Operation}
|
|
14
42
|
*/
|
|
15
|
-
export function sql(sqlQuery: string
|
|
16
|
-
writeSql?: boolean;
|
|
17
|
-
execute?: boolean;
|
|
18
|
-
}): Operation;
|
|
19
|
-
/**
|
|
20
|
-
* Execute a sequence of operations.
|
|
21
|
-
* Wraps `language-common/execute`, and prepends initial state for mysql.
|
|
22
|
-
* @private
|
|
23
|
-
* @param {Operations} operations - Operations to be performed.
|
|
24
|
-
* @returns {Operation}
|
|
25
|
-
*/
|
|
26
|
-
export function execute(...operations: Operations): Operation;
|
|
43
|
+
export function sql(sqlQuery: string, options?: sqlOptions): Operation;
|
|
27
44
|
/**
|
|
28
45
|
* Insert a record
|
|
29
|
-
* @example <caption>Insert a record into
|
|
30
|
-
* insert("users", { name:
|
|
46
|
+
* @example <caption>Insert a record into a table</caption>
|
|
47
|
+
* insert("users", { name: "one", email: "one@openfn.org" });
|
|
31
48
|
* @function
|
|
32
49
|
* @public
|
|
33
50
|
* @param {string} table - The target table
|
|
34
51
|
* @param {object} fields - A fields object
|
|
52
|
+
* @state {MySQLState}
|
|
35
53
|
* @returns {Operation}
|
|
36
54
|
*/
|
|
37
55
|
export function insert(table: string, fields: object): Operation;
|
|
38
56
|
/**
|
|
39
57
|
* Insert or Update a record if matched
|
|
40
|
-
* @example <caption>Upsert a record</caption>
|
|
41
|
-
* upsert("
|
|
58
|
+
* @example <caption>Upsert a record into a table</caption>
|
|
59
|
+
* upsert("users", { name: "Tuchi Dev" });
|
|
42
60
|
* @function
|
|
43
61
|
* @public
|
|
44
62
|
* @param {string} table - The target table
|
|
45
63
|
* @param {object} fields - A fields object
|
|
64
|
+
* @state {MySQLState}
|
|
46
65
|
* @returns {Operation}
|
|
47
66
|
*/
|
|
48
67
|
export function upsert(table: string, fields: object): Operation;
|
|
49
68
|
/**
|
|
50
69
|
* Insert or update multiple records using ON DUPLICATE KEY
|
|
51
70
|
* @public
|
|
52
|
-
* @example
|
|
71
|
+
* @example<caption>Upsert multiple records into a table</caption>
|
|
53
72
|
* upsertMany(
|
|
54
|
-
*
|
|
73
|
+
* "users", // the DB table
|
|
55
74
|
* [
|
|
56
|
-
* { name:
|
|
57
|
-
* { name:
|
|
75
|
+
* { name: "one", email: "one@openfn.org" },
|
|
76
|
+
* { name: "two", email: "two@openfn.org" },
|
|
58
77
|
* ]
|
|
59
|
-
* )
|
|
78
|
+
* );
|
|
60
79
|
* @function
|
|
61
80
|
* @public
|
|
62
81
|
* @param {string} table - The target table
|
|
63
|
-
* @param {array} data - An array of objects
|
|
82
|
+
* @param {array} data - An array of objects fields
|
|
83
|
+
* @state {MySQLState}
|
|
64
84
|
* @returns {Operation}
|
|
65
85
|
*/
|
|
66
86
|
export function upsertMany(table: string, data: any[]): Operation;
|
|
67
|
-
|
|
87
|
+
/**
|
|
88
|
+
* State object
|
|
89
|
+
*/
|
|
90
|
+
export type MySQLState = {
|
|
91
|
+
/**
|
|
92
|
+
* - the query results object
|
|
93
|
+
*/
|
|
94
|
+
data: any;
|
|
95
|
+
/**
|
|
96
|
+
* - the query result rows
|
|
97
|
+
*/
|
|
98
|
+
result: any;
|
|
99
|
+
/**
|
|
100
|
+
* - the query result fields
|
|
101
|
+
*/
|
|
102
|
+
fields: any;
|
|
103
|
+
/**
|
|
104
|
+
* - an array of queries executed. Queries are added if `options.writeSql` is true.
|
|
105
|
+
*/
|
|
106
|
+
queries: any;
|
|
107
|
+
/**
|
|
108
|
+
* - an array of all previous data objects used in the Job
|
|
109
|
+
*/
|
|
110
|
+
references: any;
|
|
111
|
+
};
|
|
112
|
+
export type sqlOptions = {
|
|
113
|
+
/**
|
|
114
|
+
* - An array of values for prepared statements.
|
|
115
|
+
*/
|
|
116
|
+
values?: any[];
|
|
117
|
+
/**
|
|
118
|
+
* - If true, logs the generated SQL statement. Defaults to false.
|
|
119
|
+
*/
|
|
120
|
+
writeSql?: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* - If false, does not execute the SQL, just logs it and adds to state.queries. Defaults to true.
|
|
123
|
+
*/
|
|
124
|
+
execute?: boolean;
|
|
125
|
+
};
|
|
126
|
+
export { fn, fnIf, each, merge, field, fields, assert, cursor, dateFns, combine, dataPath, dataValue, alterState, sourceValue, arrayToString, lastReferenceValue, as } from "@openfn/language-common";
|