sunstone 7.2.0 → 8.0.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/finder_methods.rb +5 -0
- data/ext/active_record/relation/calculations.rb +27 -6
- data/ext/active_record/relation/query_methods.rb +1 -1
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +72 -40
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +19 -24
- data/lib/sunstone/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd0eae0dbdee21a95ca29317302b67b50647f7d6654af15553425f55d1d11aed
|
4
|
+
data.tar.gz: b0cdc960489411360b1ee4f2cb4cdcce93b7df2464dabdafa2bc26955be002b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce768f425153db1d5a2242f845bc3de221a4d0d0d8a30a1428c128d2bb1e4353ef986020283fdd1d17e7652937c38d03eb1f42478acbc694da32135f335cab22
|
7
|
+
data.tar.gz: ece020a27e0554bad07f0e831919e8969cebdd6970adc344fb4f018b3a45032588dcd7c4eb512d9fcb8ff4acfc09ef27d9fe6124fa2b9db0d5eeff659885d800
|
@@ -8,6 +8,11 @@ module ActiveRecord
|
|
8
8
|
return ["1=0"] if attributes.empty?
|
9
9
|
|
10
10
|
attributes.flat_map do |key, value|
|
11
|
+
if key.is_a?(Array) && key.size == 1
|
12
|
+
key = key.first
|
13
|
+
value = value.flatten
|
14
|
+
end
|
15
|
+
|
11
16
|
if key.is_a?(Array)
|
12
17
|
queries = Array(value).map do |ids_set|
|
13
18
|
raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
|
@@ -4,6 +4,27 @@
|
|
4
4
|
module ActiveRecord
|
5
5
|
module Calculations
|
6
6
|
|
7
|
+
# Prior to Rails 8 we didn't need this method becuase it would
|
8
|
+
# return the first value if there was just one - so we'll just
|
9
|
+
# do the same as prevously because it doesn't have to be joined
|
10
|
+
def select_for_count
|
11
|
+
if select_values.empty?
|
12
|
+
:all
|
13
|
+
else
|
14
|
+
with_connection do |conn|
|
15
|
+
# Rails compiles this to a string, but we don't have string we
|
16
|
+
# have a hash
|
17
|
+
if model.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
18
|
+
sv = arel_columns(select_values)
|
19
|
+
sv.one? ? sv.first : sv
|
20
|
+
else
|
21
|
+
sv = arel_columns(select_values).map { |column| conn.visitor.compile(column) }
|
22
|
+
sv.one? ? sv.first : sv.join(", ")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
7
28
|
def pluck(*column_names)
|
8
29
|
if @none
|
9
30
|
if @async
|
@@ -25,20 +46,20 @@ module ActiveRecord
|
|
25
46
|
if has_include?(column_names.first)
|
26
47
|
relation = apply_join_dependency
|
27
48
|
relation.pluck(*column_names)
|
28
|
-
elsif
|
49
|
+
elsif model.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
29
50
|
load
|
30
|
-
return records.pluck(*column_names.map{|n| n.to_s.sub(/^#{
|
51
|
+
return records.pluck(*column_names.map{|n| n.to_s.sub(/^#{model.table_name}\./, "")})
|
31
52
|
else
|
32
|
-
|
33
|
-
columns = arel_columns(column_names)
|
53
|
+
model.disallow_raw_sql!(flattened_args(column_names))
|
34
54
|
relation = spawn
|
55
|
+
columns = relation.arel_columns(column_names)
|
35
56
|
relation.select_values = columns
|
36
57
|
result = skip_query_cache_if_necessary do
|
37
58
|
if where_clause.contradiction?
|
38
59
|
ActiveRecord::Result.empty(async: @async)
|
39
60
|
else
|
40
|
-
|
41
|
-
c.select_all(relation.arel, "#{
|
61
|
+
model.with_connection do |c|
|
62
|
+
c.select_all(relation.arel, "#{model.name} Pluck", async: @async)
|
42
63
|
end
|
43
64
|
end
|
44
65
|
end
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
|
5
5
|
def assert_modifiable!
|
6
6
|
raise UnmodifiableRelation if @loaded
|
7
|
-
raise UnmodifiableRelation if @arel && !
|
7
|
+
raise UnmodifiableRelation if @arel && !model.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
|
8
8
|
end
|
9
9
|
|
10
10
|
end
|
@@ -30,6 +30,7 @@ module ActiveRecord
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def to_sar_and_binds(arel_or_sar_string, binds = [], preparable = nil, allow_retry = false)
|
33
|
+
# Arel::TreeManager -> Arel::Node
|
33
34
|
if arel_or_sar_string.respond_to?(:ast)
|
34
35
|
arel_or_sar_string = arel_or_sar_string.ast
|
35
36
|
end
|
@@ -40,10 +41,13 @@ module ActiveRecord
|
|
40
41
|
"The values must be stored on the AST directly"
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
+
col = collector()
|
45
|
+
col.retryable = true
|
46
|
+
sar = visitor.compile(arel_or_sar_string, col)
|
44
47
|
[sar.freeze, sar.binds, false, allow_retry]
|
45
48
|
else
|
46
|
-
|
49
|
+
arel_or_sar_string = arel_or_sar_string.dup.freeze unless arel_or_sar_string.frozen?
|
50
|
+
[arel_or_sar_string, binds, false, allow_retry]
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
@@ -115,8 +119,8 @@ module ActiveRecord
|
|
115
119
|
internal_exec_query(sar, name, binds)
|
116
120
|
end
|
117
121
|
|
118
|
-
|
119
|
-
|
122
|
+
# Lowest level way to execute a query. Doesn't check for illegal writes, doesn't annotate queries, yields a native result object.
|
123
|
+
def raw_execute(arel, name = nil, binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, batch: false)
|
120
124
|
multiple_requests = arel.is_a?(Arel::Collectors::Sunstone)
|
121
125
|
type_casted_binds = binds#type_casted_binds(binds)
|
122
126
|
|
@@ -137,50 +141,73 @@ module ActiveRecord
|
|
137
141
|
multiple_requests = true
|
138
142
|
end
|
139
143
|
end
|
140
|
-
|
141
|
-
send_request = lambda { |req_arel|
|
144
|
+
|
145
|
+
send_request = lambda { |conn, req_arel, batch|
|
142
146
|
sar = to_sar(req_arel, type_casted_binds)
|
143
|
-
sars.push(sar)
|
144
147
|
log_mess = sar.path.split('?', 2)
|
145
|
-
log("#{sar.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }", name) do
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
148
|
+
log("#{sar.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }", name) do |notification_payload|
|
149
|
+
result = perform_query(conn, sar, prepare:, notification_payload:, batch: batch)
|
150
|
+
result.instance_variable_set(:@sunstone_calculation, true) if result && sar.instance_variable_get(:@sunstone_calculation)
|
151
|
+
result
|
152
|
+
end
|
153
|
+
}
|
154
|
+
|
155
|
+
result = with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
156
|
+
if multiple_requests
|
157
|
+
binds.delete_at(limit_bind_index) if limit_bind_index
|
158
|
+
|
159
|
+
limit, offset, results = allowed_limit, 0, nil
|
160
|
+
last_affected_rows = 0
|
161
|
+
while requested_limit ? offset < requested_limit : true
|
162
|
+
split_arel = arel.dup
|
163
|
+
split_arel.limit = limit
|
164
|
+
split_arel.offset = offset
|
165
|
+
request_results = send_request.call(conn, split_arel, true)
|
166
|
+
last_affected_rows += @last_affected_rows
|
167
|
+
if results
|
168
|
+
results.push(*request_results)
|
150
169
|
else
|
151
|
-
|
170
|
+
results = request_results
|
152
171
|
end
|
172
|
+
break if request_results.size < limit
|
173
|
+
offset = offset + limit
|
153
174
|
end
|
175
|
+
@last_affected_rows = last_affected_rows
|
176
|
+
results
|
177
|
+
else
|
178
|
+
send_request.call(conn, arel, true)
|
154
179
|
end
|
155
|
-
}
|
156
|
-
|
157
|
-
result = if multiple_requests
|
158
|
-
binds.delete_at(limit_bind_index) if limit_bind_index
|
159
|
-
|
160
|
-
limit, offset, results = allowed_limit, 0, []
|
161
|
-
while requested_limit ? offset < requested_limit : true
|
162
|
-
split_arel = arel.dup
|
163
|
-
split_arel.limit = limit
|
164
|
-
split_arel.offset = offset
|
165
|
-
request_results = send_request.call(split_arel)
|
166
|
-
results = results + request_results
|
167
|
-
break if request_results.size < limit
|
168
|
-
offset = offset + limit
|
169
|
-
end
|
170
|
-
results
|
171
|
-
else
|
172
|
-
send_request.call(arel)
|
173
180
|
end
|
174
|
-
|
175
|
-
|
181
|
+
|
182
|
+
result
|
183
|
+
end
|
184
|
+
|
185
|
+
def perform_query(raw_connection, sar, prepare:, notification_payload:, batch: false)
|
186
|
+
response = raw_connection.send_request(sar)
|
187
|
+
result = response.is_a?(Net::HTTPNoContent) ? nil : JSON.parse(response.body)
|
188
|
+
|
189
|
+
verified!
|
190
|
+
# handle_warnings(result)
|
191
|
+
@last_affected_rows = response['Affected-Rows'] || result&.count || 0
|
192
|
+
notification_payload[:row_count] = @last_affected_rows
|
193
|
+
result
|
194
|
+
end
|
195
|
+
|
196
|
+
# Receive a native adapter result object and returns an ActiveRecord::Result object.
|
197
|
+
def cast_result(raw_result)
|
198
|
+
if raw_result.instance_variable_defined?(:@sunstone_calculation) && raw_result.instance_variable_get(:@sunstone_calculation)
|
176
199
|
# this is a count, min, max.... yea i know..
|
177
|
-
ActiveRecord::Result.new(['all'], [
|
178
|
-
elsif
|
179
|
-
ActiveRecord::Result.new(
|
200
|
+
ActiveRecord::Result.new(['all'], [raw_result], {:all => @type_map.lookup('integer', {})})
|
201
|
+
elsif raw_result.is_a?(Array)
|
202
|
+
ActiveRecord::Result.new(raw_result[0] ? raw_result[0].keys : [], raw_result.map{|r| r.values})
|
180
203
|
else
|
181
|
-
ActiveRecord::Result.new(
|
204
|
+
ActiveRecord::Result.new(raw_result.keys, [raw_result.values])
|
182
205
|
end
|
183
206
|
end
|
207
|
+
|
208
|
+
def affected_rows(raw_result)
|
209
|
+
@last_affected_rows
|
210
|
+
end
|
184
211
|
|
185
212
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
|
186
213
|
sar, binds = to_sar_and_binds(arel, binds)
|
@@ -190,13 +217,18 @@ module ActiveRecord
|
|
190
217
|
|
191
218
|
id_value || last_inserted_id(value)
|
192
219
|
end
|
193
|
-
|
220
|
+
alias create insert
|
221
|
+
|
222
|
+
# Executes the update statement and returns the number of rows affected.
|
194
223
|
def update(arel, name = nil, binds = [])
|
195
|
-
|
224
|
+
sar, binds = to_sar_and_binds(arel, binds)
|
225
|
+
internal_exec_query(sar, name, binds)
|
196
226
|
end
|
197
227
|
|
228
|
+
# Executes the delete statement and returns the number of rows affected.
|
198
229
|
def delete(arel, name = nil, binds = [])
|
199
|
-
|
230
|
+
sql, binds = to_sar_and_binds(arel, binds)
|
231
|
+
exec_delete(sql, name, binds)
|
200
232
|
end
|
201
233
|
|
202
234
|
def last_inserted_id(result)
|
@@ -92,18 +92,30 @@ module ActiveRecord
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def active?
|
95
|
-
@
|
95
|
+
@lock.synchronize do
|
96
|
+
@raw_connection&.active?
|
97
|
+
end
|
96
98
|
end
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
-
|
100
|
+
# Connects to a StandardAPI server and sets up the adapter depending
|
101
|
+
# on the connected server's characteristics.
|
102
|
+
def connect
|
103
|
+
@raw_connection = self.class.new_client(@connection_parameters)
|
101
104
|
end
|
102
105
|
|
106
|
+
def reconnect
|
107
|
+
@lock.synchronize do
|
108
|
+
@raw_connection&.reconnect!
|
109
|
+
connect unless @raw_connection
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
103
113
|
def disconnect!
|
104
|
-
|
105
|
-
|
106
|
-
|
114
|
+
@lock.synchronize do
|
115
|
+
super
|
116
|
+
@raw_connection&.disconnect!
|
117
|
+
@raw_connection = nil
|
118
|
+
end
|
107
119
|
end
|
108
120
|
|
109
121
|
def discard! # :nodoc:
|
@@ -111,12 +123,6 @@ module ActiveRecord
|
|
111
123
|
@raw_connection = nil
|
112
124
|
end
|
113
125
|
|
114
|
-
# Executes the delete statement and returns the number of rows affected.
|
115
|
-
def delete(arel, name = nil, binds = [])
|
116
|
-
r = exec_delete(arel, name, binds)
|
117
|
-
r.rows.first.to_i
|
118
|
-
end
|
119
|
-
|
120
126
|
def native_database_types #:nodoc:
|
121
127
|
NATIVE_DATABASE_TYPES
|
122
128
|
end
|
@@ -189,17 +195,6 @@ module ActiveRecord
|
|
189
195
|
end
|
190
196
|
alias create insert
|
191
197
|
|
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
198
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
204
199
|
# This is called by #connect and should not be called manually.
|
205
200
|
def configure_connection
|
data/lib/sunstone/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunstone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 8.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Bracy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -226,14 +226,14 @@ dependencies:
|
|
226
226
|
requirements:
|
227
227
|
- - ">="
|
228
228
|
- !ruby/object:Gem::Version
|
229
|
-
version:
|
229
|
+
version: 8.0.1
|
230
230
|
type: :runtime
|
231
231
|
prerelease: false
|
232
232
|
version_requirements: !ruby/object:Gem::Requirement
|
233
233
|
requirements:
|
234
234
|
- - ">="
|
235
235
|
- !ruby/object:Gem::Version
|
236
|
-
version:
|
236
|
+
version: 8.0.1
|
237
237
|
- !ruby/object:Gem::Dependency
|
238
238
|
name: arel-extensions
|
239
239
|
requirement: !ruby/object:Gem::Requirement
|
@@ -324,7 +324,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
324
324
|
- !ruby/object:Gem::Version
|
325
325
|
version: '0'
|
326
326
|
requirements: []
|
327
|
-
rubygems_version: 3.5.
|
327
|
+
rubygems_version: 3.5.21
|
328
328
|
signing_key:
|
329
329
|
specification_version: 4
|
330
330
|
summary: A library for interacting with REST APIs
|