Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveRecord >= 6.1 compatibility #61

Merged
merged 11 commits into from
Nov 4, 2021
Merged

Conversation

acroos
Copy link
Contributor

@acroos acroos commented Nov 3, 2021

Description

Some method signatures changed (somewhat recently?) that started causing errors with the methods we've redefined around adding and removing indexes. We need to use the new method signatures so we're compatible with all versions.

Fixes #60
Fixes #59

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Manually run add_index and remove_index migrations on test ActiveRecord app
  • Add more specs

Checklist:

  • My code follows the style guidelines set by rubocop
  • I have performed a self-review of my own code
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

@acroos acroos added the bug Something isn't working label Nov 3, 2021
@acroos acroos self-assigned this Nov 3, 2021
@acroos acroos requested a review from grdw November 3, 2021 13:29
@acroos acroos force-pushed the fix/activerecord-6-1-compatibility branch 2 times, most recently from d874d66 to a9d7925 Compare November 3, 2021 13:33
@acroos acroos force-pushed the fix/activerecord-6-1-compatibility branch from a9d7925 to c303ea7 Compare November 3, 2021 18:36
@acroos
Copy link
Contributor Author

acroos commented Nov 3, 2021

ok @grdw this is finally ready!

@@ -43,4 +45,4 @@ jobs:
- name: Run rubocop
run: bundle exec rake rubocop
- name: Run tests
run: bundle exec rake spec
run: bundle exec --gemfile ${{ matrix.gemfile }} rspec
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes 100% sure that the gems used are the ones in the specified Gemfile (even though they were the ones installed in a previous step)

Metrics/BlockLength:
Exclude:
- spec/**/*_spec.rb

Metrics/ClassLength:
CountAsOne:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copying some common styles I use, I tend to find the default strictness to be a bit of a headache

@@ -1,5 +1,8 @@
# CHANGELOG

## 0.3.0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

went with a minor bump because (1) we're still at a 0. release so no rules! and (2) this fixes core functionality for a number of significant usages

@@ -0,0 +1,19 @@
#!/bin/bash
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just for testing locally. it won't try all the ruby versions, but at least it'll go through each ActiveRecord version. it's much more likely that we have a bug specific to an AR version than a ruby version

@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path(__dir__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|doc)/}) }
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|doc|bin)/}) }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no reason to have the test script and console included in the packaged gem

end
spec.require_paths = ['lib']

spec.add_dependency 'activerecord', '>= 5'
spec.add_dependency 'activerecord', '>= 5', '< 6.2'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

starting to test on 7.0 alpha already, but I didn't want to include it in here yet

index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
execute "ALTER TABLE #{quote_table_name(table_name)} ADD #{index_type} INDEX #{quote_column_name(index_name)} (#{index_columns})#{index_options}" # rubocop:disable Layout/LineLength
end
if Gem.loaded_specs['activerecord'].version >= Gem::Version.new('6.1')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if there's a prettier way of achieving this, I'm all ears. this was an easy solution that seems pretty simple to follow

Copy link
Member

@grdw grdw Nov 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are multiple ways of making this prettier:

Splitting into modules:

# in  lib/active_record/connection_adapters/mysql2_ghost_adapter/indexes_six.rb
module IndexesSix
  def add_index(....)
  end
end

# in  lib/active_record/connection_adapters/mysql2_ghost_adapter/indexes_five.rb
module IndexesFive
  def add_index(....)
  end
end

# in lib/active_record/connection_adapters/mysql2_ghost_adapter.rb
module ConnectionAdapters
    class Mysql2GhostAdapter < Mysql2Adapter
      if Gem.loaded_specs['activerecord'].version >= Gem::Version.new('6.1')
        include Mysql2GhostAdapter::IndexesSix
      else
        include Mysql2GhostAdapter::IndexesFive
      end
   end
end

Another way would be dynamically including a module based on the version:

version = if Gem.loaded_specs['activerecord'].version >= Gem::Version.new('6.1')
  "Five"
else
  "Six"
end

include const_get("SomeLib::#{version}")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the number of methods is relatively low, I somewhat prefer the existing way to including modules as its easier to navigate. the second approach is nice, though, if we end up needing another conditional. I will make an issue for it as a pattern to consider if we also need 7.0 compatibility (somewhat likely)

@@ -111,6 +144,25 @@ def schema_migration_update?(sql)
INSERT_SCHEMA_MIGRATION_PATTERN =~ sql ||
DROP_SCHEMA_MIGRATION_PATTERN =~ sql
end

def build_add_index_sql(table_name, column_names, index_name, # rubocop:disable Metrics/ParameterLists
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inspired by the ActiveRecord code used to build a CREATE INDEX query (we can't use that because gh-ost only triggers on ALTER TABLE queries

Comment on lines +15 to +16
allow(mysql_client).to receive(:escape).with(table.to_s).and_return(table.to_s)
allow(mysql_client).to receive(:more_results?)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just mocked these because tests started failing on them. I didn't do too much digging into how ActiveRecord is using these return values (other than obviously using the escape method to... escape a string)

Copy link

@larryfox larryfox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know enough about ActiveRecord internals to feel confident in my approval but it looks like good ruby 😅

bin/test_all_versions Outdated Show resolved Hide resolved
@acroos acroos merged commit 61c7b31 into main Nov 4, 2021
@acroos acroos deleted the fix/activerecord-6-1-compatibility branch November 4, 2021 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Not completely compatible with ActiveRecord >= 6.1 Adding an index through ghost_adapter breaks
3 participants