sunstone 7.0.0 → 7.2.0
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 +5 -28
- data/ext/active_record/associations.rb +12 -8
- data/ext/active_record/attribute_methods.rb +14 -13
- data/ext/active_record/callbacks.rb +4 -1
- data/ext/active_record/finder_methods.rb +14 -4
- data/ext/active_record/persistence.rb +58 -20
- data/ext/active_record/relation/calculations.rb +27 -7
- data/ext/active_record/relation/query_methods.rb +6 -4
- data/ext/active_record/transactions.rb +15 -13
- data/lib/active_record/connection_adapters/sunstone/column.rb +10 -0
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +58 -21
- data/lib/active_record/connection_adapters/sunstone/quoting.rb +19 -0
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +6 -5
- data/lib/active_record/connection_adapters/sunstone/type/binary.rb +3 -3
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +102 -75
- data/lib/arel/visitors/sunstone.rb +69 -58
- data/lib/sunstone/connection.rb +4 -4
- data/lib/sunstone/version.rb +1 -1
- data/lib/sunstone.rb +2 -14
- metadata +14 -13
@@ -0,0 +1,19 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sunstone
|
4
|
+
module Quoting
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods # :nodoc:
|
8
|
+
|
9
|
+
# Quotes column names for use in SQL queries.
|
10
|
+
def quote_column_name(name) # :nodoc:
|
11
|
+
name
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -27,8 +27,7 @@ module ActiveRecord
|
|
27
27
|
return @definitions[table_name]
|
28
28
|
end
|
29
29
|
|
30
|
-
response =
|
31
|
-
|
30
|
+
response = with_raw_connection { |conn| conn.get("/#{table_name}/schema") }
|
32
31
|
@definitions[table_name] = JSON.parse(response.body)
|
33
32
|
rescue ::Sunstone::Exception::NotFound
|
34
33
|
raise ActiveRecord::StatementInvalid, "Table \"#{table_name}\" does not exist"
|
@@ -40,7 +39,9 @@ module ActiveRecord
|
|
40
39
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
41
40
|
# - ::regclass is a function that gives the id for a table name
|
42
41
|
def column_definitions(table_name) # :nodoc:
|
43
|
-
|
42
|
+
# TODO: settle on schema, I think we've switched to attributes, so
|
43
|
+
# columns can be removed soon?
|
44
|
+
definition(table_name)['attributes'] || definition(table_name)['columns']
|
44
45
|
end
|
45
46
|
|
46
47
|
# Returns the limit definition of the table (the maximum limit that can
|
@@ -50,7 +51,7 @@ module ActiveRecord
|
|
50
51
|
end
|
51
52
|
|
52
53
|
def tables
|
53
|
-
JSON.parse(
|
54
|
+
JSON.parse(with_raw_connection { |conn| conn.get('/tables').body })
|
54
55
|
end
|
55
56
|
|
56
57
|
def views
|
@@ -63,7 +64,7 @@ module ActiveRecord
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def lookup_cast_type(options)
|
66
|
-
type_map.lookup(options['type'], options.symbolize_keys)
|
67
|
+
@type_map.lookup(options['type'], options.symbolize_keys)
|
67
68
|
end
|
68
69
|
|
69
70
|
def fetch_type_metadata(options)
|
@@ -13,11 +13,11 @@ module ActiveRecord
|
|
13
13
|
#
|
14
14
|
# +value+ The raw input, as provided from the database.
|
15
15
|
def deserialize(value)
|
16
|
-
value.nil? ? nil : Base64.strict_decode64(value)
|
16
|
+
value.nil? ? nil : Base64.strict_decode64(value)
|
17
17
|
end
|
18
18
|
|
19
|
-
# Casts a value from the ruby type to a type that the database knows
|
20
|
-
# to understand. The returned value from this method should be a
|
19
|
+
# Casts a value from the ruby type to a type that the database knows
|
20
|
+
# how to understand. The returned value from this method should be a
|
21
21
|
# +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
|
22
22
|
# +nil+.
|
23
23
|
def serialize(value)
|
@@ -3,6 +3,7 @@ require 'active_record/connection_adapters/abstract_adapter'
|
|
3
3
|
require 'arel/nodes/relation'
|
4
4
|
require 'arel/visitors/to_sql_extensions'
|
5
5
|
|
6
|
+
require 'active_record/connection_adapters/sunstone/quoting'
|
6
7
|
require 'active_record/connection_adapters/sunstone/database_statements'
|
7
8
|
require 'active_record/connection_adapters/sunstone/schema_statements'
|
8
9
|
require 'active_record/connection_adapters/sunstone/schema_dumper'
|
@@ -15,32 +16,6 @@ require 'active_record/connection_adapters/sunstone/type/uuid'
|
|
15
16
|
require 'active_record/connection_adapters/sunstone/type/json'
|
16
17
|
|
17
18
|
module ActiveRecord
|
18
|
-
module ConnectionHandling # :nodoc:
|
19
|
-
|
20
|
-
VALID_SUNSTONE_CONN_PARAMS = [:url, :host, :port, :api_key, :use_ssl, :user_agent, :ca_cert]
|
21
|
-
|
22
|
-
# Establishes a connection to the database that's used by all Active Record
|
23
|
-
# objects
|
24
|
-
def sunstone_connection(config)
|
25
|
-
conn_params = config.symbolize_keys
|
26
|
-
conn_params.delete_if { |_, v| v.nil? }
|
27
|
-
|
28
|
-
if conn_params[:url]
|
29
|
-
uri = URI.parse(conn_params.delete(:url))
|
30
|
-
conn_params[:api_key] ||= (uri.user ? CGI.unescape(uri.user) : nil)
|
31
|
-
conn_params[:host] ||= uri.host
|
32
|
-
conn_params[:port] ||= uri.port
|
33
|
-
conn_params[:use_ssl] ||= (uri.scheme == 'https')
|
34
|
-
end
|
35
|
-
|
36
|
-
# Forward only valid config params to Sunstone::Connection
|
37
|
-
conn_params.slice!(*VALID_SUNSTONE_CONN_PARAMS)
|
38
|
-
|
39
|
-
client = ::Sunstone::Connection.new(conn_params)
|
40
|
-
ConnectionAdapters::SunstoneAPIAdapter.new(client, logger, conn_params, config)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
19
|
module ConnectionAdapters
|
45
20
|
# The SunstoneAPI adapter.
|
46
21
|
#
|
@@ -54,6 +29,7 @@ module ActiveRecord
|
|
54
29
|
# <encoding></tt> call on the connection.
|
55
30
|
class SunstoneAPIAdapter < AbstractAdapter
|
56
31
|
ADAPTER_NAME = 'Sunstone'.freeze
|
32
|
+
VALID_SUNSTONE_CONN_PARAMS = [:url, :host, :port, :api_key, :use_ssl, :user_agent, :ca_cert]
|
57
33
|
|
58
34
|
NATIVE_DATABASE_TYPES = {
|
59
35
|
string: { name: "string" },
|
@@ -61,8 +37,14 @@ module ActiveRecord
|
|
61
37
|
json: { name: "json" },
|
62
38
|
boolean: { name: "boolean" }
|
63
39
|
}
|
40
|
+
|
41
|
+
class << self
|
42
|
+
def new_client(conn_params)
|
43
|
+
::Sunstone::Connection.new(conn_params)
|
44
|
+
end
|
45
|
+
end
|
64
46
|
|
65
|
-
|
47
|
+
include Sunstone::Quoting
|
66
48
|
# include PostgreSQL::ReferentialIntegrity
|
67
49
|
include Sunstone::SchemaStatements
|
68
50
|
include Sunstone::DatabaseStatements
|
@@ -72,35 +54,61 @@ module ActiveRecord
|
|
72
54
|
def supports_statement_cache?
|
73
55
|
false
|
74
56
|
end
|
57
|
+
|
58
|
+
def default_prepared_statements
|
59
|
+
false
|
60
|
+
end
|
75
61
|
|
76
|
-
def clear_cache!
|
62
|
+
def clear_cache!(new_connection: false)
|
77
63
|
# TODO move @definitions to using @schema_cache
|
78
64
|
@definitions = {}
|
79
65
|
end
|
80
66
|
|
81
67
|
# Initializes and connects a SunstoneAPI adapter.
|
82
|
-
def initialize(
|
83
|
-
super
|
68
|
+
def initialize(...)
|
69
|
+
super
|
84
70
|
|
85
|
-
|
86
|
-
|
71
|
+
conn_params = @config.compact
|
72
|
+
if conn_params[:url]
|
73
|
+
uri = URI.parse(conn_params.delete(:url))
|
74
|
+
conn_params[:api_key] ||= (uri.user ? CGI.unescape(uri.user) : nil)
|
75
|
+
conn_params[:host] ||= uri.host
|
76
|
+
conn_params[:port] ||= uri.port
|
77
|
+
conn_params[:use_ssl] ||= (uri.scheme == 'https')
|
78
|
+
end
|
87
79
|
|
88
|
-
|
89
|
-
|
80
|
+
# Forward only valid config params to Sunstone::Connection
|
81
|
+
conn_params.slice!(*VALID_SUNSTONE_CONN_PARAMS)
|
82
|
+
|
83
|
+
@connection_parameters = conn_params
|
84
|
+
|
85
|
+
@max_identifier_length = nil
|
86
|
+
@type_map = nil
|
87
|
+
@raw_connection = nil
|
90
88
|
end
|
91
89
|
|
92
|
-
def
|
93
|
-
@
|
90
|
+
def url(path=nil)
|
91
|
+
"http#{@connection_parameters[:use_ssl] ? 's' : ''}://#{@connection_parameters[:host]}#{@connection_parameters[:port] != 80 ? (@connection_parameters[:port] == 443 && @connection_parameters[:use_ssl] ? '' : ":#{@connection_parameters[:port]}") : ''}#{path}"
|
94
92
|
end
|
95
93
|
|
96
|
-
def
|
94
|
+
def active?
|
95
|
+
@raw_connection&.active?
|
96
|
+
end
|
97
|
+
|
98
|
+
def reconnect
|
97
99
|
super
|
98
|
-
@
|
100
|
+
@raw_connection&.reconnect!
|
99
101
|
end
|
100
102
|
|
101
103
|
def disconnect!
|
102
104
|
super
|
103
|
-
@
|
105
|
+
@raw_connection&.disconnect!
|
106
|
+
@raw_connection = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def discard! # :nodoc:
|
110
|
+
super
|
111
|
+
@raw_connection = nil
|
104
112
|
end
|
105
113
|
|
106
114
|
# Executes the delete statement and returns the number of rows affected.
|
@@ -134,11 +142,18 @@ module ActiveRecord
|
|
134
142
|
end
|
135
143
|
|
136
144
|
def server_config
|
137
|
-
|
145
|
+
with_raw_connection do |conn|
|
146
|
+
JSON.parse(conn.get("/configuration").body)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def return_value_after_insert?(column) # :nodoc:
|
151
|
+
column.auto_populated?
|
138
152
|
end
|
139
153
|
|
140
154
|
def lookup_cast_type_from_column(column) # :nodoc:
|
141
|
-
|
155
|
+
verify! if type_map.nil?
|
156
|
+
cast_type = @type_map.lookup(column.sql_type, {
|
142
157
|
limit: column.limit,
|
143
158
|
precision: column.precision,
|
144
159
|
scale: column.scale
|
@@ -167,55 +182,67 @@ module ActiveRecord
|
|
167
182
|
true
|
168
183
|
end
|
169
184
|
|
170
|
-
# Executes an INSERT query and returns the
|
171
|
-
#
|
172
|
-
|
173
|
-
|
174
|
-
# id and return that value.
|
175
|
-
#
|
176
|
-
# If the next id was calculated in advance (as in Oracle), it should be
|
177
|
-
# passed in as +id_value+.
|
178
|
-
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
179
|
-
exec_insert(arel, name, binds, pk, sequence_name)
|
185
|
+
# Executes an INSERT query and returns a hash of the object and
|
186
|
+
# any updated relations. This is different from AR which returns an ID
|
187
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
|
188
|
+
exec_insert(arel, name, binds, pk, sequence_name, returning: returning)
|
180
189
|
end
|
181
190
|
alias create insert
|
182
191
|
|
192
|
+
# Connects to a StandardAPI server and sets up the adapter depending
|
193
|
+
# on the connected server's characteristics.
|
194
|
+
def connect
|
195
|
+
@raw_connection = self.class.new_client(@connection_parameters)
|
196
|
+
end
|
197
|
+
|
198
|
+
def reconnect
|
199
|
+
@raw_connection&.reconnect!
|
200
|
+
connect unless @raw_connection
|
201
|
+
end
|
202
|
+
|
203
|
+
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
204
|
+
# This is called by #connect and should not be called manually.
|
205
|
+
def configure_connection
|
206
|
+
super
|
207
|
+
|
208
|
+
reload_type_map
|
209
|
+
end
|
210
|
+
|
183
211
|
def reload_type_map
|
184
|
-
type_map
|
212
|
+
if @type_map
|
213
|
+
type_map.clear
|
214
|
+
else
|
215
|
+
@type_map = Type::HashLookupTypeMap.new
|
216
|
+
end
|
217
|
+
|
185
218
|
initialize_type_map
|
186
219
|
end
|
187
220
|
|
188
221
|
private
|
189
222
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
end
|
195
|
-
|
196
|
-
def initialize_type_map(m = type_map)
|
197
|
-
self.class.initialize_type_map(m)
|
198
|
-
load_additional_types
|
223
|
+
attr_reader :type_map
|
224
|
+
|
225
|
+
def initialize_type_map(m = nil)
|
226
|
+
self.class.initialize_type_map(m || @type_map)
|
199
227
|
end
|
200
228
|
|
201
|
-
def initialize_type_map(m) # :nodoc:
|
202
|
-
m.register_type
|
203
|
-
m.register_type
|
204
|
-
Type::
|
205
|
-
end
|
206
|
-
m.register_type 'integer' do |_, options|
|
207
|
-
Type::Integer.new(**options.slice(:limit))
|
229
|
+
def self.initialize_type_map(m) # :nodoc:
|
230
|
+
m.register_type 'boolean', Type::Boolean.new
|
231
|
+
m.register_type 'binary' do |_, options|
|
232
|
+
Sunstone::Type::Binary.new(**options.slice(:limit))
|
208
233
|
end
|
209
|
-
m.register_type
|
234
|
+
m.register_type 'datetime', Sunstone::Type::DateTime.new
|
235
|
+
m.register_type 'decimal' do |_, options|
|
210
236
|
Type::Decimal.new(**options.slice(:precision, :scale))
|
211
237
|
end
|
212
|
-
m.register_type
|
213
|
-
|
238
|
+
m.register_type 'integer' do |_, options|
|
239
|
+
Type::Integer.new(**options.slice(:limit))
|
214
240
|
end
|
215
|
-
|
216
|
-
m.register_type
|
217
|
-
|
218
|
-
|
241
|
+
m.register_type 'json', Sunstone::Type::Json.new
|
242
|
+
m.register_type 'string' do |_, options|
|
243
|
+
Type::String.new(**options.slice(:limit))
|
244
|
+
end
|
245
|
+
m.register_type 'uuid', Sunstone::Type::Uuid.new
|
219
246
|
|
220
247
|
if defined?(Sunstone::Type::EWKB)
|
221
248
|
m.register_type 'ewkb', Sunstone::Type::EWKB.new
|
@@ -3,24 +3,24 @@ require 'arel/visitors/visitor'
|
|
3
3
|
module Arel
|
4
4
|
module Visitors
|
5
5
|
class Sunstone < Arel::Visitors::Visitor
|
6
|
-
|
6
|
+
|
7
7
|
def compile(node, collector = Arel::Collectors::Sunstone.new)
|
8
8
|
accept(node, collector).value
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
private
|
12
|
-
|
12
|
+
|
13
13
|
def visit_Arel_Nodes_SelectStatement o, collector
|
14
14
|
collector.table = o.cores.first.source.left.name
|
15
15
|
|
16
16
|
collector = o.cores.inject(collector) { |c,x|
|
17
17
|
visit_Arel_Nodes_SelectCore(x, c)
|
18
18
|
}
|
19
|
-
|
19
|
+
|
20
20
|
if !o.orders.empty?
|
21
21
|
collector.order = o.orders.map { |x| visit(x, collector) }
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
collector = maybe_visit o.limit, collector
|
25
25
|
collector = maybe_visit o.offset, collector
|
26
26
|
collector = maybe_visit o.eager_load, collector
|
@@ -61,27 +61,36 @@ module Arel
|
|
61
61
|
collector.request_type = Net::HTTP::Post
|
62
62
|
collector.table = o.relation.name
|
63
63
|
collector.operation = :insert
|
64
|
-
|
64
|
+
|
65
65
|
if o.values
|
66
66
|
if o.values.is_a?(Arel::Nodes::SqlLiteral) && o.values == 'DEFAULT VALUES'
|
67
67
|
collector.updates = {}
|
68
68
|
else
|
69
|
-
|
70
|
-
|
71
|
-
o.columns.map(&:name).zip(o.values.expr.first).to_h.each do |k, v|
|
72
|
-
collector.updates[k] = case v
|
73
|
-
when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
|
74
|
-
visit(v, collector)
|
75
|
-
else
|
76
|
-
v
|
77
|
-
end
|
78
|
-
end
|
69
|
+
values = visit(o.values, collector)
|
70
|
+
collector.updates = o.columns.map(&:name).zip(values).to_h
|
79
71
|
end
|
80
72
|
end
|
81
|
-
|
73
|
+
|
82
74
|
collector
|
83
75
|
end
|
84
|
-
|
76
|
+
|
77
|
+
def visit_Arel_Nodes_ValuesList o, collector
|
78
|
+
o.rows[0].map do |v|
|
79
|
+
visit_subrelation v, collector
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def visit_subrelation v, collector
|
84
|
+
case v
|
85
|
+
when Array
|
86
|
+
v.map { |v2| visit_subrelation v2, collector }
|
87
|
+
when Hash
|
88
|
+
v.transform_values { |v2| visit_subrelation v2, collector }
|
89
|
+
else
|
90
|
+
visit(v, collector)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
85
94
|
def find_bottom(hash)
|
86
95
|
if hash.is_a?(Hash)
|
87
96
|
if hash.values.first.is_a?(Array) || hash.values.first.is_a?(Hash)
|
@@ -98,10 +107,10 @@ module Arel
|
|
98
107
|
end
|
99
108
|
end
|
100
109
|
end
|
101
|
-
|
110
|
+
|
102
111
|
def add_to_bottom_of_hash_or_array(hash, value)
|
103
112
|
hash = find_bottom(hash)
|
104
|
-
|
113
|
+
|
105
114
|
if hash.is_a?(Hash)
|
106
115
|
nkey = hash.keys.first
|
107
116
|
nvalue = hash.values.first
|
@@ -147,26 +156,26 @@ module Arel
|
|
147
156
|
#
|
148
157
|
def visit_Arel_Nodes_UpdateStatement o, collector
|
149
158
|
collector.request_type = Net::HTTP::Patch
|
150
|
-
|
159
|
+
|
151
160
|
collector.table = o.relation.name
|
152
161
|
collector.operation = :update
|
153
|
-
|
162
|
+
|
154
163
|
# collector.id = o.wheres.first.children.first.right
|
155
164
|
if !o.wheres.empty?
|
156
165
|
collector.where = o.wheres.map { |x| visit(x, collector) }.inject([]) { |c, w|
|
157
166
|
w.is_a?(Array) ? c += w : c << w
|
158
167
|
}
|
159
168
|
end
|
160
|
-
|
169
|
+
|
161
170
|
if collector.where.size != 1 && collector.where.first.size != 1 && !collector.where.first['id']
|
162
171
|
raise 'Upsupported'
|
163
172
|
end
|
164
|
-
|
173
|
+
|
165
174
|
collector.where = collector.where.first
|
166
|
-
|
175
|
+
|
167
176
|
if o.values
|
168
177
|
collector.updates = {}
|
169
|
-
|
178
|
+
|
170
179
|
o.values.map { |x| visit(x, collector) }.each do |value|
|
171
180
|
value.each do |key, v|
|
172
181
|
if key.is_a?(Hash)
|
@@ -191,7 +200,7 @@ module Arel
|
|
191
200
|
end
|
192
201
|
end
|
193
202
|
end
|
194
|
-
|
203
|
+
|
195
204
|
collector
|
196
205
|
end
|
197
206
|
#
|
@@ -426,7 +435,7 @@ module Arel
|
|
426
435
|
def visit_Arel_Nodes_Descending o, collector
|
427
436
|
{ visit(o.expr, collector) => :desc }
|
428
437
|
end
|
429
|
-
|
438
|
+
|
430
439
|
def visit_Arel_Nodes_RandomOrdering o, collector
|
431
440
|
:random
|
432
441
|
end
|
@@ -468,7 +477,7 @@ module Arel
|
|
468
477
|
#
|
469
478
|
def visit_Arel_Nodes_Count o, collector
|
470
479
|
collector.operation = :calculate
|
471
|
-
|
480
|
+
|
472
481
|
collector.columns ||= []
|
473
482
|
collector.columns << {:count => (o.expressions.first.is_a?(Arel::Attributes::Attribute) ? o.expressions.first.name : o.expressions.first) }
|
474
483
|
# collector.columns = visit o.expressions.first, collector
|
@@ -476,7 +485,7 @@ module Arel
|
|
476
485
|
|
477
486
|
def visit_Arel_Nodes_Sum o, collector
|
478
487
|
collector.operation = :calculate
|
479
|
-
|
488
|
+
|
480
489
|
collector.columns ||= []
|
481
490
|
collector.columns << {:sum => (o.expressions.first.is_a?(Arel::Attributes::Attribute) ? o.expressions.first.name : o.expressions.first) }
|
482
491
|
# collector.columns = visit o.expressions.first, collector
|
@@ -484,7 +493,7 @@ module Arel
|
|
484
493
|
|
485
494
|
def visit_Arel_Nodes_Max o, collector
|
486
495
|
collector.operation = :calculate
|
487
|
-
|
496
|
+
|
488
497
|
collector.columns ||= []
|
489
498
|
if o.expressions.first.is_a?(Arel::Attributes::Attribute)
|
490
499
|
relation = o.expressions.first.relation
|
@@ -686,11 +695,11 @@ module Arel
|
|
686
695
|
end
|
687
696
|
end
|
688
697
|
alias_method :visit_Arel_Nodes_HomogeneousIn, :visit_Arel_Nodes_In
|
689
|
-
|
698
|
+
|
690
699
|
def visit_Arel_Nodes_NotIn o, collector
|
691
700
|
key = visit(o.left, collector)
|
692
701
|
value = {not_in: visit(o.right, collector)}
|
693
|
-
|
702
|
+
|
694
703
|
if hash.is_a?(Hash)
|
695
704
|
add_to_bottom_of_hash_or_array(key, value)
|
696
705
|
key
|
@@ -698,10 +707,10 @@ module Arel
|
|
698
707
|
{key => value}
|
699
708
|
end
|
700
709
|
end
|
701
|
-
|
710
|
+
|
702
711
|
# You merge a into b if a keys do not colid with b keys
|
703
712
|
def mergeable?(hash_a, hash_b)
|
704
|
-
|
713
|
+
|
705
714
|
hash_a.each do |key, value_a|
|
706
715
|
#TODO: one day maybe just use symbols for all keys?
|
707
716
|
if hash_b.has_key?(key.to_sym) || hash_b.has_key?(key.to_s)
|
@@ -715,7 +724,7 @@ module Arel
|
|
715
724
|
end
|
716
725
|
true
|
717
726
|
end
|
718
|
-
|
727
|
+
|
719
728
|
def visit_Arel_Nodes_And o, collector
|
720
729
|
ors = []
|
721
730
|
|
@@ -730,16 +739,16 @@ module Arel
|
|
730
739
|
ors << value
|
731
740
|
end
|
732
741
|
end
|
733
|
-
|
742
|
+
|
734
743
|
result = []
|
735
744
|
ors.each_with_index do |c, i|
|
736
745
|
result << c
|
737
746
|
result << 'AND' if ors.size != i + 1
|
738
747
|
end
|
739
|
-
|
748
|
+
|
740
749
|
result.size == 1 ? result.first : result
|
741
750
|
end
|
742
|
-
|
751
|
+
|
743
752
|
def visit_Arel_Nodes_Or o, collector
|
744
753
|
[visit(o.left, collector), 'OR', visit(o.right, collector)]
|
745
754
|
end
|
@@ -748,10 +757,12 @@ module Arel
|
|
748
757
|
case o.left
|
749
758
|
when Arel::Nodes::UnqualifiedColumn
|
750
759
|
case o.right
|
751
|
-
when
|
752
|
-
{ visit(o.left.expr, collector) =>
|
760
|
+
when Array
|
761
|
+
{ visit(o.left.expr, collector) => o.right.map { |i| i.transform_values { |v| visit(v, collector) } } }
|
762
|
+
when Hash
|
763
|
+
{ visit(o.left.expr, collector) => o.right.transform_values { |v| visit(v, collector) } }
|
753
764
|
else
|
754
|
-
{ visit(o.left.expr, collector) => o.right }
|
765
|
+
{ visit(o.left.expr, collector) => visit(o.right, collector) }
|
755
766
|
end
|
756
767
|
when Arel::Attributes::Attribute, Arel::Nodes::BindParam, ActiveModel::Attribute
|
757
768
|
{ visit(o.left, collector) => visit(o.right, collector) }
|
@@ -770,7 +781,7 @@ module Arel
|
|
770
781
|
okey.merge!(value)
|
771
782
|
hash
|
772
783
|
end
|
773
|
-
|
784
|
+
|
774
785
|
def add_to_bottom_of_hash(hash, value)
|
775
786
|
okey = hash
|
776
787
|
while okey.is_a?(Hash) && (okey.values.first.is_a?(Hash) || okey.values.first.is_a?(Array))
|
@@ -785,11 +796,11 @@ module Arel
|
|
785
796
|
okey[nkey] = { nvalue => value }
|
786
797
|
hash
|
787
798
|
end
|
788
|
-
|
799
|
+
|
789
800
|
def visit_Arel_Nodes_Equality o, collector
|
790
801
|
key = visit(o.left, collector)
|
791
802
|
value = (o.right.nil? ? nil : visit(o.right, collector))
|
792
|
-
|
803
|
+
|
793
804
|
if key.is_a?(Hash)
|
794
805
|
add_to_bottom_of_hash(key, {eq: value})
|
795
806
|
elsif o.left.class.name == 'Arel::Attributes::Key'
|
@@ -798,7 +809,7 @@ module Arel
|
|
798
809
|
{ key => value }
|
799
810
|
end
|
800
811
|
end
|
801
|
-
|
812
|
+
|
802
813
|
def visit_Arel_Nodes_TSMatch(o, collector)
|
803
814
|
key = visit(o.left, collector)
|
804
815
|
value = { ts_match: (o.right.nil? ? nil : visit(o.right, collector)) }
|
@@ -814,11 +825,11 @@ module Arel
|
|
814
825
|
hash
|
815
826
|
end
|
816
827
|
end
|
817
|
-
|
828
|
+
|
818
829
|
def visit_Arel_Nodes_TSVector(o, collector)
|
819
830
|
visit(o.attribute, collector)
|
820
831
|
end
|
821
|
-
|
832
|
+
|
822
833
|
def visit_Arel_Nodes_TSQuery(o, collector)
|
823
834
|
if o.language
|
824
835
|
[visit(o.expression, collector), visit(o.language, collector)]
|
@@ -826,11 +837,11 @@ module Arel
|
|
826
837
|
visit(o.expression, collector)
|
827
838
|
end
|
828
839
|
end
|
829
|
-
|
840
|
+
|
830
841
|
def visit_Arel_Nodes_HasKey o, collector
|
831
842
|
key = visit(o.left, collector)
|
832
843
|
value = {has_key: (o.right.nil? ? nil : o.right.to_s)}
|
833
|
-
|
844
|
+
|
834
845
|
if key.is_a?(Hash)
|
835
846
|
okey = key
|
836
847
|
while okey.values.first.is_a?(Hash)
|
@@ -847,7 +858,7 @@ module Arel
|
|
847
858
|
def visit_Arel_Nodes_HasKeys o, collector
|
848
859
|
key = visit(o.left, collector)
|
849
860
|
value = { has_keys: visit(o.right, collector) }
|
850
|
-
|
861
|
+
|
851
862
|
if key.is_a?(Hash)
|
852
863
|
okey = key
|
853
864
|
while okey.values.first.is_a?(Hash)
|
@@ -864,7 +875,7 @@ module Arel
|
|
864
875
|
def visit_Arel_Nodes_HasAnyKey o, collector
|
865
876
|
key = visit(o.left, collector)
|
866
877
|
value = { has_any_key: visit(o.right, collector) }
|
867
|
-
|
878
|
+
|
868
879
|
if key.is_a?(Hash)
|
869
880
|
okey = key
|
870
881
|
while okey.values.first.is_a?(Hash)
|
@@ -894,11 +905,11 @@ module Arel
|
|
894
905
|
def visit_Arel_Nodes_UnqualifiedColumn o, collector
|
895
906
|
o.name
|
896
907
|
end
|
897
|
-
|
908
|
+
|
898
909
|
def visit_Arel_Attributes_Cast(o, collector)
|
899
910
|
visit(o.relation, collector) # No casting yet
|
900
911
|
end
|
901
|
-
|
912
|
+
|
902
913
|
def visit_Arel_Attributes_Key o, collector
|
903
914
|
"#{visit(o.relation, collector)}.#{o.name}"
|
904
915
|
end
|
@@ -938,7 +949,7 @@ module Arel
|
|
938
949
|
# def visit_Arel_Attributes_EmptyRelation o, collector, top=true
|
939
950
|
# o.for_write ? "#{o.name}_attributes" : o.name
|
940
951
|
# end
|
941
|
-
|
952
|
+
|
942
953
|
def visit_Arel_Attributes_Attribute o, collector
|
943
954
|
join_name = o.relation.table_alias || o.relation.name
|
944
955
|
|
@@ -963,7 +974,7 @@ module Arel
|
|
963
974
|
o.value_for_database
|
964
975
|
end
|
965
976
|
end
|
966
|
-
|
977
|
+
|
967
978
|
def visit_Arel_Nodes_BindParam o, collector
|
968
979
|
a = collector.add_bind(o.value)
|
969
980
|
o.is_a?(Arel::Nodes::BindParam) ? o : a
|
@@ -1060,11 +1071,11 @@ module Arel
|
|
1060
1071
|
collector
|
1061
1072
|
end
|
1062
1073
|
end
|
1063
|
-
|
1074
|
+
|
1064
1075
|
def maybe_visit thing, collector
|
1065
1076
|
return collector unless thing
|
1066
1077
|
visit thing, collector
|
1067
1078
|
end
|
1068
1079
|
end
|
1069
1080
|
end
|
1070
|
-
end
|
1081
|
+
end
|