aiotu / terseq
Query Builder for AWS DynamoDB
Installs: 9 760
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 0
Open Issues: 0
Requires
- php: ^8.3
- aws/aws-sdk-php: ^3
- loophp/collection: ^7.6
- nesbot/carbon: ^3 || ^2
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^11.1
- symfony/var-dumper: ^7.0
README
This document provides a comprehensive guide on how to utilize the Terseq library to build and execute queries on AWS DynamoDB using the AWS SDK for PHP.
Features
Terseq supports building queries for the following DynamoDB operations:
Single-item operations
Query operations
Transactions
Batch
Why I should use this library?
AWS SDK for PHP is a powerful tool for working with AWS services, but it can be challenging to use due to its complexity. It requires a lot of boilerplate code to build and execute queries. Terseq simplifies this process by providing a fluent interface to build queries for DynamoDB operations. It also supports single-table design, which is a recommended practice for DynamoDB.
Installation
To install the Terseq package, run the following command in your project directory using Composer:
composer require aiotu/terseq
Usage
Initialize
Create client by AWS SDK and DatabaseManager
$client = new \Aws\DynamoDb\DynamoDbClient([ 'region' => 'us-west-2', 'version' => 'latest', ]); $manager = new \Terseq\DatabaseManager($client, new Marshaler());
Operations
GetItem
$manager->getItem() ->table(['Books', 'BookId']) ->pk('super-cool-id') ->dispatch();
PutItem
$manager->putItem() ->table(['Books', 'BookId']) ->item([ 'BookId' => 'super-cool-id', 'Title' => 'Super Cool Book', 'Author' => 'Super Cool Author', ]) ->dispatch();
UpdateItem
$manager->updateItem() ->table(['Books', 'BookId']) ->pk('super-cool-id') ->set('Title', 'Super Cool Book Updated') ->set('Author', 'Super Cool Author Updated') ->dispatch();
DeleteItem
$manager->deleteItem() ->table(['Books', 'BookId']) ->pk('super-cool-id') ->dispatch();
Query
$result = $manager->query() ->table(['Books', 'BookId']) ->pk('super-cool-id') ->consistentRead() ->disaptch();
TransactGetItems
use Terseq\Builders\Operations\TransactGetItems\Operations\Get; $manager->transactGetItems() ->get( [ static fn (Get $get) => $get->pk('super-cool-id1'), static fn (Get $get) => $get->pk('super-cool-id2'), ], table: ['Books', 'BookId'], ) ->dispatch();
TransactWriteItems
use Terseq\Builders\Operations\TransactWriteItems\Operations\Delete; use Terseq\Builders\Operations\TransactWriteItems\Operations\Put; use Terseq\Builders\Operations\TransactWriteItems\Operations\Update; $manager->transactWriteItems() ->put( [ fn (Put $put) => $put->item([ 'BookId' => 'super-book1', 'Author' => 'Unknown', ]), fn (Put $put) => $put->item([ 'BookId' => 'super-book-2', 'Author' => 'Incognito', ]), ], table: ['Books', 'BookId'], ) ->update( fn (Update $update) => $update ->pk('super-book-3') ->set('Author', 'Incognito'), table: ['Books', 'BookId'], ) ->delete( fn (Delete $delete) => $delete->pk('super-book-4'), table: ['Books', 'BookId'], ) ->dispatch();
BatchGetItem
$manager->batchGetItem() ->get( [ 'BookId' => 'super-book-1', 'Author' => 'Unknown', ], table: ['Books', 'BookId'], ) ->get( [ 'BookId' => 'super-book-2', 'Author' => 'Incognito', ], table: ['Books', 'BookId'], ) ->dispatch();
BatchWriteItem
$manager->batchWriteItem() ->put( [ 'BookId' => 'super-book-1', 'Author' => 'Unknown', ], table: ['Books', 'BookId'], ) ->put( [ 'BookId' => 'super-book-2', 'Author' => 'Incognito', ], table: ['Books', 'BookId'], ) ->delete( [ 'BookId' => 'super-book-3', ], table: ['Books', 'BookId'], ) ->dispatch();
Table
Table as abject (recommended)
Example of using table object
use Terseq\Builders\Table; class Books extends Table { public function getTableName(): string { return 'Books'; } public function getKeys(): Keys { return new Keys(partitionKey: 'BookId', sortKey: null); } }
Example with secondary indexes
use Terseq\Builders\Table; class BooksTable extends Table { /** * Table name */ public function getTableName(): string { return 'Books'; } /** * Partition key and sort key (optional) */ public function getKeys(): Keys { return new Keys(partitionKey: 'BookId', sortKey: 'ReleaseDate'); } /** * Secondary index map (optional) also known as GSI and LSI */ public function getSecondaryIndexMap(): ?array { return [ 'AuthorIndex' => new Keys(partitionKey: 'AuthorId', sortKey: 'AuthorBornYear'), 'GenreIndex' => new Keys(partitionKey: 'GenreId', sortKey: 'GenreName'), 'LsiExample' => new Keys(partitionKey: 'BookId', sortKey: 'AuthorBornYear'), ]; } }
Table as array
table(table: ['TableName', 'PartitionKey', 'SortKey']);
OR
table(table: ['TableName', 'PartitionKey']); // Sort key by default is null
OR
table(table: ['TableName']); // throws exception, because PartitionKey is required
OR
table(table: [ 'table' => 'TableName', 'pk' => 'PartitionKey', 'sk' => 'SortKey', ]);
Single-table design (recommended)
Library supports single-table design.
Example of using single-table design
$manager = new \Terseq\DatabaseManager( client: $client, marshaler: new Marshaler(), singleTable: new class extends \Terseq\Builders\Table { public function getTableName(): string { return 'Books'; } public function getKeys(): Keys { return new Keys(partitionKey: 'BookId'); } }, );
That's all! Now you can build queries without passing table name and keys.
Usage
// Query $manager->getItem()->pk('super-cool-id')->disaptch(); $manager->batchWriteItem() ->put( [ 'BookId' => 'super-book-1', 'Author' => 'Unknown', ], ) ->put( [ 'BookId' => 'super-book-2', 'Author' => 'Incognito', ], ) ->delete( [ 'BookId' => 'super-book-3', ], ) ->dispatch();
Comparison with AWS SDK
Example of using AWS SDK
$client->updateItem( [ 'TableName' => 'Books', 'UpdateExpression' => 'SET #Title = :title_0, #Author = :author_0', 'ExpressionAttributeNames' => [ '#Title' => 'Title', '#Author' => 'Author', ], 'ExpressionAttributeValues' => [ ':title_0' => [ 'S' => 'Super Cool Book Updated', ], ':author_0' => [ 'S' => 'Super Cool Author Updated', ], ], 'Key' => [ 'BookId' => [ 'S' => 'super-cool-id', ], ], ], );
Example of using Terseq
for the same operation
$manager->updateItem() ->table(['Books', 'BookId']) ->pk('super-cool-id') ->set('Title', 'Super Cool Book Updated') ->set('Author', 'Super Cool Author Updated') ->dispatch();