Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dynamo_global_index_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ type GlobalIndexInterface interface {
// returns true if items are found, returns false and nil if no items found, returns false and error in case of error
GetItemsWithContext(ctx context.Context, key KeyInterface, items interface{}) (bool, error)

// GetItemsIteratorWithContext returns an instance of an Iterator that provides methods for executing the query
GetItemsIteratorWithContext(ctx context.Context, key KeyInterface, searchLimit int64) (IteratorInterface, error)

// GetItemsWithRangeWithContext same as GetItemsWithContext, but also respects range key
GetItemsWithRangeWithContext(ctx context.Context, key KeyInterface, items interface{}) (bool, error)

Expand Down
21 changes: 21 additions & 0 deletions dynamo_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,27 @@ func (repository Repository) ScanIteratorWithContext(ctx context.Context, key Ke
return itr, nil
}

// GetItemsIteratorWithContext returns an instance of an Iterator that provides methods for executing the query
func (repository Repository) GetItemsIteratorWithContext(ctx context.Context, key KeyInterface, searchLimit int64) (IteratorInterface, error) {
if err := isValidTableName(key); err != nil {
repository.log.error(ctx, key.TableName(), err.Error())
return nil, err
}

q := repository.table(key.TableName()).Get(*key.HashKeyName(), key.HashKey())

iter := q.Iter()
itr := &QueryIterator{
query: q,
tableName: key.TableName(),
searchLimit: searchLimit,
iterator: iter,
ctx: ctx,
}

return itr, nil
}

// BatchGetItemsWithContext gets multiple items by their keys; all keys must refer to the same table.
// out must be a pointer to a slice of your model type.
// Returns (true, nil) if at least one item is found, (false, nil) if none found, or (false, err) on error.
Expand Down
3 changes: 3 additions & 0 deletions dynamo_repository_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ type RepositoryInterface interface {
// returns true if items are found, returns false and nil if no items found, returns false and error in case of error
GetItemsWithContext(ctx context.Context, key KeyInterface, out interface{}) (bool, error)

// GetItemsIteratorWithContext returns an instance of an Iterator that provides methods for executing the query
GetItemsIteratorWithContext(ctx context.Context, key KeyInterface, searchLimit int64) (IteratorInterface, error)

// QueryWithContext by query; it accepts a query interface that is used to get the table name, hash key and range key with its operator if it exists;
// context which used to enable log with context, the output will be given in items
// returns error in case of error
Expand Down
24 changes: 24 additions & 0 deletions global_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,27 @@ func (gi GlobalIndex) QueryWithContext(ctx context.Context, query QueryInterface
func (gi GlobalIndex) Query(query QueryInterface, item interface{}) error {
return gi.QueryWithContext(context.TODO(), query, item)
}

// GetItemsIteratorWithContext returns an instance of an Iterator that provides methods for executing the query
func (gi GlobalIndex) GetItemsIteratorWithContext(ctx context.Context, key KeyInterface, searchLimit int64) (IteratorInterface, error) {
if err := isValidTableName(key); err != nil {
gi.log.error(ctx, key.TableName(), err.Error())
return nil, err
}

q := gi.table(key.TableName()).
Get(*key.HashKeyName(), key.HashKey()).
Index(gi.name)

iter := q.Iter()

itr := &QueryIterator{
query: q,
tableName: key.TableName(),
searchLimit: searchLimit,
iterator: iter,
ctx: ctx,
}

return itr, nil
}
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/adjoeio/djoemo

require (
github.com/aws/aws-sdk-go v1.19.1
github.com/bouk/monkey v1.0.1
github.com/golang/mock v1.6.0
github.com/guregu/dynamo v1.2.1
github.com/onsi/ginkgo/v2 v2.22.0
github.com/onsi/gomega v1.34.2
Expand All @@ -11,7 +11,6 @@ require (
)

require (
bou.ke/monkey v1.0.2 // indirect
github.com/cenkalti/backoff v2.1.1+incompatible // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
Expand Down
26 changes: 22 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI=
bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA=
github.com/aws/aws-sdk-go v1.18.5/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.19.1 h1:8kOP0/XGJwXIFlYoD1DAtA39cAjc15Iv/QiDMKitD9U=
github.com/aws/aws-sdk-go v1.19.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/bouk/monkey v1.0.1 h1:82kWEtyEjyfkRZb0DaQ5+7O5dJfe3GzF/o97+yUo5d0=
github.com/bouk/monkey v1.0.1/go.mod h1:PG/63f4XEUlVyW1ttIeOJmJhhe1+t9EC/je3eTjvFhE=
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -16,6 +12,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
Expand All @@ -36,20 +34,40 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190318221613-d196dffd7c2b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
23 changes: 21 additions & 2 deletions iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

// IteratorInterface ...
type IteratorInterface interface {
// NextItem unmarshals the next item into out and returns if there are more items following
NextItem(out interface{}) bool
}

Expand All @@ -19,11 +20,9 @@ type Iterator struct {
searchLimit int64
lastEvaluatedKey map[string]*dynamodb.AttributeValue
iterator dynamo.PagingIter
dynamoClient *dynamo.DB
ctx context.Context
}

// NextItem unmarshals the next item into out and returns if there are more items following
func (itr *Iterator) NextItem(out interface{}) bool {
more := itr.iterator.NextWithContext(itr.ctx, out)
if !more && itr.iterator.LastEvaluatedKey() != nil {
Expand All @@ -33,3 +32,23 @@ func (itr *Iterator) NextItem(out interface{}) bool {
}
return more
}

// QueryIterator ...
type QueryIterator struct {
query *dynamo.Query
tableName string
searchLimit int64
lastEvaluatedKey map[string]*dynamodb.AttributeValue
iterator dynamo.PagingIter
ctx context.Context
}

func (itr *QueryIterator) NextItem(out interface{}) bool {
more := itr.iterator.NextWithContext(itr.ctx, out)
if !more && itr.iterator.LastEvaluatedKey() != nil {
itr.query = itr.query.StartFrom(itr.iterator.LastEvaluatedKey())
itr.iterator = itr.query.Iter()
return itr.iterator.NextWithContext(itr.ctx, out)
}
return more
}
15 changes: 15 additions & 0 deletions mock/dynamo_global_index_interface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions mock/dynamo_repository_interface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 11 additions & 7 deletions repository_save_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"time"

"github.com/bouk/monkey"
"github.com/adjoeio/djoemo"
"github.com/pkg/errors"
"go.uber.org/mock/gomock"

Expand Down Expand Up @@ -235,13 +235,17 @@ var _ = Describe("Repository", func() {
})

Describe("Optimistic Lock Save", func() {
It("should save an item with optimistic Locking", func() {
djoemoTimeNow := djoemo.Now
BeforeEach(func() {
now := time.Date(2019, 1, 1, 12, 15, 0, 0, time.UTC)

monkey.Patch(time.Now, func() time.Time {
return now
})

djoemo.Now = func() djoemo.DjoemoTime {
return djoemo.DjoemoTime{Time: now}
}
})
AfterEach(func() {
djoemo.Now = djoemoTimeNow
})
It("should save an item with optimistic Locking", func() {
type DjoemoUser struct {
Model
User
Expand Down
8 changes: 4 additions & 4 deletions time.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// TimeFormatStandard is a mysql time.Time type with some helper functions
const TimeFormatStandard = "2006-01-02T15:04:05.000Z07:00"

//TenYears ...
// TenYears ...
const TenYears = time.Duration(time.Hour * 24 * 365 * 10)

// RFC3339Milli with millisecond precision
Expand All @@ -33,7 +33,7 @@ type DjoemoTime struct {
}

// Date returns the Time corresponding to
// yyyy-mm-dd hh:mm:ss + nsec nanoseconds
// yyyy-mm-dd hh:mm:ss + nsec nanoseconds
func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) DjoemoTime {
return DjoemoTime{Time: time.Date(year, month, day, hour, min, sec, nsec, loc)}
}
Expand Down Expand Up @@ -61,7 +61,7 @@ func (dt DjoemoTime) MarshalJSON() ([]byte, error) {
return json.Marshal(dt.Time.Format(TimeFormatStandard))
}

//MarshalDynamoDBAttributeValue ...
// MarshalDynamoDBAttributeValue ...
func (dt *DjoemoTime) MarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
unix := int64(0)
if dt != nil {
Expand Down Expand Up @@ -113,7 +113,7 @@ func (dt *DjoemoTime) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValu
}

// Now returns the current local time.
func Now() DjoemoTime {
var Now = func() DjoemoTime {

t := time.Now()
// solves docker issue:
Expand Down