activerecord-postgis-array 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.travis.yml +18 -0
- data/CHANGELOG.md +99 -0
- data/CONTRIBUTING.md +35 -0
- data/Gemfile +12 -0
- data/LICENSE +22 -0
- data/README.md +87 -0
- data/Rakefile +33 -0
- data/activerecord-postgis-array.gemspec +30 -0
- data/docs/indexes.md +28 -0
- data/docs/migrations.md +92 -0
- data/docs/querying.md +170 -0
- data/docs/type_casting.md +51 -0
- data/lib/activerecord-postgis-array.rb +3 -0
- data/lib/activerecord-postgis-array/active_record.rb +4 -0
- data/lib/activerecord-postgis-array/active_record/connection_adapters.rb +1 -0
- data/lib/activerecord-postgis-array/active_record/connection_adapters/postgres_adapter.rb +346 -0
- data/lib/activerecord-postgis-array/active_record/relation.rb +2 -0
- data/lib/activerecord-postgis-array/active_record/relation/predicate_builder.rb +71 -0
- data/lib/activerecord-postgis-array/active_record/relation/query_methods.rb +84 -0
- data/lib/activerecord-postgis-array/active_record/sanitization.rb +30 -0
- data/lib/activerecord-postgis-array/active_record/schema_dumper.rb +157 -0
- data/lib/activerecord-postgis-array/arel.rb +3 -0
- data/lib/activerecord-postgis-array/arel/nodes.rb +2 -0
- data/lib/activerecord-postgis-array/arel/nodes/array_nodes.rb +9 -0
- data/lib/activerecord-postgis-array/arel/nodes/contained_within.rb +20 -0
- data/lib/activerecord-postgis-array/arel/predications.rb +25 -0
- data/lib/activerecord-postgis-array/arel/visitors.rb +2 -0
- data/lib/activerecord-postgis-array/arel/visitors/to_sql.rb +15 -0
- data/lib/activerecord-postgis-array/arel/visitors/visitor.rb +38 -0
- data/lib/activerecord-postgis-array/version.rb +3 -0
- data/spec/arel/arel_spec.rb +30 -0
- data/spec/arel/array_spec.rb +77 -0
- data/spec/columns/array_spec.rb +120 -0
- data/spec/dummy/.gitignore +15 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/images/rails.png +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/person.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml.example +14 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +38 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/db/migrate/20120501163758_create_people.rb +12 -0
- data/spec/dummy/db/schema.rb +25 -0
- data/spec/dummy/db/seeds.rb +7 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/tasks/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/index.html +241 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/factories/people.rb +7 -0
- data/spec/dummy/test/fixtures/.gitkeep +0 -0
- data/spec/dummy/test/functional/.gitkeep +0 -0
- data/spec/dummy/test/integration/.gitkeep +0 -0
- data/spec/dummy/test/performance/browsing_test.rb +12 -0
- data/spec/dummy/test/test_helper.rb +13 -0
- data/spec/dummy/test/unit/.gitkeep +0 -0
- data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/dummy/vendor/plugins/.gitkeep +0 -0
- data/spec/migrations/active_record_migration_spec.rb +29 -0
- data/spec/migrations/array_spec.rb +136 -0
- data/spec/migrations/index_spec.rb +67 -0
- data/spec/models/array_spec.rb +285 -0
- data/spec/queries/array_queries_spec.rb +72 -0
- data/spec/queries/sanity_spec.rb +16 -0
- data/spec/schema_dumper/array_spec.rb +17 -0
- data/spec/schema_dumper/extension_spec.rb +14 -0
- data/spec/schema_dumper/index_spec.rb +46 -0
- data/spec/spec_helper.rb +29 -0
- metadata +318 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'active_record/relation/predicate_builder'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class PredicateBuilder # :nodoc:
|
5
|
+
def self.build_from_hash(engine, attributes, default_table, allow_table_name = true)
|
6
|
+
predicates = attributes.map do |column, value|
|
7
|
+
table = default_table
|
8
|
+
|
9
|
+
if allow_table_name && value.is_a?(Hash)
|
10
|
+
table = Arel::Table.new(column, engine)
|
11
|
+
|
12
|
+
if value.empty?
|
13
|
+
'1 = 2'
|
14
|
+
else
|
15
|
+
build_from_hash(engine, value, table, false)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
column = column.to_s
|
19
|
+
|
20
|
+
if allow_table_name && column.include?('.')
|
21
|
+
table_name, column = column.split('.', 2)
|
22
|
+
table = Arel::Table.new(table_name, engine)
|
23
|
+
end
|
24
|
+
|
25
|
+
attribute = table[column.to_sym]
|
26
|
+
|
27
|
+
case value
|
28
|
+
when ActiveRecord::Relation
|
29
|
+
value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
|
30
|
+
attribute.in(value.arel.ast)
|
31
|
+
when Array, ActiveRecord::Associations::CollectionProxy
|
32
|
+
column_definition = engine.columns.find { |col| col.name == column }
|
33
|
+
|
34
|
+
if column_definition.respond_to?(:array) && column_definition.array
|
35
|
+
attribute.eq(value)
|
36
|
+
else
|
37
|
+
values = value.to_a.map {|x| x.is_a?(ActiveRecord::Base) ? x.id : x}
|
38
|
+
ranges, values = values.partition {|v| v.is_a?(Range) || v.is_a?(Arel::Relation)}
|
39
|
+
|
40
|
+
array_predicates = ranges.map {|range| attribute.in(range)}
|
41
|
+
|
42
|
+
if values.include?(nil)
|
43
|
+
values = values.compact
|
44
|
+
if values.empty?
|
45
|
+
array_predicates << attribute.eq(nil)
|
46
|
+
else
|
47
|
+
array_predicates << attribute.in(values.compact).or(attribute.eq(nil))
|
48
|
+
end
|
49
|
+
else
|
50
|
+
array_predicates << attribute.in(values)
|
51
|
+
end
|
52
|
+
|
53
|
+
array_predicates.inject {|composite, predicate| composite.or(predicate)}
|
54
|
+
end
|
55
|
+
when Range, Arel::Relation
|
56
|
+
attribute.in(value)
|
57
|
+
when ActiveRecord::Base
|
58
|
+
attribute.eq(value.id)
|
59
|
+
when Class
|
60
|
+
# FIXME: I think we need to deprecate this behavior
|
61
|
+
attribute.eq(value.name)
|
62
|
+
else
|
63
|
+
attribute.eq(value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
predicates.flatten
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'active_record/relation/query_methods'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module QueryMethods
|
5
|
+
class WhereChain
|
6
|
+
def initialize(scope)
|
7
|
+
@scope = scope
|
8
|
+
end
|
9
|
+
|
10
|
+
def overlap(opts)
|
11
|
+
opts.each do |key, value|
|
12
|
+
@scope = @scope.where(arel_table[key].overlap(value))
|
13
|
+
end
|
14
|
+
@scope
|
15
|
+
end
|
16
|
+
|
17
|
+
def contained_within(opts)
|
18
|
+
opts.each do |key, value|
|
19
|
+
@scope = @scope.where(arel_table[key].contained_within(value))
|
20
|
+
end
|
21
|
+
|
22
|
+
@scope
|
23
|
+
end
|
24
|
+
|
25
|
+
def contained_within_or_equals(opts)
|
26
|
+
opts.each do |key, value|
|
27
|
+
@scope = @scope.where(arel_table[key].contained_within_or_equals(value))
|
28
|
+
end
|
29
|
+
|
30
|
+
@scope
|
31
|
+
end
|
32
|
+
|
33
|
+
def contains(opts)
|
34
|
+
opts.each do |key, value|
|
35
|
+
@scope = @scope.where(arel_table[key].contains(value))
|
36
|
+
end
|
37
|
+
|
38
|
+
@scope
|
39
|
+
end
|
40
|
+
|
41
|
+
def contains_or_equals(opts)
|
42
|
+
opts.each do |key, value|
|
43
|
+
@scope = @scope.where(arel_table[key].contains_or_equals(value))
|
44
|
+
end
|
45
|
+
|
46
|
+
@scope
|
47
|
+
end
|
48
|
+
|
49
|
+
def any(opts)
|
50
|
+
equality_to_function('ANY', opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
def all(opts)
|
54
|
+
equality_to_function('ALL', opts)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def arel_table
|
60
|
+
@arel_table ||= @scope.engine.arel_table
|
61
|
+
end
|
62
|
+
|
63
|
+
def equality_to_function(function_name, opts)
|
64
|
+
opts.each do |key, value|
|
65
|
+
any_function = Arel::Nodes::NamedFunction.new(function_name, [arel_table[key]])
|
66
|
+
predicate = Arel::Nodes::Equality.new(value, any_function)
|
67
|
+
@scope = @scope.where(predicate)
|
68
|
+
end
|
69
|
+
|
70
|
+
@scope
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def where_with_chaining(*opts, &block)
|
75
|
+
if opts.empty? && !block_given?
|
76
|
+
WhereChain.new(self)
|
77
|
+
else
|
78
|
+
where_without_chaining(*opts, &block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
alias_method_chain :where, :chaining
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'active_record/sanitization'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Sanitization
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def sanitize_sql_hash_for_assignment(attrs)
|
9
|
+
attrs.map do |attr, value|
|
10
|
+
"#{connection.quote_column_name(attr)} = #{quote_bound_value(value, attr)}"
|
11
|
+
end.join(', ')
|
12
|
+
end
|
13
|
+
|
14
|
+
def quote_bound_value(value, column = nil, c = connection)
|
15
|
+
if column.present? && column != c
|
16
|
+
record_column = self.columns.select {|col| col.name == column}.first
|
17
|
+
c.quote(value, record_column)
|
18
|
+
elsif value.respond_to?(:map) && !value.acts_like?(:string)
|
19
|
+
if value.respond_to?(:empty?) && value.empty?
|
20
|
+
c.quote(nil)
|
21
|
+
else
|
22
|
+
value.map { |v| c.quote(v) }.join(',')
|
23
|
+
end
|
24
|
+
else
|
25
|
+
c.quote(value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'active_record/schema_dumper'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class SchemaDumper
|
5
|
+
VALID_COLUMN_SPEC_KEYS = [:name, :limit, :precision, :scale, :default, :null, :array]
|
6
|
+
def self.valid_column_spec_keys
|
7
|
+
VALID_COLUMN_SPEC_KEYS
|
8
|
+
end
|
9
|
+
|
10
|
+
def dump(stream)
|
11
|
+
header(stream)
|
12
|
+
# added
|
13
|
+
extensions(stream) if @connection.respond_to?(:supports_extensions?) &&
|
14
|
+
@connection.supports_extensions?
|
15
|
+
# /added
|
16
|
+
tables(stream)
|
17
|
+
trailer(stream)
|
18
|
+
stream
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def extensions(stream)
|
24
|
+
exts = @connection.extensions
|
25
|
+
|
26
|
+
unless exts.empty?
|
27
|
+
stream.puts exts.map { |name| " add_extension \"#{name}\""}.join("\n") + "\n\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def table(table, stream)
|
32
|
+
columns = @connection.columns(table)
|
33
|
+
begin
|
34
|
+
tbl = StringIO.new
|
35
|
+
|
36
|
+
# first dump primary key column
|
37
|
+
if @connection.respond_to?(:pk_and_sequence_for)
|
38
|
+
pk, _ = @connection.pk_and_sequence_for(table)
|
39
|
+
elsif @connection.respond_to?(:primary_key)
|
40
|
+
pk = @connection.primary_key(table)
|
41
|
+
end
|
42
|
+
|
43
|
+
tbl.print " create_table #{table.inspect}"
|
44
|
+
if columns.detect { |c| c.name == pk }
|
45
|
+
if pk != 'id'
|
46
|
+
tbl.print %Q(, :primary_key => "#{pk}")
|
47
|
+
end
|
48
|
+
else
|
49
|
+
tbl.print ", :id => false"
|
50
|
+
end
|
51
|
+
tbl.print ", :force => true"
|
52
|
+
tbl.puts " do |t|"
|
53
|
+
|
54
|
+
# then dump all non-primary key columns
|
55
|
+
column_specs = columns.map do |column|
|
56
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
|
57
|
+
next if column.name == pk
|
58
|
+
spec = column_spec(column)
|
59
|
+
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
|
60
|
+
spec
|
61
|
+
end.compact
|
62
|
+
|
63
|
+
# find all migration keys used in this table
|
64
|
+
keys = self.class.valid_column_spec_keys & column_specs.map{ |k| k.keys }.flatten
|
65
|
+
|
66
|
+
# figure out the lengths for each column based on above keys
|
67
|
+
lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
68
|
+
|
69
|
+
# the string we're going to sprintf our values against, with standardized column widths
|
70
|
+
format_string = lengths.map{ |len| "%-#{len}s" }
|
71
|
+
|
72
|
+
# find the max length for the 'type' column, which is special
|
73
|
+
type_length = column_specs.map{ |column| column[:type].length }.max
|
74
|
+
|
75
|
+
# add column type definition to our format string
|
76
|
+
format_string.unshift " t.%-#{type_length}s "
|
77
|
+
|
78
|
+
format_string *= ''
|
79
|
+
|
80
|
+
column_specs.each do |colspec|
|
81
|
+
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
82
|
+
values.unshift colspec[:type]
|
83
|
+
tbl.print((format_string % values).gsub(/,\s*$/, ''))
|
84
|
+
tbl.puts
|
85
|
+
end
|
86
|
+
|
87
|
+
tbl.puts " end"
|
88
|
+
tbl.puts
|
89
|
+
|
90
|
+
indexes(table, tbl)
|
91
|
+
|
92
|
+
tbl.rewind
|
93
|
+
stream.print tbl.read
|
94
|
+
rescue => e
|
95
|
+
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
96
|
+
stream.puts "# #{e.message}"
|
97
|
+
stream.puts
|
98
|
+
end
|
99
|
+
|
100
|
+
stream
|
101
|
+
end
|
102
|
+
|
103
|
+
#mostly rails 3.2 code
|
104
|
+
def indexes(table, stream)
|
105
|
+
if (indexes = @connection.indexes(table)).any?
|
106
|
+
add_index_statements = indexes.map do |index|
|
107
|
+
statement_parts = [
|
108
|
+
('add_index ' + index.table.inspect),
|
109
|
+
index.columns.inspect,
|
110
|
+
(':name => ' + index.name.inspect),
|
111
|
+
]
|
112
|
+
statement_parts << ':unique => true' if index.unique
|
113
|
+
|
114
|
+
index_lengths = (index.lengths || []).compact
|
115
|
+
statement_parts << (':length => ' + Hash[index.columns.zip(index.lengths)].inspect) unless index_lengths.empty?
|
116
|
+
|
117
|
+
index_orders = (index.orders || {})
|
118
|
+
statement_parts << (':order => ' + index.orders.inspect) unless index_orders.empty?
|
119
|
+
|
120
|
+
# changed from rails 2.3
|
121
|
+
statement_parts << (':where => ' + index.where.inspect) if index.where
|
122
|
+
statement_parts << (':using => ' + index.using.inspect) if index.using
|
123
|
+
statement_parts << (':index_opclass => ' + index.index_opclass.inspect) if index.index_opclass.present?
|
124
|
+
# /changed
|
125
|
+
|
126
|
+
' ' + statement_parts.join(', ')
|
127
|
+
end
|
128
|
+
|
129
|
+
stream.puts add_index_statements.sort.join("\n")
|
130
|
+
stream.puts
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
#mostly rails 3.2 code (pulled out of table method)
|
135
|
+
def column_spec(column)
|
136
|
+
spec = {}
|
137
|
+
spec[:name] = column.name.inspect
|
138
|
+
|
139
|
+
# AR has an optimization which handles zero-scale decimals as integers. This
|
140
|
+
# code ensures that the dumper still dumps the column as a decimal.
|
141
|
+
spec[:type] = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
|
142
|
+
'decimal'
|
143
|
+
else
|
144
|
+
column.type.to_s
|
145
|
+
end
|
146
|
+
spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
|
147
|
+
spec[:precision] = column.precision.inspect if column.precision
|
148
|
+
spec[:scale] = column.scale.inspect if column.scale
|
149
|
+
spec[:null] = 'false' unless column.null
|
150
|
+
spec[:default] = default_string(column.default) if column.has_default?
|
151
|
+
# changed from rails 3.2 code
|
152
|
+
spec[:array] = 'true' if column.respond_to?(:array) && column.array
|
153
|
+
# /changed
|
154
|
+
spec
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'arel/nodes/binary'
|
2
|
+
module Arel
|
3
|
+
module Nodes
|
4
|
+
class ContainedWithin < Arel::Nodes::Binary
|
5
|
+
def operator; :<< end
|
6
|
+
end
|
7
|
+
|
8
|
+
class ContainedWithinEquals < Arel::Nodes::Binary
|
9
|
+
def operator; '<<='.to_sym end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Contains < Arel::Nodes::Binary
|
13
|
+
def operator; :>> end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ContainsEquals < Arel::Nodes::Binary
|
17
|
+
def operator; '>>='.to_sym end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'arel/predications'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
module Predications
|
5
|
+
def contained_within(other)
|
6
|
+
Nodes::ContainedWithin.new self, other
|
7
|
+
end
|
8
|
+
|
9
|
+
def contained_within_or_equals(other)
|
10
|
+
Nodes::ContainedWithinEquals.new self, other
|
11
|
+
end
|
12
|
+
|
13
|
+
def contains(other)
|
14
|
+
Nodes::Contains.new self, other
|
15
|
+
end
|
16
|
+
|
17
|
+
def contains_or_equals(other)
|
18
|
+
Nodes::ContainsEquals.new self, other
|
19
|
+
end
|
20
|
+
|
21
|
+
def overlap(other)
|
22
|
+
Nodes::Overlap.new self, other
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'arel/visitors/to_sql'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
module Visitors
|
5
|
+
class ToSql
|
6
|
+
def visit_Array o
|
7
|
+
if last_column.respond_to?(:array) && last_column.array
|
8
|
+
quoted o
|
9
|
+
else
|
10
|
+
o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'arel/visitors/visitor'
|
2
|
+
module Arel
|
3
|
+
module Visitors
|
4
|
+
class Visitor
|
5
|
+
# We are adding our visitors to the main visitor for the time being until the right spot is found to monkey patch
|
6
|
+
private
|
7
|
+
def visit_Arel_Nodes_ContainedWithin o
|
8
|
+
"#{visit o.left} << #{visit o.right}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_Arel_Nodes_ContainedWithinEquals o
|
12
|
+
"#{visit o.left} <<= #{visit o.right}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def visit_Arel_Nodes_Contains o
|
16
|
+
left_column = o.left.relation.engine.columns.find { |col| col.name == o.left.name.to_s }
|
17
|
+
|
18
|
+
if left_column && left_column.respond_to?(:array) && left_column.array
|
19
|
+
"#{visit o.left} @> #{visit o.right}"
|
20
|
+
else
|
21
|
+
"#{visit o.left} >> #{visit o.right}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def visit_Arel_Nodes_ContainsEquals o
|
26
|
+
"#{visit o.left} >>= #{visit o.right}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def visit_Arel_Nodes_Overlap o
|
30
|
+
"#{visit o.left} && #{visit o.right}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def visit_IPAddr value
|
34
|
+
"'#{value.to_s}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}'"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|