dynamoid 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Dynamoid.gemspec +5 -3
- data/README.markdown +13 -4
- data/VERSION +1 -1
- data/lib/dynamoid/adapter.rb +6 -4
- data/lib/dynamoid/adapter/aws_sdk.rb +29 -8
- data/lib/dynamoid/adapter/local.rb +37 -12
- data/lib/dynamoid/associations/has_one.rb +10 -2
- data/lib/dynamoid/criteria.rb +1 -1
- data/lib/dynamoid/criteria/chain.rb +42 -6
- data/lib/dynamoid/errors.rb +1 -1
- data/lib/dynamoid/indexes.rb +18 -30
- data/lib/dynamoid/indexes/index.rb +62 -0
- data/lib/dynamoid/persistence.rb +7 -3
- data/spec/app/models/user.rb +4 -0
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +63 -8
- data/spec/dynamoid/adapter/local_spec.rb +89 -5
- data/spec/dynamoid/adapter_spec.rb +29 -1
- data/spec/dynamoid/criteria/chain_spec.rb +31 -8
- data/spec/dynamoid/criteria_spec.rb +1 -1
- data/spec/dynamoid/indexes/index_spec.rb +84 -0
- data/spec/dynamoid/indexes_spec.rb +9 -37
- metadata +69 -22
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dynamoid #:nodoc:
|
3
|
+
module Indexes
|
4
|
+
|
5
|
+
# The class abstracts information about an index
|
6
|
+
class Index
|
7
|
+
attr_accessor :source, :name, :hash_keys, :range_keys
|
8
|
+
alias_method :range_key?, :range_keys
|
9
|
+
|
10
|
+
def initialize(source, name, options = {})
|
11
|
+
@source = source
|
12
|
+
|
13
|
+
if options.delete(:range)
|
14
|
+
@range_keys = sort(name)
|
15
|
+
elsif options[:range_key]
|
16
|
+
@range_keys = sort(options[:range_key])
|
17
|
+
end
|
18
|
+
@hash_keys = sort(name)
|
19
|
+
@name = sort([hash_keys, range_keys])
|
20
|
+
|
21
|
+
raise Dynamoid::Errors::InvalidField, 'A key specified for an index is not a field' unless keys.all?{|n| source.attributes.include?(n)}
|
22
|
+
end
|
23
|
+
|
24
|
+
def sort(objs)
|
25
|
+
Array(objs).flatten.compact.uniq.collect(&:to_s).sort.collect(&:to_sym)
|
26
|
+
end
|
27
|
+
|
28
|
+
def keys
|
29
|
+
[Array(hash_keys) + Array(range_keys)].flatten.uniq
|
30
|
+
end
|
31
|
+
|
32
|
+
def table_name
|
33
|
+
"#{Dynamoid::Config.namespace}_index_#{source.to_s.downcase}_#{name.collect(&:to_s).collect(&:pluralize).join('_and_')}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def values(attrs)
|
37
|
+
attrs = attrs.send(:attributes) if attrs.respond_to?(:attributes)
|
38
|
+
{}.tap do |hash|
|
39
|
+
hash[:hash_value] = hash_keys.collect{|key| attrs[key]}.join('.')
|
40
|
+
hash[:range_value] = range_keys.inject(0.0) {|sum, key| sum + attrs[key].to_f} if self.range_key?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def save(obj)
|
45
|
+
values = values(obj)
|
46
|
+
return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
|
47
|
+
existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], values[:range_value])
|
48
|
+
ids = ((existing and existing[:ids]) or Set.new)
|
49
|
+
Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => ids.merge([obj.id]), :range => values[:range_value]})
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete(obj)
|
53
|
+
values = values(obj)
|
54
|
+
return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
|
55
|
+
existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], values[:range_value])
|
56
|
+
return true unless existing && existing[:ids] && existing[:ids].include?(obj.id)
|
57
|
+
Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => (existing[:ids] - Set[obj.id]), :range => values[:range_value]})
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/dynamoid/persistence.rb
CHANGED
@@ -15,8 +15,8 @@ module Dynamoid #:nodoc:
|
|
15
15
|
"#{Dynamoid::Config.namespace}_#{self.to_s.downcase.pluralize}"
|
16
16
|
end
|
17
17
|
|
18
|
-
def create_table(table_name, id = :id)
|
19
|
-
Dynamoid::Adapter.tables << table_name if Dynamoid::Adapter.create_table(table_name, id.to_sym)
|
18
|
+
def create_table(table_name, id = :id, options = {})
|
19
|
+
Dynamoid::Adapter.tables << table_name if Dynamoid::Adapter.create_table(table_name, id.to_sym, options)
|
20
20
|
end
|
21
21
|
|
22
22
|
def table_exists?(table_name)
|
@@ -43,7 +43,11 @@ module Dynamoid #:nodoc:
|
|
43
43
|
hash[attribute] = Set[value]
|
44
44
|
end
|
45
45
|
when :datetime
|
46
|
-
|
46
|
+
if value.is_a?(Date) || value.is_a?(DateTime) || value.is_a?(Time)
|
47
|
+
hash[attribute] = value
|
48
|
+
else
|
49
|
+
hash[attribute] = Time.at(value).to_datetime
|
50
|
+
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
data/spec/app/models/user.rb
CHANGED
@@ -4,10 +4,14 @@ class User
|
|
4
4
|
field :name
|
5
5
|
field :email
|
6
6
|
field :password
|
7
|
+
field :last_logged_in_at, :datetime
|
7
8
|
|
8
9
|
index :name
|
9
10
|
index :email
|
10
11
|
index [:name, :email]
|
12
|
+
index :name, :range_key => :created_at
|
13
|
+
index :name, :range_key => :last_logged_in_at
|
14
|
+
index :created_at, :range => true
|
11
15
|
|
12
16
|
has_and_belongs_to_many :subscriptions
|
13
17
|
end
|
@@ -8,10 +8,10 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
8
8
|
context 'without a preexisting table' do
|
9
9
|
# CreateTable and DeleteTable
|
10
10
|
it 'performs CreateTable and DeleteTable' do
|
11
|
-
table = Dynamoid::Adapter.create_table('CreateTable', :id)
|
12
|
-
|
11
|
+
table = Dynamoid::Adapter.create_table('CreateTable', :id, :range_key => :created_at)
|
12
|
+
|
13
13
|
Dynamoid::Adapter.connection.tables.collect{|t| t.name}.should include 'CreateTable'
|
14
|
-
|
14
|
+
|
15
15
|
Dynamoid::Adapter.delete_table('CreateTable')
|
16
16
|
end
|
17
17
|
end
|
@@ -20,6 +20,7 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
20
20
|
before(:all) do
|
21
21
|
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable1', :id) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable1')
|
22
22
|
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable2', :id) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable2')
|
23
|
+
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable3', :id, :range_key => :range) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable3')
|
23
24
|
end
|
24
25
|
|
25
26
|
# GetItem, PutItem and DeleteItem
|
@@ -37,6 +38,16 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
37
38
|
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable1', '1').should be_nil
|
38
39
|
end
|
39
40
|
|
41
|
+
it 'performs GetItem for an item that does exist with a range key' do
|
42
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 2.0})
|
43
|
+
|
44
|
+
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable3', '1', 2.0).should == {:name => 'Josh', :id => '1', :range => 2.0}
|
45
|
+
|
46
|
+
Dynamoid::Adapter.delete_item('dynamoid_tests_TestTable3', '1', 2.0)
|
47
|
+
|
48
|
+
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable3', '1', 2.0).should be_nil
|
49
|
+
end
|
50
|
+
|
40
51
|
it 'performs DeleteItem for an item that does not exist' do
|
41
52
|
Dynamoid::Adapter.delete_item('dynamoid_tests_TestTable1', '1')
|
42
53
|
|
@@ -70,6 +81,25 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
70
81
|
results['dynamoid_tests_TestTable1'].should include({:name => 'Justin', :id => '2'})
|
71
82
|
end
|
72
83
|
|
84
|
+
it 'performs BatchGetItem with one ranged key' do
|
85
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 1.0})
|
86
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '2', :name => 'Justin', :range => 2.0})
|
87
|
+
|
88
|
+
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable3' => [['1', 1.0]])
|
89
|
+
results.size.should == 1
|
90
|
+
results['dynamoid_tests_TestTable3'].should include({:name => 'Josh', :id => '1', :range => 1.0})
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'performs BatchGetItem with multiple ranged keys' do
|
94
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 1.0})
|
95
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '2', :name => 'Justin', :range => 2.0})
|
96
|
+
|
97
|
+
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable3' => [['1', 1.0],['2', 2.0]])
|
98
|
+
results.size.should == 1
|
99
|
+
results['dynamoid_tests_TestTable3'].should include({:name => 'Josh', :id => '1', :range => 1.0})
|
100
|
+
results['dynamoid_tests_TestTable3'].should include({:name => 'Justin', :id => '2', :range => 2.0})
|
101
|
+
end
|
102
|
+
|
73
103
|
# ListTables
|
74
104
|
it 'performs ListTables' do
|
75
105
|
Dynamoid::Adapter.list_tables.should include 'dynamoid_tests_TestTable1'
|
@@ -80,14 +110,41 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
80
110
|
it 'performs query on a table and returns items' do
|
81
111
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
82
112
|
|
83
|
-
Dynamoid::Adapter.query('dynamoid_tests_TestTable1', '1').should == { :id=> '1', :name=>"Josh" }
|
113
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable1', :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
|
84
114
|
end
|
85
115
|
|
86
116
|
it 'performs query on a table and returns items if there are multiple items' do
|
87
117
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
88
118
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2', :name => 'Justin'})
|
89
119
|
|
90
|
-
Dynamoid::Adapter.query('dynamoid_tests_TestTable1', '1').should == { :id=> '1', :name=>"Josh" }
|
120
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable1', :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'range queries' do
|
124
|
+
before do
|
125
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :range => 1.0})
|
126
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :range => 3.0})
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'performs query on a table with a range and selects items in a range' do
|
130
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_value => 0.0..3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'performs query on a table with a range and selects items greater than' do
|
134
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_greater_than => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(3)}]
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'performs query on a table with a range and selects items less than' do
|
138
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_less_than => 2.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}]
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'performs query on a table with a range and selects items gte' do
|
142
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_gte => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'performs query on a table with a range and selects items lte' do
|
146
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_lte => 3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
147
|
+
end
|
91
148
|
end
|
92
149
|
|
93
150
|
# Scan
|
@@ -116,9 +173,7 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
116
173
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2', :name => 'Josh'})
|
117
174
|
|
118
175
|
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', {}).should == [{:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"}]
|
119
|
-
end
|
120
|
-
|
121
|
-
|
176
|
+
end
|
122
177
|
end
|
123
178
|
|
124
179
|
# DescribeTable
|
@@ -28,6 +28,28 @@ describe Dynamoid::Adapter::Local do
|
|
28
28
|
results['table1'].should include({:name => 'Josh', :id => '1'})
|
29
29
|
results['table1'].should include({:name => 'Justin', :id => '2'})
|
30
30
|
end
|
31
|
+
|
32
|
+
it 'performs BatchGetItem with range keys' do
|
33
|
+
Dynamoid::Adapter.create_table('table1', :id, :range_key => :range)
|
34
|
+
Dynamoid::Adapter.put_item('table1', {:id => '1', :range => 1.0})
|
35
|
+
Dynamoid::Adapter.put_item('table1', {:id => '2', :range => 2.0})
|
36
|
+
|
37
|
+
results = Dynamoid::Adapter.batch_get_item('table1' => [['1', 1.0], ['2', 2.0]])
|
38
|
+
results.size.should == 1
|
39
|
+
results['table1'].should include({:id => '1', :range => 1.0})
|
40
|
+
results['table1'].should include({:id => '2', :range => 2.0})
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'performs BatchGetItem with range keys on one primary key' do
|
44
|
+
Dynamoid::Adapter.create_table('table1', :id, :range_key => :range)
|
45
|
+
Dynamoid::Adapter.put_item('table1', {:id => '1', :range => 1.0})
|
46
|
+
Dynamoid::Adapter.put_item('table1', {:id => '1', :range => 2.0})
|
47
|
+
|
48
|
+
results = Dynamoid::Adapter.batch_get_item('table1' => [['1', 1.0], ['1', 2.0]])
|
49
|
+
results.size.should == 1
|
50
|
+
results['table1'].should include({:id => '1', :range => 1.0})
|
51
|
+
results['table1'].should include({:id => '1', :range => 2.0})
|
52
|
+
end
|
31
53
|
|
32
54
|
# CreateTable
|
33
55
|
it 'performs CreateTable' do
|
@@ -78,6 +100,14 @@ describe Dynamoid::Adapter::Local do
|
|
78
100
|
|
79
101
|
Dynamoid::Adapter.get_item('Test Table', '1').should == {:id => '1', :name => 'Josh'}
|
80
102
|
end
|
103
|
+
|
104
|
+
it "performs GetItem for an item with a range key" do
|
105
|
+
Dynamoid::Adapter.create_table('Test Table', :id, :range_key => :range)
|
106
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :range => 1.0})
|
107
|
+
|
108
|
+
Dynamoid::Adapter.get_item('Test Table', '1').should be_nil
|
109
|
+
Dynamoid::Adapter.get_item('Test Table', '1', 1.0).should == {:id => '1', :range => 1.0}
|
110
|
+
end
|
81
111
|
|
82
112
|
# ListTables
|
83
113
|
it 'performs ListTables' do
|
@@ -93,15 +123,40 @@ describe Dynamoid::Adapter::Local do
|
|
93
123
|
Dynamoid::Adapter.create_table('Test Table', :id)
|
94
124
|
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Josh'})
|
95
125
|
|
96
|
-
Dynamoid::Adapter.data['Test Table'].should == {
|
126
|
+
Dynamoid::Adapter.data['Test Table'].should == {:hash_key=>:id, :range_key=>nil, :data=>{"1."=>{:id=>"1", :name=>"Josh"}}}
|
97
127
|
end
|
128
|
+
|
129
|
+
it 'puts an item twice and overwrites an existing item' do
|
130
|
+
Dynamoid::Adapter.create_table('Test Table', :id)
|
131
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Josh'})
|
132
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Justin'})
|
133
|
+
|
134
|
+
Dynamoid::Adapter.data['Test Table'].should == {:hash_key=>:id, :range_key=>nil, :data=>{"1."=>{:id=>"1", :name=>"Justin"}}}
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'puts an item twice and does not overwrite an existing item if the range key is not the same' do
|
138
|
+
Dynamoid::Adapter.create_table('Test Table', :id, :range_key => :range)
|
139
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Justin', :range => 1.0})
|
140
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Justin', :range => 2.0})
|
141
|
+
|
142
|
+
Dynamoid::Adapter.data['Test Table'].should == {:hash_key=>:id, :range_key=>:range, :data=>{"1.1.0"=>{:id=>"1", :name=>"Justin", :range => 1.0}, "1.2.0" => {:id=>"1", :name=>"Justin", :range => 2.0}}}
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'puts an item twice and does overwrite an existing item if the range key is the same' do
|
146
|
+
Dynamoid::Adapter.create_table('Test Table', :id, :range_key => :range)
|
147
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Josh', :range => 1.0})
|
148
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Justin', :range => 1.0})
|
149
|
+
|
150
|
+
Dynamoid::Adapter.data['Test Table'].should == {:hash_key=>:id, :range_key=>:range, :data=>{"1.1.0"=>{:id=>"1", :name=>"Justin", :range => 1.0}}}
|
151
|
+
end
|
152
|
+
|
98
153
|
|
99
154
|
# Query
|
100
155
|
it 'performs query on a table and returns items' do
|
101
156
|
Dynamoid::Adapter.create_table('Test Table', :id)
|
102
157
|
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Josh'})
|
103
158
|
|
104
|
-
Dynamoid::Adapter.query('Test Table', '1').should == { :id=> '1', :name=>"Josh" }
|
159
|
+
Dynamoid::Adapter.query('Test Table', :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
|
105
160
|
end
|
106
161
|
|
107
162
|
it 'performs query on a table and returns items if there are multiple items' do
|
@@ -109,9 +164,38 @@ describe Dynamoid::Adapter::Local do
|
|
109
164
|
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :name => 'Josh'})
|
110
165
|
Dynamoid::Adapter.put_item('Test Table', {:id => '2', :name => 'Justin'})
|
111
166
|
|
112
|
-
Dynamoid::Adapter.query('Test Table', '1').should == { :id=> '1', :name=>"Josh" }
|
113
|
-
end
|
114
|
-
|
167
|
+
Dynamoid::Adapter.query('Test Table', :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'range queries' do
|
171
|
+
before do
|
172
|
+
Dynamoid::Adapter.create_table('Test Table', :id, :range_key => :range)
|
173
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :range => 1.0})
|
174
|
+
Dynamoid::Adapter.put_item('Test Table', {:id => '1', :range => 2.0})
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'performs query on a table with a range and selects items in a range' do
|
178
|
+
Dynamoid::Adapter.query('Test Table', :hash_value => '1', :range_value => 0.0..3.0).should =~ [{:id => '1', :range => 1.0}, {:id => '1', :range => 2.0}]
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'performs query on a table with a range and selects items greater than' do
|
182
|
+
Dynamoid::Adapter.query('Test Table', :hash_value => '1', :range_greater_than => 1.0).should =~ [{:id => '1', :range => 2.0}]
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'performs query on a table with a range and selects items less than' do
|
186
|
+
Dynamoid::Adapter.query('Test Table', :hash_value => '1', :range_less_than => 2.0).should =~ [{:id => '1', :range => 1.0}]
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'performs query on a table with a range and selects items gte' do
|
190
|
+
Dynamoid::Adapter.query('Test Table', :hash_value => '1', :range_gte => 1.0).should =~ [{:id => '1', :range => 1.0}, {:id => '1', :range => 2.0}]
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'performs query on a table with a range and selects items lte' do
|
194
|
+
Dynamoid::Adapter.query('Test Table', :hash_value => '1', :range_lte => 2.0).should =~ [{:id => '1', :range => 1.0}, {:id => '1', :range => 2.0}]
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
115
199
|
# Scan
|
116
200
|
it 'performs scan on a table and returns items' do
|
117
201
|
Dynamoid::Adapter.create_table('Test Table', :id)
|
@@ -31,7 +31,7 @@ describe "Dynamoid::Adapter" do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'reads through the adapter for one ID' do
|
34
|
-
Dynamoid::Adapter.expects(:get_item).with('dynamoid_tests_TestTable', '123').returns(true)
|
34
|
+
Dynamoid::Adapter.expects(:get_item).with('dynamoid_tests_TestTable', '123', nil).returns(true)
|
35
35
|
|
36
36
|
Dynamoid::Adapter.read('dynamoid_tests_TestTable', '123')
|
37
37
|
end
|
@@ -41,6 +41,18 @@ describe "Dynamoid::Adapter" do
|
|
41
41
|
|
42
42
|
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'])
|
43
43
|
end
|
44
|
+
|
45
|
+
it 'reads through the adapter for one ID and a range key' do
|
46
|
+
Dynamoid::Adapter.expects(:get_item).with('dynamoid_tests_TestTable', '123', 2.0).returns(true)
|
47
|
+
|
48
|
+
Dynamoid::Adapter.read('dynamoid_tests_TestTable', '123', 2.0)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'reads through the adapter for many IDs and a range key' do
|
52
|
+
Dynamoid::Adapter.expects(:batch_get_item).with({'dynamoid_tests_TestTable' => [['1', 2.0], ['2', 2.0]]}).returns(true)
|
53
|
+
|
54
|
+
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'], 2.0)
|
55
|
+
end
|
44
56
|
end
|
45
57
|
|
46
58
|
context 'with partitioning' do
|
@@ -72,10 +84,26 @@ describe "Dynamoid::Adapter" do
|
|
72
84
|
|
73
85
|
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'])
|
74
86
|
end
|
87
|
+
|
88
|
+
it 'reads through the adapter for one ID and a range key' do
|
89
|
+
Dynamoid::Adapter.expects(:batch_get_item).with('dynamoid_tests_TestTable' => (0...Dynamoid::Config.partition_size).collect{|n| ["123.#{n}", 2.0]}).returns({})
|
90
|
+
|
91
|
+
Dynamoid::Adapter.read('dynamoid_tests_TestTable', '123', 2.0)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'reads through the adapter for many IDs and a range key' do
|
95
|
+
Dynamoid::Adapter.expects(:batch_get_item).with('dynamoid_tests_TestTable' => (0...Dynamoid::Config.partition_size).collect{|n| ["1.#{n}", 2.0]} + (0...Dynamoid::Config.partition_size).collect{|n| ["2.#{n}", 2.0]}).returns({})
|
96
|
+
|
97
|
+
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'], 2.0)
|
98
|
+
end
|
75
99
|
|
76
100
|
it 'returns an ID with all partitions' do
|
77
101
|
Dynamoid::Adapter.id_with_partitions('1').should =~ (0...Dynamoid::Config.partition_size).collect{|n| "1.#{n}"}
|
78
102
|
end
|
103
|
+
|
104
|
+
it 'returns an ID and range key with all partitions' do
|
105
|
+
Dynamoid::Adapter.id_with_partitions([['1', 1.0]]).should =~ (0...Dynamoid::Config.partition_size).collect{|n| ["1.#{n}", 1.0]}
|
106
|
+
end
|
79
107
|
|
80
108
|
it 'returns a result for one partitioned element' do
|
81
109
|
@time = DateTime.now
|
@@ -3,37 +3,52 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
3
3
|
describe "Dynamoid::Associations::Chain" do
|
4
4
|
|
5
5
|
before(:each) do
|
6
|
+
@time = DateTime.now
|
6
7
|
@user = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com', :password => 'Test123')
|
7
8
|
@chain = Dynamoid::Criteria::Chain.new(User)
|
8
9
|
end
|
9
10
|
|
10
11
|
it 'finds matching index for a query' do
|
11
12
|
@chain.query = {:name => 'Josh'}
|
12
|
-
@chain.send(:index).should == [:name]
|
13
|
+
@chain.send(:index).should == User.indexes[[:name]]
|
13
14
|
|
14
15
|
@chain.query = {:email => 'josh@joshsymonds.com'}
|
15
|
-
@chain.send(:index).should == [:email]
|
16
|
+
@chain.send(:index).should == User.indexes[[:email]]
|
16
17
|
|
17
18
|
@chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
|
18
|
-
@chain.send(:index).should == [:email, :name]
|
19
|
+
@chain.send(:index).should == User.indexes[[:email, :name]]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'finds matching index for a range query' do
|
23
|
+
@chain.query = {"created_at.gt" => @time - 1.day}
|
24
|
+
@chain.send(:index).should == User.indexes[[:created_at]]
|
25
|
+
|
26
|
+
@chain.query = {:name => 'Josh', "created_at.lt" => @time - 1.day}
|
27
|
+
@chain.send(:index).should == User.indexes[[:created_at, :name]]
|
19
28
|
end
|
20
29
|
|
21
30
|
it 'does not find an index if there is not an appropriate one' do
|
22
31
|
@chain.query = {:password => 'Test123'}
|
23
|
-
@chain.send(:index).should
|
32
|
+
@chain.send(:index).should be_nil
|
33
|
+
|
34
|
+
@chain.query = {:password => 'Test123', :created_at => @time}
|
35
|
+
@chain.send(:index).should be_nil
|
24
36
|
end
|
25
37
|
|
26
38
|
it 'returns values for index for a query' do
|
27
39
|
@chain.query = {:name => 'Josh'}
|
28
|
-
@chain.send(:
|
40
|
+
@chain.send(:index_query).should == {:hash_value => 'Josh'}
|
29
41
|
|
30
42
|
@chain.query = {:email => 'josh@joshsymonds.com'}
|
31
|
-
@chain.send(:
|
43
|
+
@chain.send(:index_query).should == {:hash_value => 'josh@joshsymonds.com'}
|
32
44
|
|
33
45
|
@chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
|
34
|
-
@chain.send(:
|
46
|
+
@chain.send(:index_query).should == {:hash_value => 'josh@joshsymonds.com.Josh'}
|
47
|
+
|
48
|
+
@chain.query = {:name => 'Josh', 'created_at.gt' => @time}
|
49
|
+
@chain.send(:index_query).should == {:hash_value => 'Josh', :range_greater_than => @time.to_f}
|
35
50
|
end
|
36
|
-
|
51
|
+
|
37
52
|
it 'finds records with an index' do
|
38
53
|
@chain.query = {:name => 'Josh'}
|
39
54
|
@chain.send(:records_with_index).should == [@user]
|
@@ -45,6 +60,14 @@ describe "Dynamoid::Associations::Chain" do
|
|
45
60
|
@chain.send(:records_with_index).should == [@user]
|
46
61
|
end
|
47
62
|
|
63
|
+
it 'returns records with an index for a ranged query' do
|
64
|
+
@chain.query = {:name => 'Josh', "created_at.gt" => @time - 1.day}
|
65
|
+
@chain.send(:records_with_index).should == [@user]
|
66
|
+
|
67
|
+
@chain.query = {:name => 'Josh', "created_at.lt" => @time + 1.day}
|
68
|
+
@chain.send(:records_with_index).should == [@user]
|
69
|
+
end
|
70
|
+
|
48
71
|
it 'finds records without an index' do
|
49
72
|
@chain.query = {:password => 'Test123'}
|
50
73
|
@chain.send(:records_without_index).should == [@user]
|