Documentation ¶
Overview ¶
Package dynami provides a simple wrapper over the official Go DynamoDB SDK.
In order to use this package effectively, an understanding of the underlying DynamoDB operations is recommended. For an introduction, please visit https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html
Items ¶
Items can be a map[string]interface{}, a struct, or a pointer to any of those. For an item to be valid, it must contain a nonempty key attribute. Key attributes are restricted to strings, numbers, and binary data. For non-key attributes, the following data types are allowed:
- Strings
- Numbers (int, uint, float32, etc)
- Binary data ([]byte up to 400KB)
- Maps (map[string]interface{})
- Structs of any of the above
- Slices of any of the above
Field Tags ¶
This package uses field tags to specify an item's primary key and secondary index properties. To designate a struct field as the item's primary key use `dbkey:"keytype"`. "keytype" can be "hash" or "range" for hash and range attributes respectively. For secondary index properties, use the tag `dbindex:"type,IndexName"`. If the tagged property is a secondary index key, set "type" to "hash" or "range". If it is a projected attribute, change "type" to "project". In addition to the said tags, `json` and `dynamodbav` tags are also supported. This is useful for optional and ignored attributes.
Example code:
// A and B constitutes the primary key. // C is the range attribute of LocalIndex. // D is the hash attribute of GlobalIndex. // A is the range attribute of GlobalIndex. // E is projected to both LocalIndex and GlobalIndex. // F is ignored and not stored. // G is an optional attribute. type TaggedStruct struct { A string `dbkey:"hash" dbindex:"range,GlobalIndex"` B string `dbkey:"range"` C string `dbindex:"range,LocalIndex"` D string `dbindex:"hash,GlobalIndex"` E string `dbindex:"project,LocalIndex,project,GlobalIndex"` F string `dynamodbav:"-"` G string `dynamodbav:",omitempty"` }
Note that for local secondary indices, only the range attribute is tagged as shown in struct field C.
Item Operations ¶
There are three basic item operations: PutItem, GetItem, and DeleteItem. Each of these operations accepts an item with nonempty primary key except GetItem which also accepts local and global secondary index keys.
Example code:
type Item struct { Key string `dbkey:"hash"` Value string } item := Item{"key", "somevalue"} client := dynami.NewClient(dynami.USEast1, "id", "key") client.PutItem("ItemTable", item) // After some time... fetched := Item{Key: "key"} client.GetItem("ItemTable", &fetched) // Do something with the fetched item client.DeleteItem("ItemTable", fetched)
Batch Operations ¶
Each of the basic item operations also has a batch version: BatchPut, BatchGet and BatchDelete. Each of these operation returns a corresponding batch operation structure which allows method chaining so that multiple items from different tables can be processed at once. Unlike the official SDK, there are no limits on how many items each batch operation can process.
Example code:
type ItemA struct { Key string `dbkey:"hash"` Value string } type ItemB struct { Key string `dbkey:"hash"` Value string } // Create items limitless := 200 itemsA := make([]ItemA, limitless) itemsB := make([]ItemB, limitless) for i := 0; i < limitless; i++ { itemsA[i] = ItemA{strconv.Itoa(i), "somevalue"} itemsB[i] = ItemB{strconv.Itoa(i), "anothervalue"} } // Add items client := dynami.NewClient(dynami.USEast1, "id", "key") client.BatchPut("ItemTableA", itemsA). Put("ItemTableB", itemsB). Run() // Some time later... fetchedA := make([]ItemA, limitless) fetchedB := make([]ItemB, limitless) for i := 0; i < limitless; i++ { fetchedA[i] = ItemA{Key: strconv.Itoa(i)} fetchedB[i] = ItemB{Key: strconv.Itoa(i)} } client.BatchGet("ItemTableA", fetchedA). Get("ItemTableB", fetchedB). Run() // Process the items client.BatchDelete("ItemTableA", fetchedA). Delete("ItemTableB", fetchedB). Run()
Queries ¶
Queries are built by chaining filters and conditions. Running a query yields a result iterator. Unlike the official SDK, there is no size limit for each query operation.
Queries retrieve items that satisfies a given set of filters. There are three types of filter: a hash filter, a range filter, and a post filter. If a query has a hash filter, running it will perform a DynamoDB query operation, otherwise, a scan operation is performed. The range filter and the post filter accepts a filter expression and a set of values. A simple filter expression might look like this:
AttributeName > :value
A filter expression is composed of an attribute name, a condition, and a value placeholder. Value placeholders always start with a colon (:) and will be replaced with their corresponding filter values when the query is run. For all valid filter expressions see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.SpecifyingConditions.html#ConditionExpressionReference Note that a range filter only accepts comparator, BETWEEN, and begins_with filter expressions.
Example code:
type Item struct { Hash string `dbkey:"hash"` Range int `dbkey:"range"` Value int } client := dynami.NewClient(dynami.USEast1, "id", "key") it := client.Query("ItemTable"). HashFilter("Hash", "somehashvalue"). RangeFilter("Range BETWEEN :rval1 AND :rval2", 1, 10). Filter("Value = :fval", 42). Run() for it.HasNext() { var item Item err := it.Next(&item) if err != nil { // Do something with item } }
Index ¶
- Variables
- type BatchDelete
- type BatchError
- type BatchGet
- type BatchPut
- type Client
- func (c *Client) BatchDelete(tableName string, items interface{}) *BatchDelete
- func (c *Client) BatchGet(tableName string, items interface{}, consistent ...bool) *BatchGet
- func (c *Client) BatchPut(tableName string, items interface{}) *BatchPut
- func (c *Client) ClearTable(tableName string) error
- func (c *Client) CreateTable(table *schema.Table) error
- func (c *Client) DeleteItem(tableName string, item interface{}) error
- func (c *Client) DeleteTable(tableName string) (*schema.Table, error)
- func (c *Client) DescribeTable(tableName string) (*schema.Table, error)
- func (c *Client) GetItem(tableName string, item interface{}, consistent ...bool) error
- func (c *Client) GetStream(tableName string) (*RecordIterator, error)
- func (c *Client) ListTables() ([]string, error)
- func (c *Client) PutItem(tableName string, item interface{}) error
- func (c *Client) Query(tableName string) *Query
- func (c *Client) UpdateTable(table *schema.Table) error
- type ItemIterator
- type Query
- func (q *Query) Consistent() *Query
- func (q *Query) Desc() *Query
- func (q *Query) Filter(expr string, values ...interface{}) *Query
- func (q *Query) HashFilter(name string, value interface{}) *Query
- func (q *Query) Index(indexName string) *Query
- func (q *Query) Limit(limit int) *Query
- func (q *Query) RangeFilter(expr string, values ...interface{}) *Query
- func (q *Query) Run() *ItemIterator
- type RecordIterator
- type RecordType
- type Region
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( USEast1 = &Region{ "us-east-1", "dynamodb.us-east-1.amazonaws.com", "streams.dynamodb.us-east-1.amazonaws.com", } USWest1 = &Region{ "us-west-1", "dynamodb.us-west-1.amazonaws.com", "streams.dynamodb.us-west-1.amazonaws.com", } USWest2 = &Region{ "us-west-2", "dynamodb.us-west-2.amazonaws.com", "streams.dynamodb.us-west-2.amazonaws.com", } EUWest1 = &Region{ "eu-west-1", "dynamodb.eu-west-1.amazonaws.com", "streams.dynamodb.eu-west-1.amazonaws.com", } EUCentral1 = &Region{ "eu-central-1", "dynamodb.eu-central-1.amazonaws.com", "streams.dynamodb.eu-central-1.amazonaws.com", } APNortheast1 = &Region{ "ap-northeast-1", "dynamodb.ap-northeast-1.amazonaws.com", "streams.dynamodb.ap-northeast-1.amazonaws.com", } APNortheast2 = &Region{ "ap-northeast-2", "dynamodb.ap-northeast-2.amazonaws.com", "streams.dynamodb.ap-northeast-2.amazonaws.com", } APSoutheast1 = &Region{ "ap-southeast-1", "dynamodb.ap-southeast-1.amazonaws.com", "streams.dynamodb.ap-southeast-1.amazonaws.com", } APSoutheast2 = &Region{ "ap-southeast-2", "dynamodb.ap-southeast-2.amazonaws.com", "streams.dynamodb.ap-southeast-2.amazonaws.com", } SAEast1 = &Region{ "sa-east-1", "dynamodb.sa-east-1.amazonaws.com", "streams.dynamodb.sa-east-1.amazonaws.com", } )
These are the list of all supported AWS regions.
var ( // ErrNoSuchItem is returned when no item is found for the given key. ErrNoSuchItem = errors.New("dynami: no such item") )
Functions ¶
This section is empty.
Types ¶
type BatchDelete ¶
type BatchDelete struct {
// contains filtered or unexported fields
}
BatchDelete can delete multiple items from one or more tables.
func (*BatchDelete) Delete ¶
func (b *BatchDelete) Delete(tableName string, items interface{}) *BatchDelete
Delete chains another batch delete operation. This can be called multiple times as long as tableName is unique for each call.
func (*BatchDelete) Run ¶
func (b *BatchDelete) Run() error
Run executes all delete operations in this batch. This may return a BatchError.
type BatchError ¶
BatchError represents a batch operation error. The outer map specifies the table where the error occurred and the inner map contains the index of the input element that caused the error.
func (BatchError) Error ¶
func (e BatchError) Error() string
type BatchGet ¶
type BatchGet struct {
// contains filtered or unexported fields
}
BatchGet represents a batch get operation. It allows fetching of multiple items from multiple tables.
type BatchPut ¶
type BatchPut struct {
// contains filtered or unexported fields
}
BatchPut represents a batch put operation. It can put multiple items in multiple tables with one DynamoDB operation.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client represents a DynamoDB client.
func (*Client) BatchDelete ¶
func (c *Client) BatchDelete(tableName string, items interface{}) *BatchDelete
BatchDelete queues a batch delete operation. items must be a []T or []*T where T is a map[string]interface{} or a struct.
func (*Client) BatchGet ¶
BatchGet queues a batch get operation. items must have the same conditions as that in BatchDelete.
func (*Client) BatchPut ¶
BatchPut queues a batch put operation. items must satisfy the same conditions as that in BatchDelete.
func (*Client) ClearTable ¶
ClearTable removes all items from a table. This is achieved by deleting items by batch.
func (*Client) CreateTable ¶
CreateTable adds a new table to the current account. This waits for the table to become useable or active before returning.
Example ¶
package main import ( "github.com/robskie/dynami" "github.com/robskie/dynami/schema" ) var client = dynami.NewClient(dynami.USEast1, "TEST_ID", "TEST_KEY") func main() { type TestItem struct { Hash string `dbkey:"hash"` Range string `dbkey:"range"` GlobalHash string `dbindex:"hash,GlobalIndex"` BigValue []byte SmallValue string `dbindex:"project,GlobalIndex"` } // Create table schema from TestItem table := schema.NewTable( "TestTable", TestItem{}, map[string]schema.Throughput{ "TestTable": schema.Throughput{ Read: 10, Write: 20, }, "GlobalIndex": schema.Throughput{ Read: 30, Write: 40, }, }, ) // Perform table creation client.CreateTable(table) }
Output:
func (*Client) DeleteItem ¶
DeleteItem removes an item from a table. item must be a map[string]interface{}, struct, or a pointer to any of the two with nonempty primary key.
func (*Client) DeleteTable ¶
DeleteTable removes a table from the current account. This blocks until the table no longer exists.
func (*Client) DescribeTable ¶
DescribeTable provides additional information about the given table. This includes the table's creation date, size in bytes, and the number of items it contains.
func (*Client) GetItem ¶
GetItem fetches an item from the database. item must be a pointer to a map[string]interface{} or pointer to a struct. In addition to retrieving items by its primary key, it can also get items using its local or global secondary index key, whichever is not empty. This only applies if item is a struct pointer.
Example ¶
package main import ( "github.com/robskie/dynami" ) var client = dynami.NewClient(dynami.USEast1, "TEST_ID", "TEST_KEY") func main() { type TestItem struct { Hash string `dbkey:"hash"` Range string `dbkey:"range"` GlobalHash string `dbindex:"hash,GlobalIndex"` Value int `dbindex:"project,GlobalIndex"` } // Fetch using primary key itemA := TestItem{ Hash: "somehash", Range: "somerange", } client.GetItem("TestTable", &itemA) // Fetch using secondary index key itemB := TestItem{ GlobalHash: "anotherhash", } client.GetItem("TestTable", &itemB) }
Output:
func (*Client) GetStream ¶
func (c *Client) GetStream(tableName string) (*RecordIterator, error)
GetStream returns the stream record iterator for the given table.
Example ¶
package main import ( "github.com/robskie/dynami" ) var client = dynami.NewClient(dynami.USEast1, "TEST_ID", "TEST_KEY") func main() { type TestItem struct { Hash string `dbkey:"hash"` Value int } it, _ := client.GetStream("TestTable") // Process each record as it arrives. // Note that this loop doesn't terminate // as long as the stream is enabled. var item TestItem for it.WaitNext() { recordType, _ := it.Next(&item) switch recordType { case dynami.AddedRecord: // Process added item case dynami.UpdatedRecord: // Process updated item case dynami.DeletedRecord: // Process deleted item } } }
Output:
func (*Client) ListTables ¶
ListTables returns all table names associated with the current account.
func (*Client) PutItem ¶
PutItem adds an item to the database. item must be a map[string]interface{}, struct, or a pointer to any of those with nonempty primary key.
func (*Client) UpdateTable ¶
UpdateTable modifies the table's throughput or global secondary indices. It can create and delete global secondary indices or update their throughputs. This method waits until all updates are finished.
Example ¶
package main import ( "github.com/robskie/dynami" "github.com/robskie/dynami/schema" ) var client = dynami.NewClient(dynami.USEast1, "TEST_ID", "TEST_KEY") func main() { // Get table schema table, _ := client.DescribeTable("TestTable") // Update table throughput table.Throughput = schema.Throughput{ Read: 10, Write: 20, } // Remove GlobalIndexA table.RemoveGlobalSecondaryIndex("GlobalIndexA") // Add GlobalIndexB table.AddGlobalSecondaryIndex(schema.SecondaryIndex{ Name: "GlobalIndexB", Throughput: schema.Throughput{ Read: 30, Write: 40, }, Key: []schema.Key{ { Name: "GlobalHashB", Type: schema.HashKey, }, }, }) table.AddAttributes([]schema.Attribute{ { Name: "GlobalHashB", Type: schema.StringType, }, }) // Update GlobalIndexC idx, _ := table.GetGlobalSecondaryIndex("GlobalIndexC") idx.Throughput = schema.Throughput{ Read: 50, Write: 60, } table.AddGlobalSecondaryIndex(idx) // Perform update client.UpdateTable(table) }
Output:
type ItemIterator ¶
type ItemIterator struct {
// contains filtered or unexported fields
}
ItemIterator iterates over the result of a query.
func (*ItemIterator) HasNext ¶
func (it *ItemIterator) HasNext() bool
HasNext returns true if there are more query results to iterate over.
func (*ItemIterator) Next ¶
func (it *ItemIterator) Next(item interface{}) error
Next loads the next result to item. item must be a pointer to map[string]interface{} or a pointer to struct.
type Query ¶
type Query struct {
// contains filtered or unexported fields
}
Query represents a client query. This may perform a DynamoDB query or scan operation depending on whether a hash filter is added or not.
func (*Query) Consistent ¶
Consistent sets the query to use strongly consistent reads. This is ignored for queries on global secondary indices.
func (*Query) Desc ¶
Desc arranges the result by range key in descending order. The default order is ascending.
func (*Query) Filter ¶
Filter adds a post filter expression to the query. Multiple filters are AND'ed together.
func (*Query) HashFilter ¶
HashFilter adds a hash filter to this query. Adding a hash filter to a query makes it perform a DynamoDB query operation instead of a scan operation.
func (*Query) RangeFilter ¶
RangeFilter adds a range filter to this query. Valid expressions are comparison, BETWEEN, and begins_with filter expressions.
func (*Query) Run ¶
func (q *Query) Run() *ItemIterator
Run executes the query and returns a result iterator.
type RecordIterator ¶
type RecordIterator struct {
// contains filtered or unexported fields
}
RecordIterator iterates through stream records.
func (*RecordIterator) HasNext ¶
func (it *RecordIterator) HasNext() bool
HasNext returns true if there are still some records to iterate over. Use this method to get all currently available records.
func (*RecordIterator) Next ¶
func (it *RecordIterator) Next(record interface{}) (RecordType, error)
Next loads the next record. record must be a pointer to struct or a pointer to a map[string]interface{}.
func (*RecordIterator) WaitNext ¶
func (it *RecordIterator) WaitNext() bool
WaitNext waits for the next record in the stream. This returns false if the stream is closed. Use this to get current and future records.
type RecordType ¶
type RecordType string
RecordType tells if an item is added, updated, or deleted from a table.
const ( AddedRecord RecordType = dynamodbstreams.OperationTypeInsert UpdatedRecord RecordType = dynamodbstreams.OperationTypeModify DeletedRecord RecordType = dynamodbstreams.OperationTypeRemove )
These are the valid record types. A record is created when an item is added, updated, or deleted from a table.