redimo

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: May 23, 2020 License: Apache-2.0 Imports: 18 Imported by: 0

README

REDIMO

Go GoDoc

Redimo is a library that allows you to use the Redis API on DynamoDB. The DynamoDB system is excellent at what it does on a specific set of use cases, but is more difficult to use than it should be because the API is very low level and requires a lot of arcane knowledge. The Redis API, on the other hand, deals with familiar data structures (key-value, sets, sorted sets, lists, streams, hash maps) that you can directly map to your application's data. Redimo bridges the two and translates the Redis API operations into space / time / cost-efficient DynamoDB API calls.

Redimo is especially well suited to serverless environments, since there is no pool of connections to handle and DynamoDB is purpose-built for near-zero management use. But you can use it with regular servers well, especially when you want excellent horizontal scalability. See the section on differences between Redis and DynamoDB below for more information.

Licensing

The default license is the Prosperity License, which allows you to use the library for noncommercial purposes and trial it for commercial purposes for 30 days. You can purchase a license as an individual developer for USD $25 here: L0

Please contact me at sudhir.j@gmail.com to purchase a business / company license for your entire organization.

Roadmap

The library is currently in v0, so I'm asking for comments and feedback on the interface and data schema. I expect to freeze the API to v1 on the 1st of July, after which all v1 releases will be guaranteed not to break backwards compatibility and work on pre-existing v1 DynamoDB tables without any data migrations. Will also be adding documentation for every method, linking to the corresponding Redis docs and detailing the differences in how they function and what their limitations are.

The first priority is to mirror the Redis API as much as possible, even in the cases where that means the DynamoDB mapping is inefficient. After v1, I'd like to add more efficient operations as extra methods.

This library is the Go version, but I'm thinking of building Ruby, JavaScript, Python and Java versions as well. You can contact me if you'd like to prioritise or sponsor any of them.

Limitations

Some parts of the Redis API are unfeasible (as far as I know, and as of now) on DynamoDB, like the binary / bit twiddling operations and their derivatives, like GETBIT, SETBIT, BITCOUNT, etc. and HyperLogLog. These have been left out of the API for now.

TTL operations are possible, but a little more complicated, and will likely be added soon.

Pub/Sub isn't possible as a DynamoDB feature itself, but it should be possible to add integration with AWS IoT Core or similar in the future. This isn't useful in a serverless environment, though, so it's a lower priority. Contact me if you disagree and want this quickly.

Lua Scripting is currently not applicable - the library runs inside your codebase, so anything you wanted to do with Lua would just be done with normal library calls inside your application, with the data loaded in and out of DynamoDB.

ACLs (access control lists) are not currently supported.

Transactions across arbitrary operations, using MULTI WATCH EXEC, are not yet supported. Talk to me if you need this.

Differences between Redis and DynamoDB

Why bother with this at all? Why not just use Redis?

  • In Redis, the size of your dataset is limited to the RAM available in a single machine, while in DynamoDB it is distributed across many machines and is effectively unlimited. Redis has separate clustering support, but it doesn't match the ease of use and automatic scalability of a managed service like DynamoDB.

  • Redis is connection based and supports a limited (but pretty large) number of connections. DynamoDB has no such limits, so it's great for serverless or very horizontally scaled deployments.

  • Redis bandwidth is limited by the network interface of the server that it's running on, DynamoDB is distributed and doesn't have hard bandwidth limits.

  • In Redis all operations run on a single CPU / thread - so each operation is extremely fast, but there's only one operation running at a time. Slow operations, or a large queue, will block other operations. In DynamoDB, each key's operations runs on different machines, so there's no block of any sort across keys. Operations on the same key will block using optimistic concurrency, though - Redimo will try the operation, but will fail if the data has been unexpectedly modified since the last check. The integrity of the data is still preserved, but in DynamoDB there's more probability that lots of operations on the same keys will step on each other's toes.

  • Redis provides very fast response times (few microseconds), but because all operations are happening one by one, the total throughput is fixed. DynamoDB is relatively slower for each individual operation (few milliseconds) but because of the distributed nature of the system the response time will remain constant at thousands or millions of requests per second. Some workloads even get faster at higher loads because the system starts allocating more servers to your table.

  • In Redis a high-availability system isn't that easy to set up, while on DynamoDB it's the default.

  • The DynamoDB Global Tables feature allows you to have your data eventually replicated in many regions across the world, enabling master-master (both reads and writes) at any region. Note that if you use Global Tables, the data structures that require lots of transactional updates – streams and lists particularly – cannot work reliably across regions. Mostly because the speed of light isn't as fast as we'd like it to be. This is still excellent for publishing metadata or any information that doesn't change every often throughout the world at low latency. Key-values, hashes, sets, sorted sets, etc. work great in a write-here and read-everywhere scenario.

  • The persistence guarantees offered by DynamoDB allows you to use the Redimo service as your primary / only ACID database, while Redis has a periodic file system sync (so you might lose data since the last sync). While you can switch Redis to wait for a file system write in all cases or set up a quorum cluster, DynamoDB has much higher reliability, including Multi-AZ guarantees, right out of the box.

  • With Redis you'll need to run servers and either buy or rent fixed units of CPU and RAM, while with DynamoDB you have the option of paying on-demand (per request) or setting up auto-scaling bandwidth slabs.

  • With DynamoDB, being a distributed system, you will not get a lot of the transactional and atomic behaviour that comes freely and easily with Redis. The Redimo library uses whatever transactional APIs are available where necessary, so the limits of those APIs will be passed on to you - in DynamoDB you can only have up to 25 items in a transaction, for example, so the MSET operation on has a 25 key limit when using Redimo / DynamoDB. Redis does not have any such limitations.

  • DynamoDB is geared towards having lots of small objects across many partitions, while Redis is workload agnostic. For example, with Redis if you can do N writes per second across one or many keys, in DynamoDB you can do only one tenth of that on a single key – but you could operate at millions of times N across all your keys, if you have a lot of keys.

  • In the same vein, Redis allows all keys and values to be up to 512MB (although big keys or values is always a bad idea and will naturally cause bandwidth constraints on a single server) - in DynamoDB your keys (and set members) can only be up to 1KB, while your values can only be up to 400KB in size.

So there's no clear-cut answer to which is better – it depends entirely on your application and expected workload. The point of this library is not to promote one over the other – it's to make your development much easier and more comfortable if you decide to use DynamoDB, because the Redis API is much more approachable and easier to model with.

If you still need help with making a decision, you can contact me at sudhir.j@gmail.com

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrXGroupNotInitialized = errors.New("group not initialized")

Functions

This section is empty.

Types

type BytesValue

type BytesValue struct {
	B []byte
}

func (BytesValue) ToAV added in v0.2.0

type Client

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

func (Client) DECR

func (c Client) DECR(key string) (after int64, err error)

func (Client) DECRBY

func (c Client) DECRBY(key string, delta int64) (after int64, err error)

func (Client) GEOADD

func (c Client) GEOADD(key string, members map[string]GLocation) (newlyAddedMembers map[string]GLocation, err error)

func (Client) GEODIST

func (c Client) GEODIST(key string, member1, member2 string, unit GUnit) (distance float64, ok bool, err error)

func (Client) GEOHASH

func (c Client) GEOHASH(key string, members ...string) (geohashes map[string]string, err error)

func (Client) GEOPOS

func (c Client) GEOPOS(key string, members ...string) (locations map[string]GLocation, err error)

func (Client) GEORADIUS

func (c Client) GEORADIUS(key string, center GLocation, radius float64, radiusUnit GUnit, count int64) (positions map[string]GLocation, err error)

func (Client) GEORADIUSBYMEMBER

func (c Client) GEORADIUSBYMEMBER(key string, member string, radius float64, radiusUnit GUnit, count int64) (positions map[string]GLocation, err error)

func (Client) GET

func (c Client) GET(key string) (val ReturnValue, err error)

GET fetches the value at the given key. If the key does not exist, the ReturnValue will be Empty().

Works similar to https://redis.io/commands/get

func (Client) GETSET

func (c Client) GETSET(key string, value Value) (oldValue ReturnValue, err error)

GETSET gets the value at the key and atomically sets it to a new value.

Works similar to https://redis.io/commands/getset

func (Client) HDEL

func (c Client) HDEL(key string, fields ...string) (deletedFields []string, err error)

func (Client) HEXISTS

func (c Client) HEXISTS(key string, field string) (exists bool, err error)

func (Client) HGET

func (c Client) HGET(key string, field string) (val ReturnValue, err error)

func (Client) HGETALL

func (c Client) HGETALL(key string) (fieldValues map[string]ReturnValue, err error)

func (Client) HINCRBY

func (c Client) HINCRBY(key string, field string, delta int64) (after int64, err error)

func (Client) HINCRBYFLOAT

func (c Client) HINCRBYFLOAT(key string, field string, delta float64) (after float64, err error)

func (Client) HKEYS

func (c Client) HKEYS(key string) (keys []string, err error)

func (Client) HLEN

func (c Client) HLEN(key string) (count int64, err error)

func (Client) HMGET

func (c Client) HMGET(key string, fields ...string) (values map[string]ReturnValue, err error)

func (Client) HMSET

func (c Client) HMSET(key string, fieldValues map[string]Value) (err error)

func (Client) HSET

func (c Client) HSET(key string, fieldValues map[string]Value) (newlySavedFields map[string]Value, err error)

func (Client) HSETNX

func (c Client) HSETNX(key string, field string, value Value) (ok bool, err error)

func (Client) HVALS

func (c Client) HVALS(key string) (values []ReturnValue, err error)

func (Client) INCR

func (c Client) INCR(key string) (after int64, err error)

func (Client) INCRBY

func (c Client) INCRBY(key string, delta int64) (after int64, err error)

func (Client) INCRBYFLOAT

func (c Client) INCRBYFLOAT(key string, delta float64) (after float64, err error)

func (Client) LINDEX

func (c Client) LINDEX(key string, index int64) (element ReturnValue, err error)

func (Client) LINSERT

func (c Client) LINSERT(key string, side LSide, pivot, element Value) (newLength int64, done bool, err error)

LINSERT inserts the given element on the given side of the pivot element.

func (Client) LLEN

func (c Client) LLEN(key string) (length int64, err error)

func (Client) LPOP

func (c Client) LPOP(key string) (element ReturnValue, err error)

func (Client) LPUSH

func (c Client) LPUSH(key string, elements ...Value) (newLength int64, err error)

func (Client) LPUSHX

func (c Client) LPUSHX(key string, elements ...Value) (newLength int64, err error)

func (Client) LRANGE

func (c Client) LRANGE(key string, start, stop int64) (elements []ReturnValue, err error)

func (Client) LREM

func (c Client) LREM(key string, side LSide, element Value) (newLength int64, done bool, err error)

LREM removes the first occurrence on the given side of the given element.

func (Client) LSET

func (c Client) LSET(key string, index int64, element string) (ok bool, err error)

func (Client) MGET

func (c Client) MGET(keys ...string) (values map[string]ReturnValue, err error)

MGET fetches the given keys atomically in a transaction. The call is limited to 25 keys and 4MB. See https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html

Works similar to https://redis.io/commands/mget

func (Client) MSET

func (c Client) MSET(data map[string]Value) (err error)

MSET sets the given keys and values atomically in a transaction. The call is limited to 25 keys and 4MB. See https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html

Works similar to https://redis.io/commands/mset

func (Client) MSETNX

func (c Client) MSETNX(data map[string]Value) (ok bool, err error)

MSETNX sets the given keys and values atomically in a transaction, but only if none of the given keys exist. If one or more of the keys already exist, nothing will be changed and MSETNX will return false.

Works similar to https://redis.io/commands/msetnx

func (Client) RPOP

func (c Client) RPOP(key string) (element ReturnValue, err error)

func (Client) RPOPLPUSH

func (c Client) RPOPLPUSH(sourceKey string, destinationKey string) (element ReturnValue, err error)

func (Client) RPUSH

func (c Client) RPUSH(key string, elements ...Value) (newLength int64, err error)

func (Client) RPUSHX

func (c Client) RPUSHX(key string, elements ...Value) (newLength int64, err error)

func (Client) SADD

func (c Client) SADD(key string, members ...string) (addedMembers []string, err error)

func (Client) SCARD

func (c Client) SCARD(key string) (count int64, err error)

func (Client) SDIFF

func (c Client) SDIFF(key string, subtractKeys ...string) (members []string, err error)

func (Client) SDIFFSTORE

func (c Client) SDIFFSTORE(destinationKey string, sourceKey string, subtractKeys ...string) (count int64, err error)

func (Client) SET

func (c Client) SET(key string, value Value, flag Flag) (ok bool, err error)

SET stores the given Value at the given key. If called as SET("key", "value", None), SET is unconditional and is not expected to fail.

The condition flags IfNotExists and IfAlreadyExists can be specified, and if they are the SET becomes conditional and will return false if the condition fails.

Works similar to https://redis.io/commands/set

func (Client) SETNX

func (c Client) SETNX(key string, value Value) (ok bool, err error)

SETNX is equivalent to SET(key, value, Flags{IfNotExists})

Works similar to https://redis.io/commands/setnx

func (Client) SINTER

func (c Client) SINTER(key string, otherKeys ...string) (members []string, err error)

func (Client) SINTERSTORE

func (c Client) SINTERSTORE(destinationKey string, sourceKey string, otherKeys ...string) (count int64, err error)

func (Client) SISMEMBER

func (c Client) SISMEMBER(key string, member string) (ok bool, err error)

func (Client) SMEMBERS

func (c Client) SMEMBERS(key string) (members []string, err error)

func (Client) SMOVE

func (c Client) SMOVE(sourceKey string, destinationKey string, member string) (ok bool, err error)

func (Client) SPOP

func (c Client) SPOP(key string, count int64) (members []string, err error)

func (Client) SRANDMEMBER

func (c Client) SRANDMEMBER(key string, count int64) (members []string, err error)

func (Client) SREM

func (c Client) SREM(key string, members ...string) (removedMembers []string, err error)

func (Client) SUNION

func (c Client) SUNION(keys ...string) (members []string, err error)

func (Client) SUNIONSTORE

func (c Client) SUNIONSTORE(destinationKey string, sourceKeys ...string) (count int64, err error)

func (Client) XACK

func (c Client) XACK(key string, group string, ids ...XID) (acknowledgedIds []XID, err error)

func (Client) XADD

func (c Client) XADD(key string, id XID, fields map[string]Value) (returnedID XID, err error)

XADD adds the given fields as a item on the stream at key. If the stream does not exist, it will be initialized.

If the XID passed in is XAutoID, an ID will be automatically generated on the current time and a sequence generator.

Note that if you pass in your own ID, the stream will never allow you to insert an item with an ID less than the greatest ID present in the stream – the stream can only move forwards. This guarantees that if you've read entries up to a given XID using XREAD, you can always continue reading from that last XID without fear of missing anything, because the IDs are always increasing.

Works similar to https://redis.io/commands/xadd

func (Client) XCLAIM

func (c Client) XCLAIM(key string, group string, consumer string, lastDeliveredBefore time.Time, ids ...XID) (items []StreamItem, err error)

func (Client) XDEL

func (c Client) XDEL(key string, ids ...XID) (deletedItems []XID, err error)

XDEL removes the given IDs and returns the IDs that were actually deleted as part of this operation.

Note that this operation is not atomic across given IDs – it's possible that an error is returned based on a problem deleting one of the IDs when the others have been deleted. Even when an error is returned, the items that were deleted will still be populated.

Works similar to https://redis.io/commands/xdel

func (Client) XGROUP

func (c Client) XGROUP(key string, group string, start XID) (err error)

func (Client) XLEN

func (c Client) XLEN(key string, start, stop XID) (count int64, err error)

func (Client) XPENDING

func (c Client) XPENDING(key string, group string, count int64) (pendingItems []PendingItem, err error)

func (Client) XRANGE

func (c Client) XRANGE(key string, start, stop XID, count int64) (streamItems []StreamItem, err error)

XRANGE fetches the stream records between two XIDs, inclusive of both the start and end IDs, limited to the count.

If you receive the entire count you've asked for, it's reasonable to suppose there might be more items in the given range that were not returned because they would exceed the count – in this case you can call the XID.Next() method on the last received stream ID for an XID to use as the start of the next call.

Common uses include fetching a single item based on XID, which would be

XRANGE(key, id, id, 1)

or fetching records in the month of February, like

XRANGE(key, NewTimeXID(beginningOfFebruary).First(), NewTimeXID(endOfFebruary).Last(), 1000)
XRANGE(key, NewTimeXID(beginningOfFebruary).First(), NewTimeXID(beginningOfMarch).First(), 1000)

Note that the two calls are equivalent, because this operation uses the DynamoDB BETWEEN operator, which translates to

start <= id <= end

There is are no offset or pagination parameters required, because when the full count is hit the next page of items can be fetched as follows:

XRANGE(key, lastFetchedItemID.Next(), NewTimeXID(endOfFebruary).Last(), 1000)

See the XID docs for more information on how to generate start and stop XIDs based on time.

Works similar to https://redis.io/commands/xrange

func (Client) XREAD

func (c Client) XREAD(key string, from XID, count int64) (items []StreamItem, err error)

XREAD reads items sequentially from a stream. The structure of a stream guarantees that the XIDs are always increasing. This implies that calling XREAD in a loop and passing in the XID of the last item read will allow iteration over all items reliably.

To start reading a stream from the beginning, use the special XStart XID.

Works similar to https://redis.io/commands/xread

func (Client) XREADGROUP

func (c Client) XREADGROUP(key string, group string, consumer string, option XReadOption, maxCount int64) (items []StreamItem, err error)

func (Client) XREVRANGE

func (c Client) XREVRANGE(key string, end, start XID, count int64) (streamItems []StreamItem, err error)

XREVRANGE is similar to XRANGE, but in reverse order. The stream items in descending chronological order. Using the same example as XRANGE, when fetching items in reverse order there are some differences when paginating. The first set of records can be fetched using:

XRANGE(key, NewTimeXID(endOfFebruary).Last(), NewTimeXID(beginningOfFebruary).First(), 1000)

he next page can be fetched using

XRANGE(key, lastFetchedItemID.Prev(), NewTimeXID(beginningOfFebruary).First(), 1000)

Works similar to https://redis.io/commands/xrevrange

func (Client) XTRIM

func (c Client) XTRIM(key string, newCount int64) (deletedCount int64, err error)

func (Client) ZADD

func (c Client) ZADD(key string, membersWithScores map[string]float64, flags Flags) (addedMembers []string, err error)

func (Client) ZCARD

func (c Client) ZCARD(key string) (count int64, err error)

func (Client) ZCOUNT

func (c Client) ZCOUNT(key string, minScore, maxScore float64) (count int64, err error)

func (Client) ZINCRBY

func (c Client) ZINCRBY(key string, member string, delta float64) (newScore float64, err error)

func (Client) ZINTER

func (c Client) ZINTER(sourceKeys []string, aggregation ZAggregation, weights map[string]float64) (membersWithScores map[string]float64, err error)

func (Client) ZINTERSTORE

func (c Client) ZINTERSTORE(destinationKey string, sourceKeys []string, aggregation ZAggregation, weights map[string]float64) (membersWithScores map[string]float64, err error)

func (Client) ZLEXCOUNT

func (c Client) ZLEXCOUNT(key string, min string, max string) (count int64, err error)

func (Client) ZPOPMAX

func (c Client) ZPOPMAX(key string, count int64) (membersWithScores map[string]float64, err error)

func (Client) ZPOPMIN

func (c Client) ZPOPMIN(key string, count int64) (membersWithScores map[string]float64, err error)

func (Client) ZRANGE

func (c Client) ZRANGE(key string, start, stop int64) (membersWithScores map[string]float64, err error)

func (Client) ZRANGEBYLEX

func (c Client) ZRANGEBYLEX(key string, min, max string, offset, count int64) (membersWithScores map[string]float64, err error)

func (Client) ZRANGEBYSCORE

func (c Client) ZRANGEBYSCORE(key string, min, max float64, offset, count int64) (membersWithScores map[string]float64, err error)

func (Client) ZRANK

func (c Client) ZRANK(key string, member string) (rank int64, found bool, err error)

func (Client) ZREM

func (c Client) ZREM(key string, members ...string) (removedMembers []string, err error)

func (Client) ZREMRANGEBYLEX

func (c Client) ZREMRANGEBYLEX(key string, min, max string) (removedMembers []string, err error)

func (Client) ZREMRANGEBYRANK

func (c Client) ZREMRANGEBYRANK(key string, start, stop int64) (removedMembers []string, err error)

func (Client) ZREMRANGEBYSCORE

func (c Client) ZREMRANGEBYSCORE(key string, min, max float64) (removedMembers []string, err error)

func (Client) ZREVRANGE

func (c Client) ZREVRANGE(key string, start, stop int64) (membersWithScores map[string]float64, err error)

func (Client) ZREVRANGEBYLEX

func (c Client) ZREVRANGEBYLEX(key string, max, min string, offset, count int64) (membersWithScores map[string]float64, err error)

func (Client) ZREVRANGEBYSCORE

func (c Client) ZREVRANGEBYSCORE(key string, max, min float64, offset, count int64) (membersWithScores map[string]float64, err error)

func (Client) ZREVRANK

func (c Client) ZREVRANK(key string, member string) (rank int64, found bool, err error)

func (Client) ZSCORE

func (c Client) ZSCORE(key string, member string) (score float64, found bool, err error)

func (Client) ZUNION

func (c Client) ZUNION(sourceKeys []string, aggregation ZAggregation, weights map[string]float64) (membersWithScores map[string]float64, err error)

func (Client) ZUNIONSTORE

func (c Client) ZUNIONSTORE(destinationKey string, sourceKeys []string, aggregation ZAggregation, weights map[string]float64) (membersWithScores map[string]float64, err error)

type Flag

type Flag string
const (
	None            Flag = "-"
	Unconditionally      = None
	IfAlreadyExists Flag = "XX"
	IfNotExists     Flag = "NX"
)

type Flags

type Flags []Flag

type FloatValue added in v0.2.0

type FloatValue struct {
	F float64
}

func (FloatValue) ToAV added in v0.2.0

type GLocation added in v0.2.0

type GLocation struct {
	Lat float64
	Lon float64
}

func (GLocation) DistanceTo added in v0.2.0

func (l GLocation) DistanceTo(other GLocation, unit GUnit) (distance float64)

func (GLocation) Geohash added in v0.2.0

func (l GLocation) Geohash() string

type GUnit added in v0.2.0

type GUnit float64
const (
	Meters     GUnit = 1.0
	Kilometers GUnit = 1000.0
	Miles      GUnit = 1609.34
	Feet       GUnit = 0.3048
)

func (GUnit) To added in v0.2.0

func (from GUnit) To(to GUnit, d float64) float64

type IntValue added in v0.2.0

type IntValue struct {
	I int64
}

func (IntValue) ToAV added in v0.2.0

func (iv IntValue) ToAV() dynamodb.AttributeValue

type LSide added in v0.2.0

type LSide string
const (
	Left  LSide = "LEFT"
	Right LSide = "RIGHT"
)

type PendingItem

type PendingItem struct {
	ID            XID
	Consumer      string
	LastDelivered time.Time
	DeliveryCount int64
}

type ReturnValue added in v0.2.0

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

ReturnValue holds a value returned by Redimo. There are convenience methods used to coerce the held value into common types, but you can also retrieve the raw dynamodb.AttributeValue by calling ToAV if you would like to do custom decoding.

func (ReturnValue) Bytes added in v0.2.0

func (rv ReturnValue) Bytes() []byte

func (ReturnValue) Empty added in v0.2.0

func (rv ReturnValue) Empty() bool

func (ReturnValue) Equals added in v0.2.0

func (rv ReturnValue) Equals(ov ReturnValue) bool

func (ReturnValue) Float added in v0.2.0

func (rv ReturnValue) Float() float64

func (ReturnValue) Int added in v0.2.0

func (rv ReturnValue) Int() int64

func (ReturnValue) Present added in v0.2.0

func (rv ReturnValue) Present() bool

func (ReturnValue) String added in v0.2.0

func (rv ReturnValue) String() string

func (ReturnValue) ToAV added in v0.2.0

type StreamItem

type StreamItem struct {
	ID     XID
	Fields map[string]ReturnValue
}

type StringValue

type StringValue struct {
	S string
}

func (StringValue) ToAV added in v0.2.0

type Value

type Value interface {
	ToAV() dynamodb.AttributeValue
}

Value allows you to store values of any type supported by DynamoDB, as long as they implement this interface and encode themselves into the dynamodb.AttributeValue returned by ToAV.

Some common value wrappers are provided, like StringValue, FloatValue, IntValue and BytesValue. The output of most operations is a ReturnValue which has convenience methods to decode the data into these common types.

You can implement the ToAV() method on any type that you would like to provide a custom encoding for. When you receive the data wrapped in a ReturnValue, the ToAV method can be used to access the raw dynamo.AttributeValue struct, allowing you to do custom deserialization.

type XID

type XID string

XID holds a stream item ID, and consists of a timestamp (one second resolution) and a sequence number.

Most code will not need to generate XIDs – using XAutoID with XADD is the most common usage. But if you do need to generate XIDs for insertion with XADD, the NewXID methods creates a complete XID.

To generate time based XIDs for time range queries with XRANGE or XREVRANGE, use NewTimeXID(startTime).First() and NewTimeXID(endTime).Last(). Calling Last() is especially important because without it none of the items in the last second of the range will match – you need the last possible sequence number in the last second of the range, which is what the Last() method provides.

const XAutoID XID = "*"
const XEnd XID = "99999999999999999999-99999999999999999999"
const XStart XID = "00000000000000000000-00000000000000000000"

func NewTimeXID added in v0.5.0

func NewTimeXID(ts time.Time) XID

NewTimeXID creates an XID with the given timestamp. To get the first or the last XID in this timestamp, use the First() or the Last() methods. This is especially important when using constructed XIDs inside a range call like XRANGE or XREVRANGE.

func NewXID

func NewXID(ts time.Time, seq uint64) XID

NewXID creates an XID with the given timestamp and sequence number.

func (XID) First added in v0.5.0

func (xid XID) First() XID

First returns the first valid XID at this timestamp. Useful for the start parameter of XRANGE or XREVRANGE.

func (XID) Last added in v0.5.0

func (xid XID) Last() XID

Last returns the last valid XID at this timestamp. Useful for the end parameter of XRANGE or XREVRANGE. Note that if the XID used as an end in the range simply based on the timestamp, the sequence number will be zero, so the query will exclude all the items in end second. This will effectively transform the query to '< endTime' instead of '<= endTime'. Using Last() prevents this mistake, if that is your intention.

func (XID) Next

func (xid XID) Next() XID

Next returns the next valid XID at the same time – it simply returns a new XID with the next sequence number.

func (XID) Prev added in v0.5.0

func (xid XID) Prev() XID

Prev returns the previous valid XID at the same time – it simply returns a new XID with the previous sequence number.

func (XID) Seq

func (xid XID) Seq() uint64

func (XID) String

func (xid XID) String() string

func (XID) Time

func (xid XID) Time() time.Time

type XReadOption

type XReadOption string
const (
	XReadPending    XReadOption = "PENDING"
	XReadNew        XReadOption = "READ_NEW"
	XReadNewAutoACK XReadOption = "READ_NEW_NO_ACK"
)

type ZAggregation added in v0.2.0

type ZAggregation string
const (
	ZAggregationSum ZAggregation = "SUM"
	ZAggregationMin ZAggregation = "MIN"
	ZAggregationMax ZAggregation = "MAX"
)

Jump to

Keyboard shortcuts

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