@susovan87/rds-data-client
TypeScript icon, indicating that this package has built-in type declarations

0.1.1 • Public • Published

RDS Data Client

A lightweight wrapper on @aws-sdk/client-rds-data that simplifies working with the Amazon Aurora Serverless Data API. This library is inspired by jeremydaly/data-api-client. Here are the key benifits of using this library over others.

  • Simplified input params & output records: It enhances functionality of AWS SDK Javascript v3 library @aws-sdk/client-rds-data by abstracting away the notion of field values. It ease supplying named params in native JavaScript types and also converts return records in native JavaScript types. See the examples below for more details.
  • Custom retries for DB connection failures: Custom retry strategy to handle DB connect timeout. This is extremely useful cater infrequest uses pattern (pause compute capacity on inactivity to save cost). Find the details on the issue aws/aws-sdk-js-v3 #3425.
  • [TBD] Proactive wakeup request: Support for proactive wakeup-request to RDS to minimize waiting time when RDS is paused due to inactivity. It could save compute time & cost. (TDB #1)
  • Extended functionality without any overlapping: The library let you access every feature of @aws-sdk/client-rds-data, while extended few essential funcationality without overlapping. So, no restriction on advance use-cases. That means you can still pass the parameters or parameterSets as query options to send named parameters in native AWS SDK format and get records as output. Though the library will accept additional query option params for simplified named parameter in native Javascript types and inject fields like recordObjects or generatedIds inside query output. Find more on examples below
  • Typescript support: So, you will get hint on what each method accepts and output.
  • Recommended option injection: Automatically inject continueAfterTimeout: true option for DML queries as recommended by AWS. Though you many override this via query options.

Installation

npm i @susovan87/rds-data-client

Simple Examples

You can simply instantiate the DBClient with required configuration and use query() method to execute SQL queries.

import {DBClient} from '@susovan87/rds-data-client'
const dbClient = new DBClient({
  secretArn: 'arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXX:secret:mySecret',
  resourceArn: 'arn:aws:rds:us-east-1:XXXXXXXXXXXX:cluster:my-cluster-name',
  database: 'myDatabase' // default database
});

// Simple SELECT
const data = await dbClient.query('SELECT * FROM myTable');
console.log(data.recordObjects)

// SELECT with named parameters
const resultParams = await dbClient.query(
  `SELECT * FROM myTable WHERE id = :id`,
  { params: { id: 2 } }
);
console.log(resultParams.recordObjects)
// Output: [ { id: 2, name: 'Mike', age: 52 } ]

// INSERT with named parameters
const insert = await dbClient.query(
  `INSERT INTO myTable (name,age,has_curls) VALUES(:name,:age,:curls)`,
  { params: { name: 'Greg', age: 18, curls: false } }
)
console.log(insert.generatedIds)
// Output: [ 4 ]

// BATCH INSERT with named parameters
const batchInsert = await dbClient.query(
  `INSERT INTO myTable (name,age,has_curls) VALUES(:name,:age,:curls)`,
  {
    params: [
      { 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 }
    ]
  }
)
console.log(batchInsert.generatedIds)
// Output: [ 5, 6, 7, 8, 9 ]

// Update with named parameters
const update = await dbClient.query(
  `UPDATE myTable SET age = :age WHERE id = :id`,
  { params: { age: 13, id: 5 } }
)
console.log(update.numberOfRecordsUpdated)
// Output: 1

// Delete with named parameters
const remove = await dbClient.query(
  `DELETE FROM myTable WHERE name = :name`,
  { params: { name: 'Jan' } }
)
console.log(update.numberOfRecordsUpdated)
// Output: 1

// A slightly more advanced example
let custom = await dbClient.query(`SELECT * FROM myOtherTable WHERE isActive = :isActive`,
  {
    params: { isActive: true },
    database: 'myOtherDatabase',
    continueAfterTimeout: true
  })
console.log(custom.recordObjects);
// Output: [
//  { id: 1, name: 'Marcia', DOB: null, weight: 81.8, bio: 'I am a Teacher', isActive: true, createdAt: '2022-03-29 04:41:33' },
//  { id: 2, name: 'Peter', DOB: '2008-07-04', weight: null, bio: 'I am a Student', isActive: true, createdAt: '2022-03-29 04:41:33' }
//]

How it is better than vanilla AWS SDK?

The RDSDataClient requires you to specify data types when passing in parameters. The basic INSERT example above would look like this using this

import { RDSDataClient } from '@aws-sdk/client-rds-data'
const client = new RDSDataClient({ region: 'us-east-1' })

// INSERT with named parameters
let insert = await client.send({
  secretArn: 'arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXX:secret:mySecret',
  resourceArn: 'arn:aws:rds:us-east-1:XXXXXXXXXXXX:cluster:my-cluster-name',
  database: 'myDatabase',
  sql: 'INSERT INTO myTable (name,age,has_curls) VALUES(:name,:age,:curls)',
  parameters: [
    { name: 'name', value: { stringValue: 'Cousin Oliver' } },
    { name: 'age', value: { longValue: 10 } },
    { name: 'curls', value: { booleanValue: false } }
  ]
)

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:

{ // id field
  "longValue": 9
},
{ // name field
  "stringValue": "Cousin Oliver"
},
{ // age field
  "longValue": 10
},
{ // has_curls field
  "booleanValue": false
}

Not only are there no column names, but you have to pull the value from the data type field. Lots of extra work this library automatically handles for you.

Transaction Support

Generate a transactionId by calling startTransaction() and pass the transactionId into every query() options that are part of same transaction. And the just call commit() or rollback() method with the same transactionId to either commit or rollback the transaction.

let transactionId;
try {
  transactionId = await dbClient.startTransaction()

  const insert = await dbClient.query(
    `INSERT INTO myTable (name,age,has_curls) VALUES(:name,:age,:curls)`,
    { params: { name: 'Smith', age: 18, curls: false } },
    transactionId
  )
  console.log(`Successfully inserted with generatedIds: ${insert?.generatedIds}`)

  const update = await dbClient.query(
    `UPDATE myTable SET age = :age WHERE name = :name`,
    { params: { name: 'Smith', age: 81 } },
    transactionId
  )
  const status = await dbClient.commit(transactionId)
  console.log('Commit transaction status:', status)

} catch (error) {
  console.error(error)
  const status = await dbClient.rollback(transactionId)
  console.log('Rollback transaction status:', status)
}

Contributions

Contributions, ideas and bug reports are welcome and greatly appreciated. Please add issues for suggestions and bug reports or create a pull request.

Package Sidebar

Install

npm i @susovan87/rds-data-client

Weekly Downloads

0

Version

0.1.1

License

MIT

Unpacked Size

1.99 MB

Total Files

28

Last publish

Collaborators

  • susovan87