From 73e119e1abe28a94ea476662b7fea68a94906060 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Mon, 10 Sep 2012 14:17:38 -0400 Subject: [PATCH] Adds array overlap arel operator --- .../arel/nodes/contained_within.rb | 5 +++++ lib/postgres_ext/arel/predications.rb | 4 ++++ lib/postgres_ext/arel/visitors/to_sql.rb | 17 +++++++++++++++ spec/arel/array_spec.rb | 21 ++++++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/postgres_ext/arel/nodes/contained_within.rb b/lib/postgres_ext/arel/nodes/contained_within.rb index d6c11d4..308caf6 100644 --- a/lib/postgres_ext/arel/nodes/contained_within.rb +++ b/lib/postgres_ext/arel/nodes/contained_within.rb @@ -10,5 +10,10 @@ class ArrayAnyEq < Arel::Nodes::Binary alias :operand1 :left alias :operand2 :right end + + class ArrayOverlap < Arel::Nodes::Binary + alias :operand1 :left + alias :operand2 :right + end end end diff --git a/lib/postgres_ext/arel/predications.rb b/lib/postgres_ext/arel/predications.rb index cf23193..dcbdc8c 100644 --- a/lib/postgres_ext/arel/predications.rb +++ b/lib/postgres_ext/arel/predications.rb @@ -9,5 +9,9 @@ def contained_within(other) def array_any_eq(other) Nodes::ArrayAnyEq.new self, other end + + def array_overlap(other) + Nodes::ArrayOverlap.new self, other + end end end diff --git a/lib/postgres_ext/arel/visitors/to_sql.rb b/lib/postgres_ext/arel/visitors/to_sql.rb index 338aa34..e7156ed 100644 --- a/lib/postgres_ext/arel/visitors/to_sql.rb +++ b/lib/postgres_ext/arel/visitors/to_sql.rb @@ -11,9 +11,26 @@ def visit_Arel_Nodes_ArrayAnyEq o "#{visit o.right} = ANY(#{visit o.left})" end + def visit_Arel_Nodes_ArrayOverlap o + if Array === o.right + right = "{#{o.right.map{|v| change_string(visit(v))}.join(',')}}" + "#{visit o.left} && '#{right}'" + else + "#{visit o.left} && #{visit o.right}" + end + end + def visit_IPAddr value "'#{value.to_s}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}'" end + + def change_string value + if value.match /"|,|{/ + value.gsub(/"/, "\"").gsub(/'/,'"') + else + value.gsub(/'/,'') + end + end end end end diff --git a/spec/arel/array_spec.rb b/spec/arel/array_spec.rb index c938e9e..412654b 100644 --- a/spec/arel/array_spec.rb +++ b/spec/arel/array_spec.rb @@ -18,7 +18,7 @@ class ArelArray < ActiveRecord::Base Object.send(:remove_const, :ArelArray) end - describe 'Array Any' do + describe 'Array Any Equal' do it 'converts Arel array_any_eq statement' do arel_table = ArelArray.arel_table @@ -33,4 +33,23 @@ class ArelArray < ActiveRecord::Base ArelArray.where(arel_table[:tags].array_any_eq('one')).should include(one) end end + + describe 'Array Overlap' do + it 'converts Arel array_overlap statment' do + arel_table = ArelArray.arel_table + + arel_table.where(arel_table[:tags].array_overlap(['tag','tag 2'])).to_sql.should match /&& '\{tag,tag 2\}'/ + end + + it 'returns matched records' do + one = ArelArray.create!(:tags => ['one']) + two = ArelArray.create!(:tags => ['two']) + arel_table = ArelArray.arel_table + + ArelArray.where(arel_table[:tags].array_overlap(['one'])).should include(one) + ArelArray.where(arel_table[:tags].array_overlap(['two'])).should include(two) + ArelArray.where(arel_table[:tags].array_overlap(['two','one'])).should include(two) + ArelArray.where(arel_table[:tags].array_overlap(['two','one'])).should include(one) + end + end end