sunstone 2.0.4 → 5.0.0.beta3
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.
- checksums.yaml +4 -4
- data/ext/active_record/associations/collection_association.rb +46 -0
- data/ext/active_record/attribute_methods.rb +137 -0
- data/ext/active_record/calculations.rb +5 -1
- data/ext/active_record/finder_methods.rb +2 -3
- data/ext/active_record/persistence.rb +21 -0
- data/ext/active_record/query_methods.rb +9 -2
- data/ext/active_record/relation.rb +3 -3
- data/ext/active_record/statement_cache.rb +1 -1
- data/ext/active_support/core_ext/object/to_query.rb +14 -1
- data/ext/arel/attributes/relation.rb +30 -0
- data/lib/active_record/connection_adapters/sunstone/column.rb +11 -9
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +1 -6
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +21 -4
- data/lib/active_record/connection_adapters/sunstone/type/array.rb +52 -10
- data/lib/active_record/connection_adapters/sunstone/type/date_time.rb +1 -1
- data/lib/active_record/connection_adapters/sunstone/type/ewkb.rb +1 -1
- data/lib/active_record/connection_adapters/sunstone/type_metadata.rb +15 -0
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +21 -5
- data/lib/arel/collectors/sunstone.rb +29 -9
- data/lib/arel/visitors/sunstone.rb +285 -56
- data/lib/sunstone.rb +6 -0
- data/lib/sunstone/connection.rb +7 -8
- data/lib/sunstone/exception.rb +0 -5
- data/lib/sunstone/version.rb +1 -1
- data/sunstone.gemspec +5 -4
- metadata +32 -13
@@ -3,28 +3,70 @@ module ActiveRecord
|
|
3
3
|
module Sunstone
|
4
4
|
module Type
|
5
5
|
class Array < ActiveRecord::Type::Value
|
6
|
-
include ActiveRecord::Type::Mutable
|
6
|
+
include ActiveRecord::Type::Helpers::Mutable
|
7
7
|
|
8
8
|
attr_reader :subtype
|
9
|
-
delegate :type, to: :subtype
|
9
|
+
delegate :type, :user_input_in_time_zone, :limit, to: :subtype
|
10
10
|
|
11
11
|
def initialize(subtype)
|
12
12
|
@subtype = subtype
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def deserialize(value)
|
16
|
+
if value.is_a?(String)
|
17
|
+
type_cast_array(JSON.parse(value), :deserialize)
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
def cast(value)
|
24
|
+
if value.is_a?(::String)
|
25
|
+
value = JSON.parse(value)
|
26
|
+
end
|
27
|
+
type_cast_array(value, :cast)
|
28
|
+
end
|
29
|
+
|
30
|
+
def serialize(value)
|
31
|
+
if value.is_a?(::Array)
|
32
|
+
type_cast_array(value, :serialize)
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(other)
|
39
|
+
other.is_a?(Array) && subtype == other.subtype
|
40
|
+
end
|
41
|
+
|
42
|
+
# def type_cast_for_schema(value)
|
43
|
+
# return super unless value.is_a?(::Array)
|
44
|
+
# "[" + value.map { |v| subtype.type_cast_for_schema(v) }.join(", ") + "]"
|
45
|
+
# end
|
46
|
+
|
47
|
+
def map(value, &block)
|
48
|
+
value.map(&block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# def cast_value(string)
|
52
|
+
# return string unless string.is_a?(::String)
|
53
|
+
# return if string.empty?
|
54
|
+
#
|
55
|
+
# JSON.parse(string)
|
56
|
+
# end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def type_cast_array(value, method)
|
61
|
+
if value.is_a?(::Array)
|
62
|
+
value.map { |item| type_cast_array(item, method) }
|
63
|
+
else
|
64
|
+
@subtype.public_send(method, value)
|
65
|
+
end
|
24
66
|
end
|
25
67
|
|
26
68
|
end
|
27
69
|
end
|
28
70
|
end
|
29
71
|
end
|
30
|
-
end
|
72
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class SunstoneSQLTypeMetadata < DelegateClass(SqlTypeMetadata)
|
4
|
+
attr_reader :array
|
5
|
+
|
6
|
+
def initialize(type_metadata, options = {})
|
7
|
+
super(type_metadata)
|
8
|
+
@type_metadata = type_metadata
|
9
|
+
@primary_key = (options['primary_key'] == true)
|
10
|
+
@array = !!options['array']
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -34,7 +34,7 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Forward only valid config params to PGconn.connect.
|
37
|
-
conn_params.
|
37
|
+
conn_params.slice!(*VALID_SUNSTONE_CONN_PARAMS)
|
38
38
|
|
39
39
|
# The postgres drivers don't allow the creation of an unconnected PGconn object,
|
40
40
|
# so just pass a nil connection object for the time being.
|
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
# * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
|
55
55
|
# <encoding></tt> call on the connection.
|
56
56
|
class SunstoneAPIAdapter < AbstractAdapter
|
57
|
-
ADAPTER_NAME = 'Sunstone'
|
57
|
+
ADAPTER_NAME = 'Sunstone'.freeze
|
58
58
|
|
59
59
|
NATIVE_DATABASE_TYPES = {
|
60
60
|
string: { name: "string" },
|
@@ -63,8 +63,12 @@ module ActiveRecord
|
|
63
63
|
boolean: { name: "boolean" }
|
64
64
|
}
|
65
65
|
|
66
|
-
include
|
66
|
+
# include PostgreSQL::Quoting
|
67
|
+
# include PostgreSQL::ReferentialIntegrity
|
67
68
|
include Sunstone::SchemaStatements
|
69
|
+
include Sunstone::DatabaseStatements
|
70
|
+
# include PostgreSQL::ColumnDumper
|
71
|
+
# include Savepoints
|
68
72
|
|
69
73
|
# Returns 'SunstoneAPI' as adapter name for identification purposes.
|
70
74
|
def adapter_name
|
@@ -80,7 +84,7 @@ module ActiveRecord
|
|
80
84
|
|
81
85
|
# Initializes and connects a SunstoneAPI adapter.
|
82
86
|
def initialize(connection, logger, connection_parameters, config)
|
83
|
-
super(connection, logger)
|
87
|
+
super(connection, logger, config)
|
84
88
|
|
85
89
|
@visitor = Arel::Visitors::Sunstone.new
|
86
90
|
@connection_parameters, @config = connection_parameters, config
|
@@ -149,6 +153,15 @@ module ActiveRecord
|
|
149
153
|
def server_config
|
150
154
|
Wankel.parse(@connection.get("/configuration").body)
|
151
155
|
end
|
156
|
+
|
157
|
+
def lookup_cast_type_from_column(column) # :nodoc:
|
158
|
+
if column.array
|
159
|
+
Sunstone::Type::Array.new(type_map.lookup(column.sql_type))
|
160
|
+
else
|
161
|
+
type_map.lookup(column.sql_type)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
152
165
|
|
153
166
|
private
|
154
167
|
|
@@ -158,7 +171,7 @@ module ActiveRecord
|
|
158
171
|
m.register_type 'integer', Type::Integer.new
|
159
172
|
m.register_type 'decimal', Type::Decimal.new
|
160
173
|
m.register_type 'datetime', Sunstone::Type::DateTime.new
|
161
|
-
m.register_type '
|
174
|
+
m.register_type 'json', Type::Internal::AbstractJson.new
|
162
175
|
m.register_type 'ewkb', Sunstone::Type::EWKB.new
|
163
176
|
end
|
164
177
|
|
@@ -186,6 +199,9 @@ module ActiveRecord
|
|
186
199
|
def create_table_definition(name, temporary, options, as = nil) # :nodoc:
|
187
200
|
SunstoneAPI::TableDefinition.new native_database_types, name, temporary, options, as
|
188
201
|
end
|
202
|
+
|
203
|
+
ActiveRecord::Type.add_modifier({ array: true }, Sunstone::Type::Array, adapter: :sunstone)
|
204
|
+
# ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
189
205
|
end
|
190
206
|
end
|
191
207
|
end
|
@@ -4,21 +4,41 @@ module Arel
|
|
4
4
|
|
5
5
|
attr_accessor :request_type, :table, :where, :limit, :offset, :order, :operation, :columns, :updates, :eager_loads, :id
|
6
6
|
|
7
|
+
def cast_attribute(v)
|
8
|
+
if (v.is_a?(ActiveRecord::Attribute))
|
9
|
+
v.value_for_database
|
10
|
+
else
|
11
|
+
v
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
7
15
|
def substitute_binds hash, bvs
|
8
16
|
if hash.is_a?(Array)
|
9
|
-
hash.map
|
10
|
-
|
17
|
+
hash.map do |v|
|
18
|
+
if v.is_a?(Arel::Nodes::BindParam)
|
19
|
+
cast_attribute(bvs.last.is_a?(Array) ? bvs.shift.last : bvs.shift)
|
20
|
+
elsif v.is_a?(Hash) || v.is_a?(Array)
|
21
|
+
substitute_binds(v, bvs)
|
22
|
+
else
|
23
|
+
v
|
24
|
+
end
|
25
|
+
end
|
26
|
+
elsif hash.is_a?(Hash)
|
11
27
|
newhash = {}
|
12
28
|
hash.each do |k, v|
|
13
|
-
if Arel::Nodes::BindParam
|
14
|
-
newhash[k] = (bvs.last.is_a?(Array) ? bvs.shift.last : bvs.shift)
|
29
|
+
if v.is_a?(Arel::Nodes::BindParam)
|
30
|
+
newhash[k] = cast_attribute(bvs.last.is_a?(Array) ? bvs.shift.last : bvs.shift)
|
15
31
|
elsif v.is_a?(Hash)
|
16
32
|
newhash[k] = substitute_binds(v, bvs)
|
33
|
+
elsif v.is_a?(Array)
|
34
|
+
newhash[k] = substitute_binds(v, bvs)
|
17
35
|
else
|
18
36
|
newhash[k] = v
|
19
37
|
end
|
20
38
|
end
|
21
39
|
newhash
|
40
|
+
else
|
41
|
+
cast_attribute(bvs.last.is_a?(Array) ? bvs.shift.last : bvs.shift)
|
22
42
|
end
|
23
43
|
end
|
24
44
|
|
@@ -55,9 +75,9 @@ module Arel
|
|
55
75
|
get_params[:include] = eager_loads.clone
|
56
76
|
end
|
57
77
|
|
58
|
-
get_params[:limit] = limit if limit
|
59
|
-
get_params[:offset] = offset if offset
|
60
|
-
get_params[:order] = order if order
|
78
|
+
get_params[:limit] = substitute_binds(limit, bvs) if limit
|
79
|
+
get_params[:offset] = substitute_binds(offset, bvs) if offset
|
80
|
+
get_params[:order] = substitute_binds(order, bvs) if order
|
61
81
|
|
62
82
|
case operation
|
63
83
|
when :count
|
@@ -69,9 +89,9 @@ module Arel
|
|
69
89
|
path += "/#{get_params[:where]['id']}"
|
70
90
|
get_params.delete(:where)
|
71
91
|
end
|
72
|
-
|
92
|
+
|
73
93
|
if get_params.size > 0
|
74
|
-
path += '?' + get_params
|
94
|
+
path += '?m=' + URI.escape(CGI.escape(MessagePack.pack(get_params)))
|
75
95
|
end
|
76
96
|
|
77
97
|
request = request_type.new(path)
|
@@ -18,8 +18,12 @@ module Arel
|
|
18
18
|
accept(node, Arel::Collectors::SQLString.new, &block).value
|
19
19
|
end
|
20
20
|
|
21
|
+
def preparable
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
21
25
|
private
|
22
|
-
|
26
|
+
|
23
27
|
def visit_Arel_Nodes_SelectStatement o, collector
|
24
28
|
collector = o.cores.inject(collector) { |c,x|
|
25
29
|
visit_Arel_Nodes_SelectCore(x, c)
|
@@ -64,17 +68,76 @@ module Arel
|
|
64
68
|
collector
|
65
69
|
end
|
66
70
|
|
71
|
+
def visit_Arel_Nodes_Overlaps o, collector
|
72
|
+
{ visit(o.left, collector) => {overlaps: o.left.type_cast_for_database(o.right) }}
|
73
|
+
end
|
74
|
+
|
67
75
|
def visit_Arel_Nodes_InsertStatement o, collector
|
68
76
|
collector.request_type = Net::HTTP::Post
|
69
77
|
collector.table = o.relation.name
|
70
78
|
collector.operation = :insert
|
71
79
|
|
72
80
|
if o.values
|
73
|
-
|
81
|
+
keys = o.values.right.map { |x| visit(x, collector) }
|
82
|
+
values = o.values.left
|
83
|
+
collector.updates = {}
|
84
|
+
|
85
|
+
|
86
|
+
keys.each_with_index do |k, i|
|
87
|
+
if k.is_a?(Hash)
|
88
|
+
add_to_bottom_of_hash_or_array(k, values[i])
|
89
|
+
collector.updates.deep_merge!(k) { |key, v1, v2|
|
90
|
+
if (v1.is_a?(Array) && v2.is_a?(Array))
|
91
|
+
v2.each_with_index do |v, i|
|
92
|
+
if v1[i].nil?
|
93
|
+
v1[i] = v2[i]
|
94
|
+
else
|
95
|
+
v1[i].deep_merge!(v2[i]) unless v2[i].nil?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
v1
|
99
|
+
else
|
100
|
+
v2
|
101
|
+
end
|
102
|
+
}
|
103
|
+
else
|
104
|
+
collector.updates[k] = values[i]
|
105
|
+
end
|
106
|
+
end
|
74
107
|
end
|
75
108
|
|
76
109
|
collector
|
77
110
|
end
|
111
|
+
|
112
|
+
def find_bottom(hash)
|
113
|
+
if hash.is_a?(Hash)
|
114
|
+
if hash.values.first.is_a?(Array) || hash.values.first.is_a?(Hash)
|
115
|
+
find_bottom(hash.values.first)
|
116
|
+
else
|
117
|
+
hash
|
118
|
+
end
|
119
|
+
elsif hash.is_a?(Array)
|
120
|
+
fnn = hash.find { |i| !i.nil? }
|
121
|
+
if fnn.is_a?(Array) || fnn.is_a?(Hash)
|
122
|
+
fnn
|
123
|
+
else
|
124
|
+
hash
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def add_to_bottom_of_hash_or_array(hash, value)
|
130
|
+
hash = find_bottom(hash)
|
131
|
+
if hash.is_a?(Hash)
|
132
|
+
nkey = hash.keys.first
|
133
|
+
nvalue = hash.values.first
|
134
|
+
hash[nkey] = { nvalue => value }
|
135
|
+
elsif hash.is_a?(Array)
|
136
|
+
fnni = hash.find_index { |i| !i.nil? }
|
137
|
+
nvalue = hash[fnni]
|
138
|
+
hash[fnni] = { nvalue => value }
|
139
|
+
end
|
140
|
+
end
|
78
141
|
|
79
142
|
|
80
143
|
private
|
@@ -112,22 +175,50 @@ module Arel
|
|
112
175
|
collector.request_type = Net::HTTP::Patch
|
113
176
|
collector.table = o.relation.name
|
114
177
|
collector.operation = :update
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
else
|
122
|
-
collector.where = wheres
|
178
|
+
|
179
|
+
# collector.id = o.wheres.first.children.first.right
|
180
|
+
if !o.wheres.empty?
|
181
|
+
collector.where = o.wheres.map { |x| visit(x, collector) }.inject([]) { |c, w|
|
182
|
+
w.is_a?(Array) ? c += w : c << w
|
183
|
+
}
|
123
184
|
end
|
124
185
|
|
125
|
-
collector.
|
186
|
+
if collector.where.size != 1 && collector.where.first.size != 1 && !collector.where.first['id']
|
187
|
+
raise 'Upsupported'
|
188
|
+
end
|
189
|
+
if !collector.where.first['id']
|
190
|
+
collector.table = collector.where.first.keys.first
|
191
|
+
collector.where[0] = {'id' => collector.where.first.values.first.values.first}
|
192
|
+
end
|
126
193
|
|
127
194
|
if o.values
|
128
|
-
collector.updates =
|
195
|
+
collector.updates = {}
|
196
|
+
|
197
|
+
o.values.map { |x| visit(x, collector) }.each do |value|
|
198
|
+
value.each do |key, v|
|
199
|
+
if key.is_a?(Hash)
|
200
|
+
add_to_bottom_of_hash_or_array(key, v)
|
201
|
+
collector.updates.deep_merge!(key) { |key, v1, v2|
|
202
|
+
if (v1.is_a?(Array) && v2.is_a?(Array))
|
203
|
+
v2.each_with_index do |v, i|
|
204
|
+
if v1[i].nil?
|
205
|
+
v1[i] = v2[i]
|
206
|
+
else
|
207
|
+
v1[i].deep_merge!(v2[i]) unless v2[i].nil?
|
208
|
+
end
|
209
|
+
end
|
210
|
+
v1
|
211
|
+
else
|
212
|
+
v2
|
213
|
+
end
|
214
|
+
}
|
215
|
+
else
|
216
|
+
collector.updates[key] = v
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
129
220
|
end
|
130
|
-
|
221
|
+
|
131
222
|
collector
|
132
223
|
end
|
133
224
|
#
|
@@ -457,31 +548,63 @@ module Arel
|
|
457
548
|
# collector << " BETWEEN "
|
458
549
|
# visit o.right, collector
|
459
550
|
# end
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
551
|
+
|
552
|
+
def visit_Arel_Nodes_GreaterThanOrEqual o, collector
|
553
|
+
key = visit(o.left, collector)
|
554
|
+
value = { :gte => visit(o.right, collector) }
|
555
|
+
if key.is_a?(Hash)
|
556
|
+
if o.left.is_a?(Arel::Attributes::Cast)
|
557
|
+
merge_to_bottom_hash(key, value)
|
558
|
+
else
|
559
|
+
add_to_bottom_of_hash(key, value)
|
560
|
+
end
|
561
|
+
else
|
562
|
+
{ key => value }
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
467
566
|
def visit_Arel_Nodes_GreaterThan o, collector
|
468
|
-
|
469
|
-
|
470
|
-
|
567
|
+
key = visit(o.left, collector)
|
568
|
+
value = { :gt => visit(o.right, collector) }
|
569
|
+
if key.is_a?(Hash)
|
570
|
+
if o.left.is_a?(Arel::Attributes::Cast)
|
571
|
+
merge_to_bottom_hash(key, value)
|
572
|
+
else
|
573
|
+
add_to_bottom_of_hash(key, value)
|
574
|
+
end
|
575
|
+
else
|
576
|
+
{ key => value }
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
def visit_Arel_Nodes_LessThanOrEqual o, collector
|
581
|
+
key = visit(o.left, collector)
|
582
|
+
value = { :lte => visit(o.right, collector) }
|
583
|
+
if key.is_a?(Hash)
|
584
|
+
if o.left.is_a?(Arel::Attributes::Cast)
|
585
|
+
merge_to_bottom_hash(key, value)
|
586
|
+
else
|
587
|
+
add_to_bottom_of_hash(key, value)
|
588
|
+
end
|
589
|
+
else
|
590
|
+
{ key => value }
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
def visit_Arel_Nodes_LessThan o, collector
|
595
|
+
key = visit(o.left, collector)
|
596
|
+
value = { :lte => visit(o.right, collector) }
|
597
|
+
if key.is_a?(Hash)
|
598
|
+
if o.left.is_a?(Arel::Attributes::Cast)
|
599
|
+
merge_to_bottom_hash(key, value)
|
600
|
+
else
|
601
|
+
add_to_bottom_of_hash(key, value)
|
602
|
+
end
|
603
|
+
else
|
604
|
+
{ key => value }
|
605
|
+
end
|
471
606
|
end
|
472
607
|
|
473
|
-
# def visit_Arel_Nodes_LessThanOrEqual o, collector
|
474
|
-
# collector = visit o.left, collector
|
475
|
-
# collector << " <= "
|
476
|
-
# visit o.right, collector
|
477
|
-
# end
|
478
|
-
#
|
479
|
-
# def visit_Arel_Nodes_LessThan o, collector
|
480
|
-
# collector = visit o.left, collector
|
481
|
-
# collector << " < "
|
482
|
-
# visit o.right, collector
|
483
|
-
# end
|
484
|
-
#
|
485
608
|
# def visit_Arel_Nodes_Matches o, collector
|
486
609
|
# collector = visit o.left, collector
|
487
610
|
# collector << " LIKE "
|
@@ -561,15 +684,11 @@ module Arel
|
|
561
684
|
end
|
562
685
|
end
|
563
686
|
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
# collector << " IN ("
|
570
|
-
# visit(o.right, collector) << ")"
|
571
|
-
# end
|
572
|
-
# end
|
687
|
+
def visit_Arel_Nodes_In o, collector
|
688
|
+
{
|
689
|
+
visit(o.left, collector) => {in: visit(o.right, collector)}
|
690
|
+
}
|
691
|
+
end
|
573
692
|
#
|
574
693
|
# def visit_Arel_Nodes_NotIn o, collector
|
575
694
|
# if Array === o.right && o.right.empty?
|
@@ -587,10 +706,11 @@ module Arel
|
|
587
706
|
ors << o.children.inject({}) do |c, x|
|
588
707
|
value = visit(x, collector)
|
589
708
|
if value.is_a?(Hash)
|
590
|
-
c.deep_merge(value)
|
709
|
+
c.deep_merge!(value)
|
591
710
|
elsif value.is_a?(Array)
|
592
711
|
value.size == 1 ? ors << value : ors += value
|
593
712
|
end
|
713
|
+
c
|
594
714
|
end
|
595
715
|
ors
|
596
716
|
end
|
@@ -605,8 +725,10 @@ module Arel
|
|
605
725
|
end
|
606
726
|
|
607
727
|
def visit_Arel_Nodes_Assignment o, collector
|
608
|
-
case o.
|
609
|
-
when Arel::Nodes::UnqualifiedColumn
|
728
|
+
case o.left
|
729
|
+
when Arel::Nodes::UnqualifiedColumn
|
730
|
+
{ visit(o.left.expr, collector) => visit(o.right, collector) }
|
731
|
+
when Arel::Attributes::Attribute, Arel::Nodes::BindParam
|
610
732
|
{ visit(o.left, collector) => visit(o.right, collector) }
|
611
733
|
else
|
612
734
|
collector = visit o.left, collector
|
@@ -615,20 +737,91 @@ module Arel
|
|
615
737
|
end
|
616
738
|
end
|
617
739
|
|
740
|
+
def merge_to_bottom_hash(hash, value)
|
741
|
+
okey = hash
|
742
|
+
while okey.values.first.is_a?(Hash)
|
743
|
+
okey = okey.values.first
|
744
|
+
end
|
745
|
+
okey.merge!(value)
|
746
|
+
hash
|
747
|
+
end
|
748
|
+
|
749
|
+
def add_to_bottom_of_hash(hash, value)
|
750
|
+
okey = hash
|
751
|
+
while okey.is_a?(Hash) && (okey.values.first.is_a?(Hash) || okey.values.first.is_a?(Array))
|
752
|
+
if okey.is_a?(Array)
|
753
|
+
okey = okey.find { |i| !i.nil? }
|
754
|
+
else
|
755
|
+
okey = okey.values.first
|
756
|
+
end
|
757
|
+
end
|
758
|
+
nkey = okey.keys.first
|
759
|
+
nvalue = okey.values.first
|
760
|
+
okey[nkey] = { nvalue => value }
|
761
|
+
hash
|
762
|
+
end
|
763
|
+
|
618
764
|
def visit_Arel_Nodes_Equality o, collector
|
619
|
-
key = visit(o.left, collector)
|
765
|
+
key = visit(o.left, collector)
|
620
766
|
value = (o.right.nil? ? nil : visit(o.right, collector))
|
621
767
|
|
622
|
-
|
623
|
-
key
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
768
|
+
if key.is_a?(Hash)
|
769
|
+
add_to_bottom_of_hash(key, {eq: value})
|
770
|
+
else
|
771
|
+
key = key.to_s.split('.')
|
772
|
+
hash = { key.pop => value }
|
773
|
+
while key.size > 0
|
774
|
+
hash = { key.pop => hash }
|
775
|
+
end
|
776
|
+
hash
|
628
777
|
end
|
629
|
-
hash
|
630
778
|
end
|
779
|
+
|
780
|
+
def visit_Arel_Nodes_TSMatch(o, collector)
|
781
|
+
key = visit(o.left, collector)
|
782
|
+
value = { ts_match: (o.right.nil? ? nil : visit(o.right, collector)) }
|
631
783
|
|
784
|
+
if key.is_a?(Hash)
|
785
|
+
add_to_bottom_of_hash(key, value)
|
786
|
+
else
|
787
|
+
key = key.to_s.split('.')
|
788
|
+
hash = { key.pop => value }
|
789
|
+
while key.size > 0
|
790
|
+
hash = { key.pop => hash }
|
791
|
+
end
|
792
|
+
hash
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
def visit_Arel_Nodes_TSVector(o, collector)
|
797
|
+
visit(o.attribute, collector)
|
798
|
+
end
|
799
|
+
|
800
|
+
def visit_Arel_Nodes_TSQuery(o, collector)
|
801
|
+
if o.language
|
802
|
+
[visit(o.expression, collector), visit(o.language, collector)]
|
803
|
+
else
|
804
|
+
visit(o.expression, collector)
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
def visit_Arel_Nodes_HasKey o, collector
|
809
|
+
key = visit(o.left, collector)
|
810
|
+
value = {has_key: (o.right.nil? ? nil : o.right.to_s)}
|
811
|
+
|
812
|
+
if key.is_a?(Hash)
|
813
|
+
okey = key
|
814
|
+
while okey.values.first.is_a?(Hash)
|
815
|
+
okey = okey.values.first
|
816
|
+
end
|
817
|
+
nkey = okey.keys.first
|
818
|
+
nvalue = okey.values.first
|
819
|
+
okey[nkey] = { nvalue => value }
|
820
|
+
else
|
821
|
+
{ key => value }
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
632
825
|
def visit_Arel_Nodes_NotEqual o, collector
|
633
826
|
{
|
634
827
|
visit(o.left, collector) => { :not => visit(o.right, collector) }
|
@@ -645,11 +838,47 @@ module Arel
|
|
645
838
|
def visit_Arel_Nodes_UnqualifiedColumn o, collector
|
646
839
|
o.name
|
647
840
|
end
|
841
|
+
|
842
|
+
def visit_Arel_Attributes_Cast(o, collector)
|
843
|
+
key = visit(o.relation, collector)
|
844
|
+
value = { :cast => o.name }
|
845
|
+
if key.is_a?(Hash)
|
846
|
+
add_to_bottom_of_hash(key, value)
|
847
|
+
else
|
848
|
+
{ key => value }
|
849
|
+
end
|
850
|
+
end
|
851
|
+
|
852
|
+
def visit_Arel_Attributes_Key o, collector
|
853
|
+
key = visit(o.relation, collector)
|
854
|
+
if key.is_a?(Hash)
|
855
|
+
okey = key
|
856
|
+
while okey.values.first.is_a?(Hash)
|
857
|
+
okey = okey.values.first
|
858
|
+
end
|
859
|
+
nkey = okey.keys.first
|
860
|
+
value = okey.values.first
|
861
|
+
okey[nkey] = {value => o.name}
|
862
|
+
key
|
863
|
+
else
|
864
|
+
{ key => o.name }
|
865
|
+
end
|
866
|
+
end
|
648
867
|
|
868
|
+
def visit_Arel_Attributes_Relation o, collector
|
869
|
+
if o.collection
|
870
|
+
ary = []
|
871
|
+
ary[o.collection] = visit(o.relation, collector).to_s.split('.').last
|
872
|
+
{"#{o.name}_attributes" => ary}
|
873
|
+
else
|
874
|
+
{"#{o.name}_attributes" => visit(o.relation, collector).to_s.split('.').last}
|
875
|
+
end
|
876
|
+
end
|
877
|
+
|
649
878
|
def visit_Arel_Attributes_Attribute o, collector
|
650
879
|
join_name = o.relation.table_alias || o.relation.name
|
651
|
-
# collector <<
|
652
880
|
collector.table == join_name ? o.name : "#{join_name}.#{o.name}"
|
881
|
+
# o.name
|
653
882
|
end
|
654
883
|
alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
|
655
884
|
alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
|