activerecord-trilogy-adapter 2.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6012f06cd5bd29a7bd180354fd0e65c3fd11784a6a7483fac9599d87baa1b68
4
- data.tar.gz: bde2129ca1f647d6b7308c131d00ae012d614ad4aba36450f16fd3551bc303ce
3
+ metadata.gz: 778687330e4ff0e83f8cf02ea27808b9e7197c625312611c0dd004d17627a29e
4
+ data.tar.gz: f3ddf11ab50accd31b5bd3a4b41899a781f4ac04555739d1e65eff3e884b8b38
5
5
  SHA512:
6
- metadata.gz: 0ae12198df3991bccc1a17a983050457b2483d33f40078d5bd4c99a2d475d5fbdb84a2510c0beb0db65c9ebb4e431e12115ab2830c0cd5901a75cea3dfd7f75a
7
- data.tar.gz: 0aed27beca07c98b513a092345b125129999f5ec0180ee9df0c78b39348c73be71ef0ad78448a644733f8966636f8059ec43aa248b247e66fa7cfda2cb3bdae8
6
+ metadata.gz: 7b2e8b370f301aeda40bef4e1a66c16dc0351b245a5c967341a22e1ab05830e4e11d5cd1de2de2e38a246cbd5fb492e27d8e906770d4484707512a34e9d8430c
7
+ data.tar.gz: 3471e795e4942858134083a06f632da5afebb69c60a87001631486c79ecb81dc3f90e5c5cbdf5eb408c48ca125f47055ca8c08c0af945324e1043aa7996b104e
data/README.md CHANGED
@@ -1,12 +1,16 @@
1
1
  # Trilogy Adapter
2
2
 
3
- Active Record database adapter for [Trilogy](https://github.com/github/trilogy)
3
+ Active Record database adapter for [Trilogy](https://github.com/trilogy-libraries/trilogy)
4
+
5
+ This gem offers Trilogy support for versions of ActiveRecord prior to 7.1. Currently supports:
6
+
7
+ - Rails v7.0.x
4
8
 
5
9
  ## Requirements
6
10
 
7
11
  - [Ruby](https://www.ruby-lang.org) 2.7 or higher
8
- - [Active Record](https://github.com/rails/rails) 7.1 or higher
9
- - [Trilogy](https://github.com/github/trilogy) 2.1.1 or higher
12
+ - [Active Record](https://github.com/rails/rails) 7.0.x
13
+ - [Trilogy](https://github.com/trilogy-libraries/trilogy) 2.4.0 or higher
10
14
 
11
15
  ## Setup
12
16
 
@@ -15,6 +15,9 @@ module ActiveRecord
15
15
  ) # :nodoc:
16
16
  private_constant :READ_QUERY
17
17
 
18
+ HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
19
+ private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
20
+
18
21
  def write_query?(sql) # :nodoc:
19
22
  !READ_QUERY.match?(sql)
20
23
  rescue ArgumentError # Invalid encoding
@@ -30,13 +33,6 @@ module ActiveRecord
30
33
  MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
31
34
  end
32
35
 
33
- def execute(sql, name = nil, async: false)
34
- sql = transform_query(sql)
35
- check_if_write_query(sql)
36
-
37
- raw_execute(sql, name, async: async)
38
- end
39
-
40
36
  def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false)
41
37
  result = execute(sql, name, async: async)
42
38
  ActiveRecord::Result.new(result.fields, result.to_a)
@@ -55,6 +51,10 @@ module ActiveRecord
55
51
 
56
52
  alias :exec_update :exec_delete
57
53
 
54
+ def high_precision_current_timestamp
55
+ HIGH_PRECISION_CURRENT_TIMESTAMP
56
+ end
57
+
58
58
  private
59
59
  def last_inserted_id(result)
60
60
  result.last_insert_id
@@ -63,8 +63,6 @@ module ActiveRecord
63
63
 
64
64
  ER_BAD_DB_ERROR = 1049
65
65
  ER_ACCESS_DENIED_ERROR = 1045
66
- ER_CONN_HOST_ERROR = 2003
67
- ER_UNKNOWN_HOST_ERROR = 2005
68
66
 
69
67
  ADAPTER_NAME = "Trilogy"
70
68
 
@@ -82,7 +80,7 @@ module ActiveRecord
82
80
  def new_client(config)
83
81
  config[:ssl_mode] = parse_ssl_mode(config[:ssl_mode]) if config[:ssl_mode]
84
82
  ::Trilogy.new(config)
85
- rescue Trilogy::DatabaseError => error
83
+ rescue Trilogy::ConnectionError, Trilogy::ProtocolError => error
86
84
  raise translate_connect_error(config, error)
87
85
  end
88
86
 
@@ -102,14 +100,24 @@ module ActiveRecord
102
100
  ActiveRecord::NoDatabaseError.db_error(config[:database])
103
101
  when ER_ACCESS_DENIED_ERROR
104
102
  ActiveRecord::DatabaseConnectionError.username_error(config[:username])
105
- when ER_CONN_HOST_ERROR, ER_UNKNOWN_HOST_ERROR
106
- ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
107
103
  else
108
- ActiveRecord::ConnectionNotEstablished.new(error.message)
104
+ if error.message.match?(/TRILOGY_DNS_ERROR/)
105
+ ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
106
+ else
107
+ ActiveRecord::ConnectionNotEstablished.new(error.message)
108
+ end
109
109
  end
110
110
  end
111
111
  end
112
112
 
113
+ def initialize(connection, logger, connection_options, config)
114
+ super
115
+ # Ensure that we're treating prepared_statements in the same way that Rails 7.1 does
116
+ @prepared_statements = self.class.type_cast_config_to_boolean(
117
+ @config.fetch(:prepared_statements) { default_prepared_statements }
118
+ )
119
+ end
120
+
113
121
  def supports_json?
114
122
  !mariadb? && database_version >= "5.7.8"
115
123
  end
@@ -135,12 +143,53 @@ module ActiveRecord
135
143
  end
136
144
 
137
145
  def quote_string(string)
138
- with_raw_connection(allow_retry: true, uses_transaction: false) do |conn|
146
+ with_trilogy_connection(allow_retry: true, uses_transaction: false) do |conn|
139
147
  conn.escape(string)
140
148
  end
141
149
  end
142
150
 
151
+ def connect!
152
+ verify!
153
+ self
154
+ end
155
+
156
+ def reconnect!
157
+ @lock.synchronize do
158
+ disconnect!
159
+ connect
160
+ rescue StandardError => original_exception
161
+ raise translate_exception_class(original_exception, nil, nil)
162
+ end
163
+ end
164
+
165
+ def with_trilogy_connection(uses_transaction: true, **_kwargs)
166
+ @lock.synchronize do
167
+ verify!
168
+ materialize_transactions if uses_transaction
169
+ yield connection
170
+ end
171
+ end
172
+
173
+ def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: true)
174
+ mark_transaction_written_if_write(sql)
175
+
176
+ log(sql, name, async: async) do
177
+ with_trilogy_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
178
+ sync_timezone_changes(conn)
179
+ conn.query(sql)
180
+ end
181
+ end
182
+ end
183
+
184
+ def execute(sql, name = nil, **kwargs)
185
+ sql = transform_query(sql)
186
+ check_if_write_query(sql)
187
+ super
188
+ end
189
+
143
190
  def active?
191
+ return false if connection&.closed?
192
+
144
193
  connection&.ping || false
145
194
  rescue ::Trilogy::Error
146
195
  false
@@ -149,6 +198,7 @@ module ActiveRecord
149
198
  alias reset! reconnect!
150
199
 
151
200
  def disconnect!
201
+ super
152
202
  unless connection.nil?
153
203
  connection.close
154
204
  self.connection = nil
@@ -159,23 +209,6 @@ module ActiveRecord
159
209
  self.connection = nil
160
210
  end
161
211
 
162
- def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: true)
163
- mark_transaction_written_if_write(sql)
164
-
165
- log(sql, name, async: async) do
166
- with_raw_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
167
- # Sync any changes since connection last established.
168
- if default_timezone == :local
169
- conn.query_flags |= ::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
170
- else
171
- conn.query_flags &= ~::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
172
- end
173
-
174
- conn.query(sql)
175
- end
176
- end
177
- end
178
-
179
212
  def each_hash(result)
180
213
  return to_enum(:each_hash, result) unless block_given?
181
214
 
@@ -198,13 +231,7 @@ module ActiveRecord
198
231
  end
199
232
 
200
233
  private
201
- def connection
202
- @raw_connection
203
- end
204
-
205
- def connection=(conn)
206
- @raw_connection = conn
207
- end
234
+ attr_accessor :connection
208
235
 
209
236
  def connect
210
237
  self.connection = self.class.new_client(@config)
@@ -212,15 +239,80 @@ module ActiveRecord
212
239
 
213
240
  def reconnect
214
241
  connection&.close
242
+ self.connection = nil
215
243
  connect
216
244
  end
217
245
 
246
+ def sync_timezone_changes(conn)
247
+ # Sync any changes since connection last established.
248
+ if ActiveRecord.default_timezone == :local
249
+ conn.query_flags |= ::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
250
+ else
251
+ conn.query_flags &= ~::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
252
+ end
253
+ end
254
+
255
+ def execute_batch(statements, name = nil)
256
+ statements = statements.map { |sql| transform_query(sql) }
257
+ combine_multi_statements(statements).each do |statement|
258
+ with_trilogy_connection do |conn|
259
+ raw_execute(statement, name)
260
+ conn.next_result while conn.more_results_exist?
261
+ end
262
+ end
263
+ end
264
+
265
+ def multi_statements_enabled?
266
+ !!@config[:multi_statement]
267
+ end
268
+
269
+ def with_multi_statements
270
+ if multi_statements_enabled?
271
+ return yield
272
+ end
273
+
274
+ with_trilogy_connection do |conn|
275
+ conn.set_server_option(Trilogy::SET_SERVER_MULTI_STATEMENTS_ON)
276
+
277
+ yield
278
+ ensure
279
+ conn.set_server_option(Trilogy::SET_SERVER_MULTI_STATEMENTS_OFF)
280
+ end
281
+ end
282
+
283
+ def combine_multi_statements(total_sql)
284
+ total_sql.each_with_object([]) do |sql, total_sql_chunks|
285
+ previous_packet = total_sql_chunks.last
286
+ if max_allowed_packet_reached?(sql, previous_packet)
287
+ total_sql_chunks << +sql
288
+ else
289
+ previous_packet << ";\n"
290
+ previous_packet << sql
291
+ end
292
+ end
293
+ end
294
+
295
+ def max_allowed_packet_reached?(current_packet, previous_packet)
296
+ if current_packet.bytesize > max_allowed_packet
297
+ raise ActiveRecordError,
298
+ "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
299
+ elsif previous_packet.nil?
300
+ true
301
+ else
302
+ (current_packet.bytesize + previous_packet.bytesize + 2) > max_allowed_packet
303
+ end
304
+ end
305
+
306
+ def max_allowed_packet
307
+ @max_allowed_packet ||= show_variable("max_allowed_packet")
308
+ end
309
+
218
310
  def full_version
219
311
  schema_cache.database_version.full_version_string
220
312
  end
221
313
 
222
314
  def get_full_version
223
- with_raw_connection(allow_retry: true, uses_transaction: false) do |conn|
315
+ with_trilogy_connection(allow_retry: true, uses_transaction: false) do |conn|
224
316
  conn.server_info[:version]
225
317
  end
226
318
  end
@@ -14,6 +14,10 @@ module TrilogyAdapter
14
14
  # host: "localhost",
15
15
  # database: "demo_development"
16
16
  module Connection
17
+ def trilogy_adapter_class
18
+ ActiveRecord::ConnectionAdapters::TrilogyAdapter
19
+ end
20
+
17
21
  def trilogy_connection(config)
18
22
  configuration = config.dup
19
23
 
@@ -31,7 +35,7 @@ module TrilogyAdapter
31
35
  0
32
36
  ]
33
37
 
34
- ActiveRecord::ConnectionAdapters::TrilogyAdapter.new nil, logger, options, configuration
38
+ trilogy_adapter_class.new nil, logger, options, configuration
35
39
  end
36
40
  end
37
41
  end
@@ -3,43 +3,43 @@
3
3
  module TrilogyAdapter
4
4
  module Errors
5
5
  # ServerShutdown will be raised when the database server was shutdown.
6
- class ServerShutdown < ActiveRecord::ConnectionFailed
6
+ class ServerShutdown < ::ActiveRecord::QueryAborted
7
7
  end
8
8
 
9
9
  # ServerLost will be raised when the database connection was lost.
10
- class ServerLost < ActiveRecord::ConnectionFailed
10
+ class ServerLost < ::ActiveRecord::QueryAborted
11
11
  end
12
12
 
13
13
  # ServerGone will be raised when the database connection is gone.
14
- class ServerGone < ActiveRecord::ConnectionFailed
14
+ class ServerGone < ::ActiveRecord::QueryAborted
15
15
  end
16
16
 
17
17
  # BrokenPipe will be raised when a system process connection fails.
18
- class BrokenPipe < ActiveRecord::ConnectionFailed
18
+ class BrokenPipe < ::ActiveRecord::QueryAborted
19
19
  end
20
20
 
21
21
  # SocketError will be raised when Ruby encounters a network error.
22
- class SocketError < ActiveRecord::ConnectionFailed
22
+ class SocketError < ::ActiveRecord::QueryAborted
23
23
  end
24
24
 
25
25
  # ConnectionResetByPeer will be raised when a network connection is closed
26
26
  # outside the sytstem process.
27
- class ConnectionResetByPeer < ActiveRecord::ConnectionFailed
27
+ class ConnectionResetByPeer < ::ActiveRecord::QueryAborted
28
28
  end
29
29
 
30
30
  # ClosedConnection will be raised when the Trilogy encounters a closed
31
31
  # connection.
32
- class ClosedConnection < ActiveRecord::ConnectionFailed
32
+ class ClosedConnection < ::ActiveRecord::QueryAborted
33
33
  end
34
34
 
35
35
  # InvalidSequenceId will be raised when Trilogy ecounters an invalid sequence
36
36
  # id.
37
- class InvalidSequenceId < ActiveRecord::ConnectionFailed
37
+ class InvalidSequenceId < ::ActiveRecord::QueryAborted
38
38
  end
39
39
 
40
40
  # UnexpectedPacket will be raised when Trilogy ecounters an unexpected
41
41
  # response packet.
42
- class UnexpectedPacket < ActiveRecord::ConnectionFailed
42
+ class UnexpectedPacket < ::ActiveRecord::QueryAborted
43
43
  end
44
44
  end
45
45
  end
@@ -37,8 +37,10 @@ module TrilogyAdapter
37
37
  Errors::BrokenPipe.new(message)
38
38
  when SocketError, IOError
39
39
  Errors::SocketError.new(message)
40
- when Errno::ECONNRESET
41
- Errors::ConnectionResetByPeer.new(message)
40
+ when Trilogy::ConnectionError
41
+ if message.match?(/Connection reset by peer/)
42
+ Errors::ConnectionResetByPeer.new(message)
43
+ end
42
44
  end
43
45
  end
44
46
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TrilogyAdapter
4
- VERSION = "2.1.0"
4
+ VERSION = "3.0.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-trilogy-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Engineering
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-26 00:00:00.000000000 Z
11
+ date: 2023-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trilogy
@@ -16,28 +16,34 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.1.1
19
+ version: 2.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 2.1.1
26
+ version: 2.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '7.0'
34
+ - - "<"
32
35
  - !ruby/object:Gem::Version
33
- version: 7.1.a
36
+ version: 7.1a
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '7.0'
44
+ - - "<"
39
45
  - !ruby/object:Gem::Version
40
- version: 7.1.a
46
+ version: 7.1a
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: minitest
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -111,16 +117,15 @@ files:
111
117
  - lib/trilogy_adapter/connection.rb
112
118
  - lib/trilogy_adapter/errors.rb
113
119
  - lib/trilogy_adapter/lost_connection_exception_translator.rb
114
- - lib/trilogy_adapter/rails/dbconsole.rb
115
120
  - lib/trilogy_adapter/railtie.rb
116
121
  - lib/trilogy_adapter/version.rb
117
- homepage: https://github.com/github/activerecord-trilogy-adapter
122
+ homepage: https://github.com/trilogy-libraries/activerecord-trilogy-adapter
118
123
  licenses:
119
124
  - MIT
120
125
  metadata:
121
- source_code_uri: https://github.com/github/activerecord-trilogy-adapter
122
- changelog_uri: https://github.com/github/activerecord-trilogy-adapter/blob/master/CHANGELOG.md
123
- bug_tracker_uri: https://github.com/github/activerecord-trilogy-adapter/issues
126
+ source_code_uri: https://github.com/trilogy-libraries/activerecord-trilogy-adapter
127
+ changelog_uri: https://github.com/trilogy-libraries/activerecord-trilogy-adapter/blob/master/CHANGELOG.md
128
+ bug_tracker_uri: https://github.com/trilogy-libraries/activerecord-trilogy-adapter/issues
124
129
  post_install_message:
125
130
  rdoc_options: []
126
131
  require_paths:
@@ -139,5 +144,5 @@ requirements: []
139
144
  rubygems_version: 3.2.33
140
145
  signing_key:
141
146
  specification_version: 4
142
- summary: Active Record adapter for https://github.com/github/trilogy.
147
+ summary: Active Record adapter for https://github.com/trilogy-libraries/trilogy.
143
148
  test_files: []
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TrilogyAdapter
4
- module Rails
5
- module DBConsole
6
- class AdapterAdapter < SimpleDelegator
7
- def adapter
8
- "mysql"
9
- end
10
- end
11
-
12
- def db_config
13
- if super.adapter == "trilogy"
14
- AdapterAdapter.new(super)
15
- else
16
- super
17
- end
18
- end
19
- end
20
- end
21
- end