dynago

package module
v0.0.0-...-014964a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 31, 2026 License: MIT Imports: 12 Imported by: 0

README

DynaGo

CI Go Reference Go Report Card

DynaGo is a type-safe DynamoDB library for Go that leverages generics to provide a clean, expressive API for single-table and multi-table designs. It ships with an in-memory backend for fast, deterministic tests and optional OpenTelemetry middleware for production observability.

Requirements

  • Go 1.23+

Installation

go get github.com/danielmensah/dynago

For OpenTelemetry instrumentation (separate module):

go get github.com/danielmensah/dynago/dynagotel

Quick Start

package main

import (
	"context"
	"fmt"

	"github.com/danielmensah/dynago"
	"github.com/danielmensah/dynago/memdb"
)

type User struct {
	PK    string `dynamodbav:"PK"`
	SK    string `dynamodbav:"SK"`
	Name  string `dynamodbav:"Name"`
	Email string `dynamodbav:"Email"`
}

func main() {
	ctx := context.Background()

	// Create an in-memory backend and table.
	backend := memdb.New()
	backend.CreateTable("MyTable", memdb.TableSchema{
		HashKey:  memdb.KeyDef{Name: "PK", Type: memdb.StringKey},
		RangeKey: &memdb.KeyDef{Name: "SK", Type: memdb.StringKey},
	})

	db := dynago.New(backend)
	table := db.Table("MyTable")

	// Put an item.
	user := User{PK: "USER#123", SK: "PROFILE", Name: "Alice", Email: "alice@example.com"}
	_ = table.Put(ctx, user)

	// Get an item.
	got, _ := dynago.Get[User](ctx, table, dynago.Key("PK", "USER#123", "SK", "PROFILE"))
	fmt.Println(got.Name) // Alice

	// Query items by partition key.
	users, _ := dynago.Query[User](ctx, table, dynago.Partition("PK", "USER#123"))
	fmt.Println(len(users))
}

Features

  • Type-safe generics API -- Get[T], Put, Query[T], and Scan[T] work with your Go structs directly. No manual marshaling required.
  • Single-table design -- A Registry maps discriminator values to concrete types, enabling polymorphic queries with QueryCollection and ItemsOf[T].
  • In-memory testing -- The memdb package provides a complete in-memory DynamoDB backend with support for GSIs, condition expressions, filter expressions, and pagination.
  • OpenTelemetry observability -- The dynagotel middleware adds tracing spans and latency/count metrics to every operation.
  • Middleware architecture -- Wrap the backend with custom middleware for logging, retries, caching, or any cross-cutting concern.

Examples

Basic CRUD
// Put
user := User{PK: "USER#1", SK: "PROFILE", Name: "Bob", Email: "bob@example.com"}
err := table.Put(ctx, user)

// Get
user, err := dynago.Get[User](ctx, table, dynago.Key("PK", "USER#1", "SK", "PROFILE"))

// Get with consistent read and projection
user, err := dynago.Get[User](ctx, table,
	dynago.Key("PK", "USER#1", "SK", "PROFILE"),
	dynago.ConsistentRead(),
	dynago.Project("Name", "Email"),
)

// Query all items under a partition key
users, err := dynago.Query[User](ctx, table, dynago.Partition("PK", "USER#1"))

// Scan with limit
users, err := dynago.Scan[User](ctx, table, dynago.ScanLimit(100))
Query with Sort Key Conditions and Filters
// Query with begins_with on sort key
orders, err := dynago.Query[Order](ctx, table,
	dynago.Partition("PK", "USER#1").SortBeginsWith("SK", "ORDER#"),
)

// Query with sort key range
orders, err := dynago.Query[Order](ctx, table,
	dynago.Partition("PK", "USER#1").SortBetween("SK", "ORDER#2024-01", "ORDER#2024-12"),
)

// Query with filter expression, limit, and descending order
orders, err := dynago.Query[Order](ctx, table,
	dynago.Partition("PK", "USER#1").SortBeginsWith("SK", "ORDER#"),
	dynago.QueryFilter("Amount > ?", 100),
	dynago.QueryLimit(10),
	dynago.ScanForward(false),
)

// Query a secondary index
orders, err := dynago.Query[Order](ctx, table,
	dynago.Partition("GSI1PK", "STATUS#shipped"),
	dynago.QueryIndex("GSI1"),
)
Conditional Writes
// Put only if item does not already exist
err := table.Put(ctx, user, dynago.IfNotExists("PK"))

// Put with custom condition expression
err := table.Put(ctx, user, dynago.PutCondition("Version = ?", 3))
Single-Table Design with Registry
// Define entity types that implement the Entity interface.
type User struct {
	PK    string `dynamodbav:"PK"`
	SK    string `dynamodbav:"SK"`
	Name  string `dynamodbav:"Name"`
}

func (u User) DynagoEntity() dynago.EntityInfo {
	return dynago.EntityInfo{Discriminator: "USER"}
}

type Order struct {
	PK     string  `dynamodbav:"PK"`
	SK     string  `dynamodbav:"SK"`
	Amount float64 `dynamodbav:"Amount"`
}

func (o Order) DynagoEntity() dynago.EntityInfo {
	return dynago.EntityInfo{Discriminator: "ORDER"}
}

// Create a registry and attach it to the table.
reg := dynago.NewRegistry("EntityType")
reg.Register(User{})
reg.Register(Order{})

table := db.Table("MyTable", dynago.WithRegistry(reg))

// Query all entities under a partition key.
coll, err := dynago.QueryCollection(ctx, table, dynago.Partition("PK", "USER#1"))

// Extract typed slices from the collection.
users := dynago.ItemsOf[User](coll)
orders := dynago.ItemsOf[Order](coll)

// Or iterate lazily with Go 1.23+ range-over-func.
for item, err := range dynago.CollectionIter(ctx, table, dynago.Partition("PK", "USER#1")) {
	if err != nil {
		log.Fatal(err)
	}
	switch v := item.(type) {
	case User:
		fmt.Println("User:", v.Name)
	case Order:
		fmt.Println("Order:", v.Amount)
	}
}
Testing with memdb
package myapp_test

import (
	"context"
	"testing"

	"github.com/danielmensah/dynago"
	"github.com/danielmensah/dynago/dynagotest"
	"github.com/danielmensah/dynago/memdb"
)

func TestUserService(t *testing.T) {
	backend := memdb.New()
	backend.CreateTable("MyTable", memdb.TableSchema{
		HashKey:  memdb.KeyDef{Name: "PK", Type: memdb.StringKey},
		RangeKey: &memdb.KeyDef{Name: "SK", Type: memdb.StringKey},
	})

	db := dynago.New(backend)
	table := db.Table("MyTable")
	ctx := context.Background()

	// Seed test data.
	err := dynagotest.Seed(ctx, table, []any{
		User{PK: "USER#1", SK: "PROFILE", Name: "Alice"},
		User{PK: "USER#2", SK: "PROFILE", Name: "Bob"},
	})
	if err != nil {
		t.Fatal(err)
	}

	// Or seed from a DynamoDB JSON file.
	// err = dynagotest.SeedFromJSON(ctx, table, "testdata/fixtures.json")

	// Assert items exist with expected attributes.
	dynagotest.AssertItemExists(t, table,
		dynago.Key("PK", "USER#1", "SK", "PROFILE"),
		dynagotest.HasAttribute("Name", "Alice"),
	)

	// Assert an item does not exist.
	dynagotest.AssertItemNotExists(t, table,
		dynago.Key("PK", "USER#999", "SK", "PROFILE"),
	)

	// Assert query result count.
	dynagotest.AssertCount(t, table, dynago.Partition("PK", "USER#1"), 1)
}
OpenTelemetry Setup
import (
	"github.com/danielmensah/dynago"
	"github.com/danielmensah/dynago/dynagotel"
	"go.opentelemetry.io/otel"
)

tracer := otel.Tracer("myapp")
meter := otel.Meter("myapp")

otelMiddleware := dynagotel.NewMiddleware(
	dynagotel.WithTracer(tracer),
	dynagotel.WithMeter(meter),
)

db := dynago.New(backend, dynago.WithMiddleware(otelMiddleware))

This wraps every DynamoDB operation with:

  • A trace span (db.system=dynamodb, db.operation=GetItem, etc.)
  • An operation counter (dynago.operations.total)
  • A latency histogram (dynago.latency in milliseconds)
Custom Middleware
func loggingMiddleware(inner dynago.Backend) dynago.Backend {
	// Return a Backend implementation that logs before/after delegating to inner.
	// ...
}

db := dynago.New(backend, dynago.WithMiddleware(loggingMiddleware))

API Reference

Full API documentation is available on pkg.go.dev.

Packages
Package Description
dynago Core library: DB, Table, Get, Put, Query, Scan, Registry, Collection
memdb In-memory Backend for testing
dynagotest Test helpers: Seed, SeedFromJSON, AssertItemExists, AssertCount
dynagotel OpenTelemetry tracing and metrics middleware

License

MIT

Documentation

Overview

Package dynago provides a type-safe, generics-first DynamoDB client for Go.

DynaGo wraps DynamoDB operations behind a clean Backend interface, enabling in-memory testing with memdb, real AWS calls with awsbackend, and cross-cutting middleware for logging and OpenTelemetry.

Quick start:

backend := memdb.New()
backend.CreateTable("users", memdb.TableSchema{
    HashKey: memdb.KeyDef{Name: "PK", Type: memdb.StringKey},
})
db := dynago.New(backend)
table := db.Table("users")

// Put
err := table.Put(ctx, User{PK: "u#1", Name: "Alice"})

// Get
user, err := dynago.Get[User](ctx, table, dynago.Key("PK", "u#1"))

// Query
users, err := dynago.Query[User](ctx, table,
    dynago.Partition("PK", "u#1"),
    dynago.QueryLimit(10),
)

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is returned when a Get or Query returns no item.
	ErrNotFound = errors.New("dynago: item not found")

	// ErrConditionFailed is returned when a condition expression check fails.
	ErrConditionFailed = errors.New("dynago: condition check failed")

	// ErrValidation is returned for client-side validation errors such as
	// missing keys or unsupported types.
	ErrValidation = errors.New("dynago: validation error")

	// ErrTransactionCancelled is returned when a DynamoDB transaction is
	// cancelled.
	ErrTransactionCancelled = errors.New("dynago: transaction cancelled")
)

Functions

func BatchGet

func BatchGet[T any](ctx context.Context, t *Table, keys []KeyValue, opts ...BatchGetOption) ([]T, error)

BatchGet retrieves multiple items by key and returns them as a typed slice. Items are returned in arbitrary order (matching DynamoDB behavior). Keys are automatically chunked into groups of 100.

func CollectionIter

func CollectionIter(ctx context.Context, t *Table, key KeyCondition, opts ...QueryOption) iter.Seq2[any, error]

CollectionIter returns a Go 1.23+ iterator that lazily pages through Query results, unmarshaling each item polymorphically using the table's Registry. Items with unrecognized discriminators are silently skipped. If the table has no registry, the iterator yields a single error and stops.

func Get

func Get[T any](ctx context.Context, t *Table, key KeyValue, opts ...GetOption) (T, error)

Get retrieves a single item from DynamoDB by primary key and unmarshals it into T. It returns ErrNotFound when the item does not exist.

func GetAs

func GetAs[T any](result *ReadTxResult, index int) (T, error)

GetAs unmarshals the item at the given index into type T.

func IsCondCheckFailed

func IsCondCheckFailed(err error) bool

IsCondCheckFailed reports whether err matches ErrConditionFailed.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err matches ErrNotFound.

func IsTxCancelled

func IsTxCancelled(err error) bool

IsTxCancelled reports whether err matches ErrTransactionCancelled.

func IsValidation

func IsValidation(err error) bool

IsValidation reports whether err matches ErrValidation.

func ItemsOf

func ItemsOf[T any](c *Collection) []T

ItemsOf returns all items in the Collection that are of type T.

func Marshal

func Marshal(v any) (map[string]AttributeValue, error)

Marshal converts a Go struct into a DynamoDB item representation. The struct's exported fields are encoded using the cached typeCodec from the struct tag parser (US-002). Struct tags use the "dynamo" key.

func Query

func Query[T any](ctx context.Context, t *Table, key KeyCondition, opts ...QueryOption) ([]T, error)

Query executes a DynamoDB Query and unmarshals all results into a slice of T. It automatically paginates when the response contains a LastEvaluatedKey, collecting all items until done or the Limit is reached.

func QueryIter

func QueryIter[T any](ctx context.Context, t *Table, key KeyCondition, opts ...QueryOption) iter.Seq2[T, error]

QueryIter returns a Go 1.23+ iterator that lazily pages through Query results. Each call to the yield function provides a single unmarshalled item of type T. On error, the iterator yields (zero, err) as the final element and stops. Breaking out of a range loop is safe and does not leak goroutines.

func ReadModifyWrite

func ReadModifyWrite[T any](ctx context.Context, t *Table, key KeyValue, fn func(*T) error, opts ...RMWOption) error

ReadModifyWrite reads an item, applies fn to modify it, and writes it back. With OptimisticLock, it uses a condition expression to detect concurrent modifications and retries automatically.

func Scan

func Scan[T any](ctx context.Context, t *Table, opts ...ScanOption) ([]T, error)

Scan executes a DynamoDB Scan and unmarshals all results into a slice of T. It automatically paginates when the response contains a LastEvaluatedKey, collecting all items until done or the Limit is reached.

func ScanIter

func ScanIter[T any](ctx context.Context, t *Table, opts ...ScanOption) iter.Seq2[T, error]

ScanIter returns a Go 1.23+ iterator that lazily pages through Scan results. Each call to the yield function provides a single unmarshalled item of type T. On error, the iterator yields (zero, err) as the final element and stops. Breaking out of a range loop is safe and does not leak goroutines.

func SplitKey

func SplitKey(key string, delimiter string) []string

SplitKey splits a composite key string by the given delimiter. Teams use different delimiters (#, |, ::, etc.) so the delimiter is a parameter.

func Unmarshal

func Unmarshal(item map[string]AttributeValue, out any) error

Unmarshal decodes a DynamoDB item (map[string]AttributeValue) into the struct pointed to by out. out must be a non-nil pointer to a struct.

func UpdateReturning

func UpdateReturning[T any](ctx context.Context, t *Table, key KeyValue, opts ...UpdateOption) (T, error)

UpdateReturning applies update expressions to the item identified by key and returns the item (either before or after the update depending on ReturnNew/ReturnOld). At least one of ReturnNew() or ReturnOld() must be provided; otherwise ErrValidation is returned.

Types

type AttributeType

type AttributeType int

AttributeType identifies which variant of AttributeValue is populated.

const (
	TypeS    AttributeType = iota + 1 // String
	TypeN                             // Number (stored as string)
	TypeB                             // Binary
	TypeBOOL                          // Boolean
	TypeNULL                          // Null
	TypeL                             // List
	TypeM                             // Map
	TypeSS                            // String Set
	TypeNS                            // Number Set
	TypeBS                            // Binary Set
)

type AttributeValue

type AttributeValue struct {
	Type AttributeType

	S    string
	N    string // DynamoDB numbers are transmitted as strings
	B    []byte
	BOOL bool
	NULL bool
	L    []AttributeValue
	M    map[string]AttributeValue
	SS   []string
	NS   []string
	BS   [][]byte
}

AttributeValue is a library-owned sum type representing a DynamoDB attribute value. Exactly one typed field is populated, identified by Type.

type Backend

Backend is the interface that must be implemented by any DynamoDB backend (e.g. AWS SDK adapter, in-memory test backend). All request and response types are library-owned — no AWS SDK types leak through this interface.

type BatchGetItemRequest

type BatchGetItemRequest struct {
	RequestItems map[string]KeysAndProjection
}

BatchGetItemRequest describes a BatchGetItem operation.

type BatchGetItemResponse

type BatchGetItemResponse struct {
	Responses        map[string][]map[string]AttributeValue
	UnprocessedKeys  map[string]KeysAndProjection
	ConsumedCapacity []ConsumedCapacity
}

BatchGetItemResponse is the result of a BatchGetItem operation. UnprocessedKeys contains keys that were not processed due to throughput limits.

type BatchGetOption

type BatchGetOption func(*batchGetConfig)

BatchGetOption configures a BatchGet call.

func BatchGetProject

func BatchGetProject(attrs ...string) BatchGetOption

BatchGetProject specifies which attributes to retrieve in a BatchGet.

type BatchOption

type BatchOption func(*batchConfig)

BatchOption configures batch write operations.

func MaxConcurrency

func MaxConcurrency(n int) BatchOption

MaxConcurrency sets the maximum number of concurrent chunk requests. Default is 1 (sequential).

func OnProgress

func OnProgress(fn func(completed, total int)) BatchOption

OnProgress sets a callback that is invoked after each chunk completes. The callback receives the cumulative number of completed items and the total.

type BatchWriteItemRequest

type BatchWriteItemRequest struct {
	RequestItems map[string][]WriteRequest
}

BatchWriteItemRequest describes a BatchWriteItem operation.

type BatchWriteItemResponse

type BatchWriteItemResponse struct {
	UnprocessedItems map[string][]WriteRequest
	ConsumedCapacity []ConsumedCapacity
}

BatchWriteItemResponse is the result of a BatchWriteItem operation. UnprocessedItems contains requests that were not processed due to throughput limits.

type Collection

type Collection struct {
	// contains filtered or unexported fields
}

Collection holds a heterogeneous set of items unmarshaled via a Registry.

func QueryCollection

func QueryCollection(ctx context.Context, t *Table, key KeyCondition, opts ...QueryOption) (*Collection, error)

QueryCollection executes a DynamoDB Query and unmarshals items polymorphically using the table's Registry. Items with unrecognized discriminators are silently skipped. Returns an error if the table has no registry.

type ConsumedCapacity

type ConsumedCapacity struct {
	TableName          string
	CapacityUnits      float64
	ReadCapacityUnits  float64
	WriteCapacityUnits float64
}

ConsumedCapacity reports the capacity units consumed by an operation.

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB is the top-level handle for interacting with DynamoDB through a Backend. Create one with New and then call DB.Table to bind to a specific table.

func New

func New(backend Backend, opts ...Option) *DB

New creates a new DB with the given backend and options.

func (*DB) Table

func (db *DB) Table(name string, opts ...TableOption) *Table

Table creates a Table reference that uses the DB's backend.

type DeleteItemRequest

type DeleteItemRequest struct {
	TableName                 string
	Key                       map[string]AttributeValue
	ConditionExpression       string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
	ReturnValues              string
}

DeleteItemRequest describes a DeleteItem operation.

type DeleteItemResponse

type DeleteItemResponse struct {
	ConsumedCapacity *ConsumedCapacity
}

DeleteItemResponse is the result of a DeleteItem operation.

type DeleteOption

type DeleteOption func(*deleteConfig)

DeleteOption configures a Delete operation.

func DeleteCondition

func DeleteCondition(expression string, vals ...any) DeleteOption

DeleteCondition adds an arbitrary condition expression to the Delete operation. Placeholders (?) in the expression are replaced with the provided values.

type DeleteRequest

type DeleteRequest struct {
	Key map[string]AttributeValue
}

DeleteRequest is the delete-item payload within a WriteRequest.

type Entity

type Entity interface {
	DynagoEntity() EntityInfo
}

Entity is the interface that entity types must implement for polymorphic support.

type EntityInfo

type EntityInfo struct {
	Discriminator string
}

EntityInfo holds metadata about an entity type for single-table design.

type Error

type Error struct {
	Sentinel error
	Cause    error
	Message  string
}

Error is a dynago error that wraps a sentinel and an optional cause.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(target error) bool

func (*Error) Unwrap

func (e *Error) Unwrap() error

type GetItemRequest

type GetItemRequest struct {
	TableName                string
	Key                      map[string]AttributeValue
	ConsistentRead           bool
	ProjectionExpression     string
	ExpressionAttributeNames map[string]string
}

GetItemRequest describes a GetItem operation.

type GetItemResponse

type GetItemResponse struct {
	Item             map[string]AttributeValue
	ConsumedCapacity *ConsumedCapacity
}

GetItemResponse is the result of a GetItem operation. Item is nil when the key does not exist.

type GetOption

type GetOption func(*getConfig)

GetOption configures a Get[T] call.

func ConsistentRead

func ConsistentRead() GetOption

ConsistentRead requests a strongly consistent read.

func Project

func Project(attrs ...string) GetOption

Project specifies which attributes to retrieve. Each attr is a top-level attribute name; nested paths are not yet supported here.

type KeyCondition

type KeyCondition struct {
	// contains filtered or unexported fields
}

KeyCondition describes the partition key (required) and optional sort key condition for a Query operation.

func Partition

func Partition(attr string, val any) KeyCondition

Partition creates a KeyCondition requiring that attr equals val.

func (KeyCondition) SortBeginsWith

func (kc KeyCondition) SortBeginsWith(attr string, prefix any) KeyCondition

SortBeginsWith adds a begins_with condition on the sort key.

func (KeyCondition) SortBetween

func (kc KeyCondition) SortBetween(attr string, low, high any) KeyCondition

SortBetween adds a BETWEEN condition on the sort key.

func (KeyCondition) SortEquals

func (kc KeyCondition) SortEquals(attr string, val any) KeyCondition

SortEquals adds an equality condition on the sort key.

func (KeyCondition) SortGreaterOrEqual

func (kc KeyCondition) SortGreaterOrEqual(attr string, val any) KeyCondition

SortGreaterOrEqual adds a >= condition on the sort key.

func (KeyCondition) SortGreaterThan

func (kc KeyCondition) SortGreaterThan(attr string, val any) KeyCondition

SortGreaterThan adds a > condition on the sort key.

func (KeyCondition) SortLessOrEqual

func (kc KeyCondition) SortLessOrEqual(attr string, val any) KeyCondition

SortLessOrEqual adds a <= condition on the sort key.

func (KeyCondition) SortLessThan

func (kc KeyCondition) SortLessThan(attr string, val any) KeyCondition

SortLessThan adds a < condition on the sort key.

type KeyValue

type KeyValue struct {
	// contains filtered or unexported fields
}

KeyValue is an opaque type that resolves to map[string]AttributeValue internally. Use the Key(), StringKey(), or StringPairKey() helpers to construct values.

func Key

func Key(pairs ...any) KeyValue

Key builds a KeyValue from pairs of (attributeName, value). It accepts exactly 2 arguments (hash key only) or 4 arguments (hash + range).

Supported value types:

  • string → AttributeValue{Type: TypeS}
  • int, int64, float64, uint, uint64 → AttributeValue{Type: TypeN}
  • []byte → AttributeValue{Type: TypeB}

Key panics on invalid input (wrong argument count, non-string attribute name, or unsupported value type). This follows the same convention as regexp.MustCompile — key construction is a programmer error.

For the highest performance in hot paths, prefer StringKey or StringPairKey when all key values are strings.

func StringKey

func StringKey(name, val string) KeyValue

StringKey builds a KeyValue with a single string hash key. This is the zero-allocation fast path for the most common case.

func StringPairKey

func StringPairKey(hashName, hashVal, rangeName, rangeVal string) KeyValue

StringPairKey builds a KeyValue with a string hash key and a string range key. This is the zero-allocation fast path for the most common composite key case.

func (KeyValue) Map

func (kv KeyValue) Map() map[string]AttributeValue

Map returns the underlying attribute map. This is used internally by operations that need to pass the key to a Backend.

type KeysAndProjection

type KeysAndProjection struct {
	Keys                     []map[string]AttributeValue
	ProjectionExpression     string
	ExpressionAttributeNames map[string]string
	ConsistentRead           bool
}

KeysAndProjection groups keys and an optional projection for a single table in a BatchGetItem request.

type LogOption

type LogOption func(*logConfig)

LogOption configures the logging middleware.

func LogSlowOperations

func LogSlowOperations(threshold time.Duration) LogOption

LogSlowOperations sets the threshold above which operations are logged at WARN level.

type Marshaler

type Marshaler interface {
	MarshalDynamo() (AttributeValue, error)
}

Marshaler is implemented by types that can marshal themselves into a DynamoDB AttributeValue.

type Middleware

type Middleware func(Backend) Backend

Middleware wraps a Backend to add cross-cutting concerns such as logging, tracing, or metrics. See LoggingMiddleware and the dynagotel package.

func LoggingMiddleware

func LoggingMiddleware(logger *slog.Logger, opts ...LogOption) Middleware

LoggingMiddleware returns a Middleware that logs every Backend operation using the provided slog.Logger. All operations are logged at DEBUG level. If a slow threshold is set via LogSlowOperations, operations exceeding that threshold are additionally logged at WARN level.

type Option

type Option func(*DB)

Option configures a DB instance.

func WithMiddleware

func WithMiddleware(m ...Middleware) Option

WithMiddleware returns an Option that wraps the DB's backend with the given middleware. Middleware is applied in order: the last middleware becomes the outermost wrapper.

type PutItemRequest

type PutItemRequest struct {
	TableName                 string
	Item                      map[string]AttributeValue
	ConditionExpression       string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
	ReturnValues              string
}

PutItemRequest describes a PutItem operation.

type PutItemResponse

type PutItemResponse struct {
	ConsumedCapacity *ConsumedCapacity
}

PutItemResponse is the result of a PutItem operation.

type PutOption

type PutOption func(*putConfig)

PutOption configures a Put operation.

func IfNotExists

func IfNotExists(attr string) PutOption

IfNotExists adds a condition that the item must not already exist. The attr parameter is the attribute name to check (typically the partition key).

func PutCondition

func PutCondition(expression string, vals ...any) PutOption

PutCondition adds an arbitrary condition expression to the Put operation. Placeholders (?) in the expression are replaced with the provided values.

type PutRequest

type PutRequest struct {
	Item map[string]AttributeValue
}

PutRequest is the put-item payload within a WriteRequest.

type QueryOption

type QueryOption func(*queryConfig)

QueryOption configures a Query operation.

func QueryConsistentRead

func QueryConsistentRead() QueryOption

QueryConsistentRead requests a strongly consistent read.

func QueryFilter

func QueryFilter(expression string, vals ...any) QueryOption

QueryFilter adds a filter expression to the query.

func QueryIndex

func QueryIndex(name string) QueryOption

QueryIndex specifies a secondary index to query.

func QueryLimit

func QueryLimit(n int) QueryOption

QueryLimit sets the maximum number of items to return across all pages.

func QueryProject

func QueryProject(attrs ...string) QueryOption

QueryProject specifies which attributes to retrieve.

func ScanForward

func ScanForward(forward bool) QueryOption

ScanForward sets the scan direction. True for ascending (default), false for descending.

type QueryRequest

type QueryRequest struct {
	TableName                 string
	IndexName                 string
	KeyConditionExpression    string
	FilterExpression          string
	ProjectionExpression      string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
	Limit                     int32
	ScanIndexForward          *bool
	ExclusiveStartKey         map[string]AttributeValue
	ConsistentRead            bool
}

QueryRequest describes a Query operation.

type QueryResponse

type QueryResponse struct {
	Items            []map[string]AttributeValue
	Count            int32
	ScannedCount     int32
	LastEvaluatedKey map[string]AttributeValue
	ConsumedCapacity *ConsumedCapacity
}

QueryResponse is the result of a Query operation. LastEvaluatedKey is non-nil when more pages are available.

type RMWOption

type RMWOption func(*rmwConfig)

RMWOption configures a ReadModifyWrite call.

func MaxRetries

func MaxRetries(n int) RMWOption

MaxRetries sets the maximum number of retry attempts on condition check failure. Default is 3.

func OptimisticLock

func OptimisticLock(versionAttr string) RMWOption

OptimisticLock enables optimistic locking using the given attribute as a version counter. The attribute must be a numeric field on the struct.

type ReadTxBuilder

type ReadTxBuilder struct {
	// contains filtered or unexported fields
}

ReadTxBuilder accumulates operations for a DynamoDB TransactGetItems call.

func ReadTx

func ReadTx(ctx context.Context, db *DB) *ReadTxBuilder

ReadTx creates a new read transaction builder.

func (*ReadTxBuilder) Get

func (b *ReadTxBuilder) Get(t *Table, key KeyValue, opts ...GetOption) *ReadTxBuilder

Get adds a get operation to the transaction.

func (*ReadTxBuilder) Run

func (b *ReadTxBuilder) Run() (*ReadTxResult, error)

Run executes the read transaction.

type ReadTxResult

type ReadTxResult struct {
	// contains filtered or unexported fields
}

ReadTxResult holds the response from a read transaction.

func (*ReadTxResult) Item

func (r *ReadTxResult) Item(index int) (map[string]AttributeValue, bool)

Item returns the raw item at the given index. If the index is out of range or the item is nil/empty, ok is false.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry maps discriminator strings to concrete Go types for polymorphic unmarshaling in single-table designs.

func NewRegistry

func NewRegistry(discriminatorAttr string) *Registry

NewRegistry creates a new Registry that uses the given attribute name as the discriminator field in DynamoDB items.

func (*Registry) DiscriminatorAttr

func (r *Registry) DiscriminatorAttr() string

DiscriminatorAttr returns the attribute name used as the discriminator.

func (*Registry) Lookup

func (r *Registry) Lookup(discriminator string) (reflect.Type, bool)

Lookup returns the reflect.Type registered for the given discriminator. The second return value is false if no type is registered.

func (*Registry) Register

func (r *Registry) Register(e Entity)

Register adds the Entity's concrete type to the registry, keyed by its discriminator value. It panics if another type is already registered with the same discriminator.

type ScanOption

type ScanOption func(*scanConfig)

ScanOption configures a Scan operation.

func ScanConsistentRead

func ScanConsistentRead() ScanOption

ScanConsistentRead requests a strongly consistent read.

func ScanFilter

func ScanFilter(expression string, vals ...any) ScanOption

ScanFilter adds a filter expression to the scan.

func ScanIndex

func ScanIndex(name string) ScanOption

ScanIndex specifies a secondary index to scan.

func ScanLimit

func ScanLimit(n int) ScanOption

ScanLimit sets the maximum number of items to return across all pages.

func ScanProject

func ScanProject(attrs ...string) ScanOption

ScanProject specifies which attributes to retrieve.

type ScanRequest

type ScanRequest struct {
	TableName                 string
	IndexName                 string
	FilterExpression          string
	ProjectionExpression      string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
	Limit                     int32
	ExclusiveStartKey         map[string]AttributeValue
	ConsistentRead            bool
}

ScanRequest describes a Scan operation.

type ScanResponse

type ScanResponse struct {
	Items            []map[string]AttributeValue
	Count            int32
	ScannedCount     int32
	LastEvaluatedKey map[string]AttributeValue
	ConsumedCapacity *ConsumedCapacity
}

ScanResponse is the result of a Scan operation. LastEvaluatedKey is non-nil when more pages are available.

type Table

type Table struct {
	// contains filtered or unexported fields
}

Table represents a single DynamoDB table bound to the DB's backend. Use DB.Table to create one and pass it to operations such as Get, Query, and Table.Put.

func (*Table) Backend

func (t *Table) Backend() Backend

Backend returns the table's backend. This is used internally by free functions such as Get[T] and Query[T].

func (*Table) BatchDelete

func (t *Table) BatchDelete(ctx context.Context, keys []KeyValue, opts ...BatchOption) error

BatchDelete deletes multiple items by key in batches of 25.

func (*Table) BatchPut

func (t *Table) BatchPut(ctx context.Context, items []any, opts ...BatchOption) error

BatchPut writes multiple items in batches of 25. It retries unprocessed items with exponential backoff and reports progress via OnProgress.

func (*Table) Delete

func (t *Table) Delete(ctx context.Context, key KeyValue, opts ...DeleteOption) error

Delete removes the item identified by the given key from the table. Options such as DeleteCondition can be used to add condition expressions.

func (*Table) Name

func (t *Table) Name() string

Name returns the table's DynamoDB table name.

func (*Table) Put

func (t *Table) Put(ctx context.Context, item any, opts ...PutOption) error

Put marshals the given item and stores it in the table. Options such as IfNotExists and PutCondition can be used to add condition expressions.

func (*Table) Registry

func (t *Table) Registry() *Registry

Registry returns the table's Registry, or nil if none is set.

func (*Table) Update

func (t *Table) Update(ctx context.Context, key KeyValue, opts ...UpdateOption) error

Update applies update expressions to the item identified by key. It does not return the updated item; use UpdateReturning[T] if you need the result.

type TableOption

type TableOption func(*Table)

TableOption configures a Table instance.

func WithRegistry

func WithRegistry(r *Registry) TableOption

WithRegistry attaches a Registry to the table for polymorphic support.

type TransactConditionCheck

type TransactConditionCheck struct {
	TableName                 string
	Key                       map[string]AttributeValue
	ConditionExpression       string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
}

TransactConditionCheck is a condition-only check within a write transaction. It verifies a condition without modifying any data.

type TransactDelete

type TransactDelete struct {
	TableName                 string
	Key                       map[string]AttributeValue
	ConditionExpression       string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
}

TransactDelete is a delete operation within a write transaction.

type TransactGetItem

type TransactGetItem struct {
	TableName                string
	Key                      map[string]AttributeValue
	ProjectionExpression     string
	ExpressionAttributeNames map[string]string
}

TransactGetItem is a single get within a read transaction.

type TransactGetItemsRequest

type TransactGetItemsRequest struct {
	TransactItems []TransactGetItem
}

TransactGetItemsRequest describes a TransactGetItems operation.

type TransactGetItemsResponse

type TransactGetItemsResponse struct {
	Responses        []map[string]AttributeValue
	ConsumedCapacity []ConsumedCapacity
}

TransactGetItemsResponse is the result of a TransactGetItems operation. Responses are ordered to match the input TransactItems.

type TransactPut

type TransactPut struct {
	TableName                 string
	Item                      map[string]AttributeValue
	ConditionExpression       string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
}

TransactPut is a put operation within a write transaction.

type TransactUpdate

type TransactUpdate struct {
	TableName                 string
	Key                       map[string]AttributeValue
	UpdateExpression          string
	ConditionExpression       string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
}

TransactUpdate is an update operation within a write transaction.

type TransactWriteItem

type TransactWriteItem struct {
	Put            *TransactPut
	Delete         *TransactDelete
	Update         *TransactUpdate
	ConditionCheck *TransactConditionCheck
}

TransactWriteItem is a single operation within a write transaction. Exactly one of Put, Delete, Update, or ConditionCheck must be set.

type TransactWriteItemsRequest

type TransactWriteItemsRequest struct {
	TransactItems []TransactWriteItem
}

TransactWriteItemsRequest describes a TransactWriteItems operation.

type TransactWriteItemsResponse

type TransactWriteItemsResponse struct {
	ConsumedCapacity []ConsumedCapacity
}

TransactWriteItemsResponse is the result of a TransactWriteItems operation.

type TxCancelReason

type TxCancelReason struct {
	Code    string
	Message string
}

TxCancelReason describes why a single operation within a transaction was cancelled.

func TxCancelReasons

func TxCancelReasons(err error) []TxCancelReason

TxCancelReasons extracts the per-operation cancellation reasons from err. It returns nil if err is not a TxCancelledError.

type TxCancelledError

type TxCancelledError struct {
	Reasons []TxCancelReason
}

TxCancelledError is returned when a DynamoDB transaction is cancelled. It contains per-operation failure reasons.

func (*TxCancelledError) Error

func (e *TxCancelledError) Error() string

Error returns a human-readable description of the cancelled transaction.

func (*TxCancelledError) Is

func (e *TxCancelledError) Is(target error) bool

Is reports whether this error matches target. It matches ErrTransactionCancelled and ErrConditionFailed (when at least one reason has code "ConditionalCheckFailed").

type Unmarshaler

type Unmarshaler interface {
	UnmarshalDynamo(AttributeValue) error
}

Unmarshaler is implemented by types that can unmarshal an AttributeValue into themselves.

type UpdateItemRequest

type UpdateItemRequest struct {
	TableName                 string
	Key                       map[string]AttributeValue
	UpdateExpression          string
	ConditionExpression       string
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues map[string]AttributeValue
	ReturnValues              string
}

UpdateItemRequest describes an UpdateItem operation.

type UpdateItemResponse

type UpdateItemResponse struct {
	Attributes       map[string]AttributeValue
	ConsumedCapacity *ConsumedCapacity
}

UpdateItemResponse is the result of an UpdateItem operation. Attributes is populated when ReturnValues is set.

type UpdateOption

type UpdateOption func(*updateConfig)

UpdateOption configures an Update or UpdateReturning call.

func Add

func Add(attr string, val any) UpdateOption

Add adds an ADD action. For numbers this increments; for sets this unions.

func Delete

func Delete(attr string, val any) UpdateOption

Delete adds a DELETE action that removes elements from a set attribute.

func IfCondition

func IfCondition(expression string, vals ...any) UpdateOption

IfCondition adds a condition expression for the update. Placeholders (?) in the expression are replaced with the provided values.

func Remove

func Remove(attr string) UpdateOption

Remove adds a REMOVE action that deletes the given attribute.

func ReturnNew

func ReturnNew() UpdateOption

ReturnNew requests that the updated item (after the update) is returned.

func ReturnOld

func ReturnOld() UpdateOption

ReturnOld requests that the item (before the update) is returned.

func Set

func Set(attr string, val any) UpdateOption

Set adds a SET action that assigns val to the given attribute.

type WriteRequest

type WriteRequest struct {
	PutItem    *PutRequest
	DeleteItem *DeleteRequest
}

WriteRequest is a single put or delete within a BatchWriteItem call. Exactly one of PutItem or DeleteItem must be set.

type WriteTxBuilder

type WriteTxBuilder struct {
	// contains filtered or unexported fields
}

WriteTxBuilder accumulates operations for a DynamoDB TransactWriteItems call.

func WriteTx

func WriteTx(ctx context.Context, db *DB) *WriteTxBuilder

WriteTx creates a new write transaction builder.

func (*WriteTxBuilder) Check

func (b *WriteTxBuilder) Check(t *Table, key KeyValue, condition string, vals ...any) *WriteTxBuilder

Check adds a condition check (no data modification) to the transaction.

func (*WriteTxBuilder) Delete

func (b *WriteTxBuilder) Delete(t *Table, key KeyValue, opts ...DeleteOption) *WriteTxBuilder

Delete adds a delete operation to the transaction.

func (*WriteTxBuilder) Put

func (b *WriteTxBuilder) Put(t *Table, item any, opts ...PutOption) *WriteTxBuilder

Put adds a put operation to the transaction. The item is marshalled and optional conditions are applied.

func (*WriteTxBuilder) Run

func (b *WriteTxBuilder) Run() error

Run executes the write transaction.

func (*WriteTxBuilder) Update

func (b *WriteTxBuilder) Update(t *Table, key KeyValue, opts ...UpdateOption) *WriteTxBuilder

Update adds an update operation to the transaction.

Directories

Path Synopsis
Package awsbackend provides a dynago.Backend implementation backed by the AWS SDK for Go v2.
Package awsbackend provides a dynago.Backend implementation backed by the AWS SDK for Go v2.
Package dynagotest provides test helpers for the dynago DynamoDB library.
Package dynagotest provides test helpers for the dynago DynamoDB library.
Package internal contains shared helpers for the dynago library.
Package internal contains shared helpers for the dynago library.
expr
Package expr defines the expression AST used to represent DynamoDB condition, filter, projection, and update expressions.
Package expr defines the expression AST used to represent DynamoDB condition, filter, projection, and update expressions.
Package memdb provides an in-memory implementation of the dynago.Backend interface for testing.
Package memdb provides an in-memory implementation of the dynago.Backend interface for testing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL