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
- func Load[T any, PT interface{ ... }](ctx context.Context, c *dynamodb.Client, table string, key dynamodb.Key, ...) (T, error)
- func LoadAll[T any, PT interface{ ... }](ctx context.Context, c *dynamodb.Client, table string, keys []dynamodb.Key, ...) ([]T, []dynamodb.Key, error)
- func Query[T any, PT interface{ ... }](ctx context.Context, c *dynamodb.Client, table, keyCond string, ...) iter.Seq2[T, error]
- func Remove[T Keyer](ctx context.Context, c *dynamodb.Client, table string, v T, ...) error
- func RemoveReturning[T Keyer, PT interface{ ... }](ctx context.Context, c *dynamodb.Client, table string, v T, ...) (T, bool, error)
- func Scan[T any, PT interface{ ... }](ctx context.Context, c *dynamodb.Client, table string, ...) iter.Seq2[T, error]
- func Store[T ItemEncoder](ctx context.Context, c *dynamodb.Client, table string, v T, ...) error
- func StoreAll[T ItemEncoder](ctx context.Context, c *dynamodb.Client, table string, vs []T) ([]T, error)
- func StoreReturning[T ItemEncoder, PT interface{ ... }](ctx context.Context, c *dynamodb.Client, table string, v T, ...) (T, bool, error)
- func TypeError(attribute, expected string, got dynamodb.AttributeValue) error
- func Update[T Keyer](ctx context.Context, c *dynamodb.Client, table string, v T, update string, ...) error
- func ValueError(attribute, message string, cause error) error
- type Error
- type ItemDecoder
- type ItemEncoder
- type Keyer
- type Page
Constants ¶
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 ¶
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.
type ItemDecoder ¶
ItemDecoder fills a value from a DynamoDB item. Generated code implements it on the pointer receiver.
type ItemEncoder ¶
ItemEncoder converts a value into a DynamoDB item. Generated code implements it on the value receiver.
type Keyer ¶
Keyer reports the primary key of a value. Generated code implements it when the type carries a partitionkey tag.
type Page ¶
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.