Class: Exwiw::Adapter::MysqlClient
- Inherits:
-
Object
- Object
- Exwiw::Adapter::MysqlClient
- Defined in:
- lib/exwiw/adapter/mysql_client.rb
Overview
Thin wrapper over the MySQL driver so MysqlAdapter does not care whether the host app ships the ‘mysql2` gem or the `trilogy` gem. exwiw only runs simple SELECT / EXPLAIN queries, so both drivers are normalized to the same shape: rows as arrays of String|nil plus the column names.
Values are normalized to strings to match mysql2’s ‘cast: false` mode, where every column comes back as a raw string and is quoted uniformly downstream (see MysqlAdapter#escape_value). mysql2 already returns strings in that mode; trilogy always casts to Ruby types (Integer / BigDecimal / Time / Date / …), so its values are stringified back into the same literal form here.
Defined Under Namespace
Classes: Result
Constant Summary collapse
- DRIVERS =
[:mysql2, :trilogy].freeze
Instance Attribute Summary collapse
-
#driver ⇒ Object
readonly
Returns the value of attribute driver.
Class Method Summary collapse
-
.detect_driver ⇒ Object
Pick the available driver, preferring mysql2 (exwiw’s historical default).
-
.stringify_value(value) ⇒ Object
Render a driver-returned value as the raw string mysql2’s ‘cast: false` would have produced, so trilogy’s typed values quote identically.
Instance Method Summary collapse
-
#initialize(connection_config, driver: nil) ⇒ MysqlClient
constructor
‘driver:` is mainly a test seam to force a specific driver; in normal use it is auto-detected.
-
#query(sql) ⇒ Result
Fields (Array<String>) and rows (Array<Array<String|nil>>).
Constructor Details
#initialize(connection_config, driver: nil) ⇒ MysqlClient
‘driver:` is mainly a test seam to force a specific driver; in normal use it is auto-detected.
83 84 85 86 87 |
# File 'lib/exwiw/adapter/mysql_client.rb', line 83 def initialize(connection_config, driver: nil) @connection_config = connection_config @driver = (driver || self.class.detect_driver).to_sym ensure_driver_loaded! end |
Instance Attribute Details
#driver ⇒ Object (readonly)
Returns the value of attribute driver.
79 80 81 |
# File 'lib/exwiw/adapter/mysql_client.rb', line 79 def driver @driver end |
Class Method Details
.detect_driver ⇒ Object
Pick the available driver, preferring mysql2 (exwiw’s historical default). require returns false when already loaded, so this is safe to call repeatedly.
Set EXWIW_MYSQL_DRIVER=trilogy to force the pure-Ruby trilogy driver. This is useful when the mysql2 gem is linked against a libmysqlclient that can no longer load the server’s auth plugin (e.g. MySQL 9.x client dropped the ‘mysql_native_password` plugin .so, raising “Authentication plugin ’mysql_native_password’ cannot be loaded” on connect).
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/exwiw/adapter/mysql_client.rb', line 31 def self.detect_driver forced = ENV['EXWIW_MYSQL_DRIVER'] if forced && !forced.empty? sym = forced.to_sym unless DRIVERS.include?(sym) raise ArgumentError, "EXWIW_MYSQL_DRIVER must be one of #{DRIVERS.join(', ')}, got #{forced.inspect}." end return sym end require 'mysql2' :mysql2 rescue LoadError begin require 'trilogy' :trilogy rescue LoadError raise LoadError, "exwiw needs the 'mysql2' or 'trilogy' gem to connect to MySQL. " \ "Add `gem \"mysql2\"` (or `gem \"trilogy\"`) to your Gemfile." end end |
.stringify_value(value) ⇒ Object
Render a driver-returned value as the raw string mysql2’s ‘cast: false` would have produced, so trilogy’s typed values quote identically.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/exwiw/adapter/mysql_client.rb', line 57 def self.stringify_value(value) case value when nil then nil when String then value when Time # Emit fractional seconds only when present. A Time can't tell us the # column's declared precision, so a zero fraction on a DATETIME(6) # column comes out as "...:00" here whereas mysql2's `cast: false` # echoes the raw "...:00.000000"; both re-insert to the same instant. value.nsec.zero? ? value.strftime('%Y-%m-%d %H:%M:%S') : value.strftime('%Y-%m-%d %H:%M:%S.%6N') when Date then value.strftime('%Y-%m-%d') when true then '1' when false then '0' else if defined?(BigDecimal) && value.is_a?(BigDecimal) value.to_s('F') else value.to_s end end end |
Instance Method Details
#query(sql) ⇒ Result
Returns fields (Array<String>) and rows (Array<Array<String|nil>>).
91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/exwiw/adapter/mysql_client.rb', line 91 def query(sql) case @driver when :mysql2 res = raw.query(sql, cast: false, as: :array) Result.new(res.fields, res.to_a) when :trilogy res = raw.query(sql) rows = res.rows.map { |row| row.map { |value| self.class.stringify_value(value) } } Result.new(res.fields, rows) else raise "Unsupported MySQL driver: #{@driver.inspect}" end end |