dynamo

package
v0.5.7 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package dynamo opens the application's DynamoDB client from configuration and keeps it as process state every operation reaches through Handle.

Importing it registers the [middleware.dynamo] binding, so a project that does not use DynamoDB gains no configuration key and links no driver:

import _ "github.com/shibukawa/popcornweb/database/dynamo"

It wraps no operation. There is no database/sql here to hide three engines behind, so a handler calls tinybind's dynamobind directly, handing it the process handle. A generated .pw.dynamo query resolves the same handle itself, so its call sites stay context-only:

h, err := dynamo.Handle(ctx)
reading, err := h.Load[Reading](ctx, "reading", key)
for reading, err := range records.ReadingsSince(ctx, sensor, from) { ... }

The client is a deployment fact fixed for a process, so nothing is installed into request contexts: no context.Value stands between a call site and the client.

Table names in source are the declared ones. The deployed name comes from the configured prefix or mapping, carried by the handle and applied inside the runtime entry, so no call site builds a deployed name.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Client

func Client(ctx context.Context) (*dynamodb.Client, error)

Client returns the process client, for an operation dynamobind does not wrap.

Reach for this only when calling the driver directly; everything dynamobind wraps takes the whole Handle instead, which also carries the table naming.

func EnsureClient

func EnsureClient(ctx context.Context) (context.Context, bool)

EnsureClient returns a context on which dynamobind's context-form entries resolve the process client, reporting false when none can be reached.

A pw call site does not need it: Handle reads the process state directly, so neither a request context nor a setup context carries a client node. It remains for code handing a context to something that still calls the context-form dynamobind entries. A context that already carries a client is returned unchanged.

func Handle

func Handle(ctx context.Context) (dynamobind.Handle, error)

Handle returns the DynamoDB client bound to the deployed table naming, which is what the "On"-suffixed dynamobind entries take and what every generated .pw.dynamo query resolves through.

The client is a deployment fact fixed for a process, so the common path reads process state and walks no context chain. When the process holds no client — a unit test building its own context, or a tool running without this extension — a handle installed with dynamobind.WithClient or WithHandle is honoured instead.

func RegisterTable

func RegisterTable(declared string, factory TableFactory)

RegisterTable records the definition of one declared table. Generated code registers an application table and an imported framework package registers its own, so the desired schema is exactly what the binary links.

Registering the same declared name twice is a programming error rather than a configuration one: two definitions of one table cannot both be right.

Types

type Change

type Change string

Change is what one table needs, decided by comparing the registered definition against what the account reports.

const (
	// ChangeNone means the deployed table already matches.
	ChangeNone Change = "none"
	// ChangeCreate means the table is absent.
	ChangeCreate Change = "create"
	// ChangeMismatch means the table exists with a key schema this build does
	// not expect. DynamoDB cannot alter a key, so it is reported and never
	// performed.
	ChangeMismatch Change = "mismatch"
)

type Config

type Config struct {
	// Enabled opens the client and installs the middleware.
	Enabled bool `toml:"enabled" help:"Enabled opens the client and installs the middleware"`
	// Region names the AWS region. Empty falls back to the environment, and a
	// region resolvable from neither is a startup error.
	Region string `` /* 142-byte string literal not displayed */
	// Endpoint overrides the regional host, which is how a local emulator is
	// reached.
	Endpoint string `toml:"endpoint" help:"Endpoint overrides the regional host, which is how a local emulator is reached"`
	// AccessKeyID and its siblings are static credentials. All three are
	// optional; empty selects the driver's environment credentials.
	//
	// All three are masked by tag. They were masked before only because their
	// names happen to contain tokens the binder's name heuristic looks for,
	// which is a coincidence rather than a decision: renaming a field would have
	// silently started printing it.
	AccessKeyID     string `` /* 169-byte string literal not displayed */
	SecretAccessKey string `secret:"mask" toml:"secret_access_key"`
	SessionToken    string `secret:"mask" toml:"session_token"`
	// TablePrefix is prepended to a declared table name.
	TablePrefix string `toml:"table_prefix" help:"TablePrefix is prepended to a declared table name"`
	// TableNames maps a declared name onto a deployed one, for a name no
	// prefix produces. An entry wins over the prefix.
	//
	// It is an array of tables rather than a map because configbind binds no
	// map type, and because that is the form middleware.rdb.connections
	// already uses for a repeated element.
	TableNames []TableName `` /* 139-byte string literal not displayed */
	// Timeout bounds one request.
	Timeout time.Duration `toml:"timeout" default:"10s" help:"Timeout bounds one request"`
	// MaxIdleConns sizes the connection pool. The rule of thumb is the
	// expected concurrency.
	MaxIdleConns int `` /* 126-byte string literal not displayed */
	// VerifySchema reads every registered table once at startup and refuses to
	// serve on a mismatch. It is the one check deployment tooling cannot make
	// for itself, so it defaults on.
	VerifySchema bool `` /* 217-byte string literal not displayed */
	// AutoMigrate creates missing tables during startup. It is a development
	// convenience and is rejected elsewhere.
	AutoMigrate bool `` /* 135-byte string literal not displayed */
}

Config is the [middleware.dynamo] runtime binding. It is registered when this package is imported, so a project that does not use DynamoDB gains no key.

It carries no billing mode and no capacity. Table creation happens in development and test, where the target is an emulator that ignores both, and a deployed table is defined by deployment tooling.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig is the binding's zero-value replacement, and the same values the default struct tags carry.

Both exist because they answer different questions: configbind reads the tags to fill an unset key, and a caller building a Config in Go reads this. TestDefaultConfigMatchesTheBoundDefaults keeps them from drifting.

type Result

type Result struct {
	// Created lists the deployed names created, in plan order.
	Created []string
	// Unchanged lists the deployed names that already matched.
	Unchanged []string
}

Result reports what an apply did.

func Migrate

func Migrate(ctx context.Context) (Result, error)

Migrate creates the tables that are missing and leaves everything else alone.

It never deletes, never alters, and never reads the operational surface a deployment owns, so the only outcome besides success is a report.

type TableChange

type TableChange struct {
	// Declared is the name source uses.
	Declared string
	// Deployed is the name the resolver produced.
	Deployed string
	// Change is what this table needs.
	Change Change
	// Detail explains a mismatch. It is empty otherwise.
	Detail string
}

TableChange is one entry of a plan.

func Plan

func Plan(ctx context.Context) ([]TableChange, error)

Plan reports what schema application would do, without sending a write.

It is the production-relevant entry: deployment tooling knows what it created, and only the application knows what it expects, so comparing the two is a question nothing else can answer.

type TableFactory

type TableFactory func(name string) dynamodb.TableDefinition

TableFactory builds one table definition for a deployed name. It is the shape tinybind generates beside an item codec, so a registered entry is the generated constructor itself rather than a copy of what it returns.

type TableName

type TableName struct {
	Declared string `toml:"declared"`
	Deployed string `toml:"deployed"`
}

TableName is one [[middleware.dynamo.table_names]] element: the name source declares, and the name this deployment gave it.

type TableResolver

type TableResolver = dynamobind.TableResolver

TableResolver maps a declared table name onto the deployed one.

It is an alias rather than a type of its own: this is the seam tinybind runs inside every entry, and a second named type would only need converting back.

Jump to

Keyboard shortcuts

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