dynamodb-expressions

Helpers for creating DynamoDB expressions

Usage no npm install needed!

<script type="module">
  import dynamodbExpressions from 'https://cdn.skypack.dev/dynamodb-expressions';
</script>

README

dynamodb-expressions

Zero-dependency library of helpers for creating DynamoDB expressions without the hassle of maintaining ExpressionAttributeValues, escaping reserved attribute names, dealing with #param, :value etc! 🎉

Introduction

This module enables building complex DynamoDB expressions (update expressions or condition expressions) using a simple syntax, with TypeScript typing. A condition string is built from attributes, and attribute names and values are handled and added to the supplied params.

Update expressions

A simple update of attributes foo and bar:


await ddb.update(buildUpdateParams({
  params: {
    TableName: 'my-stuff',
    Key: {id: '42'},
  },
  attributes: {
    foo: 42,
    bar: 'HELLO'
  }
}));

Note that buildUpdateParams will add UpdateExpression, ExpressionAttributeNames and ExpressionAttributeValues to the given params and return the combined object. If ExpressionAttributeNames or ExpressionAttributeValues already exists in the given params, they will be built upon, meaning you can combine calls to buildUpdateParams and e.g. buildConditionParams.

Alternatively you may of course add your other params separately:

await ddb.update({
  TableName: 'my-stuff',
  Key: {id: '42'},
  ...buildUpdateParams({
    attributes: {
      foo: 42,
      bar: 'HELLO'
    }
  })
};

The library offers a simple syntax for producing complex conditions.

Examples of more advanced operations:

{
  foo: 42, // set scalar value
  bar: UpdateAction.remove(), // remove attribute
  baz: UpdateAction.add(1), // increment number by 1
  mySet: UpdateAction.add(new Set([4])), // add 4 to mySet
  myOtherSet: UpdateAction.delete(new Set([5, 7])), // remove 5 and 7 from myOtherSet
  myList: UpdateAction.set(SetValue.append([1, 2])), // append 1, 2 to myList
  qux: UpdateAction.set(SetValue.ifNotExists('qux', 42)), // Set qux to 42 if it doesn't exist 
}

You may also use the (legacy) function buildUpdateExpression, which returns the UpdateExpression as a single string. However, to obtain the ExpressionAttributeNames and ExpressionAttributeValues you must pass an in/out object which you then manually merge, since it contains ExpressionAttributeNames and ExpressionAttributeValues after the call to buildUpdateExpression() has returned:

const params = {};

await ddb.update(
  TableName: 'my-stuff',
  Key: {id: '42'},
  UpdateExpression: buildUpdateExpression({
    foo: 42,
    bar: 'HELLO'
  }, params),
  ...params
};

Update operators:

All operators supported by DynamoDB as per https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html are included:

  • SET
  • REMOVE
  • ADD
  • DELETE

Nested attributes, lists, sets and built-in DynamoDB functions such as list_append, if_not_exists etc are supported.

Condition expressions

This is very similar to update expressions, but may instead produce ConditionExpression or KeyConditionExpression values.

await ddb.query(buildKeyConditionParams({
  params: {
    TableName: 'my-stuff',
    IndexName: 'my-index',
  },
  conditions: {
    foo: 42, // foo = 42
    bar: Condition.gt(4), // bar > 4
    baz: Condition.between(7, 12) // baz BETWEEN 7, 12
    qux: Condition.in([1, 2, 4]) // qux IN (1, 2, 4)
    str: Condition.beginsWith('foo') // begins_with(str, 'foo')
  }
}));

Alternatively:

await ddb.query({
  TableName: 'my-stuff',
  IndexName: 'my-index',
  ...buildKeyConditionParams({
    conditions: {
      foo: 42, // foo = 42
      bar: Condition.gt(4), // bar > 4
      baz: Condition.between(7, 12) // baz BETWEEN 7, 12
      qux: Condition.in([1, 2, 4]) // qux IN (1, 2, 4)
      str: Condition.beginsWith('foo') // begins_with(str, 'foo')
    }
  });
});

Legacy function with manual passing of params:

const params = {};

const ConditionExpression = buildConditionExpression({
  foo: 42, // foo = 42
  bar: Condition.gt(4), // bar > 4
  baz: Condition.between(7, 12) // baz BETWEEN 7, 12
  qux: Condition.in([1, 2, 4]) // qux IN (1, 2, 4)
  str: Condition.beginsWith('foo') // begins_with(str, 'foo')
}, params);

await ddb.query({
  TableName: 'my-stuff',
  IndexName: 'my-index',
  KeyConditionExpression,
  ...params
});

Condition operators:

The operators and functions described at https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html are all supported:

  • Arithmetic
    • =
    • <>
    • <
    • <=
    • >
    • >=
  • Value sets
    • IN
  • Value ranges
    • BETWEEN
  • Boolean operators
    • AND
    • OR
    • NOT
  • Functions:
    • attribute_exists
    • attribute_not_exists
    • attribute_type
    • begins_with
    • contains
    • size