The recommended way to interact with QLDB is by using the official QLDB driver. The driver is open sourced on GitHub and available for the following programming languages:

This guide currently provides examples and code snippets in Node.js, but will be extended to support other programming languages.

Environment Setup

A typical setup of dependencies required to interact with QLDB is shown below:


{
 "dependencies": {
    "amazon-qldb-driver-nodejs": "^2.0.0",
    "aws-sdk": "^2.778.0",
    "aws-xray-sdk-core": "^3.2.0",
    "ion-js": "^4.0.1",
    "jsbi": "^3.1.4"
  },
}
  • The amazon-qldb-driver-nodejs module is the official driver provided by AWS
  • The aws-sdk and aws-xray-sdk-core modules are needed to support tracing with X-Ray
  • The ion-js and jsbi modules are needed to easily interact with Amazon ION documents

Connect to Ledger

The first step in writing to code to interact with QLDB is to create a QldbDriver. This driver provides a high-level abstraction layer above the transaction data API (QLDB Session). It takes care of connection pooling and managing sessions, transactions and retry policies.



const { QldbDriver, RetryConfig } = require('amazon-qldb-driver-nodejs');
const qldbDriver = createQldbDriver();
function createQldbDriver(
      ledgerName = process.env.LEDGER_NAME,
      serviceConfigurationOptions = {},
) {
      const retryConfig = new RetryConfig(4);
      const qldbDriver = new QldbDriver(ledgerName, serviceConfigurationOptions, 10, retryConfig);
      return qldbDriver;
}
function getQldbDriver() {
  return qldbDriver;
}

The constructor for a new QldbDriver can take four parameters:

  • ledgerName - the name of the ledger to connect to
  • qldbClientOptions - an object that contains options for configuring the low level client. More details can be found here.
  • maxConcurrentTransactions - the number of sessions the driver can hold in the pool, with the default set to the maximum number of sockets specified in the global agent
  • RetryConfig - config to specify max number of retries, base and custom backoff strategy for retries

The RetryConfig was introduced in version 2 of the Nodejs driver. It consists of two attributes:

  • retryLimit - tells the driver how many times to retry when there are failures. The value must be greater than 0. The default value is 4.
  • backoffFunction - A custom function that accepts a retry count, error, transaction id and returns the amount of time to delay in milliseconds. A default backoff function is provided

Execute Lambda

The executeLambda method on the QldbDriver is the primary method to execute a transaction against a QLDB ledger. When this method is invoked, the driver acquires a Transaction and hands it to the TransactionExecutor that is passed in. Once all execution is complete, the driver attempts to commit the transaction. If there is a failure, then the driver will attempt to retry the entire transaction block, so your code should be idempotent.


const createLicence = async (param1, param2, ...) => {
  const qldbDriver = await getQldbDriver();
  await qldbDriver.executeLambda(async (txn) => {
    // all functionality committed as one atomic transaction
    ...
  });
};

In the example above, if multiple statements are executed, they will all either succeed or be rolled back in one atomic transaction. The driver will only attempt to commit the transaction once all the execution is carried out. If there is a failure, then the driver will attempt to retry the entire transaction block.

CRUD Operations

Creating a record

To insert a new document into a table, the following syntax is used:


await qldbDriver.executeLambda(async txn => {
    const document = [{'Name': 'name', 'Email': 'name@email.com', 'Telephone': '01234'}];
    const statement = 'INSERT INTO Table ?';
    const result = await txn.execute(statement, document);
    const docIdArray = result.getResultList()
    console.log(JSON.stringify(values, null, 2))
})

The execute method returns a Promise that resolves to a Result object. This class represents the fully buffered set of results from QLDB in an array. When a new record is inserted, the result object contains the document ID of the record.


[
  {
    "documentId": "7ISClqWTgkcLNnBlgdtKYa"
  }
]

To extract the documentId from the returned array, you can use the following syntax:


  const result = await insertDocument(txn, docToInsert);
  const docIdArray = result.getResultList();
  const docId = docIdArray[0].get('documentId').stringValue();

Reading a record

To read a record, execute a select statement against a table:


const getRecord = async (id) => {
    await qldbDriver.executeLambda(async (txn) => {
        const query = `SELECT * FROM Table WHERE Attribute = ?`;
        const result = await txn.execute(query, id);
        const resultList = result.getResultList();
        ...
    };
};

The Result object returned represents the buffered set of results in an array. The getResultList() function returns the list of Ion values returned from the enquiry. You can check the length property to determine how many results were returned:


  const resultList = result.getResultList();
  ...
  if (resultList.length === 0) {
      // no record found processing
  } else if (resultList.length === 1) {
      // single record found processing
  } else {
      // multiple records found processing
  }
};

If you just want to log the document revision returned by QLDB, you can use JSON.stringify() to cast the ION to JSON:


  JSON.stringify(resultList[0], null, 2)};

Otherwise, you can use simple calls to retrieve specific values out of the record that is returned. The following code will retrieve the name as a string value, and a points attribute as a number value:


  const statement = ‘SELECT name, points FROM Licence where ID =  ?’;
  const result = txn.execute(statement, ID);
  const resultList = result.getResultList();
  const name = resultList[0].get('name').stringValue();
  const points = resultList[0].get('points').numberValue();

You can also use multiple attributes with a WHERE predicate clause.


  const statement = `SELECT * FROM Table WHERE a = ? AND b = ?`;
  const result = await txn.execute(statement, "valueA", "valueB");
  ...
};

Updating a record

To update a record, execute an update statement against a table:


await qldbDriver.executeLambda(async (txn) => {
  const statement = `UPDATE Table SET A = ?, B = ?, C = ? WHERE D = ?`;
  const result = await txn.execute(statement, valueA, valueB, valueC, valueD);
  const resultList = result.getResultList();
  ...
};

In the same way as for creating a record, the result object returned contains the document ID of the record that has been updated.

Deleting a record

To delete a record, execute a delete statement against a table:


await qldbDriver.executeLambda(async (txn) => {
  const statement = `DELETE FROM Table WHERE id = ?`;
  const result = await txn.execute(statement, id);
  const resultList = result.getResultList();
  ...
};

The result object returned contains the document ID of the record that has been deleted.

QLDB Shell

Amazon QLDB provides a command line shell for interaction with the transactional data plane. The QLDB shell enables you to run PartiQL statements on ledger data. This shell is written in Python and is open-sourced in a GitHub repository. The shell is a great way to try and PartiQL statements and interact with a ledger from a developer perspective.

More details can be found in the developer guide

Using the QLDB Shell