diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 00edf89..d0a06b7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,14 +10,15 @@ jobs: strategy: matrix: ruby: - - '3.0' - - '3.1' - '3.2' - '3.3' + - '3.4' + - '4.0' rails: - - '6.1' - - '7.0' - '7.1' + - '7.2' + - '8.0' + - '8.1' runs-on: ubuntu-22.04 name: RSpec (Rails ${{ matrix.rails }}) (Ruby ${{ matrix.ruby }}) diff --git a/.gitignore b/.gitignore index eb10a5b..4579abf 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ gemfiles/*.lock .env.local +*.gem +/.claude diff --git a/Appraisals b/Appraisals index b85fe68..2633c7d 100644 --- a/Appraisals +++ b/Appraisals @@ -1,11 +1,15 @@ -appraise "rails-6.1" do - gem "rails", "~> 6.1" +appraise "rails-7.1" do + gem "rails", "~> 7.1.0" end -appraise "rails-7.0" do - gem "rails", "~> 7.0" +appraise "rails-7.2" do + gem "rails", "~> 7.2.0" end -appraise "rails-7.1" do - gem "rails", "~> 7.1" +appraise "rails-8.0" do + gem "rails", "~> 8.0.0" +end + +appraise "rails-8.1" do + gem "rails", "~> 8.1.0" end diff --git a/Dockerfile b/Dockerfile index fb8c4cb..ca8c75b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.0 +FROM ruby:3.4 WORKDIR /usr/src/app diff --git a/Gemfile.lock b/Gemfile.lock index 5a641cb..dfd841e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,42 +1,59 @@ PATH remote: . specs: - sql_enum (1.0.0) - activerecord (>= 6.1.0) - activesupport (>= 6.1.0) + sql_enum (2.0.0) + activerecord (>= 7.1.0) + activesupport (>= 7.1.0) mysql2 GEM remote: https://rubygems.org/ specs: - activemodel (7.0.8) - activesupport (= 7.0.8) - activerecord (7.0.8) - activemodel (= 7.0.8) - activesupport (= 7.0.8) - activesupport (7.0.8) - concurrent-ruby (~> 1.0, >= 1.0.2) + activemodel (8.1.2) + activesupport (= 8.1.2) + activerecord (8.1.2) + activemodel (= 8.1.2) + activesupport (= 8.1.2) + timeout (>= 0.4.0) + activesupport (8.1.2) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) appraisal (2.5.0) bundler rake thor (>= 0.14.0) awesome_print (1.9.2) - concurrent-ruby (1.2.3) + base64 (0.3.0) + bigdecimal (4.0.1) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) debug (1.9.1) irb (~> 1.10) reline (>= 0.3.8) diff-lcs (1.5.0) + drb (2.2.3) i18n (1.14.1) concurrent-ruby (~> 1.0) io-console (0.7.2) irb (1.11.1) rdoc reline (>= 0.4.2) - minitest (5.21.2) + json (2.18.1) + logger (1.7.0) + minitest (6.0.1) + prism (~> 1.5) mysql2 (0.5.5) + prism (1.9.0) psych (5.1.2) stringio rake (13.1.0) @@ -57,10 +74,13 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) rspec-support (3.12.1) + securerandom (0.4.1) stringio (3.1.0) thor (1.3.0) + timeout (0.6.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + uri (1.1.1) PLATFORMS ruby diff --git a/README.md b/README.md index 444c070..c27c2b6 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ Enables usage of native sql enums with ActiveRecord ## NOTE -Version 1.0 of this is compatible with Rails 7 and above. +Version 2.0 of this gem requires Rails 7.1+ and Ruby 3.2+. -For Rails versions below Rails 7, use version 0.4 +For Rails 7.0 and 7.1, use version 1.0. For Rails versions below 7, use version 0.4. ## Installation @@ -30,7 +30,7 @@ Or install it yourself as: Use a part of table definition: ```ruby -class CreateUsers < ActiveRecord::Migration[5.1] +class CreateUsers < ActiveRecord::Migration[7.1] def change create_table :users do |t| t.enum :status, limit: [:active, :pending, :inactive], default: :active diff --git a/gemfiles/rails_7.1.gemfile b/gemfiles/rails_7.1.gemfile index 1d906c3..35a0ba3 100644 --- a/gemfiles/rails_7.1.gemfile +++ b/gemfiles/rails_7.1.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "rails", "~> 7.1" +gem "rails", "~> 7.1.0" gemspec path: "../" diff --git a/gemfiles/rails_6.1.gemfile b/gemfiles/rails_7.2.gemfile similarity index 79% rename from gemfiles/rails_6.1.gemfile rename to gemfiles/rails_7.2.gemfile index c34b486..92cc2b2 100644 --- a/gemfiles/rails_6.1.gemfile +++ b/gemfiles/rails_7.2.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "rails", "~> 6.1" +gem "rails", "~> 7.2.0" gemspec path: "../" diff --git a/gemfiles/rails_7.0.gemfile b/gemfiles/rails_8.0.gemfile similarity index 79% rename from gemfiles/rails_7.0.gemfile rename to gemfiles/rails_8.0.gemfile index 9d2735b..3b3765b 100644 --- a/gemfiles/rails_7.0.gemfile +++ b/gemfiles/rails_8.0.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "rails", "~> 7.0" +gem "rails", "~> 8.0.0" gemspec path: "../" diff --git a/gemfiles/rails_8.1.gemfile b/gemfiles/rails_8.1.gemfile new file mode 100644 index 0000000..cedb65f --- /dev/null +++ b/gemfiles/rails_8.1.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rails", "~> 8.1.0" + +gemspec path: "../" diff --git a/lib/active_record/connection_adapters/abstract_mysql.rb b/lib/active_record/connection_adapters/abstract_mysql.rb index b5d0841..6795572 100644 --- a/lib/active_record/connection_adapters/abstract_mysql.rb +++ b/lib/active_record/connection_adapters/abstract_mysql.rb @@ -9,39 +9,10 @@ def register_enum_type(mapping) end end - # In Rails 6.1, registering the enum type is an instance method and is - # done on initialization, In Rails 7.0 it is a class method and - # the registration happens when the class is loaded. So, in Rails 6.1, - # we can override the `initialize_type_map` method to register the enum - # but in Rails 7.1, we need to call register_enum_type explicitly. - - if SqlEnum.rails_version_match?("6.1") - module SqlEnumMapper - def initialize_type_map(m = type_map) - super(m) - AbstractMysqlAdapter.register_enum_type(m) - end - end - - ActiveRecord::ConnectionAdapters::Mysql2Adapter.prepend(SqlEnumMapper) - end - - - if SqlEnum.rails_version_match?("7.0") - [ - ActiveRecord::ConnectionAdapters::Mysql2Adapter::TYPE_MAP, - ActiveRecord::ConnectionAdapters::Mysql2Adapter::TYPE_MAP_WITH_BOOLEAN - ].each do |m| - AbstractMysqlAdapter.register_enum_type(m) - end - end - - # Rails 7.1 drops the TYPE_MAP_WITH_BOOLEAN constant - if SqlEnum.rails_version_match?("7.1") - AbstractMysqlAdapter.register_enum_type( - ActiveRecord::ConnectionAdapters::Mysql2Adapter::TYPE_MAP - ) - end + # Rails 7.1+ uses a single TYPE_MAP constant on the adapter class + AbstractMysqlAdapter.register_enum_type( + ActiveRecord::ConnectionAdapters::Mysql2Adapter::TYPE_MAP + ) end end end diff --git a/lib/active_record/connection_adapters/mysql2.rb b/lib/active_record/connection_adapters/mysql2.rb index 79ebd48..c5f427a 100644 --- a/lib/active_record/connection_adapters/mysql2.rb +++ b/lib/active_record/connection_adapters/mysql2.rb @@ -7,16 +7,17 @@ def native_database_types self.class::NATIVE_DATABASE_TYPES.merge(enum: {name: "enum"}) end - def type_to_sql_with_enum(type, limit: nil, precision: nil, scale: nil, unsigned: nil, **) - if type.to_sym == :enum - "#{type}(#{limit.map{|n| "'#{n}'"}.join(",")})" - else - type_to_sql_without_enum(type, limit: limit, precision: precision, scale: scale, unsigned: unsigned) + module SqlEnumTypeToSql + def type_to_sql(type, limit: nil, **) + if type.to_sym == :enum + "#{type}(#{limit.map { |n| "'#{n}'" }.join(",")})" + else + super + end end end - alias_method :type_to_sql_without_enum, :type_to_sql - alias_method :type_to_sql, :type_to_sql_with_enum + prepend SqlEnumTypeToSql end end end diff --git a/lib/sql_enum.rb b/lib/sql_enum.rb index 792e215..879521a 100644 --- a/lib/sql_enum.rb +++ b/lib/sql_enum.rb @@ -7,10 +7,6 @@ def self.configure self.configuration ||= Configuration.new yield(configuration) end - - def self.rails_version_match?(version_string) - ActiveSupport.version.to_s.start_with?(version_string) - end end require 'active_record' diff --git a/lib/sql_enum/class_methods.rb b/lib/sql_enum/class_methods.rb index 890991f..f15d83a 100644 --- a/lib/sql_enum/class_methods.rb +++ b/lib/sql_enum/class_methods.rb @@ -13,11 +13,20 @@ def sql_enum(column_name, options = {}) suffix = options.fetch(:_suffix, !!SqlEnum.configuration&.default_suffix) # Define enum using Rails enum - enum(column_name => values_map, _prefix: prefix, _suffix: suffix) + enum(column_name, values_map, prefix: prefix, suffix: suffix) # Override reader to return symbols - type_definition = ->(subtype) { EnumType.new(attr, send(column_name.to_s.pluralize), subtype) } - attribute(column_name, &type_definition) + col_name = column_name.to_s + enum_type = ->(subtype) do + subtype = subtype.subtype if ActiveRecord::Enum::EnumType === subtype + EnumType.new(col_name, send(col_name.pluralize), subtype) + end + + if respond_to?(:decorate_attributes, true) + decorate_attributes([col_name]) { |_name, subtype| enum_type.call(subtype) } + else + attribute(column_name, &enum_type) + end prefix_str = format_affix(column_name, prefix, suffix: '_') suffix_str = format_affix(column_name, suffix, prefix: '_') diff --git a/lib/sql_enum/enum_column.rb b/lib/sql_enum/enum_column.rb index 786951d..4294c1c 100644 --- a/lib/sql_enum/enum_column.rb +++ b/lib/sql_enum/enum_column.rb @@ -9,15 +9,15 @@ def values private def schema_values - ActiveRecord::Base.connection.exec_query(schema_values_query).rows.dig(0, 0) + if ActiveRecord::Base.respond_to?(:with_connection) + ActiveRecord::Base.with_connection { |conn| conn.exec_query(schema_values_query).rows.dig(0, 0) } + else + ActiveRecord::Base.connection.exec_query(schema_values_query).rows.dig(0, 0) + end end def database_name - if ActiveRecord::Base.respond_to?(:connection_db_config) - ActiveRecord::Base.connection_db_config.configuration_hash[:database] - else - ActiveRecord::Base.connection_config.values_at(:database, :database_name).find(&:present?) - end + ActiveRecord::Base.connection_db_config.configuration_hash[:database] end def schema_values_query diff --git a/lib/sql_enum/version.rb b/lib/sql_enum/version.rb index b58f273..5666529 100644 --- a/lib/sql_enum/version.rb +++ b/lib/sql_enum/version.rb @@ -1,3 +1,3 @@ module SqlEnum - VERSION = "1.0.0" + VERSION = "2.0.0" end diff --git a/sql_enum-1.0.0.gem b/sql_enum-1.0.0.gem new file mode 100644 index 0000000..653d457 Binary files /dev/null and b/sql_enum-1.0.0.gem differ diff --git a/sql_enum.gemspec b/sql_enum.gemspec index 686fc63..50e1269 100644 --- a/sql_enum.gemspec +++ b/sql_enum.gemspec @@ -25,9 +25,11 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] + spec.required_ruby_version = ">= 3.2.0" + spec.add_dependency "mysql2" - spec.add_dependency "activesupport", ">= 6.1.0" - spec.add_dependency "activerecord", ">= 6.1.0" + spec.add_dependency "activesupport", ">= 7.1.0" + spec.add_dependency "activerecord", ">= 7.1.0" spec.add_development_dependency "appraisal" spec.add_development_dependency "awesome_print"