ddb

package module
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Feb 24, 2025 License: Apache-2.0 Imports: 14 Imported by: 1

README

DynamoDB goodies

Go Reference

This module adds optimistic locking and auto-generated timestamps by modifying the expressions being created as part of a DynamoDB service call.

Usage

Get with:

go get github.com/nguyengg/go-aws-commons/ddb
package main

import (
	"context"
	"time"

	"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
	"github.com/nguyengg/go-aws-commons/ddb"
)

type Item struct {
	Id           string    `dynamodbav:"id,hashkey" tableName:"my-table"`
	Sort         string    `dynamodbav:"sort,sortkey"`
	Version      int64     `dynamodbav:"version,version"`
	CreatedTime  time.Time `dynamodbav:"createdTime,createdTime,unixtime"`
	ModifiedTime time.Time `dynamodbav:"modifiedTime,modifiedTime,unixtime"`
}

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

	// ddbfns.Put and ddbfns.Update is smart enough to add condition expression for me.
	item := Item{
		Id:   "hello",
		Sort: "world",
		// Since version has zero value, ddbfns.Put and ddbfns.Put will add a condition expression that's basically
		// `attribute_not_exists (id)`, and increment the version's value in the request for me.
		Version: 0,
		// Since these timestamps have zero value, they will be updated to the same time.Now in the request for me.
		CreatedTime:  time.Time{},
		ModifiedTime: time.Time{},
	}

	// my original item is never mutated by ddbfns.
	// Instead, the map[string]AttributeValue sent to DynamoDB is the one that is modified along with its
	// the request's ConditionExpression, ExpressionAttributeNames, and ExpressionAttributeValues.
	_, _ = ddb.Put(ctx, item)

	// If the version is not at zero value, ddbfns.Put and ddbfns.Update knows to add `#version = :old_value` instead.
	item = Item{
		Id:   "hello",
		Sort: "world",
		// Since version has non-zero value, ddbfns.Put and ddbfns.Put will add `#version = 3` instead, and increment
		// the version's value in the request for me.
		Version: 3,
		// In ddbfns.Update, only ModifiedTime is updated with a `SET #modifiedTime = :now`.
		ModifiedTime: time.Time{},
	}

	// Update requires me to specify at least one update expression. Here's an example of how to return updated values
	// as well.
	_, _ = ddb.Update(ctx, Item{Id: "hello", Sort: " world", Version: 3}, func(options *ddb.UpdateOptions) {
		options.
			Set("anotherField", "notes").
			// by passing a struct pointer to WithReturnValues, ddbfns will unmarshall the response to
			// this struct so that item will have updated attribute values.
			WithReturnValues(types.ReturnValueAllNew, &item)
	})

	// ddbfns.Delete will only use the version attribute, and it does not care if the attribute has zero value or not
	// (i.e. you can't attempt to delete an item that doesn't exist).
	_, _ = ddb.Delete(ctx, Item{
		Id: "hello",
		// Even if the version's value was 0, `SET #version = :old_value` is used regardless.
		Version: 3,
	})

	// ddbfns.Get accepts a key which can be struct or struct pointer, and an optional struct pointer argument to
	// unmarshal the response of the GetItem request.
	item = Item{}
	_, _ = ddb.Get(ctx, Item{Id: "hello", Sort: "world"}, &item)
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultBuilder = &Builder{}

DefaultBuilder is the zero-value Builder instance used by CreateDeleteItem, CreateGetItem, CreatePutItem, and CreateUpdateItem.

View Source
var DefaultManager = &Manager{Builder: DefaultBuilder}

DefaultManager is the zero-value Manager that uses DefaultBuilder and is used by Delete, Get, Put, and Update.

View Source
var (
	// ErrNoAttribute is returned by Table.Get if there is no attribute with the requested name.
	ErrNoAttribute = errors.New("ddb: named attribute not present")
)

Functions

func CreateCompositeKey added in v0.1.4

func CreateCompositeKey[T interface{}](partitionKey, sortKey interface{}) (key map[string]types.AttributeValue, tableName string, err error)

CreateCompositeKey creates the `map[string]types.AttributeValue` containing both the partition and sort keys for items of type T.

The table name is also returned for convenience. Use this method if you need to extract the key to execute DynamoDB calls that have no out-of-the-box support in this package (e.g. Query, Scan). The method does not validate whether if the type of key arguments do not match or do not encode to same DynamoDB data type as the actual keys modeled in struct type T. The method does return an error if struct T does not model both a hashkey and sortkey.

[DefaultBuilder.Encoder] is used to produce the returned values.

func CreateDeleteItem

func CreateDeleteItem(key interface{}, optFns ...func(*DeleteOptions)) (*dynamodb.DeleteItemInput, error)

CreateDeleteItem creates the DeleteItem input parameters for the given key.

The argument key is a struct or pointer to struct containing the key values since DynamoDB DeleteItem only requires key attributes. The argument key should also include the version field that will be used to create the `#version = :version` condition expression if optimistic locking is enabled.

This method is a wrapper around [DefaultFns.CreateDeleteItem].

func CreateGetItem

func CreateGetItem(key interface{}, optFns ...func(*GetOptions)) (*dynamodb.GetItemInput, error)

CreateGetItem creates the GetItem input parameters for the given key.

The argument key is a struct or pointer to struct containing the key values since DynamoDB GetItem only requires key attributes.

This method is a wrapper around [DefaultFns.CreateGetItem].

func CreateKey added in v0.1.4

func CreateKey[T interface{}](partitionKey interface{}) (key map[string]types.AttributeValue, tableName string, err error)

CreateKey creates the `map[string]types.AttributeValue` containing just the partition key for items of type T.

The table name is also returned for convenience. Use this method if you need to extract the key to execute DynamoDB calls that have no out-of-the-box support in this package (e.g. Query, Scan). The method does not validate whether the type of partitionKey argument does not match or does not encode to same DynamoDB data type as the actual key modeled in struct type T. The method does return an error if struct T does not model a hashkey.

[DefaultBuilder.Encoder] is used to produce the returned values.

func CreatePutItem

func CreatePutItem(item interface{}, optFns ...func(*PutOptions)) (*dynamodb.PutItemInput, error)

CreatePutItem creates the PutItem input parameters for the given item.

The argument item is a struct or pointer to struct containing all attributes to be written to DynamoDB.

If the item's version has zero value, `attribute_not_exists(#hash_key)` is used as the condition expression to prevent overriding an existing item with the same key. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

If the item's version is not zero value, `#version = :version` is used as the condition expression to add optimistic locking. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

Any zero-value created or modified timestamps will be set to time.Now.

This method is a wrapper around [DefaultFns.CreatePutItem].

func CreateUpdateItem

func CreateUpdateItem(key interface{}, required func(*UpdateOptions), optFns ...func(opts *UpdateOptions)) (*dynamodb.UpdateItemInput, error)

CreateUpdateItem creates the UpdateItem input parameters for the given key and at least one update expression.

The argument key is a struct or pointer to struct containing the key values since DynamoDB UpdateItem only requires key attributes. The argument key should also include the version field that will be used to create the condition expressions for optimistic locking.

If the key's version has zero value, `attribute_not_exists(#hash_key)` is used as the condition expression to prevent overriding an existing item with the same key. An `ADD #version 1` update expression will be used to update the version.

If the key's version is not zero value, `#version = :version` is used as the condition expression to add optimistic locking. An `ADD #version 1` update expression will be used to update the version.

Modified time will always be set to time.Now.

func Delete

func Delete(ctx context.Context, key interface{}, optFns ...func(*DeleteOptions)) (*dynamodb.DeleteItemOutput, error)

Delete creates and executes a DynamoDB DeleteItem request from the given arguments.

The argument key is a struct or pointer to struct containing the key values since DynamoDB DeleteItem only requires key attributes. The argument key should also include the version attribute that will be used to create the `#version = :version` condition expression if optimistic locking is enabled.

A common use case for Delete is to delete and return old values of an item; pass DeleteOptions.WithReturnAllOldValues to do so. You can also use DeleteOptions.WithReturnAllOldValuesOnConditionCheckFailure if optimistic locking is enabled; they don't have to be pointers to the same struct.

If you need to pass SDK-level options (in addition to options specified by NewManager), use DeleteOptions.WithOptions.

This method is a wrapper around [DefaultManager.Delete].

func DereferencedType added in v0.2.0

func DereferencedType(t reflect.Type) reflect.Type

DereferencedType returns the innermost type that is not reflect.Interface or reflect.Ptr.

func Get

func Get(ctx context.Context, key interface{}, out interface{}, optFns ...func(opts *GetOptions)) (*dynamodb.GetItemOutput, error)

Get creates and executes a DynamoDB GetRequest request from the given arguments.

The argument key is a struct or pointer to struct containing the key values since DynamoDB GetItem only requires key attributes.

The argument out is an optional pointer to struct to decode the returned attributes with attributevalue.Decoder.Decode. A common use case for Get is to make a GetItem request and unmarshall the DynamoDB response to a struct; pass a pointer to struct as the out argument to do so.

If you need to pass SDK-level options (in addition to options specified by NewManager), use GetOptions.WithOptions.

This method is a wrapper around [DefaultManager.Get].

func Put

func Put(ctx context.Context, item interface{}, optFns ...func(opts *PutOptions)) (*dynamodb.PutItemOutput, error)

Put creates and executes a DynamoDB PutItem request from the given arguments.

The argument item is a struct or pointer to struct containing all attributes to be written to DynamoDB.

If the item's version has zero value, `attribute_not_exists(#hash_key)` is used as the condition expression to prevent overriding an existing item with the same key. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

If the item's version is not zero value, `#version = :version` is used as the condition expression to add optimistic locking. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

Any zero-value created or modified timestamps will be set to time.Now.

You can use PutOptions.WithReturnAllOldValues if you wish to return and unmarshal the old values to a struct, or PutOptions.WithReturnAllOldValuesOnConditionCheckFailure in case optimistic locking fails; they don't have to be pointers to the same struct.

If you need to pass SDK-level options (in addition to options specified by NewManager), use PutOptions.WithOptions.

This method is a wrapper around [DefaultManager.Put].

func Update

func Update(ctx context.Context, key interface{}, required func(*UpdateOptions), optFns ...func(*UpdateOptions)) (*dynamodb.UpdateItemOutput, error)

Update creates and executes a DynamoDB UpdateItem request from the given arguments.

The argument key is a struct or pointer to struct containing the key values since DynamoDB UpdateItem only requires key attributes. The argument key should also include the version field that will be used to create the condition expressions for optimistic locking.

If the key's version has zero value, `attribute_not_exists(#hash_key)` is used as the condition expression to prevent overriding an existing item with the same key. An `ADD #version 1` update expression will be used to update the version.

If the key's version is not zero value, `#version = :version` is used as the condition expression to add optimistic locking. An `ADD #version 1` update expression will be used to update the version.

Modified time will always be set to time.Now.

This method is a wrapper around [DefaultManager.Update].

Types

type Attribute added in v0.2.0

type Attribute struct {
	reflect.StructField

	// AttributeName is the first tag value in the `dynamodbav` struct tag which is also the name of the attribute
	// in DynamoDB.
	//
	// Note: AttributeName is often different from [Attribute.StructField.Name]. For example, given this struct:
	//
	//	type MyStruct struct {
	//		Field string `dynamodbav:"field"`
	//	}
	//
	// The Attribute for Field would have AttributeName="field" while Name="Field".
	AttributeName string
	// OmitEmpty is true only if the `dynamodbav` struct tag also includes `omitempty`.
	OmitEmpty bool
	// UnixTime is true only if the `dynamodbav` struct tag also includes `unixtime`.
	UnixTime bool
}

Attribute is a reflect.StructField that is tagged with `dynamodbav` (or whatever TagKey passed to Parse).

func (*Attribute) GetFieldValue added in v0.2.1

func (s *Attribute) GetFieldValue(v reflect.Value) (reflect.Value, error)

GetFieldValue is given a struct v (wrapped as a reflect.Value) that contains the Attribute.StructField in order to return the value (also wrapped as a reflect.Value) of that StructField in the struct v.

Usage example:

type MyStruct struct {
	Name string `dynamodbav:"-"`
}

// nameAV is a Attribute modeling the Name field above, this can be used to get and/or set the value of that
// field like this:
v := MyStruct{Name: "John"}
nameAv.GetFieldValue(reflect.ValueOf(v)).String() // would return "John"
nameAv.GetFieldValue(reflect.ValueOf(v)).SetString("Jane") // would change v.Name to "Jane"

You can use the returned reflect.Value to further set arbitrary values in the struct, though this will panic if the types aren't compatible.

type Builder

type Builder struct {
	// Encoder is the attributevalue.Encoder to marshal structs into DynamoDB items.
	//
	// If nil, a default one will be created.
	Encoder *attributevalue.Encoder
	// Decoder is the attributevalue.Decoder to unmarshal results from DynamoDB.
	//
	// If nil, a default one will be created.
	Decoder *attributevalue.Decoder
	// contains filtered or unexported fields
}

Builder parses and creates Table instances which then are used to create DynamoDB request input parameters.

See Table for the `dynamodbav` tags that must be used. Builder is an abstraction on top of Table to create input parameters for DynamoDB DeleteItem (CreateDeleteItem), GetItem (CreateGetItem), PutItem (CreatePutItem), and UpdateItem (CreateUpdateItem).

The zero-value Builder instance is ready for use.

func (*Builder) CreateDeleteItem

func (b *Builder) CreateDeleteItem(key interface{}, optFns ...func(*DeleteOptions)) (*dynamodb.DeleteItemInput, error)

CreateDeleteItem creates the DeleteItem input parameters for the given key.

The argument key is a struct or pointer to struct containing the key values since DynamoDB DeleteItem only requires key attributes. The argument key should also include the version field that will be used to create the `#version = :version` condition expression if optimistic locking is enabled.

func (*Builder) CreateGetItem

func (b *Builder) CreateGetItem(key interface{}, optFns ...func(*GetOptions)) (*dynamodb.GetItemInput, error)

CreateGetItem creates the GetItem input parameters for the given key.

The argument key is a struct or pointer to struct containing the key values since DynamoDB GetItem only requires key attributes.

func (*Builder) CreatePutItem

func (b *Builder) CreatePutItem(item interface{}, optFns ...func(*PutOptions)) (*dynamodb.PutItemInput, error)

CreatePutItem creates the PutItem input parameters for the given item.

The argument item is a struct or pointer to struct containing all attributes to be written to DynamoDB.

If the item's version has zero value, `attribute_not_exists(#hash_key)` is used as the condition expression to prevent overriding an existing item with the same key. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

If the item's version is not zero value, `#version = :version` is used as the condition expression to add optimistic locking. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

Any zero-value created or modified timestamps will be set to time.Now.

func (*Builder) CreateUpdateItem

func (b *Builder) CreateUpdateItem(key interface{}, required func(*UpdateOptions), optFns ...func(*UpdateOptions)) (*dynamodb.UpdateItemInput, error)

CreateUpdateItem creates the CreateDeleteItem input parameters for the given item.

See package-level CreateUpdateItem for more information.

type DeleteOptions

type DeleteOptions struct {
	// EnableOptimisticLocking is true by default to add optimistic locking.
	EnableOptimisticLocking bool

	// TableName modifies the [dynamodb.DeleteItemInput.TableName]
	TableName *string
	// ReturnConsumedCapacity modifies the [dynamodb.DeleteItemInput.ReturnConsumedCapacity]
	ReturnConsumedCapacity types.ReturnConsumedCapacity
	// ReturnItemCollectionMetrics modifies the [dynamodb.DeleteItemInput.ReturnItemCollectionMetrics]
	ReturnItemCollectionMetrics types.ReturnItemCollectionMetrics
	// ReturnValues modifies the [dynamodb.DeleteItemInput.ReturnValues]
	ReturnValues types.ReturnValue
	// ReturnValuesOnConditionCheckFailure modifies the [dynamodb.DeleteItemInput.ReturnValuesOnConditionCheckFailure].
	ReturnValuesOnConditionCheckFailure types.ReturnValuesOnConditionCheckFailure
	// contains filtered or unexported fields
}

DeleteOptions customises Delete and CreateDeleteItem via chainable methods.

func (*DeleteOptions) And

And adds an expression.And to the condition expression.

func (*DeleteOptions) DisableOptimisticLocking

func (o *DeleteOptions) DisableOptimisticLocking() *DeleteOptions

DisableOptimisticLocking disables optimistic locking logic.

func (*DeleteOptions) Or

Or adds an expression.Or to the condition expression.

func (*DeleteOptions) WithOptions

func (o *DeleteOptions) WithOptions(optFns ...func(*dynamodb.Options)) *DeleteOptions

WithOptions adds SDK options to the DeleteItem call following the ones provided by NewManager.

func (*DeleteOptions) WithReturnAllOldValues

func (o *DeleteOptions) WithReturnAllOldValues(out interface{}) *DeleteOptions

WithReturnAllOldValues sets the dynamodb.DeleteItemInput.ReturnValues to "ALL_OLD" and instructs Delete to decode the returned attributes to the optional out argument.

If out is given, it must be a struct pointer that can be passed to attributevalue.Decoder.Decode.

func (*DeleteOptions) WithReturnAllOldValuesOnConditionCheckFailure added in v0.1.2

func (o *DeleteOptions) WithReturnAllOldValuesOnConditionCheckFailure(out interface{}) *DeleteOptions

WithReturnAllOldValuesOnConditionCheckFailure sets the dynamodb.DeleteItemInput.ReturnValuesOnConditionCheckFailure to "ALL_OLD" and instructs Delete to decode the returned attributes to the optional out argument.

If out is given, it must be a struct pointer that can be passed to attributevalue.Decoder.Decode.

func (*DeleteOptions) WithTableName

func (o *DeleteOptions) WithTableName(tableName string) *DeleteOptions

WithTableName overrides [DeleteOptions.TableName].

type GetOptions

type GetOptions struct {
	// TableName modifies the [dynamodb.GetItemInput.TableName]
	TableName *string
	// ConsistentRead modifies the [dynamodb.GetItemInput.ConsistentRead]
	ConsistentRead *bool
	// ReturnConsumedCapacity modifies the [dynamodb.GetItemInput.ReturnConsumedCapacity]
	ReturnConsumedCapacity types.ReturnConsumedCapacity
	// contains filtered or unexported fields
}

GetOptions customises Get and CreateGetItem via chainable methods.

func (*GetOptions) WithOptions

func (o *GetOptions) WithOptions(optFns ...func(*dynamodb.Options)) *GetOptions

WithOptions adds SDK options to the GetItem call following the ones provided by NewManager.

func (*GetOptions) WithProjectionExpression

func (o *GetOptions) WithProjectionExpression(name string, names ...string) *GetOptions

WithProjectionExpression replaces the current projection expression with the given names.

func (*GetOptions) WithTableName

func (o *GetOptions) WithTableName(tableName string) *GetOptions

WithTableName overrides [GetOptions.TableName].

type InvalidModelErr added in v0.2.1

type InvalidModelErr struct {
	In    reflect.Type
	Cause error
}

InvalidModelErr is returned by NewTable or NewTableFromStruct if the struct type is invalid.

func (InvalidModelErr) Error added in v0.2.1

func (e InvalidModelErr) Error() string

type Manager

type Manager struct {
	// Client is the DynamoDB client to execute requests.
	//
	// If not given, the default config (`config.LoadDefaultConfig`) will be used to create the DynamoDB client.
	Client ManagerAPIClient

	// Builder is the Builder instance to use when building input parameters.
	//
	// Default to DefaultBuilder.
	Builder *Builder

	// ClientOptions are passed to each DynamoDB request.
	ClientOptions []func(*dynamodb.Options)
	// contains filtered or unexported fields
}

Manager provides methods to execute DynamoDB requests.

The zero-value is ready for use.

func NewManager

func NewManager(client ManagerAPIClient, optFns ...func(*Manager)) *Manager

NewManager returns a new Manager using the given client.

func (*Manager) Delete

func (m *Manager) Delete(ctx context.Context, key interface{}, optFns ...func(*DeleteOptions)) (*dynamodb.DeleteItemOutput, error)

Delete creates and executes a DynamoDB DeleteItem request from the given arguments.

The argument key is a struct or pointer to struct containing the key values since DynamoDB DeleteItem only requires key attributes. The argument key should also include the version attribute that will be used to create the `#version = :version` condition expression if optimistic locking is enabled.

A common use case for Delete is to delete and return old values of an item; pass DeleteOptions.WithReturnAllOldValues to do so. You can also use DeleteOptions.WithReturnAllOldValuesOnConditionCheckFailure if optimistic locking is enabled; they don't have to be pointers to the same struct.

If you need to pass SDK-level options (in addition to options specified by NewManager), use DeleteOptions.WithOptions.

If you need to pass SDK-level options (in addition to options specified by NewManager), use DeleteOptions.WithOptions.

func (*Manager) Get

func (m *Manager) Get(ctx context.Context, key interface{}, out interface{}, optFns ...func(opts *GetOptions)) (*dynamodb.GetItemOutput, error)

Get creates and executes a DynamoDB GetRequest request from the given arguments.

The argument key is a struct or pointer to struct containing the key values since DynamoDB GetItem only requires key attributes.

The argument out is an optional pointer to struct to decode the returned attributes with attributevalue.Decoder.Decode. A common use case for Get is to make a GetItem request and unmarshall the DynamoDB response to a struct; pass a pointer to struct as the out argument to do so.

If you need to pass SDK-level options (in addition to options specified by NewManager), use GetOptions.WithOptions.

func (*Manager) Put

func (m *Manager) Put(ctx context.Context, item interface{}, optFns ...func(opts *PutOptions)) (*dynamodb.PutItemOutput, error)

Put creates and executes a DynamoDB PutItem request from the given arguments.

The argument item is a struct or pointer to struct containing all attributes to be written to DynamoDB.

If the item's version has zero value, `attribute_not_exists(#hash_key)` is used as the condition expression to prevent overriding an existing item with the same key. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

If the item's version is not zero value, `#version = :version` is used as the condition expression to add optimistic locking. The version attribute in the returned dynamodb.PutItemInput.Item will be incremented by 1.

Any zero-value created or modified timestamps will be set to time.Now.

You can use PutOptions.WithReturnAllOldValues if you wish to return and unmarshal the old values to a struct, or PutOptions.WithReturnAllOldValuesOnConditionCheckFailure in case optimistic locking fails; they don't have to be pointers to the same struct.

If you need to pass SDK-level options (in addition to options specified by NewManager), use PutOptions.WithOptions.

func (*Manager) Update

func (m *Manager) Update(ctx context.Context, key interface{}, required func(*UpdateOptions), optFns ...func(*UpdateOptions)) (*dynamodb.UpdateItemOutput, error)

Update creates and executes a DynamoDB UpdateItem request from the given arguments.

The argument key is a struct or pointer to struct containing the key values since DynamoDB UpdateItem only requires key attributes. The argument key should also include the version field that will be used to create the condition expressions for optimistic locking.

If the key's version has zero value, `attribute_not_exists(#hash_key)` is used as the condition expression to prevent overriding an existing item with the same key. An `ADD #version 1` update expression will be used to update the version.

If the key's version is not zero value, `#version = :version` is used as the condition expression to add optimistic locking. An `ADD #version 1` update expression will be used to update the version.

Modified time will always be set to time.Now.

type ManagerAPIClient

type ManagerAPIClient interface {
	DeleteItem(ctx context.Context, params *dynamodb.DeleteItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DeleteItemOutput, error)
	GetItem(ctx context.Context, params *dynamodb.GetItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.GetItemOutput, error)
	PutItem(ctx context.Context, params *dynamodb.PutItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.PutItemOutput, error)
	UpdateItem(ctx context.Context, params *dynamodb.UpdateItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateItemOutput, error)
}

ManagerAPIClient abstracts the DynamoDB APIs that are used by Manager.

type PutOptions

type PutOptions struct {
	// EnableOptimisticLocking is true by default to add optimistic locking.
	EnableOptimisticLocking bool
	// EnableAutoGeneratedTimestamps is true by default to add generated timestamp attributes.
	EnableAutoGeneratedTimestamps bool

	// TableName modifies the [dynamodb.PutItemInput.TableName]
	TableName *string
	// ReturnConsumedCapacity modifies the [dynamodb.PutItemInput.ReturnConsumedCapacity]
	ReturnConsumedCapacity types.ReturnConsumedCapacity
	// ReturnItemCollectionMetrics modifies the [dynamodb.PutItemInput.ReturnItemCollectionMetrics]
	ReturnItemCollectionMetrics types.ReturnItemCollectionMetrics
	// ReturnValues modifies the [dynamodb.PutItemInput.ReturnValues]
	ReturnValues types.ReturnValue
	// ReturnValuesOnConditionCheckFailure modifies the [dynamodb.PutItemInput.ReturnValuesOnConditionCheckFailure].
	ReturnValuesOnConditionCheckFailure types.ReturnValuesOnConditionCheckFailure
	// contains filtered or unexported fields
}

PutOptions customises Put and CreatePutItem via chainable methods.

func (*PutOptions) And

And adds an expression.And to the condition expression.

func (*PutOptions) DisableAutoGeneratedTimestamps

func (o *PutOptions) DisableAutoGeneratedTimestamps() *PutOptions

DisableAutoGeneratedTimestamps disables auto-generated timestamps logic.

func (*PutOptions) DisableOptimisticLocking

func (o *PutOptions) DisableOptimisticLocking() *PutOptions

DisableOptimisticLocking disables optimistic locking logic.

func (*PutOptions) Or

Or adds an expression.Or to the condition expression.

func (*PutOptions) WithOptions

func (o *PutOptions) WithOptions(optFns ...func(*dynamodb.Options)) *PutOptions

WithOptions adds SDK options to the PutItem call following the ones provided by NewManager.

func (*PutOptions) WithReturnAllOldValues

func (o *PutOptions) WithReturnAllOldValues(out interface{}) *PutOptions

WithReturnAllOldValues sets the dynamodb.PutItemInput.ReturnValues to "ALL_OLD" and instructs Put to decode the returned attributes to the optional out argument.

If out is given, it must be a struct pointer that can be passed to attributevalue.Decoder.Decode.

func (*PutOptions) WithReturnAllOldValuesOnConditionCheckFailure

func (o *PutOptions) WithReturnAllOldValuesOnConditionCheckFailure(out interface{}) *PutOptions

WithReturnAllOldValuesOnConditionCheckFailure sets the dynamodb.PutItemInput.ReturnValuesOnConditionCheckFailure to "ALL_OLD" and instructs Put to decode the returned attributes to the optional out argument.

If out is given, it must be a struct pointer that can be passed to attributevalue.Decoder.Decode.

func (*PutOptions) WithTableName

func (o *PutOptions) WithTableName(tableName string) *PutOptions

WithTableName overrides [PutOptions.TableName].

type Table added in v0.2.0

type Table struct {
	TableName    string
	HashKey      *Attribute
	SortKey      *Attribute
	Version      *Attribute
	CreatedTime  *Attribute
	ModifiedTime *Attribute

	// All contains all attributes parsed from `dynamodbav` struct tags, including the special ones such has HashKey
	// and SortKey.
	//
	// The map's key is the Attribute.AttributeName. Use Table.Get for a way to retrieve the value of an attribute
	// given its struct.
	All map[string]*Attribute
	// contains filtered or unexported fields
}

Table is a collection of Attribute where the hash key must always be present.

`dynamodav` struct tag must be used to model these attributes:

// Hash key is required, sort key is optional. If present, their types must marshal to a valid key type
// (S, N, or B). The keys are required to make `attribute_not_exists` work on creating the condition expression
// for the PutItem request of an item that shouldn't exist in database.
Field string `dynamodbav:"-,hashkey" tableName:"my-table"`
Field string `dynamodbav:"-,sortkey"`

// Versioned attribute must have `version` show up in its `dynamodbav` tag. It must be a numeric type that
// marshals to type N in DynamoDB.
Field int64 `dynamodbav:"-,version"`

// Timestamp attributes must have `createdTime` and/or `modifiedTime` in its `dynamodbav` tag. It must be a
// [time.Time] value. In this example, both attributes marshal to type N in DynamoDB as epoch millisecond.
Field time.Time `dynamodbav:"-,createdTime,unixtime"`
Field time.Time `dynamodbav:"-,modifiedTime,unixtime"`

All other attributes tagged with `dynamodbav` are also stored. Attributed with no names such as `dynamodbav:"-"` are ignored.

func NewTable added in v0.2.0

func NewTable(in reflect.Type, optFns ...func(*TableOptions)) (table *Table, err error)

NewTable parses the struct tags given by its type.

Returns an InvalidModelErr error if there are validation issues.

It is recommended to add a unit test and verify your struct is modeled correctly with NewTableFromStruct.

Usage:

func TestMyStruct_IsValid(t *testing.T) {
	_, err := NewTable[MyStruct]()
	assert.NoError(t, err)
}

func NewTableFromStruct added in v0.2.0

func NewTableFromStruct(in interface{}, optFns ...func(*TableOptions)) (*Table, error)

NewTableFromStruct parses the struct tags given by an instance of the struct.

Returns an InvalidModelErr error if there are validation issues.

It is recommended to add a unit test and verify your struct is modeled correctly with NewTableFromStruct.

Usage:

func TestMyStruct_IsValid(t *testing.T) {
	_, err := NewTableFromStruct(MyStruct{})
	assert.NoError(t, err)
}

func (*Table) Get added in v0.2.0

func (t *Table) Get(in interface{}, name string) (_ interface{}, err error)

Get returns the value of the attribute with the given name in the given struct v.

Returns TypeMismatchErr if in's type is not the same as the struct type that was used to create the Table. Return ErrNoAttribute if Table.All contains no attribute with the given name.

Usage example:

type MyStruct struct {
	Name string `dynamodbav:"name"`
}

t, _ := NewTableFromStruct(&MyStruct{})
name, _ := t.Get(&MyStruct{Name: "hello"}, "name") // notice the lowercase "name" matching the dynamodbav tag.
fmt.Printf("%s", name.(string)); // # hello

func (*Table) MustGet added in v0.2.1

func (t *Table) MustGet(in interface{}, name string) interface{}

MustGet is a variant of Get that panics instead of returning any error.

Usage example:

type MyStruct struct {
	Name string `dynamodbav:"-"`
}

t, _ := NewTableFromStruct(&MyStruct{})
var name string = t.MustGet(MyStruct{Name: "hello"}).(string)

type TableOptions added in v0.2.1

type TableOptions struct {
	// Validator can be used to fail parsing early.
	//
	// Any non-nil error will stop the parsing process and is returned immediately to caller.
	Validator func(*Attribute) error
	// MustHaveSortKey, if true, will fail parsing if the struct does not have any field tagged as
	// `dynamodbav:",sortkey"`.
	MustHaveSortKey bool
	// MustHaveVersion, if true, will fail parsing if the struct does not have any field tagged as
	// `dynamodbav:",version"`.
	MustHaveVersion bool
	// MustHaveTimestamps, if true, will fail parsing if the struct does not have any field tagged as
	// `dynamodbav:",createdTime" or `dynamodbav:",modifiedTime".
	MustHaveTimestamps bool
}

TableOptions customises the behaviour of the various methods to create parse struct tags for a Table.

type TypeMismatchErr added in v0.2.1

type TypeMismatchErr struct {
	Expected, Actual reflect.Type
}

TypeMismatchErr is returned by Table.Get if the type of the argument "in" does not match the Table's type.

func (TypeMismatchErr) Error added in v0.2.1

func (e TypeMismatchErr) Error() string

type UpdateOptions

type UpdateOptions struct {
	// EnableOptimisticLocking is true by default to add optimistic locking.
	EnableOptimisticLocking bool
	// EnableAutoGeneratedTimestamps is true by default to add generated timestamp attributes.
	EnableAutoGeneratedTimestamps bool

	// TableName modifies the [dynamodb.UpdateItemInput.TableName]
	TableName *string
	// ReturnConsumedCapacity modifies the [dynamodb.UpdateItemInput.ReturnConsumedCapacity]
	ReturnConsumedCapacity types.ReturnConsumedCapacity
	// ReturnItemCollectionMetrics modifies the [dynamodb.UpdateItemInput.ReturnItemCollectionMetrics]
	ReturnItemCollectionMetrics types.ReturnItemCollectionMetrics
	// ReturnValues modifies the [dynamodb.UpdateItemInput.ReturnValues]
	ReturnValues types.ReturnValue
	// ReturnValuesOnConditionCheckFailure modifies the [dynamodb.UpdateItemInput.ReturnValuesOnConditionCheckFailure].
	ReturnValuesOnConditionCheckFailure types.ReturnValuesOnConditionCheckFailure
	// contains filtered or unexported fields
}

UpdateOptions customises Update and CreateUpdateItem via chainable methods.

func (*UpdateOptions) Add

func (o *UpdateOptions) Add(name string, value interface{}) *UpdateOptions

Add adds an expression.UpdateBuilder.Add expression.

Like all other UpdateOptions methods to modify the update expression, the name and value will be wrapped with an `expression.Name` and `expression.Value`.

func (*UpdateOptions) And

And adds an expression.And to the condition expression.

func (*UpdateOptions) Delete

func (o *UpdateOptions) Delete(name string, value interface{}) *UpdateOptions

Delete adds an expression.UpdateBuilder.Delete expression.

Like all other UpdateOptions methods to modify the update expression, the name and value will be wrapped with an `expression.Name` and `expression.Value`.

func (*UpdateOptions) DisableAutoGeneratedTimestamps

func (o *UpdateOptions) DisableAutoGeneratedTimestamps() *UpdateOptions

DisableAutoGeneratedTimestamps disables auto-generated timestamps logic.

func (*UpdateOptions) DisableOptimisticLocking

func (o *UpdateOptions) DisableOptimisticLocking() *UpdateOptions

DisableOptimisticLocking disables optimistic locking logic.

func (*UpdateOptions) Or

Or adds an expression.And to the condition expression.

func (*UpdateOptions) Remove

func (o *UpdateOptions) Remove(name string) *UpdateOptions

Remove adds an expression.UpdateBuilder.Set expression.

Like all other UpdateOptions methods to modify the update expression, the name and value will be wrapped with an `expression.Name` and `expression.Value`.

func (*UpdateOptions) Set

func (o *UpdateOptions) Set(name string, value interface{}) *UpdateOptions

Set adds an expression.UpdateBuilder.Set expression.

Like all other UpdateOptions methods to modify the update expression, the name and value will be wrapped with an `expression.Name` and `expression.Value`.

func (*UpdateOptions) SetOrRemove

func (o *UpdateOptions) SetOrRemove(set, remove bool, name string, value interface{}) *UpdateOptions

SetOrRemove adds either Set or Remove action to the update expression.

If set is true, a SET action will be added. If set is false, only when remove is true then a REMOVE action will be added.

| set | remove | action | true | * | SET | false | true | REMOVE | false | false | no-op

This is useful for distinguishing between PUT/POST (remove=true) that replaces attributes with clobbering behaviour vs. PATCH (remove=false) that will only update attributes that are non-nil. An example is given:

func PUT(body Request) {
	// because it's a PUT request, if notes is empty, instead of writing empty string to database, we'll remove it.
	opts.SetOrRemove(true, true, "notes", body.Notes)
}

func PATCH(body Request) {
	// only when notes is non-empty that we'll update it. an empty notes just means caller didn't try to update it.
	opts.SetOrRemove(body.Notes != "", false, "notes", body.Notes)
}

func CreateUpdateItem(method string, body Request) {
	// an attempt to unify the methods may look like this.
	opts.SetOrRemove(expression.UpdateBuilder{}, body.Notes != "", method != "PATCH", "notes", body.Notes)
}

Like all other UpdateOptions methods to modify the update expression, the name and value will be wrapped with an `expression.Name` and `expression.Value`.

func (*UpdateOptions) SetOrRemoveStringPointer

func (o *UpdateOptions) SetOrRemoveStringPointer(name string, ptr *string) *UpdateOptions

SetOrRemoveStringPointer is a specialization of SetOrRemove for string pointer value.

If ptr is a nil pointer, no action is taken. If ptr dereferences to an empty string, a REMOVE action is used. A non-empty string otherwise will result in a SET action.

Like all other UpdateOptions methods, the name will be wrapped with an `expression.Name` and dereferenced value `expression.Value`.

func (*UpdateOptions) WithOptions

func (o *UpdateOptions) WithOptions(optFns ...func(*dynamodb.Options)) *UpdateOptions

WithOptions adds SDK options to the UpdateItem call following the ones provided by NewManager.

func (*UpdateOptions) WithReturnValues

func (o *UpdateOptions) WithReturnValues(returnValue types.ReturnValue, out interface{}) *UpdateOptions

WithReturnValues sets [UpdateOptions.ReturnValues] and instructs Update to decode the returned attributes to the optional out argument.

If out is given, it must be a struct pointer that can be passed to attributevalue.Decoder.Decode.

func (*UpdateOptions) WithReturnValuesOnConditionCheckFailure added in v0.1.2

func (o *UpdateOptions) WithReturnValuesOnConditionCheckFailure(returnValues types.ReturnValuesOnConditionCheckFailure, out interface{}) *UpdateOptions

WithReturnValuesOnConditionCheckFailure sets [UpdateOptions.ReturnValuesOnConditionCheckFailure] and instructs Update to decode the returned attributes to the optional out argument.

If out is given, it must be a struct pointer that can be passed to attributevalue.Decoder.Decode.

func (*UpdateOptions) WithTableName

func (o *UpdateOptions) WithTableName(tableName string) *UpdateOptions

WithTableName overrides [UpdateOptions.TableName].

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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