Skip to content

Commit 192dfb1

Browse files
authored
Merge pull request #343 from opsys-saito/feature/add-or-support
Add ActiveHash::Relation#or to support OR-like queries
2 parents de01f82 + 07dbfdb commit 192dfb1

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

lib/active_hash/relation.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ def where(conditions_hash = :chain)
2424
spawn.where!(conditions_hash)
2525
end
2626

27+
def or(other)
28+
unless other.is_a?(self.class)
29+
raise ArgumentError, "or() expects an ActiveHash::Relation"
30+
end
31+
32+
unless other.klass == klass
33+
raise ArgumentError, "or() expects relations for the same model"
34+
end
35+
36+
merged = (records + other.records).uniq do |record|
37+
record.respond_to?(:id) ? record.id : record.object_id
38+
end
39+
40+
self.class.new(klass, merged, [], order_values)
41+
end
42+
2743
def pretty_print(pp)
2844
pp.pp(entries.to_ary)
2945
end

spec/active_hash/relation_spec.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,52 @@
9393
expect(out.string).to_not match(/ActiveHash::Relation/)
9494
end
9595
end
96+
97+
describe '#or' do
98+
it 'returns the union of two where relations' do
99+
r1 = model_class.where(name: "US")
100+
r2 = model_class.where(name: "Canada")
101+
102+
result = r1.or(r2)
103+
104+
expect(result.pluck(:id)).to match_array([1, 2])
105+
end
106+
107+
it 'deduplicates records by id' do
108+
r1 = model_class.where(name: "US")
109+
r2 = model_class.where(name: "US")
110+
111+
result = r1.or(r2)
112+
113+
expect(result.pluck(:id)).to eq([1])
114+
end
115+
116+
it 'returns a relation that can be chained' do
117+
r1 = model_class.where(name: "US")
118+
r2 = model_class.where(name: "Canada")
119+
120+
result = r1.or(r2).where(id: 2)
121+
122+
expect(result.pluck(:id)).to eq([2])
123+
end
124+
125+
it 'raises when OR-ing relations from different models' do
126+
other_model = Class.new(ActiveHash::Base) do
127+
self.data = [{ id: 1, name: "X" }]
128+
end
129+
130+
expect {
131+
model_class.where(name: "US").or(other_model.where(name: "X"))
132+
}.to raise_error(ArgumentError)
133+
end
134+
135+
it 'works with order applied after or' do
136+
r1 = model_class.where(id: 1)
137+
r2 = model_class.where(id: [2])
138+
139+
result = r1.or(r2).order(id: :desc)
140+
141+
expect(result.pluck(:id)).to eq([2, 1])
142+
end
143+
end
96144
end

0 commit comments

Comments
 (0)