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.
@@ -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
@@ -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
- hash[attribute] = Time.at(value).to_datetime
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
@@ -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 == { :id => :id, :data => { '1' => { :id=> '1', :name=>"Josh" }}}
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(:values_for_index).should == ['Josh']
40
+ @chain.send(:index_query).should == {:hash_value => 'Josh'}
29
41
 
30
42
  @chain.query = {:email => 'josh@joshsymonds.com'}
31
- @chain.send(:values_for_index).should == ['josh@joshsymonds.com']
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(:values_for_index).should == ['josh@joshsymonds.com', 'Josh']
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]