lotus-dynamodb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +9 -0
- data/.yardopts +5 -0
- data/Gemfile +16 -0
- data/LICENSE.md +22 -0
- data/Procfile +1 -0
- data/README.md +112 -0
- data/Rakefile +17 -0
- data/benchmarks/coercer.rb +76 -0
- data/examples/Gemfile +2 -0
- data/examples/purchase.rb +164 -0
- data/lib/lotus/dynamodb/config.rb +14 -0
- data/lib/lotus/dynamodb/version.rb +8 -0
- data/lib/lotus/model/adapters/dynamodb/coercer.rb +211 -0
- data/lib/lotus/model/adapters/dynamodb/collection.rb +321 -0
- data/lib/lotus/model/adapters/dynamodb/command.rb +117 -0
- data/lib/lotus/model/adapters/dynamodb/query.rb +559 -0
- data/lib/lotus/model/adapters/dynamodb_adapter.rb +190 -0
- data/lib/lotus-dynamodb.rb +3 -0
- data/lotus-dynamodb.gemspec +30 -0
- data/test/fixtures.rb +75 -0
- data/test/model/adapters/dynamodb/coercer_test.rb +269 -0
- data/test/model/adapters/dynamodb/query_test.rb +259 -0
- data/test/model/adapters/dynamodb_adapter_test.rb +940 -0
- data/test/test_helper.rb +46 -0
- data/test/version_test.rb +7 -0
- metadata +203 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8b6e1c051b76f678f3694e0e0cb8f70871a3dbce
|
4
|
+
data.tar.gz: d7e164efdaa51814a36a7c803c959ad9c21c3b71
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5a326db3a7714f0573be6b4ebadd1dc2ad5dc7fea5303be5c61c09bcfdd37435084215ff60837156f9c4481c044f24af96b8b65d504a9b4e25a3f8f5f6069771
|
7
|
+
data.tar.gz: d1a6068ecc5898cf70ce48ed8b751498ff405fbca62f0a60990f36197d40fe4489e21c0011fff4bd04f215f7642c20763219b624966acaf2578f62be566c308a
|
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
.greenbar
|
19
|
+
.ruby-gemset
|
20
|
+
.ruby-version
|
21
|
+
.fake_dynamo.*
|
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
gemspec
|
3
|
+
|
4
|
+
if !ENV['TRAVIS']
|
5
|
+
gem 'byebug', require: false, platforms: :ruby if RUBY_VERSION == '2.1.2'
|
6
|
+
gem 'yard', require: false
|
7
|
+
end
|
8
|
+
|
9
|
+
gem 'simplecov', require: false
|
10
|
+
gem 'coveralls', require: false
|
11
|
+
|
12
|
+
# Benchmarking
|
13
|
+
gem 'benchmark-ips', '~> 1.2'
|
14
|
+
|
15
|
+
# Fixes are not merged yet
|
16
|
+
gem 'fake_dynamo', github: 'krasnoukhov/fake_dynamo'
|
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Dmitry Krasnoukhov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Procfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
fake_dynamo: bundle exec fake_dynamo -l debug -d .fake_dynamo.db
|
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# Lotus::Model DynamoDB Adapter
|
2
|
+
|
3
|
+
> An adapter is a concrete implementation of persistence logic for a specific
|
4
|
+
> database.
|
5
|
+
>
|
6
|
+
> -- <cite>[jodosha](https://github.com/jodosha), [Lotus::Model](https://github.com/lotus/model)</cite>
|
7
|
+
|
8
|
+
This adapter implements persistence layer for a [Amazon DynamoDB](https://aws.amazon.com/dynamodb/),
|
9
|
+
and it pretends to be a _really_ sane solution to fully experience DynamoDB advantages with Ruby.
|
10
|
+
|
11
|
+
It is built using ```AWS::DynamoDB::Client```, which is a part of ```aws-sdk``` gem and implements latest version of DynamoDB protocol.
|
12
|
+
|
13
|
+
## Status
|
14
|
+
|
15
|
+
[![Gem Version](https://badge.fury.io/rb/lotus-dynamodb.svg)](http://badge.fury.io/rb/lotus-dynamodb)
|
16
|
+
[![Build Status](https://secure.travis-ci.org/krasnoukhov/lotus-dynamodb.svg?branch=master)](http://travis-ci.org/krasnoukhov/lotus-dynamodb?branch=master)
|
17
|
+
[![Coverage Status](https://img.shields.io/coveralls/krasnoukhov/lotus-dynamodb.svg)](https://coveralls.io/r/krasnoukhov/lotus-dynamodb?branch=master)
|
18
|
+
[![Code Climate](https://img.shields.io/codeclimate/github/krasnoukhov/lotus-dynamodb.svg)](https://codeclimate.com/github/krasnoukhov/lotus-dynamodb)
|
19
|
+
[![Inline docs](http://inch-pages.github.io/github/krasnoukhov/lotus-dynamodb.svg)](http://inch-pages.github.io/github/krasnoukhov/lotus-dynamodb)
|
20
|
+
[![Dependencies](https://gemnasium.com/krasnoukhov/lotus-dynamodb.svg)](https://gemnasium.com/krasnoukhov/lotus-dynamodb)
|
21
|
+
|
22
|
+
## Links
|
23
|
+
|
24
|
+
* API Doc: [http://rdoc.info/github/krasnoukhov/lotus-dynamodb](http://rdoc.info/github/krasnoukhov/lotus-dynamodb)
|
25
|
+
* Bugs/Issues: [https://github.com/krasnoukhov/lotus-dynamodb/issues](https://github.com/krasnoukhov/lotus-dynamodb/issues)
|
26
|
+
|
27
|
+
## Installation
|
28
|
+
|
29
|
+
Add this line to your application's Gemfile:
|
30
|
+
|
31
|
+
gem 'lotus-dynamodb'
|
32
|
+
|
33
|
+
And then execute:
|
34
|
+
|
35
|
+
$ bundle
|
36
|
+
|
37
|
+
Or install it yourself as:
|
38
|
+
|
39
|
+
$ gem install lotus-dynamodb
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
Please refer to [Lotus::Model](https://github.com/lotus/model#usage) docs for any details related to Entity, Repository, Data Mapper and Adapter.
|
44
|
+
|
45
|
+
### Data types
|
46
|
+
|
47
|
+
This adapter supports coercion to all DynamoDB types, including blobs and sets.
|
48
|
+
|
49
|
+
List of Ruby types that are supported:
|
50
|
+
|
51
|
+
* AWS::DynamoDB::Binary – ```B```
|
52
|
+
* Array – ```S``` (via MultiJson)
|
53
|
+
* Boolean – ```N``` (1 for true and 0 for false)
|
54
|
+
* Date – ```N``` (Integer, seconds since Epoch)
|
55
|
+
* DateTime – ```N``` (Float, seconds since Epoch)
|
56
|
+
* Float – ```N```
|
57
|
+
* Hash – ```S``` (via MultiJson)
|
58
|
+
* Integer – ```N```
|
59
|
+
* Set – ```SS```, ```NS```, ```BS``` (Set of String, Number or AWS::DynamoDB::Binary)
|
60
|
+
* String – ```S```
|
61
|
+
* Time – ```N``` (Float, seconds since Epoch)
|
62
|
+
|
63
|
+
### Repository methods
|
64
|
+
|
65
|
+
See [complete list](https://github.com/lotus/model#repositories) of Repository methods provided by ```Lotus::Model```.
|
66
|
+
|
67
|
+
Following methods are not supported since it's incompatible with DynamoDB:
|
68
|
+
|
69
|
+
* first
|
70
|
+
* last
|
71
|
+
|
72
|
+
### Query methods
|
73
|
+
|
74
|
+
Generic methods supported by DynamoDB adapter:
|
75
|
+
|
76
|
+
* [all](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#all-instance_method)
|
77
|
+
* [where](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#where-instance_method) (aliases: ```eq```, ```in```, ```between```)
|
78
|
+
* [or](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#or-instance_method)
|
79
|
+
* [exclude](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#exclude-instance_method) (aliases: ```not```, ```ne```)
|
80
|
+
* [select](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#select-instance_method)
|
81
|
+
* [order](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#order-instance_method) (alias: ```asc```)
|
82
|
+
* [desc](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#desc-instance_method)
|
83
|
+
* [limit](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#limit-instance_method)
|
84
|
+
* [exists?](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#exist%3F-instance_method) (alias: ```exist?```)
|
85
|
+
* [count](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#count-instance_method)
|
86
|
+
|
87
|
+
DynamoDB-specific methods:
|
88
|
+
|
89
|
+
* [query](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#query-instance_method) – ensure ```query``` operation is performed instead of ```scan```
|
90
|
+
* [consistent](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#consistent-instance_method) – require consistent read for query
|
91
|
+
* [index](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#index-instance_method) – perform query on specific index
|
92
|
+
* [le](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#le-instance_method)
|
93
|
+
* [lt](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#lt-instance_method)
|
94
|
+
* [ge](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#ge-instance_method)
|
95
|
+
* [gt](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#gt-instance_method)
|
96
|
+
* [contains](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#contains-instance_method)
|
97
|
+
* [not_contains](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#not_contains-instance_method)
|
98
|
+
* [begins_with](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#begins_with-instance_method)
|
99
|
+
* [null](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#null-instance_method)
|
100
|
+
* [not_null](http://rdoc.info/github/krasnoukhov/lotus-dynamodb/Lotus/Model/Adapters/Dynamodb/Query#not_null-instance_method)
|
101
|
+
|
102
|
+
### Example
|
103
|
+
|
104
|
+
Check out the simple example in [examples/purchase.rb](examples/purchase.rb).
|
105
|
+
|
106
|
+
## Contributing
|
107
|
+
|
108
|
+
1. Fork it
|
109
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
110
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
111
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
112
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
t.pattern = 'test/**/*_test.rb'
|
7
|
+
t.libs.push 'test'
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace :test do
|
11
|
+
task :coverage do
|
12
|
+
ENV['COVERAGE'] = 'true'
|
13
|
+
Rake::Task['test'].invoke
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task default: :test
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# Link to original gist: https://gist.github.com/jodosha/17a8bd1a49899753f617
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'benchmark'
|
8
|
+
require 'benchmark/ips'
|
9
|
+
require 'lotus/model'
|
10
|
+
require 'lotus-dynamodb'
|
11
|
+
|
12
|
+
GC.disable
|
13
|
+
TIMES = (ENV['TIMES'] || 1_000_000).to_i
|
14
|
+
|
15
|
+
class Project
|
16
|
+
include Lotus::Entity
|
17
|
+
self.attributes = :attr1, :attr2, :attr3, :attr4,
|
18
|
+
:attr5, :attr6, :attr7, :attr8, :attr9
|
19
|
+
end
|
20
|
+
|
21
|
+
default_collection = Lotus::Model::Mapping::Collection.new(:projects, Lotus::Model::Mapping::Coercer) do
|
22
|
+
entity Project
|
23
|
+
|
24
|
+
attribute :id, Integer
|
25
|
+
attribute :attr1, String
|
26
|
+
attribute :attr2, String
|
27
|
+
attribute :attr3, String
|
28
|
+
attribute :attr4, String
|
29
|
+
attribute :attr5, String
|
30
|
+
attribute :attr6, String
|
31
|
+
attribute :attr7, String
|
32
|
+
attribute :attr8, String
|
33
|
+
attribute :attr9, String
|
34
|
+
end
|
35
|
+
|
36
|
+
dynamodb_collection = Lotus::Model::Mapping::Collection.new(:projects, Lotus::Model::Adapters::Dynamodb::Coercer) do
|
37
|
+
entity Project
|
38
|
+
|
39
|
+
attribute :id, Integer
|
40
|
+
attribute :attr1, String
|
41
|
+
attribute :attr2, String
|
42
|
+
attribute :attr3, String
|
43
|
+
attribute :attr4, String
|
44
|
+
attribute :attr5, String
|
45
|
+
attribute :attr6, String
|
46
|
+
attribute :attr7, String
|
47
|
+
attribute :attr8, String
|
48
|
+
attribute :attr9, String
|
49
|
+
end
|
50
|
+
|
51
|
+
record = Hash[id: '23', attr1: 'attr1', attr2: 'attr2',
|
52
|
+
attr3: 'attr3', attr4: 'attr4', attr5: 'attr5',
|
53
|
+
attr6: 'attr6', attr7: 'attr7', attr8: 'attr8',
|
54
|
+
attr9: 'attr9']
|
55
|
+
|
56
|
+
default_collection.load!
|
57
|
+
dynamodb_collection.load!
|
58
|
+
|
59
|
+
Benchmark.bm(30) do |bm|
|
60
|
+
bm.report 'default' do
|
61
|
+
TIMES.times do
|
62
|
+
default_collection.deserialize([record])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
bm.report 'dynamodb' do
|
67
|
+
TIMES.times do
|
68
|
+
dynamodb_collection.deserialize([record])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Benchmark.ips do |x|
|
74
|
+
x.report('default') { default_collection.deserialize([record]) }
|
75
|
+
x.report('dynamodb') { dynamodb_collection.deserialize([record]) }
|
76
|
+
end
|
data/examples/Gemfile
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require(:default)
|
3
|
+
|
4
|
+
require 'lotus/model'
|
5
|
+
require 'lotus-dynamodb'
|
6
|
+
|
7
|
+
AWS.config(
|
8
|
+
use_ssl: false,
|
9
|
+
dynamo_db_endpoint: 'localhost',
|
10
|
+
dynamo_db_port: 4567,
|
11
|
+
access_key_id: '',
|
12
|
+
secret_access_key: '',
|
13
|
+
)
|
14
|
+
|
15
|
+
#
|
16
|
+
# Say, we have a ```purchases``` DynamoDB table
|
17
|
+
#
|
18
|
+
# This table stores purchases which are split by a ```region``` and sorted by
|
19
|
+
# creation time.
|
20
|
+
# Local secondary index allows sorting records by subtotal, and global index is
|
21
|
+
# used to retrieve specific records by ```uuid``` attribute, even if we don't
|
22
|
+
# know a ```region``` of these records.
|
23
|
+
#
|
24
|
+
|
25
|
+
DB = AWS::DynamoDB::Client.new(api_version: Lotus::Dynamodb::API_VERSION)
|
26
|
+
|
27
|
+
begin
|
28
|
+
DB.describe_table("purchases")
|
29
|
+
rescue AWS::DynamoDB::Errors::ResourceNotFoundException
|
30
|
+
DB.create_table(
|
31
|
+
table_name: "purchases",
|
32
|
+
|
33
|
+
# List of all attributes which are used as table and indexes keys
|
34
|
+
attribute_definitions: [
|
35
|
+
{ attribute_name: "region", attribute_type: "S" },
|
36
|
+
{ attribute_name: "created_at", attribute_type: "N" },
|
37
|
+
{ attribute_name: "subtotal", attribute_type: "N" },
|
38
|
+
{ attribute_name: "uuid", attribute_type: "S" },
|
39
|
+
],
|
40
|
+
|
41
|
+
# Key schema of table
|
42
|
+
key_schema: [
|
43
|
+
{ attribute_name: "region", key_type: "HASH" },
|
44
|
+
{ attribute_name: "created_at", key_type: "RANGE" },
|
45
|
+
],
|
46
|
+
|
47
|
+
# List of local indexes
|
48
|
+
local_secondary_indexes: [{
|
49
|
+
index_name: "by_subtotal",
|
50
|
+
key_schema: [
|
51
|
+
{ attribute_name: "region", key_type: "HASH" },
|
52
|
+
{ attribute_name: "subtotal", key_type: "RANGE" },
|
53
|
+
],
|
54
|
+
projection: {
|
55
|
+
projection_type: "ALL",
|
56
|
+
},
|
57
|
+
}],
|
58
|
+
|
59
|
+
# List of global indexes
|
60
|
+
global_secondary_indexes: [{
|
61
|
+
index_name: "by_uuid",
|
62
|
+
key_schema: [
|
63
|
+
{ attribute_name: "uuid", key_type: "HASH" },
|
64
|
+
],
|
65
|
+
projection: {
|
66
|
+
projection_type: "ALL",
|
67
|
+
},
|
68
|
+
provisioned_throughput: {
|
69
|
+
read_capacity_units: 10,
|
70
|
+
write_capacity_units: 10,
|
71
|
+
},
|
72
|
+
}],
|
73
|
+
|
74
|
+
# Capacity
|
75
|
+
provisioned_throughput: {
|
76
|
+
read_capacity_units: 10,
|
77
|
+
write_capacity_units: 10,
|
78
|
+
},
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Entity
|
84
|
+
#
|
85
|
+
|
86
|
+
class Purchase
|
87
|
+
include Lotus::Entity
|
88
|
+
self.attributes = :id, :region, :subtotal, :item_ids, :content, :created_at
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Repository
|
93
|
+
#
|
94
|
+
|
95
|
+
class PurchaseRepository
|
96
|
+
include Lotus::Repository
|
97
|
+
|
98
|
+
class << self
|
99
|
+
def find_by_uuid(uuid)
|
100
|
+
query do
|
101
|
+
index("by_uuid").where(uuid: uuid).limit(1)
|
102
|
+
end.all.first
|
103
|
+
end
|
104
|
+
|
105
|
+
def top_by_subtotal(region, limit)
|
106
|
+
query do
|
107
|
+
index("by_subtotal").where(region: region).desc.limit(limit)
|
108
|
+
end.all
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Mapper
|
115
|
+
#
|
116
|
+
|
117
|
+
coercer = Lotus::Model::Adapters::Dynamodb::Coercer
|
118
|
+
mapper = Lotus::Model::Mapper.new(coercer) do
|
119
|
+
collection :purchases do
|
120
|
+
entity Purchase
|
121
|
+
|
122
|
+
attribute :id, String, as: :uuid
|
123
|
+
attribute :region, String
|
124
|
+
attribute :subtotal, Float
|
125
|
+
attribute :item_ids, Set
|
126
|
+
attribute :content, AWS::DynamoDB::Binary
|
127
|
+
attribute :created_at, Time
|
128
|
+
|
129
|
+
identity :uuid
|
130
|
+
end
|
131
|
+
end.load!
|
132
|
+
|
133
|
+
#
|
134
|
+
# Adapter
|
135
|
+
#
|
136
|
+
|
137
|
+
PurchaseRepository.adapter = Lotus::Model::Adapters::DynamodbAdapter.new(mapper)
|
138
|
+
|
139
|
+
#
|
140
|
+
# Create some data
|
141
|
+
#
|
142
|
+
|
143
|
+
purchases = [
|
144
|
+
{ region: "europe", subtotal: 15.0, item_ids: [1, 2] },
|
145
|
+
{ region: "europe", subtotal: 10.0, content: "Huge Blob Here" },
|
146
|
+
{ region: "usa", subtotal: 5.0, item_ids: ["strings", "as", "well"] },
|
147
|
+
{ region: "asia", subtotal: 100.0 },
|
148
|
+
].map do |purchase|
|
149
|
+
PurchaseRepository.create(
|
150
|
+
Purchase.new(purchase.merge(created_at: Time.new))
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Perform queries
|
156
|
+
#
|
157
|
+
|
158
|
+
puts "Find by UUID"
|
159
|
+
puts PurchaseRepository.find_by_uuid(purchases.first.id).inspect
|
160
|
+
puts
|
161
|
+
|
162
|
+
puts "Top by subtotal"
|
163
|
+
puts PurchaseRepository.top_by_subtotal("europe", 50).map(&:inspect)
|
164
|
+
puts
|