Tsynamo
Type-friendly DynamoDB query builder! Inspired by Kysely.
Usable with AWS SDK v3 DynamoDBDocumentClient
.
Installation
Available in NPM.
npm i tsynamo
pnpm install tsynamo
yarn add tsynamo
Usage
Creating a Tsynamo client
- Define the types for your DynamoDB tables:
import { PartitionKey, SortKey } from "tsynamo";
export interface DDB {
UserEvents: {
userId: PartitionKey<string>;
eventId: SortKey<number>;
eventType: string;
userAuthenticated: boolean;
};
}
Notice that you can have multiple tables in the DDB schema. Nested attributes are supported too.
- Create a DynamoDB document client:
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
const ddbClient = DynamoDBDocumentClient.from(
new DynamoDBClient({
})
);
The document client must come from @aws-sdk/lib-dynamodb!
- Create a Tsynamo client with the defined DynamoDB types and client:
const tsynamoClient = new Tsynamo<DDB>({
ddbClient: dynamoDbDocumentClient,
});
Get item
await tsynamoClient
.getItem("UserEvents")
.keys({
userId: "123",
eventId: 222,
})
.attributes(["userId"])
.execute();
Query item
Partition key condition
await tsynamoClient
.query("UserEvents")
.keyCondition("userId", "=", "123")
.execute();
Partition and sort key conditions
await tsynamoClient
.query("UserEvents")
.keyCondition("userId", "=", "123")
.keyCondition("eventId", "<", 1000)
.execute();
Simple filter expression
await tsynamoClient
.query("UserEvents")
.keyCondition("userId", "=", "123")
.filterExpression("eventType", "=", "LOG_IN_EVENT")
.execute();
Filter expression with a function
await tsynamoClient
.query("UserEvents")
.keyCondition("userId", "=", "123")
.filterExpression("eventType", "begins_with", "LOG")
.execute();
Multiple filter expressions
await tsynamoClient
.query("UserEvents")
.keyCondition("userId", "=", "123")
.filterExpression("eventType", "begins_with", "LOG_IN")
.orFilterExpression("eventType", "begins_with", "SIGN_IN")
.execute();
Nested filter expressions
await tsynamoClient
.query("UserEvents")
.keyCondition("userId", "=", "123")
.filterExpression("eventType", "=", "LOG_IN")
.orFilterExpression((qb) =>
qb
.filterExpression("eventType", "=", "UNAUTHORIZED_ACCESS")
.filterExpression("userAuthenticated", "=", true)
)
.orFilterExpression("eventType", "begins_with", "SIGN_IN")
.execute();
This would compile as the following FilterExpression:
eventType = "LOG_IN" OR (eventType = "UNAUTHORIZED_ACCESS" AND userAuthenticated = true
)
NOT filter expression
await tsynamoClient
.query("UserEvents")
.keyCondition("userId", "=", "123")
.filterExpression("NOT", (qb) =>
qb.filterExpression("eventType", "=", "LOG_IN")
)
.execute();
This would compile as the following FilterExpression:
NOT eventType = "LOG_IN"
, i.e. return all events whose types is not "LOG_IN"
Put item
Simple put item
await tsynamoClient
.putItem("myTable")
.item({
userId: "123",
eventId: 313,
})
.execute();
Put item with ConditionExpression
await tsynamoClient
.putItem("myTable")
.item({
userId: "123",
eventId: 313,
})
.conditionExpression("userId", "attribute_not_exists")
.execute();
Put item with multiple ConditionExpressions
await tsynamoClient
.putItem("myTable")
.item({
userId: "123",
eventId: 313,
})
.conditionExpression("userId", "attribute_not_exists")
.orConditionExpression("eventType", "begins_with", "LOG_")
.execute();
Delete item
Simple delete item
await tsynamoClient
.deleteItem("myTable")
.keys({
userId: "123",
eventId: 313,
})
.execute();
Simple delete item with ConditionExpression
await tsynamoClient
.deleteItem("myTable")
.keys({
userId: "123",
eventId: 313,
})
.conditionExpression("eventType", "attribute_not_exists")
.execute();
Update item
WIP
Scan
WIP
Contributors