Skip to content

Commit

Permalink
Merge pull request #531 from rails/main
Browse files Browse the repository at this point in the history
Create a new pull request by comparing changes across two branches
  • Loading branch information
GulajavaMinistudio authored Apr 18, 2023
2 parents 1eaa302 + 732a474 commit 8dfabd0
Show file tree
Hide file tree
Showing 95 changed files with 2,890 additions and 209 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ gem "listen", "~> 3.3", require: false
gem "libxml-ruby", platforms: :ruby
gem "connection_pool", require: false
gem "rexml", require: false
gem "msgpack", ">= 1.7.0", require: false

# for railties
gem "bootsnap", ">= 1.4.4", require: false
Expand Down Expand Up @@ -149,6 +150,7 @@ platforms :ruby, :windows do
group :db do
gem "pg", "~> 1.3"
gem "mysql2", "~> 0.5"
gem "trilogy", "~> 2.4"
end
end

Expand Down
5 changes: 4 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ GEM
mixlib-shellout (3.2.7)
chef-utils
mono_logger (1.1.1)
msgpack (1.6.0)
msgpack (1.7.0)
multi_json (1.15.0)
multipart-post (2.2.3)
mustermann (3.0.0)
Expand Down Expand Up @@ -507,6 +507,7 @@ GEM
timeout (0.3.2)
tomlrb (2.0.3)
trailblazer-option (0.1.2)
trilogy (2.4.0)
turbo-rails (1.3.2)
actionpack (>= 6.0.0)
activejob (>= 6.0.0)
Expand Down Expand Up @@ -580,6 +581,7 @@ DEPENDENCIES
minitest-bisect
minitest-ci
minitest-retry
msgpack (>= 1.7.0)
mysql2 (~> 0.5)
nokogiri (>= 1.8.1, != 1.11.0)
pg (~> 1.3)
Expand Down Expand Up @@ -617,6 +619,7 @@ DEPENDENCIES
sucker_punch
tailwindcss-rails
terser (>= 1.1.4)
trilogy (~> 2.4)
turbo-rails
tzinfo-data
w3c_validators (~> 1.3.6)
Expand Down
12 changes: 6 additions & 6 deletions actionpack/lib/action_controller/metal/live.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ module ActionController
# the main thread. Make sure your actions are thread safe, and this shouldn't
# be a problem (don't share state across threads, etc).
#
# Note that Rails includes `Rack::ETag` by default, which will buffer your
# Note that \Rails includes +Rack::ETag+ by default, which will buffer your
# response. As a result, streaming responses may not work properly with Rack
# `2.2.x`, and you may need to implement workarounds in your application.
# You can either set the `ETag` or `Last-Modified` response headers or remove
# `Rack::ETag` from the middleware stack to address this issue.
# 2.2.x, and you may need to implement workarounds in your application.
# You can either set the +ETag+ or +Last-Modified+ response headers or remove
# +Rack::ETag+ from the middleware stack to address this issue.
#
# Here's an example of how you can set the `Last-Modified` header if your Rack
# version is `2.2.x`:
# Here's an example of how you can set the +Last-Modified+ header if your Rack
# version is 2.2.x:
#
# def stream
# response.headers["Content-Type"] = "text/event-stream"
Expand Down
26 changes: 26 additions & 0 deletions actiontext/app/models/action_text/rich_text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ module ActionText
# It also holds all the references to the embedded files, which are stored using Active Storage.
# This record is then associated with the Active Record model the application desires to have
# rich text content using the +has_rich_text+ class method.
#
# class Message < ActiveRecord::Base
# has_rich_text :content
# end
#
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content #=> #<ActionText::RichText....
# message.content.to_s # => "<h1>Funny times!</h1>"
# message.content.to_plain_text # => "Funny times!"
#
class RichText < Record
self.table_name = "action_text_rich_texts"

Expand All @@ -20,10 +30,26 @@ class RichText < Record
self.embeds = body.attachables.grep(ActiveStorage::Blob).uniq if body.present?
end

# Returns the +body+ attribute as plain text with all HTML tags removed.
#
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content.to_plain_text # => "Funny times!"
def to_plain_text
body&.to_plain_text.to_s
end

# Returns the +body+ attribute in a format that makes it editable in the Trix
# editor. Previews of attachments are rendered inline.
#
# content = "<h1>Funny Times!</h1><figure data-trix-attachment='{\"sgid\":\"..."\}'></figure>"
# message = Message.create!(content: content)
# message.content.to_trix_html # =>
# # <div class="trix-content">
# # <h1>Funny times!</h1>
# # <figure data-trix-attachment='{\"sgid\":\"..."\}'>
# # <img src="http://example.org/rails/active_storage/.../funny.jpg">
# # </figure>
# # </div>
def to_trix_html
body&.to_trix_html
end
Expand Down
20 changes: 20 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
* Introduce adapter for Trilogy database client

Trilogy is a MySQL-compatible database client. Rails applications can use Trilogy
by configuring their `config/database.yml`:

```yaml
development:
adapter: trilogy
database: blog_development
pool: 5
```
Or by using the `DATABASE_URL` environment variable:

```ruby
ENV['DATABASE_URL'] # => "trilogy://localhost/blog_development?pool=5"
```

*Adrianna Chang*

* `after_commit` callbacks defined on models now execute in the correct order.

```ruby
Expand Down
1 change: 1 addition & 0 deletions activerecord/RUNNING_UNIT_TESTS.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ example:
Simply executing <tt>bundle exec rake test</tt> is equivalent to the following:

$ bundle exec rake test:mysql2
$ bundle exec rake test:trilogy
$ bundle exec rake test:postgresql
$ bundle exec rake test:sqlite3

Expand Down
13 changes: 7 additions & 6 deletions activerecord/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,24 @@ def run_without_aborting(*tasks)
abort "Errors running #{errors.join(', ')}" if errors.any?
end

desc "Run mysql2, sqlite, and postgresql tests by default"
desc "Run mysql2, trilogy, sqlite, and postgresql tests by default"
task default: :test

task :package

desc "Run mysql2, sqlite, and postgresql tests"
desc "Run mysql2, trilogy, sqlite, and postgresql tests"
task :test do
tasks = defined?(JRUBY_VERSION) ?
%w(test_jdbcmysql test_jdbcsqlite3 test_jdbcpostgresql) :
%w(test_mysql2 test_sqlite3 test_postgresql)
%w(test_mysql2 test_trilogy test_sqlite3 test_postgresql)
run_without_aborting(*tasks)
end

namespace :test do
task :isolated do
tasks = defined?(JRUBY_VERSION) ?
%w(isolated_test_jdbcmysql isolated_test_jdbcsqlite3 isolated_test_jdbcpostgresql) :
%w(isolated_test_mysql2 isolated_test_sqlite3 isolated_test_postgresql)
%w(isolated_test_mysql2 isolated_test_trilogy isolated_test_sqlite3 isolated_test_postgresql)
run_without_aborting(*tasks)
end

Expand All @@ -56,18 +56,19 @@ namespace :db do
task drop: ["db:mysql:drop", "db:postgresql:drop"]
end

%w( mysql2 postgresql sqlite3 sqlite3_mem oracle jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb ).each do |adapter|
%w( mysql2 trilogy postgresql sqlite3 sqlite3_mem oracle jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb ).each do |adapter|
namespace :test do
Rake::TestTask.new(adapter => "#{adapter}:env") do |t|
adapter_short = adapter[/^[a-z0-9]+/]
t.libs << "test"
files = (FileList["test/cases/**/*_test.rb"].reject {
|x| x.include?("/adapters/") || x.include?("/encryption/performance")
} + FileList["test/cases/adapters/#{adapter_short}/**/*_test.rb"])
files = files + FileList["test/cases/adapters/abstract_mysql_adapter/**/*_test.rb"] if adapter == "mysql2"
files = files + FileList["test/cases/adapters/abstract_mysql_adapter/**/*_test.rb"] if ["mysql2", "trilogy"].include?(adapter)

t.test_files = files

t.test_files = files
t.warning = true
t.verbose = true
t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
Expand Down
2 changes: 1 addition & 1 deletion activerecord/bin/test
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Minitest
opts.separator ""
opts.separator "Active Record options:"
opts.on("-a", "--adapter [ADAPTER]",
"Run tests using a specific adapter (sqlite3, sqlite3_mem, mysql2, postgresql)") do |adapter|
"Run tests using a specific adapter (sqlite3, sqlite3_mem, mysql2, trilogy, postgresql)") do |adapter|
ENV["ARCONN"] = adapter.strip
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -684,9 +684,10 @@ def remove_connection_from_thread_cache(conn, owner_thread = conn.owner)
alias_method :release, :remove_connection_from_thread_cache

def new_connection
Base.public_send(db_config.adapter_method, db_config.configuration_hash).tap do |conn|
conn.check_version
end
connection = Base.public_send(db_config.adapter_method, db_config.configuration_hash)
connection.pool = self
connection.check_version
connection
end

# If the pool is not at a <tt>@size</tt> limit, establish new connection. Connecting
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module ActiveRecord
module ConnectionAdapters
module Trilogy
module Errors
# ServerShutdown will be raised when the database server was shutdown.
class ServerShutdown < ActiveRecord::ConnectionFailed
end

# ServerLost will be raised when the database connection was lost.
class ServerLost < ActiveRecord::ConnectionFailed
end

# ServerGone will be raised when the database connection is gone.
class ServerGone < ActiveRecord::ConnectionFailed
end

# BrokenPipe will be raised when a system process connection fails.
class BrokenPipe < ActiveRecord::ConnectionFailed
end

# SocketError will be raised when Ruby encounters a network error.
class SocketError < ActiveRecord::ConnectionFailed
end

# ConnectionResetByPeer will be raised when a network connection is closed
# outside the sytstem process.
class ConnectionResetByPeer < ActiveRecord::ConnectionFailed
end

# ClosedConnection will be raised when the Trilogy encounters a closed
# connection.
class ClosedConnection < ActiveRecord::ConnectionFailed
end

# InvalidSequenceId will be raised when Trilogy ecounters an invalid sequence
# id.
class InvalidSequenceId < ActiveRecord::ConnectionFailed
end

# UnexpectedPacket will be raised when Trilogy ecounters an unexpected
# response packet.
class UnexpectedPacket < ActiveRecord::ConnectionFailed
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

module ActiveRecord
module ConnectionAdapters
module Trilogy
class LostConnectionExceptionTranslator
attr_reader :exception, :message, :error_number

def initialize(exception, message, error_number)
@exception = exception
@message = message
@error_number = error_number
end

def translate
translate_database_exception || translate_ruby_exception || translate_trilogy_exception
end

private
ER_SERVER_SHUTDOWN = 1053
CR_SERVER_LOST = 2013
CR_SERVER_LOST_EXTENDED = 2055
CR_SERVER_GONE_ERROR = 2006

def translate_database_exception
case error_number
when ER_SERVER_SHUTDOWN
Errors::ServerShutdown.new(message)
when CR_SERVER_LOST, CR_SERVER_LOST_EXTENDED
Errors::ServerLost.new(message)
when CR_SERVER_GONE_ERROR
Errors::ServerGone.new(message)
end
end

def translate_ruby_exception
case exception
when Errno::EPIPE
Errors::BrokenPipe.new(message)
when SocketError, IOError
Errors::SocketError.new(message)
when ::Trilogy::ConnectionError
if message.include?("Connection reset by peer")
Errors::ConnectionResetByPeer.new(message)
end
end
end

def translate_trilogy_exception
return unless exception.is_a?(::Trilogy::Error)

case message
when /TRILOGY_CLOSED_CONNECTION/
Errors::ClosedConnection.new(message)
when /TRILOGY_INVALID_SEQUENCE_ID/
Errors::InvalidSequenceId.new(message)
when /TRILOGY_UNEXPECTED_PACKET/
Errors::UnexpectedPacket.new(message)
end
end
end
end
end
end
Loading

0 comments on commit 8dfabd0

Please sign in to comment.