data-api-client 1.3.1 → 2.0.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/index.js DELETED
@@ -1,625 +0,0 @@
1
- 'use strict'
2
-
3
- /*
4
- * This module provides a simplified interface into the Aurora Serverless
5
- * Data API by abstracting away the notion of field values.
6
- *
7
- * More detail regarding the Aurora Serverless Data APIcan be found here:
8
- * https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html
9
- *
10
- * @author Jeremy Daly <jeremy@jeremydaly.com>
11
- * @version 1.2.0
12
- * @license MIT
13
- */
14
-
15
- // Require the aws-sdk. This is a dev dependency, so if being used
16
- // outside of a Lambda execution environment, it must be manually installed.
17
- const AWS = require('aws-sdk')
18
-
19
- // Require sqlstring to add additional escaping capabilities
20
- const sqlString = require('sqlstring')
21
-
22
- // Supported value types in the Data API
23
- const supportedTypes = [
24
- 'arrayValue',
25
- 'blobValue',
26
- 'booleanValue',
27
- 'doubleValue',
28
- 'isNull',
29
- 'longValue',
30
- 'stringValue',
31
- 'structValue'
32
- ]
33
-
34
- /********************************************************************/
35
- /** PRIVATE METHODS **/
36
- /********************************************************************/
37
-
38
- // Simple error function
39
- const error = (...err) => {
40
- throw Error(...err)
41
- }
42
-
43
- // Parse SQL statement from provided arguments
44
- const parseSQL = (args) =>
45
- typeof args[0] === 'string'
46
- ? args[0]
47
- : typeof args[0] === 'object' && typeof args[0].sql === 'string'
48
- ? args[0].sql
49
- : error(`No 'sql' statement provided.`)
50
-
51
- // Parse the parameters from provided arguments
52
- const parseParams = (args) =>
53
- Array.isArray(args[0].parameters)
54
- ? args[0].parameters
55
- : typeof args[0].parameters === 'object'
56
- ? [args[0].parameters]
57
- : Array.isArray(args[1])
58
- ? args[1]
59
- : typeof args[1] === 'object'
60
- ? [args[1]]
61
- : args[0].parameters
62
- ? error(`'parameters' must be an object or array`)
63
- : args[1]
64
- ? error('Parameters must be an object or array')
65
- : []
66
-
67
- // Parse the supplied database, or default to config
68
- const parseDatabase = (config, args) =>
69
- config.transactionId
70
- ? config.database
71
- : typeof args[0].database === 'string'
72
- ? args[0].database
73
- : args[0].database
74
- ? error(`'database' must be a string.`)
75
- : config.database
76
- ? config.database
77
- : undefined // removed for #47 - error('No \'database\' provided.')
78
-
79
- // Parse the supplied hydrateColumnNames command, or default to config
80
- const parseHydrate = (config, args) =>
81
- typeof args[0].hydrateColumnNames === 'boolean'
82
- ? args[0].hydrateColumnNames
83
- : args[0].hydrateColumnNames
84
- ? error(`'hydrateColumnNames' must be a boolean.`)
85
- : config.hydrateColumnNames
86
-
87
- // Parse the supplied format options, or default to config
88
- const parseFormatOptions = (config, args) =>
89
- typeof args[0].formatOptions === 'object'
90
- ? {
91
- deserializeDate:
92
- typeof args[0].formatOptions.deserializeDate === 'boolean'
93
- ? args[0].formatOptions.deserializeDate
94
- : args[0].formatOptions.deserializeDate
95
- ? error(`'formatOptions.deserializeDate' must be a boolean.`)
96
- : config.formatOptions.deserializeDate,
97
- treatAsLocalDate:
98
- typeof args[0].formatOptions.treatAsLocalDate == 'boolean'
99
- ? args[0].formatOptions.treatAsLocalDate
100
- : args[0].formatOptions.treatAsLocalDate
101
- ? error(`'formatOptions.treatAsLocalDate' must be a boolean.`)
102
- : config.formatOptions.treatAsLocalDate
103
- }
104
- : args[0].formatOptions
105
- ? error(`'formatOptions' must be an object.`)
106
- : config.formatOptions
107
-
108
- // Prepare method params w/ supplied inputs if an object is passed
109
- const prepareParams = ({ secretArn, resourceArn }, args) => {
110
- return Object.assign(
111
- { secretArn, resourceArn }, // return Arns
112
- typeof args[0] === 'object' ? omit(args[0], ['hydrateColumnNames', 'parameters']) : {} // merge any inputs
113
- )
114
- }
115
-
116
- // Utility function for removing certain keys from an object
117
- const omit = (obj, values) =>
118
- Object.keys(obj).reduce((acc, x) => (values.includes(x) ? acc : Object.assign(acc, { [x]: obj[x] })), {})
119
-
120
- // Utility function for picking certain keys from an object
121
- const pick = (obj, values) =>
122
- Object.keys(obj).reduce((acc, x) => (values.includes(x) ? Object.assign(acc, { [x]: obj[x] }) : acc), {})
123
-
124
- // Utility function for flattening arrays
125
- const flatten = (arr) => arr.reduce((acc, x) => acc.concat(x), [])
126
-
127
- // Normize parameters so that they are all in standard format
128
- const normalizeParams = (params) =>
129
- params.reduce(
130
- (acc, p) =>
131
- Array.isArray(p)
132
- ? acc.concat([normalizeParams(p)])
133
- : (Object.keys(p).length === 2 && p.name && typeof p.value !== 'undefined') ||
134
- (Object.keys(p).length === 3 && p.name && typeof p.value !== 'undefined' && p.cast)
135
- ? acc.concat(p)
136
- : acc.concat(splitParams(p)),
137
- []
138
- ) // end reduce
139
-
140
- // Prepare parameters
141
- const processParams = (engine, sql, sqlParams, params, formatOptions, row = 0) => {
142
- return {
143
- processedParams: params.reduce((acc, p) => {
144
- if (Array.isArray(p)) {
145
- const result = processParams(engine, sql, sqlParams, p, formatOptions, row)
146
- if (row === 0) {
147
- sql = result.escapedSql
148
- row++
149
- }
150
- return acc.concat([result.processedParams])
151
- } else if (sqlParams[p.name]) {
152
- if (sqlParams[p.name].type === 'n_ph') {
153
- if (p.cast) {
154
- const regex = new RegExp(':' + p.name + '\\b', 'g')
155
- sql = sql.replace(regex, engine === 'pg' ? `:${p.name}::${p.cast}` : `CAST(:${p.name} AS ${p.cast})`)
156
- }
157
- acc.push(formatParam(p.name, p.value, formatOptions))
158
- } else if (row === 0) {
159
- const regex = new RegExp('::' + p.name + '\\b', 'g')
160
- sql = sql.replace(regex, sqlString.escapeId(p.value))
161
- }
162
- return acc
163
- } else {
164
- return acc
165
- }
166
- }, []),
167
- escapedSql: sql
168
- }
169
- }
170
-
171
- // Converts parameter to the name/value format
172
- const formatParam = (n, v, formatOptions) => formatType(n, v, getType(v), getTypeHint(v), formatOptions)
173
-
174
- // Converts object params into name/value format
175
- const splitParams = (p) => Object.keys(p).reduce((arr, x) => arr.concat({ name: x, value: p[x] }), [])
176
-
177
- // Get all the sql parameters and assign them types
178
- const getSqlParams = (sql) => {
179
- // TODO: probably need to remove comments from the sql
180
- // TODO: placeholders?
181
- // sql.match(/\:{1,2}\w+|\?+/g).map((p,i) => {
182
- return (sql.match(/:{1,2}\w+/g) || [])
183
- .map((p) => {
184
- // TODO: future support for placeholder parsing?
185
- // return p === '??' ? { type: 'id' } // identifier
186
- // : p === '?' ? { type: 'ph', label: '__d'+i } // placeholder
187
- return p.startsWith('::')
188
- ? { type: 'n_id', label: p.substr(2) } // named id
189
- : { type: 'n_ph', label: p.substr(1) } // named placeholder
190
- })
191
- .reduce((acc, x) => {
192
- return Object.assign(acc, {
193
- [x.label]: {
194
- type: x.type
195
- }
196
- })
197
- }, {}) // end reduce
198
- }
199
-
200
- // Gets the value type and returns the correct value field name
201
- // TODO: Support more types as the are released
202
- const getType = (val) =>
203
- typeof val === 'string'
204
- ? 'stringValue'
205
- : typeof val === 'boolean'
206
- ? 'booleanValue'
207
- : typeof val === 'number' && parseInt(val) === val
208
- ? 'longValue'
209
- : typeof val === 'number' && parseFloat(val) === val
210
- ? 'doubleValue'
211
- : val === null
212
- ? 'isNull'
213
- : isDate(val)
214
- ? 'stringValue'
215
- : Buffer.isBuffer(val)
216
- ? 'blobValue'
217
- : // : Array.isArray(val) ? 'arrayValue' This doesn't work yet
218
- // TODO: there is a 'structValue' now for postgres
219
- typeof val === 'object' && Object.keys(val).length === 1 && supportedTypes.includes(Object.keys(val)[0])
220
- ? null
221
- : undefined
222
-
223
- // Hint to specify the underlying object type for data type mapping
224
- const getTypeHint = (val) => (isDate(val) ? 'TIMESTAMP' : undefined)
225
-
226
- const isDate = (val) => val instanceof Date
227
-
228
- // Creates a standard Data API parameter using the supplied inputs
229
- const formatType = (name, value, type, typeHint, formatOptions) => {
230
- return Object.assign(
231
- typeHint != null ? { name, typeHint } : { name },
232
- type === null
233
- ? { value }
234
- : {
235
- value: {
236
- [type ? type : error(`'${name}' is an invalid type`)]:
237
- type === 'isNull'
238
- ? true
239
- : isDate(value)
240
- ? formatToTimeStamp(value, formatOptions && formatOptions.treatAsLocalDate)
241
- : value
242
- }
243
- }
244
- )
245
- } // end formatType
246
-
247
- // Formats the (UTC) date to the AWS accepted YYYY-MM-DD HH:MM:SS[.FFF] format
248
- // See https://docs.aws.amazon.com/rdsdataservice/latest/APIReference/API_SqlParameter.html
249
- const formatToTimeStamp = (date, treatAsLocalDate) => {
250
- const pad = (val, num = 2) => '0'.repeat(num - (val + '').length) + val
251
-
252
- const year = treatAsLocalDate ? date.getFullYear() : date.getUTCFullYear()
253
- const month = (treatAsLocalDate ? date.getMonth() : date.getUTCMonth()) + 1 // Convert to human month
254
- const day = treatAsLocalDate ? date.getDate() : date.getUTCDate()
255
-
256
- const hours = treatAsLocalDate ? date.getHours() : date.getUTCHours()
257
- const minutes = treatAsLocalDate ? date.getMinutes() : date.getUTCMinutes()
258
- const seconds = treatAsLocalDate ? date.getSeconds() : date.getUTCSeconds()
259
- const ms = treatAsLocalDate ? date.getMilliseconds() : date.getUTCMilliseconds()
260
-
261
- const fraction = ms <= 0 ? '' : `.${pad(ms, 3)}`
262
-
263
- return `${year}-${pad(month)}-${pad(day)} ${pad(hours)}:${pad(minutes)}:${pad(seconds)}${fraction}`
264
- }
265
-
266
- // Converts the string value to a Date object.
267
- // If standard TIMESTAMP format (YYYY-MM-DD[ HH:MM:SS[.FFF]]) without TZ + treatAsLocalDate=false then assume UTC Date
268
- // In all other cases convert value to datetime as-is (also values with TZ info)
269
- const formatFromTimeStamp = (value, treatAsLocalDate) =>
270
- !treatAsLocalDate && /^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2}(\.\d+)?)?$/.test(value)
271
- ? new Date(value + 'Z')
272
- : new Date(value)
273
-
274
- // Formats the results of a query response
275
- const formatResults = (
276
- {
277
- // destructure results
278
- columnMetadata, // ONLY when hydrate or includeResultMetadata is true
279
- numberOfRecordsUpdated, // ONLY for executeStatement method
280
- records, // ONLY for executeStatement method
281
- generatedFields, // ONLY for INSERTS
282
- updateResults // ONLY on batchExecuteStatement
283
- },
284
- hydrate,
285
- includeMeta,
286
- formatOptions
287
- ) =>
288
- Object.assign(
289
- includeMeta ? { columnMetadata } : {},
290
- numberOfRecordsUpdated !== undefined && !records ? { numberOfRecordsUpdated } : {},
291
- records
292
- ? {
293
- records: formatRecords(records, columnMetadata, hydrate, formatOptions)
294
- }
295
- : {},
296
- updateResults ? { updateResults: formatUpdateResults(updateResults) } : {},
297
- generatedFields && generatedFields.length > 0 ? { insertId: generatedFields[0].longValue } : {}
298
- )
299
-
300
- // Processes records and either extracts Typed Values into an array, or
301
- // object with named column labels
302
- const formatRecords = (recs, columns, hydrate, formatOptions) => {
303
- // Create map for efficient value parsing
304
- let fmap =
305
- recs && recs[0]
306
- ? recs[0].map((x, i) => {
307
- return Object.assign({}, columns ? { label: columns[i].label, typeName: columns[i].typeName } : {}) // add column label and typeName
308
- })
309
- : {}
310
-
311
- // Map over all the records (rows)
312
- return recs
313
- ? recs.map((rec) => {
314
- // Reduce each field in the record (row)
315
- return rec.reduce(
316
- (acc, field, i) => {
317
- // If the field is null, always return null
318
- if (field.isNull === true) {
319
- return hydrate // object if hydrate, else array
320
- ? Object.assign(acc, { [fmap[i].label]: null })
321
- : acc.concat(null)
322
-
323
- // If the field is mapped, return the mapped field
324
- } else if (fmap[i] && fmap[i].field) {
325
- const value = formatRecordValue(field[fmap[i].field], fmap[i].typeName, formatOptions)
326
- return hydrate // object if hydrate, else array
327
- ? Object.assign(acc, { [fmap[i].label]: value })
328
- : acc.concat(value)
329
-
330
- // Else discover the field type
331
- } else {
332
- // Look for non-null fields
333
- Object.keys(field).map((type) => {
334
- if (type !== 'isNull' && field[type] !== null) {
335
- fmap[i]['field'] = type
336
- }
337
- })
338
-
339
- // Return the mapped field (this should NEVER be null)
340
- const value = formatRecordValue(field[fmap[i].field], fmap[i].typeName, formatOptions)
341
- return hydrate // object if hydrate, else array
342
- ? Object.assign(acc, { [fmap[i].label]: value })
343
- : acc.concat(value)
344
- }
345
- },
346
- hydrate ? {} : []
347
- ) // init object if hydrate, else init array
348
- })
349
- : [] // empty record set returns an array
350
- } // end formatRecords
351
-
352
- // Format record value based on its value, the database column's typeName and the formatting options
353
- const formatRecordValue = (value, typeName, formatOptions) => {
354
- if (
355
- formatOptions &&
356
- formatOptions.deserializeDate &&
357
- ['DATE', 'DATETIME', 'TIMESTAMP', 'TIMESTAMPTZ', 'TIMESTAMP WITH TIME ZONE'].includes(typeName.toUpperCase())
358
- ) {
359
- return formatFromTimeStamp(
360
- value,
361
- (formatOptions && formatOptions.treatAsLocalDate) || typeName === 'TIMESTAMP WITH TIME ZONE'
362
- )
363
- } else if (typeName === 'JSON') {
364
- return JSON.parse(value)
365
- } else {
366
- return value
367
- }
368
- }
369
-
370
- // Format updateResults and extract insertIds
371
- const formatUpdateResults = (res) =>
372
- res.map((x) => {
373
- return x.generatedFields && x.generatedFields.length > 0 ? { insertId: x.generatedFields[0].longValue } : {}
374
- })
375
-
376
- // Merge configuration data with supplied arguments
377
- const mergeConfig = (initialConfig, args) => Object.assign(initialConfig, args)
378
-
379
- /********************************************************************/
380
- /** QUERY MANAGEMENT **/
381
- /********************************************************************/
382
-
383
- // Query function (use standard form for `this` context)
384
- const query = async function (config, ..._args) {
385
- // Flatten array if nested arrays (fixes #30)
386
- const args = Array.isArray(_args[0]) ? flatten(_args) : _args
387
-
388
- // Parse and process sql
389
- const sql = parseSQL(args)
390
- const sqlParams = getSqlParams(sql)
391
-
392
- // Parse hydration setting
393
- const hydrateColumnNames = parseHydrate(config, args)
394
-
395
- // Parse data format settings
396
- const formatOptions = parseFormatOptions(config, args)
397
-
398
- // Parse and normalize parameters
399
- const parameters = normalizeParams(parseParams(args))
400
-
401
- // Process parameters and escape necessary SQL
402
- const { processedParams, escapedSql } = processParams(config.engine, sql, sqlParams, parameters, formatOptions)
403
-
404
- // Determine if this is a batch request
405
- const isBatch = processedParams.length > 0 && Array.isArray(processedParams[0])
406
-
407
- // Create/format the parameters
408
- const params = Object.assign(
409
- prepareParams(config, args),
410
- {
411
- database: parseDatabase(config, args), // add database
412
- sql: escapedSql // add escaped sql statement
413
- },
414
- // Only include parameters if they exist
415
- processedParams.length > 0
416
- ? // Batch statements require parameterSets instead of parameters
417
- { [isBatch ? 'parameterSets' : 'parameters']: processedParams }
418
- : {},
419
- // Force meta data if set and not a batch
420
- hydrateColumnNames && !isBatch ? { includeResultMetadata: true } : {},
421
- // If a transactionId is passed, overwrite any manual input
422
- config.transactionId ? { transactionId: config.transactionId } : {}
423
- ) // end params
424
-
425
- try {
426
- // attempt to run the query
427
-
428
- // Capture the result for debugging
429
- let result = await (isBatch
430
- ? config.RDS.batchExecuteStatement(params).promise()
431
- : config.RDS.executeStatement(params).promise())
432
-
433
- // Format and return the results
434
- return formatResults(result, hydrateColumnNames, args[0].includeResultMetadata === true, formatOptions)
435
- } catch (e) {
436
- if (this && this.rollback) {
437
- let rollback = await config.RDS.rollbackTransaction(
438
- pick(params, ['resourceArn', 'secretArn', 'transactionId'])
439
- ).promise()
440
-
441
- this.rollback(e, rollback)
442
- }
443
- // Throw the error
444
- throw e
445
- }
446
- } // end query
447
-
448
- /********************************************************************/
449
- /** TRANSACTION MANAGEMENT **/
450
- /********************************************************************/
451
-
452
- // Init a transaction object and return methods
453
- const transaction = (config, _args) => {
454
- let args = typeof _args === 'object' ? [_args] : [{}]
455
- let queries = [] // keep track of queries
456
- let rollback = () => {} // default rollback event
457
-
458
- const txConfig = Object.assign(prepareParams(config, args), {
459
- database: parseDatabase(config, args), // add database
460
- hydrateColumnNames: parseHydrate(config, args), // add hydrate
461
- formatOptions: parseFormatOptions(config, args), // add formatOptions
462
- RDS: config.RDS // reference the RDSDataService instance
463
- })
464
-
465
- return {
466
- query: function (...args) {
467
- if (typeof args[0] === 'function') {
468
- queries.push(args[0])
469
- } else {
470
- queries.push(() => [...args])
471
- }
472
- return this
473
- },
474
- rollback: function (fn) {
475
- if (typeof fn === 'function') {
476
- rollback = fn
477
- }
478
- return this
479
- },
480
- commit: async function () {
481
- return await commit(txConfig, queries, rollback)
482
- }
483
- }
484
- }
485
-
486
- // Commit transaction by running queries
487
- const commit = async (config, queries, rollback) => {
488
- let results = [] // keep track of results
489
-
490
- // Start a transaction
491
- const { transactionId } = await config.RDS.beginTransaction(
492
- pick(config, ['resourceArn', 'secretArn', 'database'])
493
- ).promise()
494
-
495
- // Add transactionId to the config
496
- let txConfig = Object.assign(config, { transactionId })
497
-
498
- // Loop through queries
499
- for (let i = 0; i < queries.length; i++) {
500
- // Execute the queries, pass the rollback as context
501
- let result = await query.apply({ rollback }, [config, queries[i](results[results.length - 1], results)])
502
- // Add the result to the main results accumulator
503
- results.push(result)
504
- }
505
-
506
- // Commit our transaction
507
- const { transactionStatus } = await txConfig.RDS.commitTransaction(
508
- pick(config, ['resourceArn', 'secretArn', 'transactionId'])
509
- ).promise()
510
-
511
- // Add the transaction status to the results
512
- results.push({ transactionStatus })
513
-
514
- // Return the results
515
- return results
516
- }
517
-
518
- /********************************************************************/
519
- /** INSTANTIATION **/
520
- /********************************************************************/
521
-
522
- // Export main function
523
- /**
524
- * Create a Data API client instance
525
- * @param {object} params
526
- * @param {'mysql'|'pg'} [params.engine=mysql] The type of database (MySQL or Postgres)
527
- * @param {string} params.resourceArn The ARN of your Aurora Serverless Cluster
528
- * @param {string} params.secretArn The ARN of the secret associated with your
529
- * database credentials
530
- * @param {string} [params.database] The name of the database
531
- * @param {boolean} [params.hydrateColumnNames=true] Return objects with column
532
- * names as keys
533
- * @param {object} [params.options={}] Configuration object passed directly
534
- * into RDSDataService
535
- * @param {object} [params.formatOptions] Date-related formatting options
536
- * @param {boolean} [params.formatOptions.deserializeDate=false]
537
- * @param {boolean} [params.formatOptions.treatAsLocalDate=false]
538
- * @param {boolean} [params.keepAlive] DEPRECATED
539
- * @param {boolean} [params.sslEnabled=true] DEPRECATED
540
- * @param {string} [params.region] DEPRECATED
541
- *
542
- */
543
- const init = (params) => {
544
- // Set the options for the RDSDataService
545
- const options =
546
- typeof params.options === 'object'
547
- ? params.options
548
- : params.options !== undefined
549
- ? error(`'options' must be an object`)
550
- : {}
551
-
552
- // Update the AWS http agent with the region
553
- if (typeof params.region === 'string') {
554
- options.region = params.region
555
- }
556
-
557
- // Disable ssl if wanted for local development
558
- if (params.sslEnabled === false) {
559
- options.sslEnabled = false
560
- }
561
-
562
- // Set the configuration for this instance
563
- const config = {
564
- // Require engine
565
- engine: typeof params.engine === 'string' ? params.engine : 'mysql',
566
-
567
- // Require secretArn
568
- secretArn: typeof params.secretArn === 'string' ? params.secretArn : error(`'secretArn' string value required`),
569
-
570
- // Require resourceArn
571
- resourceArn:
572
- typeof params.resourceArn === 'string' ? params.resourceArn : error(`'resourceArn' string value required`),
573
-
574
- // Load optional database
575
- database:
576
- typeof params.database === 'string'
577
- ? params.database
578
- : params.database !== undefined
579
- ? error(`'database' must be a string`)
580
- : undefined,
581
-
582
- // Load optional schema DISABLED for now since this isn't used with MySQL
583
- // schema: typeof params.schema === 'string' ? params.schema
584
- // : params.schema !== undefined ? error(`'schema' must be a string`)
585
- // : undefined,
586
-
587
- // Set hydrateColumnNames (default to true)
588
- hydrateColumnNames: typeof params.hydrateColumnNames === 'boolean' ? params.hydrateColumnNames : true,
589
-
590
- // Value formatting options. For date the deserialization is enabled and (re)stored as UTC
591
- formatOptions: {
592
- deserializeDate:
593
- typeof params.formatOptions === 'object' && params.formatOptions.deserializeDate === false ? false : true,
594
- treatAsLocalDate: typeof params.formatOptions === 'object' && params.formatOptions.treatAsLocalDate
595
- },
596
-
597
- // TODO: Put this in a separate module for testing?
598
- // Create an instance of RDSDataService
599
- RDS: params.AWS ? new params.AWS.RDSDataService(options) : new AWS.RDSDataService(options)
600
- } // end config
601
-
602
- // Return public methods
603
- return {
604
- // Query method, pass config and parameters
605
- query: (...x) => query(config, ...x),
606
- // Transaction method, pass config and parameters
607
- transaction: (x) => transaction(config, x),
608
-
609
- // Export promisified versions of the RDSDataService methods
610
- batchExecuteStatement: (args) =>
611
- config.RDS.batchExecuteStatement(
612
- mergeConfig(pick(config, ['resourceArn', 'secretArn', 'database']), args)
613
- ).promise(),
614
- beginTransaction: (args) =>
615
- config.RDS.beginTransaction(mergeConfig(pick(config, ['resourceArn', 'secretArn', 'database']), args)).promise(),
616
- commitTransaction: (args) =>
617
- config.RDS.commitTransaction(mergeConfig(pick(config, ['resourceArn', 'secretArn']), args)).promise(),
618
- executeStatement: (args) =>
619
- config.RDS.executeStatement(mergeConfig(pick(config, ['resourceArn', 'secretArn', 'database']), args)).promise(),
620
- rollbackTransaction: (args) =>
621
- config.RDS.rollbackTransaction(mergeConfig(pick(config, ['resourceArn', 'secretArn']), args)).promise()
622
- }
623
- } // end exports
624
-
625
- module.exports = init