DynamoDB

Overview

DevCloud DynamoDB persists tables and items in SQLite (dynamodb.db under the service’s data_dir), with table metadata also held in an in-memory index guarded by an RWMutex.

All ten AttributeValue types are supported: S, N, B, BOOL, NULL, L (List), M (Map), and the SS / NS / BS sets.

Supported APIs

These 29 operations are hand-verified, implemented by the provider, not by the CRUD engine. Everything else DynamoDB models is served at a lower tier or not at all; fidelity-manifest.md is the per-operation answer.

OperationDescription
CreateTableCreate table with partition key (HASH), optional sort key (RANGE), GSIs, LSIs and a StreamSpecification
UpdateTable / DescribeTable / DeleteTable / ListTablesManage and inspect tables
PutItemInsert or overwrite an item; honours ConditionExpression
GetItemRetrieve an item by primary key; honours ProjectionExpression
UpdateItemApply an UpdateExpression to one item
DeleteItemDelete an item by primary key; honours ConditionExpression
QueryQuery by partition key, against the table or a named IndexName; honours FilterExpression
ScanFull table scan; honours FilterExpression
BatchGetItem / BatchWriteItemMulti-item reads and writes
TransactGetItems / TransactWriteItemsTransactional reads and writes
UpdateTimeToLive / DescribeTimeToLiveStore and read back a table’s TTL configuration
TagResource / UntagResource / ListTagsOfResourceManage table tags

Writes to a table created with StreamEnabled are published to the dynamodbstreams service, which is what makes DynamoDB Streams -> Lambda event source mappings fire.

boto3 Examples

Create a table and write items

import boto3

dynamodb = boto3.client(
    "dynamodb",
    endpoint_url="http://localhost:4747",
    aws_access_key_id="test",
    aws_secret_access_key="test",
    region_name="us-east-1",
)

# Create table
dynamodb.create_table(
    TableName="users",
    KeySchema=[
        {"AttributeName": "pk", "KeyType": "HASH"},
        {"AttributeName": "sk", "KeyType": "RANGE"},
    ],
    AttributeDefinitions=[
        {"AttributeName": "pk", "AttributeType": "S"},
        {"AttributeName": "sk", "AttributeType": "S"},
    ],
    BillingMode="PAY_PER_REQUEST",
)

# Put item
dynamodb.put_item(
    TableName="users",
    Item={
        "pk": {"S": "user#123"},
        "sk": {"S": "profile"},
        "name": {"S": "Alice"},
        "age": {"N": "30"},
    },
)

# Get item
response = dynamodb.get_item(
    TableName="users",
    Key={"pk": {"S": "user#123"}, "sk": {"S": "profile"}},
)
print(response["Item"])

Query and scan

# Query by partition key
response = dynamodb.query(
    TableName="users",
    KeyConditionExpression="pk = :pk",
    ExpressionAttributeValues={":pk": {"S": "user#123"}},
)
for item in response["Items"]:
    print(item)

# Full table scan
response = dynamodb.scan(TableName="users")
for item in response["Items"]:
    print(item)

AWS CLI Examples

# Create table
aws --endpoint-url http://localhost:4747 dynamodb create-table \
  --table-name my-table \
  --key-schema AttributeName=pk,KeyType=HASH \
  --attribute-definitions AttributeName=pk,AttributeType=S \
  --billing-mode PAY_PER_REQUEST

# Put item
aws --endpoint-url http://localhost:4747 dynamodb put-item \
  --table-name my-table \
  --item '{"pk": {"S": "key1"}, "data": {"S": "value1"}}'

# Get item
aws --endpoint-url http://localhost:4747 dynamodb get-item \
  --table-name my-table \
  --key '{"pk": {"S": "key1"}}'

Known Limitations

  • TTL is configuration only. UpdateTimeToLive stores the attribute name and echoes it back; nothing sweeps expired items, so a row past its TTL is still returned.
  • No pagination or capacity reporting. Responses carry no LastEvaluatedKey and no ConsumedCapacity, so Query/Scan return the whole matching set in one page and code that loops on the cursor sees one iteration.
  • PartiQL subset only: ExecuteStatement, ExecuteTransaction and BatchExecuteStatement support single-table SELECT, INSERT, UPDATE, and DELETE. WHERE clauses are limited to simple equality (=). No nested paths, subqueries, or arithmetic.
  • Backups and global tables answer from the CRUD engine. CreateBackup, CreateGlobalTable, DescribeContinuousBackups and their neighbours return stored, plausible shapes with no behaviour behind them. However, ExportTableToPointInTime, ImportTable, RestoreTableFromBackup, and RestoreTableToPointInTime are fully handled by the provider (cloning tables and items in SQLite).
  • No Kinesis active replication. EnableKinesisStreamingDestination and DisableKinesisStreamingDestination persist configuration, but write events are not actively replicated to Kinesis streams.
  • No provisioned-throughput accounting or throttling; BillingMode is recorded, never enforced
  • Single account model (account ID: 000000000000)