dynago

package module
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2015 License: MIT Imports: 13 Imported by: 5

README

Dynago

Dynago is a DynamoDB client API for Go.

This attempts to be a really simple, principle of least-surprise client for the DynamoDB API.

Key design tenets of Dynago:

  • Most actions are done via chaining to build filters and conditions
  • objects are completely safe for passing between goroutines (even queries and the like)
  • To make understanding easier via docs, we use amazon's naming wherever possible.

Installation

Install using go get:

go get gopkg.in/underarmour/dynago.v1

Docs are at http://godoc.org/gopkg.in/underarmour/dynago.v1

Example

Run a query:

client := dynago.NewClient(endpoint, accessKey, secretKey)

query := client.Query(table).
	KeyConditionExpression("UserId = :uid", dynago.Param{":uid", 42}).
	FilterExpression("NumViews > :views").
	Param(":views", 50).
	Desc()

result, err := query.Execute()
if err != nil {
	// do something
}
for _, row := range result.Items {
	fmt.Printf("Name: %s, Views: %d", row["Name"], row["NumViews"])
}

Type Marshaling

Dynago lets you use go types instead of having to understand a whole lot about dynamo's internal type system.

Example:

doc := dynago.Document{
	"name": "Bob",
	"age": 45,
	"height": 2.1,
	"address": dynago.Document{
		"city": "Boston",
	},
	"tags": dynago.StringSet{"male", "middle_aged"},
}
client.PutItem("person", doc).Execute()
  • Strings use golang string
  • Numbers can be input as int (int64, uint64, etc) or float64 but always are returned as dynago.Number to not lose precision.
  • Maps can be either map[string]interface{} or dynago.Document
  • Opaque binary data can be put in []byte
  • String sets, number sets, binary sets are supported using dynago.StringSet dynago.NumberSet dynago.BinarySet
  • Lists are supported using dynago.List
  • time.Time is only accepted if it's a UTC time, and is marshaled to a dynamo string in iso8601 compact format. It comes back as a string, an can be got back using GetTime() on Document.

Debugging

Dynago can dump request or response information for you for use in debugging. Simply set dynago.Debug with the necessary flags:

dynago.Debug = dynago.DebugRequests | dynago.DebugResponses

If you would like to change how the debugging is printed, please set dynago.DebugFunc (func(string, ...interface{})) to your preference.

Additional resources

  • DynamoDB's own API reference explains the operations that DynamoDB supports, and as such will provide more information on how specific parameters and values within dynago actually work.
  • http://godoc.org/github.com/crast/dynatools is a collection of packages with "edge" functionality for dynago, which includes additional libraries to add on, and some functionality fixes which may be considered for merging into dynago core in the future. It includes bits such as pluggable authentication, support for DynamoDB streams, and more.

The past, and the future

Dynago came out of a dissatisfaction with the existing features of the major implementation of DynamoDB for Go that existed back in April 2015, because many operations used deprecated API's (at the time) and made it very difficult to know which operations we should actually use. Not to mention, the annoying parts of dealing with DynamoDB types.

AWS-SDK-Go exists as of June 2015 and has a very up to date API, but it also comes with the pain of using bare structs which minimally wrap protocol-level details of DynamoDB, which makes it a pain to use for writing applications (dealing with DynamoDB's internal type system is boilerplatey). For this reason, there's still a reason for Dynago to exist, but once Amazon has trued up their SDK and brought it out of developer preview, the plan is to have Dynago use it as the underlying protocol and signature implementation, but keep providing dynago's clean and simple API for building queries and marshaling datatypes in dynamodb.

Documentation

Overview

Dynago is a DynamoDB client API for Go.

Dynago differs from other Dynamo clients for Go in that it tries to mirror DynamoDB's core API closely: Most methods, attributes, and names are made following Dynamo's own naming conventions. This allows it to be clear which API is being accessed and allows finding complementary docs on Amazon's side easier.

Filter Chaining

A key design concept is the use of chaining to build filters and conditions, similar to some ORM frameworks. This allows using sub-features like conditional puts, expression post-filtering, and so on to be clearer, because this means a conditional put is simply a PutItem with a condition expression tacked on.

query := client.Query("Table").
    KeyConditionExpression("Foo = :foo", dynago.Param{":foo", 42}).
    Limit(40).Desc()
result, err := query.Execute()

All the various item-based query actions are evaluated when you call the Execute() method on a filter chain.

Type Marshaling

Dynago tries to marshal to/from Go types where possible:

  • Strings use golang string
  • Numbers can be input as int, int64, float64, etc but always are returned as dynago.Number to not lose precision.
  • Maps can be either map[string]interface{} or dynago.Document
  • Opaque binary data can be put in []byte
  • String sets, number sets, binary sets are supported using dynago.StringSet, dynago.NumberSet, dynago.BinarySet
  • Lists are supported using dynago.List
  • time.Time is only accepted if it's a UTC time, and is marshaled to a dynamo string in iso8601 compact format. It comes back as a string, an can be unmarshaled back using GetTime on document.

Query Parameters

Nearly all the operations on items allow using DynamoDB's expression language to do things like query filtering, attribute projection, and so on. In order to provide literal values, queries are parametric, just like many SQL engines:

SET Foo = Foo + :incr
DELETE Person.#n

DynamoDB has two fields it uses for parameters: ExpressionAttributeNames for name aliases, and ExpressionAttributeValues for parametric values. For simplicity, in the Dynago library both of those are serviced by Param. This is okay because parameters and aliases are non-ambiguous in that the former are named e.g. ":foo" and the latter "#foo".

So a conditional PutItem might look like:

client.PutItem(table, item).
    ConditionExpression("Foo.#n = :fooName").
    Param("#n", "Name").Param(":fooName", "Bob").
    Execute()

In this case, we only execute the query if the value at document path Foo.Name was the string value "Bob". Note we used the "Param" helper for setting both values.

There are also helpers that let you set multiple parameters, or inline with expressions:

query.FilterExpression("#foo > :foo", Param{":foo", 45}, Param{"#foo", "Foo"})
-or-
query.Params(Param{":foo", 45}, Param{"#foo", "Foo"})
-or-
query.Params(Document{":foo":45, "#foo": "Foo"})
Example
package main

import (
	"fmt"
	"gopkg.in/underarmour/dynago.v1"
)

var region, accessKey, secretKey, table string

func main() {
	client := dynago.NewAwsClient(region, accessKey, secretKey)

	query := client.Query(table).
		FilterExpression("NumViews > :views").
		Param(":views", 50).
		Desc()

	result, err := query.Execute()
	if err != nil {
		// do something
	}
	for _, row := range result.Items {
		fmt.Printf("Name: %s, Views: %d", row["Name"], row["NumViews"])
	}
}

func main(client *dynago.Client) {
	type MyStruct struct {
		Id          int64
		Name        string
		Description string
		Tags        []string
		Address     struct {
			City  string
			State string
		}
	}

	var data MyStruct

	doc := dynago.Document{
		// Basic fields like numbers and strings get marshaled automatically
		"Id":          data.Id,
		"Name":        data.Name,
		"Description": data.Description,
		// StringSet is compatible with []string so we can simply cast it
		"Tags": dynago.StringSet(data.Tags),
		// We don't automatically marshal structs, nest it in a document
		"Address": dynago.Document{
			"City":  data.Address.City,
			"State": data.Address.State,
		},
	}

	client.PutItem("Table", doc).Execute()
}

Index

Examples

Constants

View Source
const (
	ErrorUnknown codes.ErrorCode = iota

	ErrorConditionFailed        // Conditional put/update failed; condition not met
	ErrorCollectionSizeExceeded // Item collection (local secondary index) too large
	ErrorThroughputExceeded     // Exceeded provisioned throughput for table or shard
	ErrorNotFound               // Resource referenced by key not found
	ErrorInternalFailure        // Internal server error
	ErrorAuth                   // Encapsulates various authorization errors
	ErrorInvalidParameter       // Encapsulates many forms of invalid input errors
	ErrorServiceUnavailable     // Amazon service unavailable
	ErrorThrottling             // Amazon is throttling us, try later
	ErrorResourceInUse          // Tried to create existing table, delete a table in CREATING state, etc.

	// DynamoDB Streams-specific errors
	ErrorExpiredIterator // Iterator is no longer valid
	ErrorTrimmedData     // Attempted to access data older than 24h
)

Variables

View Source
var DebugFunc func(format string, v ...interface{}) = func(format string, v ...interface{}) {
	log.Printf("Dynago DEBUG: "+format, v...)
}

Set the target of debug. Must be set for debug to be used.

Functions

This section is empty.

Types

type AwsExecutor

type AwsExecutor struct {
	// Underlying implementation that makes requests for this executor. It
	// is called to make every request that the executor makes. Swapping the
	// underlying implementation is not thread-safe and therefore not
	// recommended in production code.
	Requester AwsRequester
}

The AwsExecutor is the actual underlying implementation that turns dynago request structs and makes actual queries.

func NewAwsExecutor

func NewAwsExecutor(endpoint, region, accessKey, secretKey string) *AwsExecutor

Create an AWS executor with a specified endpoint and AWS parameters.

func (*AwsExecutor) BatchGetItem added in v1.2.1

func (e *AwsExecutor) BatchGetItem(b *BatchGet) (result *BatchGetResult, err error)

func (*AwsExecutor) BatchWriteItem

func (e *AwsExecutor) BatchWriteItem(b *BatchWrite) (result *BatchWriteResult, err error)

func (*AwsExecutor) DeleteItem

func (e *AwsExecutor) DeleteItem(d *DeleteItem) (res *DeleteItemResult, err error)

func (*AwsExecutor) GetItem

func (e *AwsExecutor) GetItem(g *GetItem) (result *GetItemResult, err error)

func (*AwsExecutor) MakeRequestUnmarshal

func (e *AwsExecutor) MakeRequestUnmarshal(method string, document interface{}, dest interface{}) (err error)

Make a request to the underlying requester, marshaling document as JSON, and if the requester doesn't error, unmarshaling the response back into dest.

This method is mostly exposed for those implementing custom executors or prototyping new functionality.

func (*AwsExecutor) PutItem

func (e *AwsExecutor) PutItem(p *PutItem) (res *PutItemResult, err error)

func (*AwsExecutor) Query

func (e *AwsExecutor) Query(q *Query) (result *QueryResult, err error)

func (*AwsExecutor) Scan

func (e *AwsExecutor) Scan(s *Scan) (result *ScanResult, err error)

func (*AwsExecutor) SchemaExecutor

func (e *AwsExecutor) SchemaExecutor() SchemaExecutor

func (*AwsExecutor) UpdateItem

func (e *AwsExecutor) UpdateItem(u *UpdateItem) (result *UpdateItemResult, err error)

type AwsRequester

type AwsRequester interface {
	MakeRequest(target string, body []byte) ([]byte, error)
}

type BatchGet added in v1.2.1

type BatchGet struct {
	// contains filtered or unexported fields
}

func (BatchGet) ConsistentRead added in v1.3.1

func (b BatchGet) ConsistentRead(table string, consistent bool) *BatchGet

Set consistent read mode for a table.

Consistent read is scoped to each table, so must be called for each table in this BatchGet for which you want consistent reads.

func (*BatchGet) Execute added in v1.2.1

func (b *BatchGet) Execute() (result *BatchGetResult, err error)

Execute this batch get.

func (BatchGet) Get added in v1.2.1

func (b BatchGet) Get(table string, keys ...Document) *BatchGet

Set which keys to get. Can be called multiple times to queue up gets for multiple tables.

func (BatchGet) ProjectionExpression added in v1.2.1

func (b BatchGet) ProjectionExpression(table string, expression string, params ...Params) *BatchGet

Add a ProjectionExpression for a table.

Projection expression is scoped to each table, and must be called for each table on which you want a ProjectionExpression.

type BatchGetResult added in v1.2.1

type BatchGetResult struct {
	// Responses to the Batch Get query which were resolved.
	// Note that the order of documents is not guaranteed to be the same as
	// the order of documents requested in building this query.
	Responses map[string][]Document // table name -> list of items.

	// Unprocessed keys are keys which for some reason could not be retrieved.
	// This could be because of response size exceeding the limit or the
	// provisioned throughput being exceeded on one or more tables in this request.
	UnprocessedKeys BatchGetTableMap // Table name -> keys and settings
}

type BatchGetTableEntry added in v1.2.1

type BatchGetTableEntry struct {
	Keys []Document

	ProjectionExpression string `json:",omitempty"`
	ConsistentRead       bool   `json:",omitempty"`
	// contains filtered or unexported fields
}

type BatchGetTableMap added in v1.2.1

type BatchGetTableMap map[string]*BatchGetTableEntry

type BatchWrite

type BatchWrite struct {
	// contains filtered or unexported fields
}

func (BatchWrite) Delete

func (b BatchWrite) Delete(table string, keys ...Document) *BatchWrite

Add some number of deletes for a table.

func (*BatchWrite) Execute

func (b *BatchWrite) Execute() (*BatchWriteResult, error)

func (BatchWrite) Put

func (b BatchWrite) Put(table string, items ...Document) *BatchWrite

Add some number of puts for a table.

type BatchWriteResult

type BatchWriteResult struct {
	UnprocessedItems BatchWriteTableMap
}

type BatchWriteTableEntry

type BatchWriteTableEntry struct {
	DeleteRequest *batchDelete `json:",omitempty"`
	PutRequest    *batchPut    `json:",omitempty"`
}

func (*BatchWriteTableEntry) SetDelete

func (e *BatchWriteTableEntry) SetDelete(key Document)

Set this table entry as a delete request

func (*BatchWriteTableEntry) SetPut

func (e *BatchWriteTableEntry) SetPut(item Document)

type BatchWriteTableMap

type BatchWriteTableMap map[string][]*BatchWriteTableEntry

func (BatchWriteTableMap) GetDeleteKeys

func (m BatchWriteTableMap) GetDeleteKeys(table string) (deletes []Document)

Convenience method to get delete keys in this batch write map for a specific table

func (BatchWriteTableMap) GetPuts

func (m BatchWriteTableMap) GetPuts(table string) (puts []Document)

Convenience method to get all put documents in this batch write map for a specific table

type BinarySet

type BinarySet [][]byte

A set of binary blobs.

Note that BinarySet doesn't guarantee ordering on retrieval.

type CapacityDetail

type CapacityDetail string
const (
	CapacityIndexes CapacityDetail = "INDEXES"
	CapacityTotal   CapacityDetail = "TOTAL"
	CapacityNone    CapacityDetail = "NONE"
)

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the primary start point of interaction with Dynago.

Client is concurrency safe, and completely okay to be used in multiple threads/goroutines, as are the operations involving chaining on the client.

func NewAwsClient

func NewAwsClient(region string, accessKey string, secretKey string) *Client

Create a new dynamo client set up for AWS executor.

region is the AWS region, e.g. us-east-1. accessKey is your amazon access key ID. secretKey is your amazon secret key ID.

func NewClient

func NewClient(executor Executor) *Client

Create a new client.

For most use cases other than testing and mocking, you should be able to use NewAwsClient which is a shortcut for this

func (*Client) BatchGet added in v1.2.1

func (c *Client) BatchGet() *BatchGet

Compose a batch get operation.

Batch gets allow you to get up to 100 keys, in parallel, even across multiple tables, in a single operation.

func (*Client) BatchWrite

func (c *Client) BatchWrite() *BatchWrite

Compose a batch write.

Batch writes can compose a number of put or delete, even across multiple tables, in a single operation.

func (*Client) CreateTable

func (c *Client) CreateTable(req *schema.CreateRequest) (*schema.CreateResult, error)

Create a table.

func (*Client) DeleteItem

func (c *Client) DeleteItem(table string, key Document) *DeleteItem

Compose a DeleteItem on a dynamo key

func (*Client) DeleteTable

func (c *Client) DeleteTable(table string) (*schema.DeleteResult, error)

Delete a table.

func (*Client) DescribeTable

func (c *Client) DescribeTable(table string) (*schema.DescribeResponse, error)

func (*Client) GetItem

func (c *Client) GetItem(table string, key Document) *GetItem

Compose a GetItem on a dynamo table.

key should be a Document containing enough attributes to describe the primary key.

You can use the HashKey or HashRangeKey helpers to help build a key:

client.GetItem("foo", dynago.HashKey("Id", 45))

client.GetItem("foo", dynago.HashRangeKey("UserId", 45, "Date", "20140512"))

func (*Client) ListTables

func (c *Client) ListTables() *ListTables

func (*Client) PutItem

func (c *Client) PutItem(table string, item Document) *PutItem

Compose a PutItem on a dynamo table.

item should be a document representing the record and containing the attributes for the primary key.

Like all the other requests, you must call `Execute()` to run this.

func (*Client) Query

func (c *Client) Query(table string) *Query

Compose a Query on a dynamo table.

This returns a new Query struct which you can compose via chaining to build the query you want. Then finish the chain by calling Execute() to run the query.

func (*Client) Scan

func (c *Client) Scan(table string) *Scan

Compose a Scan on a dynamo table.

func (*Client) UpdateItem

func (c *Client) UpdateItem(table string, key Document) *UpdateItem

Compose an UpdateItem on a dynamo table.

type DebugFlags

type DebugFlags uint
const (
	DebugRequests DebugFlags = 1 << iota
	DebugResponses
	DebugAuth
)
var Debug DebugFlags

Set the debug mode.

This is a set of bit-flags you can use to set up how much debugging dynago uses:

dynago.Debug = dynago.DebugRequests | dynago.DebugResponses

Debug flags are copied into any executors, requesters, etc at creation time so the flags must be set before creating any Executor or client for them to take effect.

func (DebugFlags) HasFlag

func (v DebugFlags) HasFlag(flag DebugFlags) bool

Convenience method to check if a value has a flag:

Debug.HasFlags(DebugRequests)

type DeleteItem

type DeleteItem struct {
	// contains filtered or unexported fields
}

func (DeleteItem) ConditionExpression

func (d DeleteItem) ConditionExpression(expression string, params ...Params) *DeleteItem

Set a ConditionExpression to do a conditional DeleteItem.

func (*DeleteItem) Execute

func (d *DeleteItem) Execute() (res *DeleteItemResult, err error)

Actually Execute this putitem.

DeleteItemResult will be nil unless ReturnValues is set.

func (DeleteItem) ReturnValues

func (d DeleteItem) ReturnValues(returnValues ReturnValues) *DeleteItem

Set ReturnValues. For DeleteItem, it can only be ReturnAllOld

type DeleteItemResult

type DeleteItemResult struct {
	Attributes Document
}

type Document

type Document map[string]interface{}

Represents an entire document structure composed of keys and dynamo value

func HashKey

func HashKey(name string, value interface{}) Document

Helper to build a hash key.

func HashRangeKey

func HashRangeKey(hashName string, hashVal interface{}, rangeName string, rangeVal interface{}) Document

Helper to build a hash-range key.

func (Document) AsParams

func (d Document) AsParams() (params []Param)

Allow a document to be used to specify params

func (Document) GetBool

func (d Document) GetBool(key string) bool

Gets the value at the key as a boolean.

If the value does not exist in this Document, returns false. If the value is the nil interface, also returns false. If the value is a bool, returns the value of the bool. If the value is a Number, returns true if value is non-zero. For any other values, panics.

func (Document) GetList

func (d Document) GetList(key string) List

Helper to get a key from document as a List.

If value at key is nil, returns a nil list. If value at key is not a List, will panic.

func (Document) GetNumber

func (d Document) GetNumber(key string) Number

Helper to get a Number from a document.

func (Document) GetString

func (d Document) GetString(key string) string

Helper to get a string from a document.

func (Document) GetStringSet

func (d Document) GetStringSet(key string) StringSet

Helper to get a key from a document as a StringSet.

If value at key does not exist; returns an empty StringSet. If it exists but is not a StringSet, panics.

func (Document) GetTime

func (d Document) GetTime(key string) (t *time.Time)

Helper to get a Time from a document.

If the value is omitted from the DB, or an empty string, then the return is nil. If the value fails to parse as iso8601, then this method panics.

func (Document) MarshalJSON

func (d Document) MarshalJSON() ([]byte, error)

func (*Document) UnmarshalJSON

func (d *Document) UnmarshalJSON(buf []byte) error

type Error

type Error struct {
	Type          codes.ErrorCode // Parsed and mapped down type
	AmazonRawType string          // Raw error type from amazon
	Exception     string          // Exception from amazon
	Message       string          // Raw message from amazon
	Request       *http.Request   // If available, HTTP request
	RequestBody   []byte          // If available, raw request body bytes
	Response      *http.Response  // If available, HTTP response
	ResponseBody  []byte          // If available, raw response body bytes
}

Encapsulates errors coming from amazon/dynamodb

func (*Error) Error

func (e *Error) Error() string

type Executor

type Executor interface {
	BatchGetItem(*BatchGet) (*BatchGetResult, error)
	BatchWriteItem(*BatchWrite) (*BatchWriteResult, error)
	DeleteItem(*DeleteItem) (*DeleteItemResult, error)
	GetItem(*GetItem) (*GetItemResult, error)
	PutItem(*PutItem) (*PutItemResult, error)
	Query(*Query) (*QueryResult, error)
	Scan(*Scan) (*ScanResult, error)
	UpdateItem(*UpdateItem) (*UpdateItemResult, error)
	SchemaExecutor() SchemaExecutor
}

This interface defines how all the various queries manage their internal execution logic.

Executor is primarily provided so that testing and mocking can be done on the API level, not just the transport level.

Executor can also optionally return a SchemaExecutor to execute schema actions.

type GetItem

type GetItem struct {
	// contains filtered or unexported fields
}

func (GetItem) ConsistentRead

func (p GetItem) ConsistentRead(strong bool) *GetItem

Set up this get to be a strongly consistent read.

func (*GetItem) Execute

func (p *GetItem) Execute() (result *GetItemResult, err error)

Execute the get item.

func (GetItem) Param

func (p GetItem) Param(key string, value interface{}) *GetItem

Shortcut to set an ExpressionAttributeValue for used in expression query

func (GetItem) Params

func (p GetItem) Params(params ...Params) *GetItem

func (GetItem) ProjectionExpression

func (p GetItem) ProjectionExpression(expression string, params ...Params) *GetItem

Set the ProjectionExpression for this GetItem (which attributes to get)

type GetItemResult

type GetItemResult struct {
	Item             Document
	ConsumedCapacity interface{} // TODO
}

The result from executing a GetItem.

type List

type List []interface{}

Lists represent DynamoDB lists, which are functionally very similar to JSON lists. Like JSON lists, these lists are heterogeneous, which means that the elements of the list can be any valid value type, which includes other lists, documents, numbers, strings, etc.

Example
package main

import (
	"fmt"

	"gopkg.in/underarmour/dynago.v1"
)

func main() {
	l := dynago.List{
		1234,
		"Foo",
		dynago.Document{"Foo": "Bar"},
	}
	fmt.Printf("%s", l[1])
}
Output:
Foo

func (List) AsDocumentList

func (l List) AsDocumentList() ([]Document, error)

Return a copy of this list with all elements coerced as Documents.

It's very common to use lists in dynago where all elements in the list are a Document. For that reason, this method is provided as a convenience to get back your list as a list of documents.

If any element in the List is not a document, this will error. As a convenience, even when it errors, a slice containing any elements preceding the one which errored as documents will be given.

type ListTables

type ListTables struct {
	// contains filtered or unexported fields
}

func (*ListTables) Execute

func (l *ListTables) Execute() (result *ListTablesResult, err error)

func (ListTables) Limit

func (l ListTables) Limit(limit uint) *ListTables

type ListTablesResult

type ListTablesResult struct {
	TableNames []string
	// contains filtered or unexported fields
}

func (ListTablesResult) Next

func (r ListTablesResult) Next() *ListTables

Helper to get the ListTables for the next page of listings. If there is not a next page, returns nil

type MockExecutor

type MockExecutor struct {
	Calls []MockExecutorCall // All calls made through this executor

	DeleteItemCalled bool
	DeleteItemCall   *MockExecutorCall
	DeleteItemResult *DeleteItemResult
	DeleteItemError  error

	PutItemCalled bool
	PutItemCall   *MockExecutorCall
	PutItemResult *PutItemResult
	PutItemError  error

	GetItemCalled bool
	GetItemCall   *MockExecutorCall
	GetItemResult *GetItemResult
	GetItemError  error

	BatchGetItemCalled bool
	BatchGetItemCall   *MockExecutorCall
	BatchGetItemResult *BatchGetResult

	BatchWriteItemCalled bool
	BatchWriteItemCall   *MockExecutorCall
	BatchWriteItemError  error

	QueryCalled bool              // True if query was called at least once
	QueryCall   *MockExecutorCall // Info for the last call to Query
	QueryError  error             // Specify the error from Query
	QueryResult *QueryResult      // Specify the result from Query

	ScanCalled bool
	ScanCall   *MockExecutorCall
	ScanResult *ScanResult
	ScanError  error

	UpdateItemCalled bool
	UpdateItemCall   *MockExecutorCall
	UpdateItemResult *UpdateItemResult
	UpdateItemError  error
}

A Mock executor for purpose of testing.

This Executor doesn't actually run any network requests, so it can be used in unit testing for your own application which uses Dynago. It can be asserted on whether a specific underlying method got called, what it was called with, and the nature of how the query was built. You can also for most methods control which result is returned in order to control how results make it back to the application.

// example, normally you'd call into a real application not inside your
// test module and use dependency injection to specify the client.
func application(client *dynago.Client) int {
	result, err := client.PutItem("mytable", doc).Execute()
	// do something with result maybe.
}

func TestApplication() {
	executor := &dynago.MockExecutor{}
	client := dynago.NewClient(executor)
	executor.PutItemResult = &dynago.PutItemResult{}

	// call into application
	application(client)

	// assert things on the executor.
	assert.Equal(true, executor.PutItemCalled)
	assert.Equal("mytable", executor.PutItemCall.Table)
	... and so on
}

func (*MockExecutor) BatchGetItem added in v1.2.1

func (e *MockExecutor) BatchGetItem(batchGet *BatchGet) (*BatchGetResult, error)

func (*MockExecutor) BatchWriteItem

func (e *MockExecutor) BatchWriteItem(batchWrite *BatchWrite) (*BatchWriteResult, error)

func (*MockExecutor) DeleteItem

func (e *MockExecutor) DeleteItem(deleteItem *DeleteItem) (*DeleteItemResult, error)

func (*MockExecutor) GetItem

func (e *MockExecutor) GetItem(getItem *GetItem) (*GetItemResult, error)

func (*MockExecutor) PutItem

func (e *MockExecutor) PutItem(putItem *PutItem) (*PutItemResult, error)

func (*MockExecutor) Query

func (e *MockExecutor) Query(query *Query) (*QueryResult, error)

func (*MockExecutor) Scan

func (e *MockExecutor) Scan(scan *Scan) (*ScanResult, error)

func (*MockExecutor) SchemaExecutor

func (e *MockExecutor) SchemaExecutor() SchemaExecutor

Currently we don't implement mocking for SchemaExecutor. Returns nil.

func (*MockExecutor) UpdateItem

func (e *MockExecutor) UpdateItem(update *UpdateItem) (*UpdateItemResult, error)

type MockExecutorCall

type MockExecutorCall struct {
	// used for all calls
	Method string
	Table  string

	// used for calls with expressions (most of them)
	ExpressionAttributeNames  map[string]string
	ExpressionAttributeValues Document

	Key                 Document
	Item                Document
	UpdateExpression    string
	ConditionExpression string
	ReturnValues        ReturnValues
	ConsistentRead      bool

	// Query and Scan
	IndexName              string
	KeyConditionExpression string
	FilterExpression       string
	ProjectionExpression   string
	Ascending              bool
	Limit                  uint
	ExclusiveStartKey      Document
	Select                 Select
	Segment                *int
	TotalSegments          *int

	BatchWrites BatchWriteTableMap
	BatchGets   BatchGetTableMap
}

Mock executor calls

type Number

type Number string

Represents a number.

DynamoDB returns numbers as a string representation because they have a single high-precision number type that can take the place of integers, floats, and decimals for the majority of types.

This method has helpers to get the value of this number as one of various Golang numeric type.

func (Number) FloatVal

func (n Number) FloatVal() (float64, error)

func (Number) Int64Val

func (n Number) Int64Val() (int64, error)

func (Number) IntVal

func (n Number) IntVal() (int, error)

func (Number) Uint64Val

func (n Number) Uint64Val() (uint64, error)

type NumberSet

type NumberSet []string

A set of numbers.

type Param

type Param struct {
	Key   string
	Value interface{}
}

func (Param) AsParams

func (p Param) AsParams() []Param

Allows a solo Param to also satisfy the Params interface

type Params

type Params interface {
	AsParams() []Param
}

Anything which implements Params can be used as expression parameters for dynamodb expressions.

DynamoDB item queries using expressions can be provided parameters in a number of handy ways:

.Param(":k1", v1).Param(":k2", v2)
-or-
.Params(Param{":k1", v1}, Param{":k2", v2})
-or-
.FilterExpression("...", Param{":k1", v1}, Param{":k2", v2})
-or-
.FilterExpression("...", Document{":k1": v1, ":k2": v2})

Or any combination of Param, Document, or potentially other custom types which provide the Params interface.

type PutItem

type PutItem struct {
	// contains filtered or unexported fields
}

func (PutItem) ConditionExpression

func (p PutItem) ConditionExpression(expression string, params ...Params) *PutItem

Set a ConditionExpression to do a conditional PutItem.

func (*PutItem) Execute

func (p *PutItem) Execute() (res *PutItemResult, err error)

Actually Execute this putitem.

PutItemResult will be nil unless ReturnValues or ReturnConsumedCapacity is set.

func (PutItem) Param

func (p PutItem) Param(key string, value interface{}) *PutItem

Set parameter for ConditionExpression

func (PutItem) Params

func (p PutItem) Params(params ...Params) *PutItem

func (PutItem) ReturnValues

func (p PutItem) ReturnValues(returnValues ReturnValues) *PutItem

Set ReturnValues.

type PutItemResult

type PutItemResult struct {
	Attributes Document
}

type Query

type Query struct {
	// contains filtered or unexported fields
}

func (Query) ConsistentRead

func (q Query) ConsistentRead(strong bool) *Query

If strong is true, do a strongly consistent read. (defaults to false)

func (*Query) Desc

func (q *Query) Desc() *Query

Return results descending. Equivalent to q.ScanIndexForward(false)

func (Query) ExclusiveStartKey

func (q Query) ExclusiveStartKey(key Document) *Query

Set the start key (effectively the offset cursor)

func (*Query) Execute

func (q *Query) Execute() (result *QueryResult, err error)

Execute this query and return results.

func (Query) FilterExpression

func (q Query) FilterExpression(expression string, params ...Params) *Query

Set a post-filter expression for the results we scan.

func (Query) IndexName

func (q Query) IndexName(name string) *Query

func (Query) KeyConditionExpression

func (q Query) KeyConditionExpression(expression string, params ...Params) *Query

Set a condition expression on the key to narrow down what we scan

func (Query) Limit

func (q Query) Limit(limit uint) *Query

Set the limit on results count.

Note that getting less than `limit` records doesn't mean you're at the last page of results, that can only be safely asserted if there is no LastEvaluatedKey on the result.

func (Query) Param

func (q Query) Param(key string, value interface{}) *Query

Shortcut to set a single parameter for ExpressionAttributeValues.

func (Query) Params

func (q Query) Params(params ...Params) *Query

Set a param, a document of params, or multiple params

func (Query) ProjectionExpression

func (q Query) ProjectionExpression(expression string, params ...Params) *Query

Set a Projection Expression for controlling which attributes are returned.

func (Query) ScanIndexForward added in v1.3.1

func (q Query) ScanIndexForward(forward bool) *Query

Whether to scan the query index forward (true) or backwards (false).

Defaults to forward (true) if not called.

func (Query) Select added in v1.1.2

func (q Query) Select(value Select) *Query

Select specifies how attributes are chosen, or enables count mode.

Most of the time, specifying Select is not required, because the DynamoDB API does the "right thing" inferring values based on other attributes like the projection expression, index, etc.

type QueryResult

type QueryResult struct {
	Items            []Document // All the items in the result
	Count            int        // The total number of items in the result
	ScannedCount     int        // How many items were scanned past to get the result
	LastEvaluatedKey Document   // The offset key for the next page.
	// contains filtered or unexported fields
}

The result returned from a query.

func (*QueryResult) Next

func (qr *QueryResult) Next() (query *Query)

Helper for getting a query which will get the next page of results. Returns nil if there's no next page.

type ReturnValues

type ReturnValues string
const (
	ReturnNone       ReturnValues = "NONE"
	ReturnAllOld     ReturnValues = "ALL_OLD"
	ReturnUpdatedOld ReturnValues = "UPDATED_OLD"
	ReturnAllNew     ReturnValues = "ALL_NEW"
	ReturnUpdatedNew ReturnValues = "UPDATED_NEW"
)

type Scan

type Scan struct {
	// contains filtered or unexported fields
}

func (Scan) ExclusiveStartKey

func (s Scan) ExclusiveStartKey(key Document) *Scan

Set the start key (effectively the offset cursor).

func (*Scan) Execute

func (s *Scan) Execute() (*ScanResult, error)

Execute this scan query.

func (Scan) FilterExpression

func (s Scan) FilterExpression(expression string, params ...Params) *Scan

Set a filter expression on this scan.

Scans with a FilterExpression may return 0 results due to scanning past records which don't match the filter, but still have more results to get.

func (Scan) IndexName

func (s Scan) IndexName(name string) *Scan

Run this scan on an index of a table.

func (Scan) Limit

func (s Scan) Limit(limit uint) *Scan

Maximum number of results to return per call.

func (Scan) ProjectionExpression

func (s Scan) ProjectionExpression(expression string, params ...Params) *Scan

Set which keys are used on this scan.

func (Scan) Segment

func (s Scan) Segment(segment, total int) *Scan

Choose the parallel segment of the table to scan.

func (Scan) Select added in v1.1.2

func (s Scan) Select(value Select) *Scan

Select specifies how attributes are chosen, or enables count mode.

Most of the time, specifying Select is not required, because the DynamoDB API does the "right thing" inferring values based on other attributes like the projection expression, index, etc.

type ScanResult

type ScanResult struct {
	Items            []Document
	LastEvaluatedKey Document
	// contains filtered or unexported fields
}

func (*ScanResult) Next

func (r *ScanResult) Next() *Scan

Helper to get the scan query representing the next page of results.

If the scan has a LastEvaluatedKey, returns another Scan. Otherwise, returns nil.

type SchemaExecutor

type SchemaExecutor interface {
	CreateTable(*schema.CreateRequest) (*schema.CreateResult, error)
	DeleteTable(*schema.DeleteRequest) (*schema.DeleteResult, error)
	DescribeTable(*schema.DescribeRequest) (*schema.DescribeResponse, error)
	ListTables(*ListTables) (*schema.ListResponse, error)
}

type Select

type Select string
const (
	SelectAllAttributes      Select = "ALL_ATTRIBUTES"
	SelectAllProjected       Select = "ALL_PROJECTED_ATTRIBUTES"
	SelectCount              Select = "COUNT"
	SelectSpecificAttributes Select = "SPECIFIC_ATTRIBUTES"
)

type StringSet

type StringSet []string

Store a set of strings.

Sets in DynamoDB do not guarantee any ordering, so storing and retrieving a StringSet may not give you back the same order you put it in. The main advantage of using sets in DynamoDB is using atomic updates with ADD and DELETE in your UpdateExpression.

type UpdateItem

type UpdateItem struct {
	// contains filtered or unexported fields
}

func (UpdateItem) ConditionExpression

func (u UpdateItem) ConditionExpression(expression string, params ...Params) *UpdateItem

Set a condition expression for conditional update.

func (*UpdateItem) Execute

func (u *UpdateItem) Execute() (res *UpdateItemResult, err error)

Execute this UpdateItem and return the result.

func (UpdateItem) Param

func (u UpdateItem) Param(key string, value interface{}) *UpdateItem

Quick-set a single parameter

func (UpdateItem) Params

func (u UpdateItem) Params(params ...Params) *UpdateItem

Set multiple parameters at once.

func (UpdateItem) ReturnValues

func (u UpdateItem) ReturnValues(returnValues ReturnValues) *UpdateItem

If set, then we will get return values of either updated or old fields (see ReturnValues const)

func (UpdateItem) UpdateExpression

func (u UpdateItem) UpdateExpression(expression string, params ...Params) *UpdateItem

Set an update expression to update specific fields and values.

type UpdateItemResult

type UpdateItemResult struct {
	Attributes Document
}

Directories

Path Synopsis
internal
aws
Provide AWS signature and other AWS-specific auth functions.
Provide AWS signature and other AWS-specific auth functions.
codes
package codes defines the error types dynago maps.
package codes defines the error types dynago maps.
dynamodb
package dynamodb maps information from dynamo itself, such as error tables and formats.
package dynamodb maps information from dynamo itself, such as error tables and formats.
Provides DynamoDB streams support for Dynago.
Provides DynamoDB streams support for Dynago.

Jump to

Keyboard shortcuts

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