data-api-client 2.0.0-beta.0 → 2.1.0

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