ar_pg_array 0.9.13 → 0.10.1
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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/ar_pg_array.rb +1 -6
- data/lib/ar_pg_array/allways_save.rb +12 -28
- data/lib/ar_pg_array/parser.rb +160 -0
- data/lib/ar_pg_array/querying.rb +15 -27
- data/lib/ar_pg_array/schema.rb +77 -110
- data/lib/ar_pg_array/schema_cacheable.rb +5 -10
- data/spec/fixtures/item.rb +1 -0
- data/spec/fixtures/schema.rb +24 -18
- data/spec/fixtures/unrelated.rb +21 -0
- data/spec/fixtures/unrelateds.yml +3 -0
- data/spec/pg_array_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- metadata +19 -8
- data/lib/ar_pg_array/querying_arel.rb +0 -234
- data/lib/ar_pg_array/schema_arel.rb +0 -105
- data/lib/ar_pg_array/schema_cachable.rb +0 -11
data/Rakefile
CHANGED
@@ -30,7 +30,7 @@ begin
|
|
30
30
|
gemspec.email = "funny.falcon@gmail.com"
|
31
31
|
gemspec.homepage = "http://github.com/funny-falcon/activerecord-postgresql-arrays"
|
32
32
|
gemspec.authors = ["Sokolov Yura aka funny_falcon"]
|
33
|
-
gemspec.add_dependency('activerecord', '>= 2.3.5')
|
33
|
+
gemspec.add_dependency('activerecord', '>= 2.3.5', '<3.0')
|
34
34
|
gemspec.rubyforge_project = 'ar-pg-array'
|
35
35
|
end
|
36
36
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.10.0
|
data/lib/ar_pg_array.rb
CHANGED
@@ -7,9 +7,4 @@ require 'ar_pg_array/schema_cacheable'
|
|
7
7
|
require 'ar_pg_array/querying'
|
8
8
|
require 'ar_pg_array/allways_save'
|
9
9
|
require 'ar_pg_array/references_by'
|
10
|
-
|
11
|
-
require 'ar_pg_array/schema_arel'
|
12
|
-
require 'ar_pg_array/querying_arel'
|
13
|
-
else
|
14
|
-
require 'ar_pg_array/schema_fix_will_change'
|
15
|
-
end
|
10
|
+
require 'ar_pg_array/schema_fix_will_change'
|
@@ -1,37 +1,21 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
2
|
+
module CheckArrayBeforeUpdate
|
3
|
+
def mark_arrays_for_update
|
4
|
+
@attributes_cache.each do |name, value|
|
5
|
+
attribute_will_change!(name) if Array === value && _read_attribute(name) != value
|
7
6
|
end
|
8
7
|
end
|
9
|
-
|
10
|
-
module CheckArrayBeforeUpdate
|
11
|
-
def self.included(base)
|
12
|
-
base.alias_method_chain :update, :check_array
|
13
|
-
base.send(:alias_method, :_read_attribute, :read_attribute)
|
14
|
-
end
|
8
|
+
end
|
15
9
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
module CheckArrayBeforeUpdate
|
11
|
+
def self.included(base)
|
12
|
+
base.alias_method_chain :update, :check_array
|
13
|
+
base.send(:alias_method, :_read_attribute, :read_attribute)
|
20
14
|
end
|
21
|
-
else
|
22
|
-
module CheckArrayBeforeUpdate
|
23
|
-
include ActiveSupport::Concern
|
24
15
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def update(*)
|
32
|
-
mark_arrays_for_update
|
33
|
-
super
|
34
|
-
end
|
16
|
+
def update_with_check_array
|
17
|
+
mark_arrays_for_update
|
18
|
+
update_without_check_array
|
35
19
|
end
|
36
20
|
end
|
37
21
|
Base.__send__ :include, CheckArrayBeforeUpdate
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module PgArrayParser
|
4
|
+
CURLY_BRACKETS = '{}'.freeze
|
5
|
+
SQUARE_BRACKETS = '[]'.freeze
|
6
|
+
NULL = 'NULL'.freeze
|
7
|
+
NIL = 'nil'.freeze
|
8
|
+
ESCAPE_HASH={'\\'.freeze=>'\\\\'.freeze, '"'.freeze=>'\\"'.freeze}
|
9
|
+
|
10
|
+
def parse_numeric_pgarray(text)
|
11
|
+
text = text.tr(CURLY_BRACKETS, SQUARE_BRACKETS)
|
12
|
+
text.downcase!
|
13
|
+
JSON.load(text)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_safe_pgarray(text, &block)
|
17
|
+
if text =~ /^\{([^\}]*)\}$/
|
18
|
+
$1.split(/,\s*/).map!{|v| v == NULL ? nil : yield(v)}
|
19
|
+
else
|
20
|
+
raise "Mailformed array" unless text =~ /^\{\s*/
|
21
|
+
ar, rest = _parse_safe_pgarray($')
|
22
|
+
ar
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def _parse_safe_pgarray(text, &block)
|
27
|
+
values = []
|
28
|
+
return values if text =~ /^\}\s*/
|
29
|
+
if text =~ /^\{\s*/
|
30
|
+
text = $'
|
31
|
+
while true
|
32
|
+
ar, rest = _parse_safe_pgarray(text, &block)
|
33
|
+
values << ar
|
34
|
+
if rest =~ /^\}\s*/
|
35
|
+
return values, $'
|
36
|
+
elsif rest =~ /^,\s*/
|
37
|
+
rest = $'
|
38
|
+
else
|
39
|
+
raise "Mailformed postgres array"
|
40
|
+
end
|
41
|
+
text = rest
|
42
|
+
end
|
43
|
+
else
|
44
|
+
while true
|
45
|
+
raise 'Mailformed Array' unless text =~ /^([^,\}]*)([,\}])\s*/
|
46
|
+
val, sep, rest = $1, $2, $'
|
47
|
+
values << (val == NULL ? nil : yield(val))
|
48
|
+
if sep == '}'
|
49
|
+
return values, rest
|
50
|
+
end
|
51
|
+
text = rest
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_pgarray(text, &block)
|
57
|
+
raise "Mailformed postgres array" unless text =~ /^\{\s*/
|
58
|
+
ar, rest = _parse_pgarray($', &block)
|
59
|
+
ar
|
60
|
+
end
|
61
|
+
|
62
|
+
def _parse_pgarray(text, &block)
|
63
|
+
values = []
|
64
|
+
return values if text =~ /^\}\s*/
|
65
|
+
if text =~ /^\{\s*/
|
66
|
+
text = $'
|
67
|
+
while true
|
68
|
+
ar, rest = _parse_pgarray(text, &block)
|
69
|
+
values << ar
|
70
|
+
if rest =~ /^\}\s*/
|
71
|
+
return values, $'
|
72
|
+
elsif rest =~ /^,\s*{\s*/
|
73
|
+
rest = $'
|
74
|
+
else
|
75
|
+
raise "Mailformed postgres array"
|
76
|
+
end
|
77
|
+
text = rest
|
78
|
+
end
|
79
|
+
else
|
80
|
+
while true
|
81
|
+
if text =~ /^"((?:\\.|[^"\\])*)"([,}])\s*/
|
82
|
+
val, sep, rest = $1, $2, $'
|
83
|
+
val.gsub!(/\\(.)/, '\1')
|
84
|
+
val = yield val
|
85
|
+
elsif text =~ /^([^,\}]*)([,}])\s*/
|
86
|
+
val, sep, rest = $1, $2, $'
|
87
|
+
val = val == NULL ? nil : yield(val)
|
88
|
+
else
|
89
|
+
raise "Mailformed postgres array"
|
90
|
+
end
|
91
|
+
values << val
|
92
|
+
if sep == '}'
|
93
|
+
return values, rest
|
94
|
+
end
|
95
|
+
text = rest
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def prepare_pg_integer_array(value)
|
101
|
+
val = value.map{|v| v.nil? ? nil : v.to_i}.inspect
|
102
|
+
val.gsub!(NIL, NULL)
|
103
|
+
val.tr!(SQUARE_BRACKETS, CURLY_BRACKETS)
|
104
|
+
val
|
105
|
+
end
|
106
|
+
|
107
|
+
def prepare_pg_float_array(value)
|
108
|
+
val = value.map{|v| v.nil? ? nil : v.to_f}.inspect
|
109
|
+
val.gsub!(NIL, NULL)
|
110
|
+
val.tr!(SQUARE_BRACKETS, CURLY_BRACKETS)
|
111
|
+
val
|
112
|
+
end
|
113
|
+
|
114
|
+
def prepare_pg_safe_array(value)
|
115
|
+
value = value.map{|val|
|
116
|
+
case val
|
117
|
+
when Array
|
118
|
+
prepare_pg_safe_array(val)
|
119
|
+
when nil
|
120
|
+
NULL
|
121
|
+
else
|
122
|
+
val.to_s
|
123
|
+
end
|
124
|
+
}.join(',')
|
125
|
+
"{#{value}}"
|
126
|
+
end
|
127
|
+
|
128
|
+
def prepare_pg_text_array(value)
|
129
|
+
value = value.map{|val|
|
130
|
+
case val
|
131
|
+
when Array
|
132
|
+
prepare_pg_text_array(val)
|
133
|
+
when nil
|
134
|
+
NULL
|
135
|
+
else
|
136
|
+
"\"#{val.to_s.gsub(/\\|"/){|s| ESCAPE_HASH[s]}}\""
|
137
|
+
end
|
138
|
+
}.join(',')
|
139
|
+
"{#{value}}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def prepare_pg_string_array(value, &block)
|
143
|
+
value = value.map{|val|
|
144
|
+
case val
|
145
|
+
when Array
|
146
|
+
prepare_pg_string_array(val, &block)
|
147
|
+
when nil
|
148
|
+
NULL
|
149
|
+
else
|
150
|
+
val = yield val
|
151
|
+
if val =~ /^'(.*)'$/m
|
152
|
+
"\"#{ $1.gsub(/\\|"/){|s| ESCAPE_HASH[s]} }\""
|
153
|
+
else
|
154
|
+
val
|
155
|
+
end
|
156
|
+
end
|
157
|
+
}.join(',')
|
158
|
+
"{#{value}}"
|
159
|
+
end
|
160
|
+
end
|
data/lib/ar_pg_array/querying.rb
CHANGED
@@ -1,37 +1,25 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
class Base
|
3
3
|
class << self
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
else "#{quoted_column_name} = ?"
|
12
|
-
end
|
13
|
-
else
|
14
|
-
attribute_condition_without_postgresql_arrays(quoted_column_name, argument)
|
4
|
+
def attribute_condition_with_postgresql_arrays(quoted_column_name, argument)
|
5
|
+
if ::PGArrays::PgArray === argument
|
6
|
+
case argument
|
7
|
+
when ::PGArrays::PgAny then "#{quoted_column_name} && ?"
|
8
|
+
when ::PGArrays::PgAll then "#{quoted_column_name} @> ?"
|
9
|
+
when ::PGArrays::PgIncludes then "#{quoted_column_name} <@ ?"
|
10
|
+
else "#{quoted_column_name} = ?"
|
15
11
|
end
|
12
|
+
else
|
13
|
+
attribute_condition_without_postgresql_arrays(quoted_column_name, argument)
|
16
14
|
end
|
17
|
-
alias_method_chain :attribute_condition, :postgresql_arrays
|
18
15
|
end
|
16
|
+
alias_method_chain :attribute_condition, :postgresql_arrays
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
quote_bound_value_without_postgresql_arrays(value)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
else
|
29
|
-
def quote_bound_value_with_postgresql_arrays(value, c = connection)
|
30
|
-
if ::PGArrays::PgArray === value
|
31
|
-
c.quote_array_by_base_type(value, value.base_type)
|
32
|
-
else
|
33
|
-
quote_bound_value_without_postgresql_arrays(value, c)
|
34
|
-
end
|
18
|
+
def quote_bound_value_with_postgresql_arrays(value)
|
19
|
+
if ::PGArrays::PgArray === value
|
20
|
+
connection.quote_array_by_base_type(value, value.base_type)
|
21
|
+
else
|
22
|
+
quote_bound_value_without_postgresql_arrays(value)
|
35
23
|
end
|
36
24
|
end
|
37
25
|
alias_method_chain :quote_bound_value, :postgresql_arrays
|
data/lib/ar_pg_array/schema.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
+
require 'ar_pg_array/parser'
|
1
2
|
module ActiveRecord
|
2
3
|
module ConnectionAdapters
|
3
4
|
class PostgreSQLColumn < Column #:nodoc:
|
5
|
+
include PgArrayParser
|
6
|
+
extend PgArrayParser
|
7
|
+
|
4
8
|
BASE_TYPE_COLUMNS = Hash.new{|h, base_type|
|
5
9
|
base_column= new(nil, nil, base_type.to_s, true)
|
6
10
|
h[base_type] = h[base_column.type]= base_column
|
7
11
|
}
|
8
12
|
attr_reader :base_column
|
9
|
-
|
13
|
+
|
10
14
|
def initialize(name, default, sql_type = nil, null = true)
|
11
15
|
if sql_type =~ /^(.+)\[\]$/
|
12
16
|
@base_sql_type = $1
|
@@ -14,7 +18,7 @@ module ActiveRecord
|
|
14
18
|
end
|
15
19
|
super(name, self.class.extract_value_from_default(default), sql_type, null)
|
16
20
|
end
|
17
|
-
|
21
|
+
|
18
22
|
def simplified_type_with_postgresql_arrays(field_type)
|
19
23
|
if field_type=~/^(.+)\[\]$/
|
20
24
|
:"#{simplified_type_without_postgresql_arrays($1)}_array"
|
@@ -36,17 +40,17 @@ module ActiveRecord
|
|
36
40
|
return nil if value.nil?
|
37
41
|
case type
|
38
42
|
when :integer_array, :float_array
|
39
|
-
|
43
|
+
string_to_num_array(value)
|
40
44
|
when :decimal_array, :date_array, :boolean_array
|
41
45
|
safe_string_to_array(value)
|
42
46
|
when :timestamp_array, :time_array, :datetime_array, :binary_array
|
43
47
|
string_to_array(value)
|
44
48
|
when :text_array, :string_array
|
45
|
-
|
49
|
+
string_to_text_array(value)
|
46
50
|
else super
|
47
51
|
end
|
48
52
|
end
|
49
|
-
|
53
|
+
|
50
54
|
def type_cast_code(var_name)
|
51
55
|
case type
|
52
56
|
when :integer_array, :float_array
|
@@ -60,70 +64,79 @@ module ActiveRecord
|
|
60
64
|
else super
|
61
65
|
end
|
62
66
|
end
|
63
|
-
|
64
|
-
def
|
67
|
+
|
68
|
+
def default
|
69
|
+
res = super
|
70
|
+
Array === res ? res.dup : res
|
71
|
+
end
|
72
|
+
|
73
|
+
def self._string_to_array(string)
|
65
74
|
return string unless string.is_a? String
|
66
75
|
return nil if string.empty?
|
67
|
-
|
68
|
-
|
76
|
+
|
77
|
+
yield
|
69
78
|
end
|
70
|
-
|
71
|
-
def
|
79
|
+
|
80
|
+
def _string_to_array(string)
|
72
81
|
return string unless string.is_a? String
|
73
82
|
return nil if string.empty?
|
74
|
-
|
75
|
-
|
83
|
+
|
84
|
+
yield
|
85
|
+
end
|
86
|
+
|
87
|
+
def safe_string_to_array(string)
|
88
|
+
_string_to_array(string) do
|
89
|
+
parse_safe_pgarray(string){|v| @base_column.type_cast(v)}
|
90
|
+
end
|
76
91
|
end
|
77
|
-
|
92
|
+
|
78
93
|
def self.safe_string_to_array(string, sql_type)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
94
|
+
_string_to_array(string) do
|
95
|
+
base_column = BASE_TYPE_COLUMNS[sql_type]
|
96
|
+
parse_safe_pgarray(string){|v| base_column.type_cast(v)}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def string_to_array(string)
|
101
|
+
_string_to_array(string) do
|
102
|
+
parse_pgarray(string){|v| @base_column.type_cast(v)}
|
103
|
+
end
|
84
104
|
end
|
85
|
-
|
105
|
+
|
86
106
|
def self.string_to_array(string, sql_type)
|
87
|
-
|
88
|
-
|
107
|
+
_string_to_array(string) do
|
108
|
+
base_column = BASE_TYPE_COLUMNS[sql_type]
|
109
|
+
parse_pgarray(string){|v| base_column.type_cast(v)}
|
110
|
+
end
|
111
|
+
end
|
89
112
|
|
90
|
-
|
91
|
-
|
113
|
+
def string_to_num_array(string)
|
114
|
+
_string_to_array(string) do
|
115
|
+
parse_numeric_pgarray(string)
|
116
|
+
end
|
92
117
|
end
|
93
|
-
|
118
|
+
|
94
119
|
def self.string_to_num_array(string)
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
120
|
+
_string_to_array(string) do
|
121
|
+
parse_numeric_pgarray(string)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def string_to_text_array(string)
|
126
|
+
_string_to_array(string) do
|
127
|
+
parse_pgarray(string){|v| v}
|
128
|
+
end
|
99
129
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
return value unless value.is_a? String
|
105
|
-
return nil if value.empty?
|
106
|
-
|
107
|
-
values = value[1...-1].split(',')
|
108
|
-
partial = false
|
109
|
-
values.inject([]) do |res, s|
|
110
|
-
if partial
|
111
|
-
s = res.pop << ",#{s}"
|
112
|
-
elsif s=~ SARRAY_PARTIAL
|
113
|
-
partial = true
|
114
|
-
end
|
115
|
-
if s =~ SARRAY_QUOTED
|
116
|
-
s = $1.gsub(/\\(.)/,'\1')
|
117
|
-
partial = false
|
118
|
-
elsif s == 'NULL'
|
119
|
-
s = nil
|
120
|
-
end
|
121
|
-
res << s
|
130
|
+
|
131
|
+
def self.string_to_text_array(string)
|
132
|
+
_string_to_array(string) do
|
133
|
+
parse_pgarray(string){|v| v}
|
122
134
|
end
|
123
135
|
end
|
124
136
|
end
|
125
|
-
|
137
|
+
|
126
138
|
class PostgreSQLAdapter #:nodoc:
|
139
|
+
include PgArrayParser
|
127
140
|
def quote_with_postgresql_arrays(value, column = nil)
|
128
141
|
if Array === value && column && "#{column.type}" =~ /^(.+)_array$/
|
129
142
|
quote_array_by_base_type(value, $1, column)
|
@@ -132,29 +145,19 @@ module ActiveRecord
|
|
132
145
|
end
|
133
146
|
end
|
134
147
|
alias_method_chain :quote, :postgresql_arrays
|
135
|
-
|
148
|
+
|
136
149
|
def quote_array_by_base_type(value, base_type, column = nil)
|
137
150
|
case base_type.to_sym
|
138
|
-
when :integer, :float, :decimal, :boolean, :date, :safe,
|
139
|
-
|
140
|
-
|
151
|
+
when :integer, :float, :decimal, :boolean, :date, :safe, :datetime, :timestamp, :time
|
152
|
+
"'#{ prepare_array_for_arel_by_base_type(value, base_type) }'"
|
153
|
+
when :string, :text, :other
|
154
|
+
pa = prepare_array_for_arel_by_base_type(value, base_type)
|
155
|
+
"'#{ quote_string( pa ) }'"
|
141
156
|
else
|
142
157
|
"'#{ prepare_pg_string_array(value, base_type, column) }'"
|
143
158
|
end
|
144
159
|
end
|
145
160
|
|
146
|
-
def quote_array_for_arel_by_base_type( value, base_type )
|
147
|
-
case base_type.to_sym
|
148
|
-
when :integer, :float, :decimal, :boolean, :date, :safe, :datetime, :timestamp, :time
|
149
|
-
"'#{ prepare_array_for_arel_by_base_type(value, base_type) }'"
|
150
|
-
when :string, :text, :other
|
151
|
-
pa = prepare_array_for_arel_by_base_type(value, base_type)
|
152
|
-
"'#{ quote_string( pa ) }'"
|
153
|
-
else
|
154
|
-
raise "Unsupported array base type #{base_type} for arel"
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
161
|
def prepare_array_for_arel_by_base_type(value, base_type)
|
159
162
|
case base_type.to_sym
|
160
163
|
when :integer
|
@@ -166,57 +169,21 @@ module ActiveRecord
|
|
166
169
|
when :datetime, :timestamp, :time
|
167
170
|
prepare_pg_string_array(value, base_type)
|
168
171
|
when :decimal, :boolean, :date, :safe
|
169
|
-
|
172
|
+
prepare_pg_safe_array(value)
|
170
173
|
else
|
171
174
|
raise "Unsupported array base type #{base_type} for arel"
|
172
175
|
end
|
173
176
|
end
|
174
|
-
|
175
|
-
def prepare_pg_integer_array(value)
|
176
|
-
"{#{ value.map{|v| v.nil? ? 'NULL' : v.to_i}.join(',')}}"
|
177
|
-
end
|
178
|
-
|
179
|
-
def prepare_pg_float_array(value)
|
180
|
-
"{#{ value.map{|v| v.nil? ? 'NULL' : v.to_f}.join(',')}}"
|
181
|
-
end
|
182
|
-
|
183
|
-
def prepare_pg_string_safe_array(value)
|
184
|
-
"{#{ value.map{|v| v.nil? ? 'NULL' : v.to_s}.join(',')}}"
|
185
|
-
end
|
186
|
-
|
187
|
-
ESCAPE_HASH={'\\'=>'\\\\', '"'=>'\\"'}
|
177
|
+
|
188
178
|
def prepare_pg_string_array(value, base_type, column=nil)
|
189
179
|
base_column= if column
|
190
180
|
column.base_column
|
191
181
|
else
|
192
182
|
PostgreSQLColumn::BASE_TYPE_COLUMNS[base_type.to_sym]
|
193
183
|
end
|
194
|
-
value
|
195
|
-
unless v.nil?
|
196
|
-
v = quote_without_postgresql_arrays(v, base_column)
|
197
|
-
if v=~/^'(.+)'$/m then
|
198
|
-
"\"#{$1.gsub(/\\|"/){|s| ESCAPE_HASH[s]}}\""
|
199
|
-
else
|
200
|
-
v
|
201
|
-
end
|
202
|
-
else
|
203
|
-
'NULL'
|
204
|
-
end
|
205
|
-
end
|
206
|
-
"{#{ value.join(',')}}"
|
184
|
+
super(value){|v| quote_without_postgresql_arrays(v, base_column)}
|
207
185
|
end
|
208
186
|
|
209
|
-
class CNULL; def inspect; 'NULL'; end; alias to_s inspect end
|
210
|
-
NULL = CNULL.new
|
211
|
-
|
212
|
-
TESCAPE_HASH={'\\'=>'\\\\', '"'=>'\\"'}
|
213
|
-
def prepare_pg_text_array(value)
|
214
|
-
value = value.map{|v|
|
215
|
-
v ? "\"#{v.to_s.gsub(/\\|"/){|s| TESCAPE_HASH[s]}}\"" : NULL
|
216
|
-
}.join(',')
|
217
|
-
"{#{value}}"
|
218
|
-
end
|
219
|
-
|
220
187
|
NATIVE_DATABASE_TYPES.keys.each do |key|
|
221
188
|
unless key==:primary_key
|
222
189
|
base = NATIVE_DATABASE_TYPES[key].dup
|
@@ -242,7 +209,7 @@ module ActiveRecord
|
|
242
209
|
EOV
|
243
210
|
end
|
244
211
|
end
|
245
|
-
|
212
|
+
|
246
213
|
def add_column_with_postgresql_arrays( table, column, type, options = {} )
|
247
214
|
if type.to_s =~ /^(.+)_array$/ && options[:default].is_a?(Array)
|
248
215
|
options = options.merge(:default => prepare_array_for_arel_by_base_type(options[:default], $1))
|
@@ -250,7 +217,7 @@ module ActiveRecord
|
|
250
217
|
add_column_without_postgresql_arrays( table, column, type, options )
|
251
218
|
end
|
252
219
|
alias_method_chain :add_column, :postgresql_arrays
|
253
|
-
|
220
|
+
|
254
221
|
def type_to_sql_with_postgresql_arrays(type, limit = nil, precision = nil, scale = nil)
|
255
222
|
if type.to_s =~ /^(.+)_array$/
|
256
223
|
type_to_sql_without_postgresql_arrays($1.to_sym, limit, precision, scale)+'[]'
|
@@ -258,7 +225,7 @@ module ActiveRecord
|
|
258
225
|
type_to_sql_without_postgresql_arrays(type, limit, precision, scale)
|
259
226
|
end
|
260
227
|
end
|
261
|
-
|
228
|
+
|
262
229
|
alias_method_chain :type_to_sql, :postgresql_arrays
|
263
230
|
end
|
264
231
|
end
|
@@ -1,11 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
7
|
-
if ActiveRecord::VERSION::MAJOR < 3
|
8
|
-
adjust_cached_types.call(ActiveRecord::AttributeMethods::ATTRIBUTE_TYPES_CACHED_BY_DEFAULT)
|
9
|
-
else
|
10
|
-
adjust_cached_types.call(ActiveRecord::AttributeMethods::Read::ATTRIBUTE_TYPES_CACHED_BY_DEFAULT)
|
1
|
+
atcbd = ActiveRecord::AttributeMethods::ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
|
2
|
+
|
3
|
+
atcbd << /_array$/
|
4
|
+
def atcbd.include?(val)
|
5
|
+
any?{|type| type === val}
|
11
6
|
end
|
data/spec/fixtures/item.rb
CHANGED
data/spec/fixtures/schema.rb
CHANGED
@@ -1,22 +1,28 @@
|
|
1
1
|
ActiveRecord::Schema.define do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
2
|
+
create_table "tags", :force => true do |t|
|
3
|
+
t.string :name
|
4
|
+
t.timestamps
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table "items", :force => true do |t|
|
8
|
+
t.string :value
|
9
|
+
t.integer_array :tag_ids, :default => [1, 2]
|
10
|
+
t.string_array :tag_names, :default => %w{as so}
|
11
|
+
t.text :for_yaml
|
12
|
+
end
|
13
|
+
|
13
14
|
create_table "bulks", :force => true do |t|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
t.string :value, :default => "'"
|
16
|
+
t.integer_array :ints, :default => [1, 2]
|
17
|
+
t.string_array :strings, :default => %w{as so}
|
18
|
+
t.timestamp_array :times, :default => %w{2010-01-01 2010-02-01}
|
19
|
+
t.float_array :floats, :default => [1.0, 1.2]
|
20
|
+
t.decimal_array :decimals, :default => [1.0, 1.2]
|
20
21
|
t.text_array :texts, :default => [nil, 'Text', 'NULL', 'Text with nil', 'Text with , nil, !"\\', 'nil']
|
21
|
-
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table "unrelateds", :force => true do |t|
|
25
|
+
t.text :for_yaml
|
26
|
+
t.text :for_custom_serialize
|
27
|
+
end
|
22
28
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'base64'
|
2
|
+
class Unrelated < ActiveRecord::Base
|
3
|
+
class MySerializer
|
4
|
+
def initialize(val)
|
5
|
+
@val = val
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.dump(obj)
|
9
|
+
Base64.encode64(Marshal.dump(obj))
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.load(str)
|
13
|
+
if str
|
14
|
+
Marshal.load(Base64.decode64(str))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
serialize :for_yaml
|
20
|
+
serialize :for_custom_serialize, MySerializer
|
21
|
+
end
|
data/spec/pg_array_spec.rb
CHANGED
@@ -83,6 +83,13 @@ describe "PgArray" do
|
|
83
83
|
map_times(bulk.times).should ==
|
84
84
|
map_times(parse_times(%w{2010-01-01 2010-02-01}))
|
85
85
|
end
|
86
|
+
|
87
|
+
it "should not alter defaults" do
|
88
|
+
bulk = Bulk.new
|
89
|
+
bulk.strings.push :foo
|
90
|
+
bulk = Bulk.new
|
91
|
+
bulk.strings.should == %w{as so}
|
92
|
+
end
|
86
93
|
|
87
94
|
it "should save changes" do
|
88
95
|
bulk = Bulk.find(3)
|
@@ -152,6 +159,39 @@ describe "PgArray" do
|
|
152
159
|
bulk.ints.should == new
|
153
160
|
end
|
154
161
|
|
162
|
+
it 'should not break yaml serialization on model with array' do
|
163
|
+
item = Item.find(1)
|
164
|
+
item.for_yaml = {:a => :b}
|
165
|
+
item.save.should be_true
|
166
|
+
copy = Item.find(1)
|
167
|
+
copy.for_yaml.should == {:a => :b}
|
168
|
+
copy.for_yaml = ['a', 'b']
|
169
|
+
copy.save.should be_true
|
170
|
+
copy = Item.find(1)
|
171
|
+
copy.for_yaml.should == ['a', 'b']
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should not break yaml serialization on unrelated model' do
|
175
|
+
item = Unrelated.find(1)
|
176
|
+
item.for_yaml.should == {'a' => 'b'}
|
177
|
+
item.for_yaml = {:a => :b}
|
178
|
+
item.save.should be_true
|
179
|
+
copy = Unrelated.find(1)
|
180
|
+
copy.for_yaml.should == {:a => :b}
|
181
|
+
copy.for_yaml = ['a', 'b']
|
182
|
+
copy.save.should be_true
|
183
|
+
copy = Unrelated.find(1)
|
184
|
+
copy.for_yaml.should == ['a', 'b']
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should not break custom serialization on model with array' do
|
188
|
+
obj = Unrelated::MySerializer.new(%w{hello world})
|
189
|
+
model = Unrelated.create!(:for_custom_serialize => obj)
|
190
|
+
model.for_custom_serialize.to_yaml.should == obj.to_yaml
|
191
|
+
model2 = Unrelated.find(model.id)
|
192
|
+
model2.for_custom_serialize.to_yaml.should == obj.to_yaml
|
193
|
+
end
|
194
|
+
|
155
195
|
def map_times(times)
|
156
196
|
times.map{|t| t.strftime("%F %T")}
|
157
197
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar_pg_array
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,19 +9,30 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
+
- - <
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
19
22
|
- - ! '>='
|
20
23
|
- !ruby/object:Gem::Version
|
21
24
|
version: 2.3.5
|
22
25
|
type: :runtime
|
23
26
|
prerelease: false
|
24
|
-
version_requirements:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - <
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.0'
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 2.3.5
|
25
36
|
description: ar_pg_array includes support of PostgreSQL's int[], float[], text[],
|
26
37
|
timestamptz[] etc. into ActiveRecord. You could define migrations for array columns,
|
27
38
|
query on array columns.
|
@@ -38,12 +49,10 @@ files:
|
|
38
49
|
- init.rb
|
39
50
|
- lib/ar_pg_array.rb
|
40
51
|
- lib/ar_pg_array/allways_save.rb
|
52
|
+
- lib/ar_pg_array/parser.rb
|
41
53
|
- lib/ar_pg_array/querying.rb
|
42
|
-
- lib/ar_pg_array/querying_arel.rb
|
43
54
|
- lib/ar_pg_array/references_by.rb
|
44
55
|
- lib/ar_pg_array/schema.rb
|
45
|
-
- lib/ar_pg_array/schema_arel.rb
|
46
|
-
- lib/ar_pg_array/schema_cachable.rb
|
47
56
|
- lib/ar_pg_array/schema_cacheable.rb
|
48
57
|
- lib/ar_pg_array/schema_fix_will_change.rb
|
49
58
|
- spec/fixtures/bulk.rb
|
@@ -53,6 +62,8 @@ files:
|
|
53
62
|
- spec/fixtures/schema.rb
|
54
63
|
- spec/fixtures/tag.rb
|
55
64
|
- spec/fixtures/tags.yml
|
65
|
+
- spec/fixtures/unrelated.rb
|
66
|
+
- spec/fixtures/unrelateds.yml
|
56
67
|
- spec/pg_array_spec.rb
|
57
68
|
- spec/spec.opts
|
58
69
|
- spec/spec_helper.rb
|
@@ -76,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
87
|
version: '0'
|
77
88
|
requirements: []
|
78
89
|
rubyforge_project: ar-pg-array
|
79
|
-
rubygems_version: 1.8.
|
90
|
+
rubygems_version: 1.8.24
|
80
91
|
signing_key:
|
81
92
|
specification_version: 3
|
82
93
|
summary: Use power of PostgreSQL Arrays in ActiveRecord
|
@@ -1,234 +0,0 @@
|
|
1
|
-
if Arel::VERSION >= '2.0'
|
2
|
-
module Arel
|
3
|
-
module Nodes
|
4
|
-
class ArrayAny < Arel::Nodes::Binary
|
5
|
-
end
|
6
|
-
|
7
|
-
class ArrayAll < Arel::Nodes::Binary
|
8
|
-
end
|
9
|
-
|
10
|
-
class ArrayIncluded < Arel::Nodes::Binary
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module Predications
|
15
|
-
def ar_any other
|
16
|
-
Nodes::ArrayAny.new self, other
|
17
|
-
end
|
18
|
-
|
19
|
-
def ar_all other
|
20
|
-
Nodes::ArrayAll.new self, other
|
21
|
-
end
|
22
|
-
|
23
|
-
def ar_included other
|
24
|
-
Nodes::ArrayIncluded.new self, other
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
module Visitors
|
29
|
-
class PostgreSQL
|
30
|
-
def visit_Arel_Nodes_ArrayAny o
|
31
|
-
"#{visit o.left} && #{visit o.right}"
|
32
|
-
end
|
33
|
-
|
34
|
-
def visit_Arel_Nodes_ArrayAll o
|
35
|
-
"#{visit o.left} @> #{visit o.right}"
|
36
|
-
end
|
37
|
-
|
38
|
-
def visit_Arel_Nodes_ArrayIncluded o
|
39
|
-
"#{visit o.left} <@ #{visit o.right}"
|
40
|
-
end
|
41
|
-
|
42
|
-
def visit_PGArrays_PgArray o
|
43
|
-
@connection.quote_array_for_arel_by_base_type(o, o.base_type)
|
44
|
-
end
|
45
|
-
|
46
|
-
alias :visit_PGArrays_PgAny :visit_PGArrays_PgArray
|
47
|
-
alias :visit_PGArrays_PgAll :visit_PGArrays_PgArray
|
48
|
-
alias :visit_PGArrays_PgIncluded :visit_PGArrays_PgArray
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
else
|
53
|
-
module Arel
|
54
|
-
module Predicates
|
55
|
-
class ArrayAny < Binary
|
56
|
-
def eval(row)
|
57
|
-
!(operand1.eval(row) & operand2.eval(row)).empty?
|
58
|
-
end
|
59
|
-
|
60
|
-
def predicate_sql
|
61
|
-
"&&"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
class ArrayAll < Binary
|
66
|
-
def eval(row)
|
67
|
-
(operand2.eval(row) - operand1.eval(row)).empty?
|
68
|
-
end
|
69
|
-
|
70
|
-
def predicate_sql
|
71
|
-
"@>"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class ArrayIncluded < Binary
|
76
|
-
def eval(row)
|
77
|
-
(operand1.eval(row) - operand2.eval(row)).empty?
|
78
|
-
end
|
79
|
-
|
80
|
-
def predicate_sql
|
81
|
-
"<@"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
class Attribute
|
87
|
-
methods = lambda do
|
88
|
-
def ar_any(other)
|
89
|
-
Predicates::ArrayAny.new(self, other)
|
90
|
-
end
|
91
|
-
|
92
|
-
def ar_all(other)
|
93
|
-
Predicates::ArrayAll.new(self, other)
|
94
|
-
end
|
95
|
-
|
96
|
-
def ar_included(other)
|
97
|
-
Predicates::ArrayIncluded.new(self, other)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
if defined? PREDICATES
|
101
|
-
PREDICATES.concat [:ar_any, :ar_all, :ar_included]
|
102
|
-
class_exec &methods
|
103
|
-
else
|
104
|
-
Predications.class_exec &methods
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
module PGArrays
|
110
|
-
class PgArray
|
111
|
-
def to_sql( formatter = nil )
|
112
|
-
formatter.engine.connection.quote_array_for_arel_by_base_type(self, base_type)
|
113
|
-
end
|
114
|
-
|
115
|
-
def to_a
|
116
|
-
self
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
if ActiveRecord::VERSION::STRING < '3.1'
|
123
|
-
module ActiveRecord
|
124
|
-
class PredicateBuilder
|
125
|
-
def build_from_hash(attributes, default_table)
|
126
|
-
predicates = attributes.map do |column, value|
|
127
|
-
table = default_table
|
128
|
-
|
129
|
-
if value.is_a?(Hash)
|
130
|
-
table = Arel::Table.new(column, :engine => @engine)
|
131
|
-
build_from_hash(value, table)
|
132
|
-
else
|
133
|
-
column = column.to_s
|
134
|
-
|
135
|
-
if column.include?('.')
|
136
|
-
table_name, column = column.split('.', 2)
|
137
|
-
table = Arel::Table.new(table_name, :engine => @engine)
|
138
|
-
end
|
139
|
-
|
140
|
-
attribute = table[column] || Arel::Attribute.new(table, column)
|
141
|
-
|
142
|
-
case value
|
143
|
-
when PGArrays::PgAny
|
144
|
-
attribute.ar_any(value)
|
145
|
-
when PGArrays::PgAll
|
146
|
-
attribute.ar_all(value)
|
147
|
-
when PGArrays::PgIncludes
|
148
|
-
attribute.ar_included(value)
|
149
|
-
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation
|
150
|
-
values = value.to_a.map { |x|
|
151
|
-
x.is_a?(ActiveRecord::Base) ? x.id : x
|
152
|
-
}
|
153
|
-
attribute.in(values)
|
154
|
-
when Range, Arel::Relation
|
155
|
-
attribute.in(value)
|
156
|
-
when ActiveRecord::Base
|
157
|
-
attribute.eq(value.id)
|
158
|
-
when Class
|
159
|
-
# FIXME: I think we need to deprecate this behavior
|
160
|
-
attribute.eq(value.name)
|
161
|
-
else
|
162
|
-
attribute.eq(value)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
predicates.flatten
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
else
|
172
|
-
module ActiveRecord
|
173
|
-
class PredicateBuilder
|
174
|
-
def self.build_from_hash(engine, attributes, default_table)
|
175
|
-
predicates = attributes.map do |column, value|
|
176
|
-
table = default_table
|
177
|
-
|
178
|
-
if value.is_a?(Hash)
|
179
|
-
table = Arel::Table.new(column, engine)
|
180
|
-
build_from_hash(engine, value, table)
|
181
|
-
else
|
182
|
-
column = column.to_s
|
183
|
-
|
184
|
-
if column.include?('.')
|
185
|
-
table_name, column = column.split('.', 2)
|
186
|
-
table = Arel::Table.new(table_name, engine)
|
187
|
-
end
|
188
|
-
|
189
|
-
attribute = table[column.to_sym]
|
190
|
-
|
191
|
-
case value
|
192
|
-
when PGArrays::PgAny
|
193
|
-
attribute.ar_any(value)
|
194
|
-
when PGArrays::PgAll
|
195
|
-
attribute.ar_all(value)
|
196
|
-
when PGArrays::PgIncludes
|
197
|
-
attribute.ar_included(value)
|
198
|
-
when ActiveRecord::Relation
|
199
|
-
value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
|
200
|
-
attribute.in(value.arel.ast)
|
201
|
-
when Array, ActiveRecord::Associations::CollectionProxy
|
202
|
-
values = value.to_a.map { |x|
|
203
|
-
x.is_a?(ActiveRecord::Base) ? x.id : x
|
204
|
-
}
|
205
|
-
|
206
|
-
if values.include?(nil)
|
207
|
-
values = values.compact
|
208
|
-
if values.empty?
|
209
|
-
attribute.eq nil
|
210
|
-
else
|
211
|
-
attribute.in(values.compact).or attribute.eq(nil)
|
212
|
-
end
|
213
|
-
else
|
214
|
-
attribute.in(values)
|
215
|
-
end
|
216
|
-
|
217
|
-
when Range, Arel::Relation
|
218
|
-
attribute.in(value)
|
219
|
-
when ActiveRecord::Base
|
220
|
-
attribute.eq(value.id)
|
221
|
-
when Class
|
222
|
-
# FIXME: I think we need to deprecate this behavior
|
223
|
-
attribute.eq(value.name)
|
224
|
-
else
|
225
|
-
attribute.eq(value)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
predicates.flatten
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
3
|
-
class PostgreSQLAdapter
|
4
|
-
def prepare_for_arel( value, column )
|
5
|
-
return value unless value
|
6
|
-
if Array === value && "#{column.type}" =~ /^(.+)_array$/
|
7
|
-
prepare_array_for_arel_by_base_type(value, $1)
|
8
|
-
else
|
9
|
-
super
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module ActiveRecord
|
17
|
-
# I hope ticket 5047 will be included in Rails 3 reliz
|
18
|
-
unless ConnectionAdapters::AbstractAdapter.method_defined? :prepare_for_arel
|
19
|
-
module ConnectionAdapters
|
20
|
-
class AbstractAdapter
|
21
|
-
def prepare_for_arel( value, column )
|
22
|
-
if value && (value.is_a?(Hash) || value.is_a?(Array))
|
23
|
-
value.to_yaml
|
24
|
-
else
|
25
|
-
value
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class Base
|
32
|
-
private
|
33
|
-
# Returns a copy of the attributes hash where all the values have been safely quoted for use in
|
34
|
-
# an Arel insert/update method.
|
35
|
-
def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
|
36
|
-
attrs = {}
|
37
|
-
attribute_names.each do |name|
|
38
|
-
if (column = column_for_attribute(name)) && (include_primary_key || !column.primary)
|
39
|
-
|
40
|
-
if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name))
|
41
|
-
value = read_attribute(name)
|
42
|
-
|
43
|
-
if value && self.class.serialized_attributes.has_key?(name) && (value.acts_like?(:date) || value.acts_like?(:time))
|
44
|
-
value = value.to_yaml
|
45
|
-
else
|
46
|
-
value = self.class.connection.prepare_for_arel(value, column)
|
47
|
-
end
|
48
|
-
attrs[self.class.arel_table[name]] = value
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
attrs
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
module Arel
|
59
|
-
module Attributes
|
60
|
-
%w{Integer Float Decimal Boolean String Time}.each do |basetype|
|
61
|
-
module_eval <<-"END"
|
62
|
-
class #{basetype}Array < Attribute
|
63
|
-
end
|
64
|
-
END
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
if Arel::VERSION < '2.0'
|
69
|
-
module Sql
|
70
|
-
module Attributes
|
71
|
-
class << self
|
72
|
-
def for_with_postgresql_arrays(column)
|
73
|
-
if column.type.to_s =~ /^(.+)_array$/
|
74
|
-
('Arel::Sql::Attributes::' + for_without_postgresql_arrays(column.base_column).name.split('::').last + 'Array').constantize
|
75
|
-
else
|
76
|
-
for_without_postgresql_arrays(column)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
alias_method_chain :for, :postgresql_arrays
|
80
|
-
end
|
81
|
-
|
82
|
-
%w{Integer Float Decimal Boolean String Time}.each do |basetype|
|
83
|
-
module_eval <<-"END"
|
84
|
-
class #{basetype}Array < Arel::Attributes::#{basetype}Array
|
85
|
-
include Attributes
|
86
|
-
end
|
87
|
-
END
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
else
|
92
|
-
module Attributes
|
93
|
-
class << self
|
94
|
-
def for_with_postgresql_arrays(column)
|
95
|
-
if column.type.to_s =~ /^(.+)_array$/
|
96
|
-
('Arel::Attributes::' + for_without_postgresql_arrays(column.base_column).name.split('::').last + 'Array').constantize
|
97
|
-
else
|
98
|
-
for_without_postgresql_arrays(column)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
alias_method_chain :for, :postgresql_arrays
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
adjust_cached_types = lambda do |atcbd|
|
2
|
-
atcbd << /_array$/
|
3
|
-
def atcbd.include?(val)
|
4
|
-
any?{|type| type === val}
|
5
|
-
end
|
6
|
-
end
|
7
|
-
if ActiveRecord::VERSION::MAJOR < 3
|
8
|
-
adjust_cached_types.call(ActiveRecord::AttributeMethods::ATTRIBUTE_TYPES_CACHED_BY_DEFAULT)
|
9
|
-
else
|
10
|
-
adjust_cached_types.call(ActiveRecord::AttributeMethods::Read::ATTRIBUTE_TYPES_CACHED_BY_DEFAULT)
|
11
|
-
end
|