Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

data-api-client

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

data-api-client - npm Package Compare versions

Comparing version 1.0.0-beta to 1.0.0

654

index.js

@@ -22,2 +22,14 @@ 'use strict'

// Supported value types in the Data API
const supportedTypes = [
'arrayValue',
'blobValue',
'booleanValue',
'doubleValue',
'isNull',
'longValue',
'stringValue',
'structValue'
]
/**********************************************************************/

@@ -28,10 +40,10 @@ /** Enable HTTP Keep-Alive per https://vimeo.com/287511222 **/

const https = require('https')
const https = require('https')
const sslAgent = new https.Agent({
keepAlive: true,
maxSockets: 50, // same as aws-sdk
rejectUnauthorized: true // same as aws-sdk
})
sslAgent.setMaxListeners(0) // same as aws-sdk
const sslAgent = new https.Agent({
keepAlive: true,
maxSockets: 50, // same as aws-sdk
rejectUnauthorized: true // same as aws-sdk
})
sslAgent.setMaxListeners(0) // same as aws-sdk

@@ -43,232 +55,238 @@

// Simple error function
const error = (...err) => { throw Error(...err) }
// Simple error function
const error = (...err) => { throw Error(...err) }
// Parse SQL statement from provided arguments
const parseSQL = args =>
typeof args[0] === 'string' ? args[0]
: typeof args[0] === 'object' && typeof args[0].sql === 'string' ? args[0].sql
: error(`No 'sql' statement provided.`)
// Parse SQL statement from provided arguments
const parseSQL = args =>
typeof args[0] === 'string' ? args[0]
: typeof args[0] === 'object' && typeof args[0].sql === 'string' ? args[0].sql
: error('No \'sql\' statement provided.')
// Parse the parameters from provided arguments
const parseParams = args =>
Array.isArray(args[0].parameters) ? args[0].parameters
: typeof args[0].parameters === 'object' ? [args[0].parameters]
: Array.isArray(args[1]) ? args[1]
: typeof args[1] === 'object' ? [args[1]]
: args[0].parameters ? error(`'parameters' must be an object or array`)
: args[1] ? error(`Parameters must be an object or array`)
: []
// Parse the parameters from provided arguments
const parseParams = args =>
Array.isArray(args[0].parameters) ? args[0].parameters
: typeof args[0].parameters === 'object' ? [args[0].parameters]
: Array.isArray(args[1]) ? args[1]
: typeof args[1] === 'object' ? [args[1]]
: args[0].parameters ? error('\'parameters\' must be an object or array')
: args[1] ? error('Parameters must be an object or array')
: []
// Parse the supplied database, or default to config
const parseDatabase = (config,args) =>
config.transactionId ? config.database
: typeof args[0].database === 'string' ? args[0].database
: args[0].database ? error(`'database' must be a string.`)
: config.database ? config.database
: error(`No 'database' provided.`)
// Parse the supplied database, or default to config
const parseDatabase = (config,args) =>
config.transactionId ? config.database
: typeof args[0].database === 'string' ? args[0].database
: args[0].database ? error('\'database\' must be a string.')
: config.database ? config.database
: error('No \'database\' provided.')
// Parse the supplied hydrateColumnNames command, or default to config
const parseHydrate = (config,args) =>
typeof args[0].hydrateColumnNames === 'boolean' ? args[0].hydrateColumnNames
: args[0].hydrateColumnNames ? error(`'hydrateColumnNames' must be a boolean.`)
: config.hydrateColumnNames
// Parse the supplied hydrateColumnNames command, or default to config
const parseHydrate = (config,args) =>
typeof args[0].hydrateColumnNames === 'boolean' ? args[0].hydrateColumnNames
: args[0].hydrateColumnNames ? error('\'hydrateColumnNames\' must be a boolean.')
: config.hydrateColumnNames
// Prepare method params w/ supplied inputs if an object is passed
const prepareParams = ({ secretArn,resourceArn },args) => {
return Object.assign(
{ secretArn,resourceArn }, // return Arns
typeof args[0] === 'object' ?
omit(args[0],['hydrateColumnNames','parameters']) : {} // merge any inputs
)
}
// Prepare method params w/ supplied inputs if an object is passed
const prepareParams = ({ secretArn,resourceArn },args) => {
return Object.assign(
{ secretArn,resourceArn }, // return Arns
typeof args[0] === 'object' ?
omit(args[0],['hydrateColumnNames','parameters']) : {} // merge any inputs
)
}
// Utility function for removing certain keys from an object
const omit = (obj,values) => Object.keys(obj).reduce((acc,x) =>
values.includes(x) ? acc : Object.assign(acc,{ [x]: obj[x] })
// Utility function for removing certain keys from an object
const omit = (obj,values) => Object.keys(obj).reduce((acc,x) =>
values.includes(x) ? acc : Object.assign(acc,{ [x]: obj[x] })
,{})
// Utility function for picking certain keys from an object
const pick = (obj,values) => Object.keys(obj).reduce((acc,x) =>
values.includes(x) ? Object.assign(acc,{ [x]: obj[x] }) : acc
// Utility function for picking certain keys from an object
const pick = (obj,values) => Object.keys(obj).reduce((acc,x) =>
values.includes(x) ? Object.assign(acc,{ [x]: obj[x] }) : acc
,{})
// Utility function for flattening arrays
const flatten = arr => arr.reduce((acc,x) => acc.concat(x),[])
// Utility function for flattening arrays - deprecated
// const flatten = arr => arr.reduce((acc,x) => acc.concat(x),[])
// Normize parameters so that they are all in standard format
const normalizeParams = params => params.reduce((acc,p) =>
Array.isArray(p) ? acc.concat([normalizeParams(p)])
: Object.keys(p).length === 2 && p.name && p.value ? acc.concat(p)
: acc.concat(splitParams(p))
// Normize parameters so that they are all in standard format
const normalizeParams = params => params.reduce((acc,p) =>
Array.isArray(p) ? acc.concat([normalizeParams(p)])
: Object.keys(p).length === 2 && p.name && p.value ? acc.concat(p)
: acc.concat(splitParams(p))
,[]) // end reduce
// Annotate parameters with correct types
const annotateParams = params => params.reduce((acc,p) =>
Array.isArray(p) ? acc.concat([annotateParams(p)])
: Object.keys(p).length === 2 && p.name && p.value ? acc.concat(p)
: acc.concat(
formatParam(Object.keys(p)[0],Object.values(p)[0])
)
,[]) // end reduce
// // Annotate parameters with correct types
// const annotateParams = params => params.reduce((acc,p) =>
// Array.isArray(p) ? acc.concat([annotateParams(p)])
// : Object.keys(p).length === 2 && p.name && p.value ? acc.concat(p)
// : acc.concat(
// formatParam(Object.keys(p)[0],Object.values(p)[0])
// )
// ,[]) // end reduce
// Prepare parameters
const processParams = (sql,sqlParams,params,row=0) => {
return {
processedParams: params.reduce((acc,p,i) => {
if (Array.isArray(p)) {
let result = processParams(sql,sqlParams,p,row)
if (row === 0) { sql = result.escapedSql; row++ }
return acc.concat([result.processedParams])
} else if (sqlParams[p.name]) {
if (sqlParams[p.name].type === 'n_ph') {
acc[sqlParams[p.name].index] = formatParam(p.name,p.value)
} else if (row === 0) {
let regex = new RegExp('::' + p.name + '\\b','g')
sql = sql.replace(regex,sqlString.escapeId(p.value))
}
return acc
} else {
return acc
// Prepare parameters
const processParams = (sql,sqlParams,params,row=0) => {
return {
processedParams: params.reduce((acc,p) => {
if (Array.isArray(p)) {
let result = processParams(sql,sqlParams,p,row)
if (row === 0) { sql = result.escapedSql; row++ }
return acc.concat([result.processedParams])
} else if (sqlParams[p.name]) {
if (sqlParams[p.name].type === 'n_ph') {
acc.push(formatParam(p.name,p.value))
} else if (row === 0) {
let regex = new RegExp('::' + p.name + '\\b','g')
sql = sql.replace(regex,sqlString.escapeId(p.value))
}
},[]),
escapedSql: sql
}
return acc
} else {
return acc
}
},[]),
escapedSql: sql
}
}
// Converts parameter to the name/value format
const formatParam = (n,v) => formatType(n,v,getType(v))
// Converts parameter to the name/value format
const formatParam = (n,v) => formatType(n,v,getType(v))
const splitParams = p => Object.keys(p).reduce((arr,x) =>
arr.concat({ name: x, value: p[x] }),[])
// Converts object params into name/value format
const splitParams = p => Object.keys(p).reduce((arr,x) =>
arr.concat({ name: x, value: p[x] }),[])
// This appears to be a bug, so hopefully it will go away soon, but named
// parameters will *not* work if they are out of order! :facepalm:
const getSqlParams = sql => {
let p = 0 // position index for named parameters
// TODO: probably need to remove comments from the sql
// TODO: placeholders?
// sql.match(/\:{1,2}\w+|\?+/g).map((p,i) => {
return (sql.match(/\:{1,2}\w+/g) || []).map((p,i) => {
return p === '??' ? { type: 'id' } // identifier
: p === '?' ? { type: 'ph', label: '__d'+i } // placeholder
: p.startsWith('::') ? { type: 'n_id', label: p.substr(2) } // named id
: { type: 'n_ph', label: p.substr(1) } // named placeholder
}).reduce((acc,x,i) => {
return Object.assign(acc,
{
[x.label]: {
type: x.type, index: x.type === 'n_ph' ? p++ : undefined
}
// Get all the sql parameters and assign them types
const getSqlParams = sql => {
// TODO: probably need to remove comments from the sql
// TODO: placeholders?
// sql.match(/\:{1,2}\w+|\?+/g).map((p,i) => {
return (sql.match(/:{1,2}\w+/g) || []).map((p) => {
// TODO: future support for placeholder parsing?
// return p === '??' ? { type: 'id' } // identifier
// : p === '?' ? { type: 'ph', label: '__d'+i } // placeholder
return p.startsWith('::') ? { type: 'n_id', label: p.substr(2) } // named id
: { type: 'n_ph', label: p.substr(1) } // named placeholder
}).reduce((acc,x) => {
return Object.assign(acc,
{
[x.label]: {
type: x.type
}
)
},{}) // end reduce
}
}
)
},{}) // end reduce
}
// Gets the value type and returns the correct value field name
// TODO: Support more types as the are released
const getType = val =>
typeof val === 'string' ? 'stringValue'
: typeof val === 'boolean' ? 'booleanValue'
: typeof val === 'number' && parseInt(val) === val ? 'longValue'
: typeof val === 'number' && parseFloat(val) === val ? 'doubleValue'
: val === null ? 'isNull'
: Buffer.isBuffer(val) ? 'blobValue'
// : Array.isArray(val) ? 'arrayValue' This doesn't work yet
: undefined
// Gets the value type and returns the correct value field name
// TODO: Support more types as the are released
const getType = val =>
typeof val === 'string' ? 'stringValue'
: typeof val === 'boolean' ? 'booleanValue'
: typeof val === 'number' && parseInt(val) === val ? 'longValue'
: typeof val === 'number' && parseFloat(val) === val ? 'doubleValue'
: val === null ? 'isNull'
: Buffer.isBuffer(val) ? 'blobValue'
// : Array.isArray(val) ? 'arrayValue' This doesn't work yet
// TODO: there is a 'structValue' now for postgres
: typeof val === 'object'
&& Object.keys(val).length === 1
&& supportedTypes.includes(Object.keys(val)[0]) ? null
: undefined
// Creates a standard Data API parameter using the supplied inputs
const formatType = (name,value,type) => {
return {
name,
// Creates a standard Data API parameter using the supplied inputs
const formatType = (name,value,type) => {
return Object.assign(
{ name },
type === null ? { value }
: {
value: {
[type ? type : error(`'${name}'' is an invalid type`)] :
type === 'isNull' ? true : value
[type ? type : error(`'${name}' is an invalid type`)]
: type === 'isNull' ? true : value
}
}
} // end formatType
)
} // end formatType
// Formats the results of a query response
// TODO: Support generatedFields (use case insertId)
const formatResults = (
{ // destructure results
columnMetadata, // ONLY when hydrate or includeResultMetadata is true
numberOfRecordsUpdated, // ONLY for executeStatement method
records, // ONLY for executeStatement method
generatedFields, // ONLY for INSERTS
updateResults // ONLY on batchExecuteStatement
},
hydrate,
includeMeta
) =>
Object.assign(
includeMeta ? { columnMetadata } : {},
numberOfRecordsUpdated !== undefined ? { numberOfRecordsUpdated } : {},
records ? {
records: formatRecords(records, hydrate ? columnMetadata : false)
} : {},
updateResults ? { updateResults: formatUpdateResults(updateResults) } : {},
generatedFields && generatedFields.length > 0 ?
{ insertId: generatedFields[0].longValue } : {}
)
// Formats the results of a query response
const formatResults = (
{ // destructure results
columnMetadata, // ONLY when hydrate or includeResultMetadata is true
numberOfRecordsUpdated, // ONLY for executeStatement method
records, // ONLY for executeStatement method
generatedFields, // ONLY for INSERTS
updateResults // ONLY on batchExecuteStatement
},
hydrate,
includeMeta
) =>
Object.assign(
includeMeta ? { columnMetadata } : {},
numberOfRecordsUpdated !== undefined && !records ? { numberOfRecordsUpdated } : {},
records ? {
records: formatRecords(records, hydrate ? columnMetadata : false)
} : {},
updateResults ? { updateResults: formatUpdateResults(updateResults) } : {},
generatedFields && generatedFields.length > 0 ?
{ insertId: generatedFields[0].longValue } : {}
)
// Processes records and either extracts Typed Values into an array, or
// object with named column labels
const formatRecords = (recs,columns) => {
// Processes records and either extracts Typed Values into an array, or
// object with named column labels
const formatRecords = (recs,columns) => {
// Create map for efficient value parsing
let fmap = recs && recs[0] ? recs[0].map((x,i) => {
return Object.assign({},
columns ? { label: columns[i].label } : {} ) // add column labels
}) : {}
// Create map for efficient value parsing
let fmap = recs && recs[0] ? recs[0].map((x,i) => {
return Object.assign({},
columns ? { label: columns[i].label } : {} ) // add column labels
}) : {}
// Map over all the records (rows)
return recs ? recs.map(rec => {
// Map over all the records (rows)
return recs ? recs.map(rec => {
// Reduce each field in the record (row)
return rec.reduce((acc,field,i) => {
// Reduce each field in the record (row)
return rec.reduce((acc,field,i) => {
// If the field is null, always return null
if (field.isNull === true) {
return columns ? // object if hydrate, else array
Object.assign(acc,{ [fmap[i].label]: null })
: acc.concat(null)
// If the field is null, always return null
if (field.isNull === true) {
return columns ? // object if hydrate, else array
Object.assign(acc,{ [fmap[i].label]: null })
: acc.concat(null)
// If the field is mapped, return the mapped field
} else if (fmap[i] && fmap[i].field) {
return columns ? // object if hydrate, else array
Object.assign(acc,{ [fmap[i].label]: field[fmap[i].field] })
: acc.concat(field[fmap[i].field])
// If the field is mapped, return the mapped field
} else if (fmap[i] && fmap[i].field) {
return columns ? // object if hydrate, else array
Object.assign(acc,{ [fmap[i].label]: field[fmap[i].field] })
: acc.concat(field[fmap[i].field])
// Else discover the field type
} else {
// Else discover the field type
} else {
// Look for non-null fields
Object.keys(field).map(type => {
if (type !== 'isNull' && field[type] !== null) {
fmap[i]['field'] = type
}
})
// Look for non-null fields
Object.keys(field).map(type => {
if (type !== 'isNull' && field[type] !== null) {
fmap[i]['field'] = type
}
})
// Return the mapped field (this should NEVER be null)
return columns ? // object if hydrate, else array
Object.assign(acc,{ [fmap[i].label]: field[fmap[i].field] })
: acc.concat(field[fmap[i].field])
}
// Return the mapped field (this should NEVER be null)
return columns ? // object if hydrate, else array
Object.assign(acc,{ [fmap[i].label]: field[fmap[i].field] })
: acc.concat(field[fmap[i].field])
}
}, columns ? {} : []) // init object if hydrate, else init array
}) : [] // empty record set returns an array
} // end formatRecords
}, columns ? {} : []) // init object if hydrate, else init array
}) : [] // empty record set returns an array
} // end formatRecords
// Format updateResults and extract insertIds
const formatUpdateResults = res => res.map(x => {
return x.generatedFields && x.generatedFields.length > 0 ?
{ insertId: x.generatedFields[0].longValue } : {}
})
// Format updateResults and extract insertIds
const formatUpdateResults = res => res.map(x => {
return x.generatedFields && x.generatedFields.length > 0 ?
{ insertId: x.generatedFields[0].longValue } : {}
})
// Merge configuration data with supplied arguments
const mergeConfig = ({secretArn,resourceArn,database},args) =>
Object.assign({secretArn,resourceArn,database},args)
// Merge configuration data with supplied arguments
const mergeConfig = (initialConfig,args) =>
Object.assign(initialConfig,args)

@@ -281,70 +299,71 @@

// Query function (use standard form for `this` context)
const query = async function(config,..._args) {
// Query function (use standard form for `this` context)
const query = async function(config,...args) {
// Flatten passed in args to single depth array
const args = flatten(_args)
// Deprecated this since it was collapsing batches
// const args = flatten(_args)
// Parse and process sql
const sql = parseSQL(args)
const sqlParams = getSqlParams(sql)
// Parse and process sql
const sql = parseSQL(args)
const sqlParams = getSqlParams(sql)
// Parse hydration setting
const hydrateColumnNames = parseHydrate(config,args)
// Parse hydration setting
const hydrateColumnNames = parseHydrate(config,args)
// Parse and normalize parameters
const parameters = normalizeParams(parseParams(args))
// Parse and normalize parameters
const parameters = normalizeParams(parseParams(args))
// Process parameters and escape necessary SQL
const { processedParams,escapedSql } = processParams(sql,sqlParams,parameters)
// Process parameters and escape necessary SQL
const { processedParams,escapedSql } = processParams(sql,sqlParams,parameters)
// Determine if this is a batch request
const isBatch = processedParams.length > 0
&& Array.isArray(processedParams[0]) ? true : false
// Determine if this is a batch request
const isBatch = processedParams.length > 0
&& Array.isArray(processedParams[0]) ? true : false
const params = Object.assign(
prepareParams(config,args),
{
database: parseDatabase(config,args), // add database
sql: escapedSql // add escaped sql statement
},
// Only include parameters if they exist
processedParams.length > 0 ?
// Batch statements require parameterSets instead of parameters
{ [isBatch ? 'parameterSets' : 'parameters']: processedParams } : {},
// Force meta data if set and not a batch
hydrateColumnNames && !isBatch ? { includeResultMetadata: true } : {},
// If a transactionId is passed, overwrite any manual input
config.transactionId ? { transactionId: config.transactionId } : {}
) // end params
// Create/format the parameters
const params = Object.assign(
prepareParams(config,args),
{
database: parseDatabase(config,args), // add database
sql: escapedSql // add escaped sql statement
},
// Only include parameters if they exist
processedParams.length > 0 ?
// Batch statements require parameterSets instead of parameters
{ [isBatch ? 'parameterSets' : 'parameters']: processedParams } : {},
// Force meta data if set and not a batch
hydrateColumnNames && !isBatch ? { includeResultMetadata: true } : {},
// If a transactionId is passed, overwrite any manual input
config.transactionId ? { transactionId: config.transactionId } : {}
) // end params
try { // attempt to run the query
try { // attempt to run the query
// Capture the result for debugging
let result = await (isBatch ? config.RDS.batchExecuteStatement(params).promise()
: config.RDS.executeStatement(params).promise())
// Capture the result for debugging
let result = await (isBatch ? config.RDS.batchExecuteStatement(params).promise()
: config.RDS.executeStatement(params).promise())
// console.log(result)
// FOR DEBUGGING: console.log(JSON.stringify(result,null,2))
// Format and return the results
return formatResults(
result,
hydrateColumnNames,
args[0].includeResultMetadata === true ? true : false
)
// Format and return the results
return formatResults(
result,
hydrateColumnNames,
args[0].includeResultMetadata === true ? true : false
)
} catch(e) {
} catch(e) {
if (this && this.rollback) {
let rollback = await config.RDS.rollbackTransaction(
pick(params,['resourceArn','secretArn','transactionId'])
).promise()
if (this && this.rollback) {
let rollback = await config.RDS.rollbackTransaction(
pick(params,['resourceArn','secretArn','transactionId'])
).promise()
this.rollback(e,rollback)
}
// Throw the error
throw e
this.rollback(e,rollback)
}
// Throw the error
throw e
}
} // end query
} // end query

@@ -357,67 +376,67 @@

// Init a transaction object and return methods
const transaction = (config,_args) => {
// Init a transaction object and return methods
const transaction = (config,_args) => {
let args = typeof _args === 'object' ? [_args] : [{}]
let queries = [] // keep track of queries
let rollback = () => {} // default rollback event
let args = typeof _args === 'object' ? [_args] : [{}]
let queries = [] // keep track of queries
let rollback = () => {} // default rollback event
const txConfig = Object.assign(
prepareParams(config,args),
{
database: parseDatabase(config,args), // add database
hydrateColumnNames: parseHydrate(config,args), // add hydrate
RDS: config.RDS // reference the RDSDataService instance
const txConfig = Object.assign(
prepareParams(config,args),
{
database: parseDatabase(config,args), // add database
hydrateColumnNames: parseHydrate(config,args), // add hydrate
RDS: config.RDS // reference the RDSDataService instance
}
)
return {
query: function(...args) {
if (typeof args[0] === 'function') {
queries.push(args[0])
} else {
queries.push(() => [...args])
}
)
return {
query: function(...args) {
if (typeof args[0] === 'function') {
queries.push(args[0])
} else {
queries.push(() => [...args])
}
return this
},
rollback: function(fn) {
if (typeof fn === 'function') { rollback = fn }
return this
},
commit: async function() { return await commit(txConfig,queries,rollback) }
}
return this
},
rollback: function(fn) {
if (typeof fn === 'function') { rollback = fn }
return this
},
commit: async function() { return await commit(txConfig,queries,rollback) }
}
}
// Commit transaction by running queries
const commit = async (config,queries,rollback) => {
// Commit transaction by running queries
const commit = async (config,queries,rollback) => {
let results = [] // keep track of results
let results = [] // keep track of results
// Start a transaction
const { transactionId } = await config.RDS.beginTransaction(
pick(config,['resourceArn','secretArn','database'])
).promise()
// Start a transaction
const { transactionId } = await config.RDS.beginTransaction(
pick(config,['resourceArn','secretArn','database'])
).promise()
// Add transactionId to the config
let txConfig = Object.assign(config, { transactionId })
// Add transactionId to the config
let txConfig = Object.assign(config, { transactionId })
// Loop through queries
for (let i = 0; i < queries.length; i++) {
// Execute the queries, pass the rollback as context
let result = await query.apply({rollback},[config,queries[i](results[results.length-1],results)])
// Add the result to the main results accumulator
results.push(result)
}
// Loop through queries
for (let i = 0; i < queries.length; i++) {
// Execute the queries, pass the rollback as context
let result = await query.apply({rollback},[config,queries[i](results[results.length-1],results)])
// Add the result to the main results accumulator
results.push(result)
}
// Commit our transaction
const { transactionStatus } = await txConfig.RDS.commitTransaction(
pick(config,['resourceArn','secretArn','transactionId'])
).promise()
// Commit our transaction
const { transactionStatus } = await txConfig.RDS.commitTransaction(
pick(config,['resourceArn','secretArn','transactionId'])
).promise()
// Add the transaction status to the results
results.push({transactionStatus})
// Add the transaction status to the results
results.push({transactionStatus})
// Return the results
return results
}
// Return the results
return results
}

@@ -433,10 +452,22 @@ /********************************************************************/

const options = typeof params.options === 'object' ? params.options
: params.options !== undefined ? error(`'options' must be an object`)
: params.options !== undefined ? error('\'options\' must be an object')
: {}
// Update the default AWS http agent with our new sslAgent
if (typeof params.keepAlive !== false) {
if (typeof params.keepAlive === 'boolean' ? params.keepAlive : true) {
AWS.config.update({ httpOptions: { agent: sslAgent } })
}
// Update the AWS http agent with the region
if (typeof params.region === 'string') {
AWS.config.update({ region: params.region })
}
// Disable ssl if wanted for local development
if (params.sslEnabled === false) {
// AWS.config.update({ sslEnabled: false })
options.sslEnabled = false
}
// Set the configuration for this instance

@@ -446,12 +477,15 @@ const config = {

// Require secretArn
secretArn: typeof params.secretArn === 'string' ? params.secretArn
: error(`'secretArn' string value required`),
secretArn: typeof params.secretArn === 'string' ?
params.secretArn
: error('\'secretArn\' string value required'),
// Require resourceArn
resourceArn: typeof params.resourceArn === 'string' ? params.resourceArn
: error(`'resourceArn' string value required`),
resourceArn: typeof params.resourceArn === 'string' ?
params.resourceArn
: error('\'resourceArn\' string value required'),
// Load optional database
database: typeof params.database === 'string' ? params.database
: params.database !== undefined ? error(`'database' must be a string`)
database: typeof params.database === 'string' ?
params.database
: params.database !== undefined ? error('\'database\' must be a string')
: undefined,

@@ -458,0 +492,0 @@

{
"name": "data-api-client",
"version": "1.0.0-beta",
"version": "1.0.0",
"description": "A lightweight wrapper that simplifies working with the Amazon Aurora Serverless Data API",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "jest",
"lint": "eslint ."
},

@@ -26,7 +27,15 @@ "repository": {

"devDependencies": {
"aws-sdk": "^2.466.0"
"aws-sdk": "^2.466.0",
"eslint": "^6.6.0",
"jest": "^25.0.0",
"rewire": "^4.0.1"
},
"dependencies": {
"sqlstring": "^2.3.1"
}
},
"files": [
"LICENSE",
"README.md",
"index.js"
]
}

@@ -6,4 +6,2 @@ # Aurora Serverless Data API Client

**THIS PROJECT IS IN BETA. I WOULD LOVE YOUR FEEDBACK! PLEASE FEEL FREE TO CONTACT ME ON TWITTER [@jeremy_daly](https://twitter.com/jeremy_daly)**
The **Data API Client** is a lightweight wrapper that simplifies working with the Amazon Aurora Serverless Data API by abstracting away the notion of field values. This abstraction annotates native JavaScript types supplied as input parameters, as well as converts annotated response data to native JavaScript types. It's basically a [DocumentClient](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html]) for the Data API. It also promisifies the `AWS.RDSDataService` client to make working with `async/await` or Promise chains easier AND dramatically simplifies **transactions**.

@@ -50,10 +48,9 @@

[
{ name: 'Marcia', age: 17, curls: false },
{ name: 'Peter', age: 15, curls: false },
{ name: 'Jan', age: 15, curls: false },
{ name: 'Cindy', age: 12, curls: true },
{ name: 'Bobby', age: 12, curls: false }
[{ name: 'Marcia', age: 17, curls: false }],
[{ name: 'Peter', age: 15, curls: false }],
[{ name: 'Jan', age: 15, curls: false }],
[{ name: 'Cindy', age: 12, curls: true }],
[{ name: 'Bobby', age: 12, curls: false }]
]
)
// Update with named parameters

@@ -106,41 +103,19 @@ let update = await data.query(

Specifying all of those data types in the parameters is a bit clunky, plus every query requires you to pass in the `secretArn`, `resourceArn`, `database`, and any other method parameters you might need.
Specifying all of those data types in the parameters is a bit clunky. In addition to requiring types for parameters, it also returns each field as an object with its value assigned to a key that represents its data type, like this:
In addition to requiring types for parameters, it also returns each field as an object containing all possible data types, like this:
```javascript
{ // id field
"blobValue": null,
"booleanValue": null,
"doubleValue": null,
"isNull": null,
"longValue": 9,
"stringValue": null
"longValue": 9
},
{ // name field
"blobValue": null,
"booleanValue": null,
"doubleValue": null,
"isNull": null,
"longValue": null,
"stringValue": "Cousin Oliver"
},
{ // age field
"blobValue": null,
"booleanValue": null,
"doubleValue": null,
"isNull": null,
"longValue": 10,
"stringValue": null
"longValue": 10
},
{ // has_curls field
"blobValue": null,
"booleanValue": false,
"doubleValue": null,
"isNull": null,
"longValue": null,
"stringValue": null
"booleanValue": false
}
```
Not only are there no column names, but you have to remove all `null` fields and pull the value from the remaining data type. Lots of extra work that the **Data API Client** handles automatically for you. 😀
Not only are there no column names, but you have to pull the value from the data type field. Lots of extra work that the **Data API Client** handles automatically for you. 😀

@@ -165,5 +140,6 @@ ## Installation and Setup

| keepAlive | `boolean` | Enables HTTP Keep-Alive for calls to the AWS SDK. This dramatically decreases the latency of subsequent calls. | `true` |
| sslEnabled | `boolean` | *Optional* Enables SSL HTTP endpoint. Can be disable for local development. | `true` |
| options | `object` | An *optional* configuration object that is passed directly into the RDSDataService constructor. See [here](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/RDSDataService.html#constructor-property) for available options. | `{}` |
| region | `string` | *Optional* AWS region to use. | `aws-sdk default` |
## How to use this module

@@ -328,3 +304,3 @@

## Data API Limitations / Wonkiness
The first GA release of the Data API has *a lot* of promise, unfortunately, there are still quite a few things that make it a bit wonky and may require you to implement some workarounds. I've outline some of my findings below.
The first GA release of the Data API has *a lot* of promise, unfortunately, there are still quite a few things that make it a bit wonky and may require you to implement some workarounds. I've outlined some of my findings below.

@@ -348,4 +324,4 @@ ### You can't send in an array of values

### Named parameters MUST be sent in order
Read that again if you need to. So parameters have to be **BOTH** named and *in order*, otherwise the query **may** fail. I stress **may**, because if you send in two fields of compatible type in the wrong order, the query will work, just with your values flipped. 🤦🏻‍♂️ Watch out for this one.
### ~~Named parameters MUST be sent in order~~
~~Read that again if you need to. So parameters have to be **BOTH** named and *in order*, otherwise the query **may** fail. I stress **may**, because if you send in two fields of compatible type in the wrong order, the query will work, just with your values flipped. 🤦🏻‍♂️ Watch out for this one.~~ 👈This was fixed!

@@ -444,4 +420,3 @@ ### You can't parameterize identifiers

## Contributions
Contributions, ideas and bug reports are welcome and greatly appreciated. Please add [issues](https://github.com/jeremydaly/data-api-client/issues) for suggestions and bug reports or create a pull request.
Contributions, ideas and bug reports are welcome and greatly appreciated. Please add [issues](https://github.com/jeremydaly/data-api-client/issues) for suggestions and bug reports or create a pull request. You can also contact me on Twitter: [@jeremy_daly](https://twitter.com/jeremy_daly).
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc