Tsynamo
Type-safe DynamoDB query builder! Inspired by Kysely.
Usable with AWS SDK v3 DynamoDBDocumentClient
.
[!NOTE]
Currently this is a POC and a WIP. Currently, get-item
and query
operations are
supported, but I am planning to add support for the rest of the operations too.
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
.getItemFrom("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"
Delete item
WIP
Put item
WIP
Update item
WIP
Scan
WIP
Contributors