Skip to content

Commit 17ae990

Browse files
committed
Handle edge case where there is a GSI with the same hash key as the primary index
In the current implementation, when a `where` query is performed with a hash key and range key that would match a GSI, but the hash key overlaps with the primary index, the GSI is not selected and an expensive Scan is performed instead of the cheap Query.
1 parent ae9152f commit 17ae990

File tree

2 files changed

+11
-3
lines changed

2 files changed

+11
-3
lines changed

lib/dynamoid/criteria/key_fields_detector.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ def detect_keys
3939
@range_key = lsi.range_key
4040
@index_name = lsi.name
4141
end
42-
43-
return
4442
end
4543

4644
# See if can use any global secondary index
@@ -49,7 +47,7 @@ def detect_keys
4947
# get back full data
5048
@source.global_secondary_indexes.each do |_, gsi|
5149
next unless @query.keys.map(&:to_s).include?(gsi.hash_key.to_s) && gsi.projected_attributes == :all
52-
next if @range_key.present? && !query_keys.include?(gsi.range_key.to_s)
50+
next if @hash_key.present? && !query_keys.include?(gsi.range_key.to_s)
5351

5452
@hash_key = gsi.hash_key
5553
@range_key = gsi.range_key

spec/dynamoid/criteria/chain_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ def request_params
666666
global_secondary_index hash_key: :city, range_key: :age, name: :cityage, projected_attributes: :all
667667
global_secondary_index hash_key: :city, range_key: :gender, name: :citygender, projected_attributes: :all
668668
global_secondary_index hash_key: :email, range_key: :age, name: :emailage, projected_attributes: :all
669+
global_secondary_index hash_key: :name, range_key: :age, name: :nameage, projected_attributes: :all
669670
end
670671
end
671672

@@ -766,6 +767,15 @@ def request_params
766767
expect(chain.key_fields_detector.range_key).to eq(:gender)
767768
expect(chain.key_fields_detector.index_name).to eq(:citygender)
768769
end
770+
771+
it 'uses global secondary index when secondary hash key overlaps with primary hash key and range key matches' do
772+
chain = Dynamoid::Criteria::Chain.new(model)
773+
expect(chain).to receive(:pages_via_query).and_call_original
774+
expect(chain.where(name: 'Bob', age: 10).to_a.size).to eq(1)
775+
expect(chain.key_fields_detector.hash_key).to eq(:name)
776+
expect(chain.key_fields_detector.range_key).to eq(:age)
777+
expect(chain.key_fields_detector.index_name).to eq(:nameage)
778+
end
769779
end
770780

771781
it 'supports query on global secondary index with correct start key without table range key' do

0 commit comments

Comments
 (0)