dynamobind

package
v0.2.9 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package dynamobind provides typed, reflection-free DynamoDB item binding on top of github.com/shibukawa/tinygodriver/nosql/dynamodb.

A struct declares its attributes once with dynamo tags, tinybind-gen emits the codec, and the call site never handles a map[string]dynamodb.AttributeValue:

type Reading struct {
	Sensor  string  `dynamo:"sensor,partitionkey"`
	At      int64   `dynamo:"at,sortkey"`
	Celsius float64 `dynamo:"celsius"`
}

got, err := dynamobind.Load[Reading](ctx, client, "readings", want.ItemKey())

Dispatch is by type constraint rather than by a registry, so a type without generated code fails to compile instead of failing at run time on a missing registration. Nothing here reflects on application fields.

What this package does not do

It adds no retry loop: the driver already retries with backoff, and a second loop would multiply the delivery count silently. It hides no page boundary: Query and Scan iterate, but QueryPage stays public and returns LastEvaluatedKey. It swallows no error: every driver sentinel survives errors.Is and *dynamodb.Error survives errors.As through every helper here.

Index

Constants

View Source
const (
	MaxBatchWrite = 25
	MaxBatchGet   = 100
)

DynamoDB's per-request batch limits. They are fixed by the service, so the chunking that respects them is mechanical and belongs here rather than in generated code. The size limits, 16 MB per request and 400 KB per item, are properties of the data rather than of the type, so nothing at generation time could bound them; an oversized request surfaces as dynamodb.ErrRequestTooLarge.

Variables

This section is empty.

Functions

func Load

func Load[T any, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table string, key dynamodb.Key, opts ...dynamodb.GetOption) (T, error)

Load reads one item by key and decodes it into T.

A key that matches nothing keeps the driver's dynamodb.ErrItemNotFound rather than returning a zero value, so a miss cannot be mistaken for an empty item.

func LoadAll

func LoadAll[T any, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table string, keys []dynamodb.Key, opts ...dynamodb.BatchOption) ([]T, []dynamodb.Key, error)

LoadAll reads every key, splitting the input into requests of at most MaxBatchGet keys.

DynamoDB does not promise to return batch items in request order, and a key that matches nothing is simply absent rather than an error, so len(items) can be smaller than len(keys) with no error and no unprocessed key. Keys DynamoDB declined to read come back in unprocessed, unretried.

func Query

func Query[T any, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table, keyCond string, opts ...dynamodb.QueryOption) iter.Seq2[T, error]

Query iterates every item of a query, requesting pages as the range advances.

One range can issue many requests. The iterator reports no page boundary, no Count, no ScannedCount, and no final LastEvaluatedKey, so a query that scans far more than it returns looks the same as one that does not, and an interrupted run cannot be resumed. Use QueryPage when any of that matters.

Iteration stops at the first error, which is yielded once with the zero value of T. A break stops it without issuing a further request.

func Remove

func Remove[T Keyer](ctx context.Context, c *dynamodb.Client, table string, v T, opts ...dynamodb.WriteOption) error

Remove deletes the item identified by v's key. Only the key of v is read.

func RemoveReturning

func RemoveReturning[T Keyer, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table string, v T, opts ...dynamodb.WriteOption) (T, bool, error)

RemoveReturning is Remove, and also decodes the item it deleted.

The bool is false when the key held no item, which is not an error.

func Scan

func Scan[T any, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table string, opts ...dynamodb.ScanOption) iter.Seq2[T, error]

Scan iterates every item of a table or index scan.

An unfiltered scan walks the whole table, one page per request. Everything said about Query's hidden request count applies here and costs more.

func Store

func Store[T ItemEncoder](ctx context.Context, c *dynamodb.Client, table string, v T, opts ...dynamodb.WriteOption) error

Store writes v as a whole item, replacing any item with the same key.

It is PutItem, not a partial update: every attribute of the stored item comes from v. Use Update for a partial change.

func StoreAll

func StoreAll[T ItemEncoder](ctx context.Context, c *dynamodb.Client, table string, vs []T) ([]T, error)

StoreAll writes every value, splitting the input into requests of at most MaxBatchWrite items.

What DynamoDB declined comes back in unprocessed, unretried: the driver already retries the transport, and whether a partial success is worth a second attempt is the caller's decision, not this package's. Passing unprocessed back to StoreAll is the retry, and it belongs in caller code where a backoff can live.

func StoreReturning

func StoreReturning[T ItemEncoder, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table string, v T, opts ...dynamodb.WriteOption) (T, bool, error)

StoreReturning is Store, and also decodes the item it replaced.

The bool is false when the key held no item, which is not an error. It asks the driver for ALL_OLD, so it costs a write capacity unit more than Store on a table that charges for it.

func TypeError

func TypeError(attribute, expected string, got dynamodb.AttributeValue) error

TypeError reports an attribute whose stored kind is not the one the field needs. Generated decoders call it.

func Update

func Update[T Keyer](ctx context.Context, c *dynamodb.Client, table string, v T, update string, opts ...dynamodb.WriteOption) error

Update applies a DynamoDB update expression to the item identified by v's key.

The expression is passed to the driver verbatim; nothing here generates or validates it. Only the key is typed, which is the part a struct tag can actually supply. Attribute values in the expression come from dynamodb.WithExpressionValues as usual:

err := dynamobind.Update(ctx, c, "readings", key, "SET celsius = :c",
	dynamodb.WithExpressionValues(map[string]dynamodb.AttributeValue{":c": dynamodb.N(21.5)}))

func ValueError

func ValueError(attribute, message string, cause error) error

ValueError reports an attribute whose kind is right but whose value cannot be represented by the field, such as a number too large for the Go type. Generated decoders call it.

Types

type Error

type Error struct {
	// Attribute is the attribute that failed, or "" for a whole-item failure.
	Attribute string
	// Expected and Got name attribute kinds, such as "S" or "N".
	Expected string
	Got      string
	Message  string
	// contains filtered or unexported fields
}

Error describes an item mapping failure. Attribute names the attribute that failed, which is the DynamoDB name rather than the Go field name, because that is the name the stored data uses.

func AsError

func AsError(err error) (*Error, bool)

AsError finds a dynamobind Error in a chain without errors.As, which needs reflection. Whether reflect is linked at all is the driver's business, not this package's.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ItemDecoder

type ItemDecoder interface {
	DecodeItem(item dynamodb.Item) error
}

ItemDecoder fills a value from a DynamoDB item. Generated code implements it on the pointer receiver.

type ItemEncoder

type ItemEncoder interface {
	EncodeItem() dynamodb.Item
}

ItemEncoder converts a value into a DynamoDB item. Generated code implements it on the value receiver.

type Keyer

type Keyer interface {
	ItemKey() dynamodb.Key
}

Keyer reports the primary key of a value. Generated code implements it when the type carries a partitionkey tag.

type Page

type Page[T any] struct {
	Items            []T
	LastEvaluatedKey dynamodb.Key
	Count            int
	ScannedCount     int
}

Page is one page of decoded items.

LastEvaluatedKey is the continuation and is the authority on whether more pages follow: a non-nil key means more, whatever Count says, because a filter can empty a page that still has a successor.

func QueryPage

func QueryPage[T any, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table, keyCond string, opts ...dynamodb.QueryOption) (Page[T], error)

QueryPage runs one Query and decodes its page.

This is the form that keeps the request count visible: one call is one request. Query iterates instead, at the cost of hiding how many requests that takes.

func ScanPage

func ScanPage[T any, PT interface {
	*T
	ItemDecoder
}](ctx context.Context, c *dynamodb.Client, table string, opts ...dynamodb.ScanOption) (Page[T], error)

ScanPage runs one Scan and decodes its page.

func (Page[T]) HasMore

func (p Page[T]) HasMore() bool

HasMore reports whether another page follows this one.

Jump to

Keyboard shortcuts

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