Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: CI

on:
push:
branches:
- master
pull_request:

jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby:
- 2.5
- 2.6
- 2.7
- 3.0
- ruby-head
- jruby
gemfile:
- ar52
- ar60
- ar61
- ar-head
exclude:
- gemfile: ar52
ruby: 3.0
- gemfile: ar52
ruby: ruby-head
continue-on-error: ${{ matrix.ruby == 'jruby' || matrix.ruby == 'ruby-head' || matrix.gemfile == 'ar-head' }}
services:
postgres:
image: postgis/postgis:12-3.1
ports:
- 5432:5432
env:
POSTGRES_HOST_AUTH_METHOD: trust
POSTGRES_DB: makara_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
mysql:
image: mysql:5.7
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: makara_test
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
JRUBY_OPTS: --dev -J-Xmx1024M
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- run: |
bundle exec rake
env:
PGHOST: localhost
PGUSER: postgres
MYSQL_HOST: 127.0.0.1
RAILS_ENV: test

32 changes: 15 additions & 17 deletions lib/makara/connection_wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,28 +95,22 @@ def execute(*args)

# we want to forward all private methods, since we could have kicked out from a private scenario
def method_missing(m, *args, &block)
if _makara_connection.respond_to?(m)
_makara_connection.public_send(m, *args, &block)
else # probably private method
_makara_connection.__send__(m, *args, &block)
end
_makara_connection.send(m, *args, &block)
end

ruby2_keywords :method_missing if Module.private_method_defined?(:ruby2_keywords)

class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def respond_to#{RUBY_VERSION.to_s =~ /^1.8/ ? nil : '_missing'}?(m, include_private = false)
_makara_connection.respond_to?(m, true)
end
RUBY_EVAL

def respond_to_missing?(m, include_private = false)
_makara_connection.respond_to?(m, true)
end

protected

# once the underlying connection is present we must evaluate extra functionality into it.
# all extra functionality is in the format of _makara*
def _makara_decorate_connection(con)

extension = %Q{
extension = <<~RUBY
# the proxy object controlling this connection
def _makara
@_makara
Expand All @@ -140,22 +134,26 @@ def _makara_hijack
def _makara_name
#{@config[:name].inspect}
end
}
RUBY

args = RUBY_VERSION >= "3.0.0" ? "..." : "*args, &block"

# Each method the Makara::Proxy needs to hijack should be redefined in the underlying connection.
# The new definition should allow for the proxy to intercept the invocation if required.
@proxy.class.hijack_methods.each do |meth|
extension << %Q{
def #{meth}(*args, &block)
method_call = RUBY_VERSION >= "3.0.0" ? "public_send(#{meth.inspect}, ...)" : "#{meth}(*args, &block)"

extension << <<~RUBY
def #{meth}(#{args})
_makara_hijack do |proxy|
if proxy
proxy.#{meth}(*args, &block)
proxy.#{method_call}
else
super
end
end
end
}
RUBY
end

# extend the instance
Expand Down
35 changes: 19 additions & 16 deletions lib/makara/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,23 @@ def hijack_method(*method_names)
self.hijack_methods |= method_names

method_names.each do |method_name|
define_method method_name do |*args, &block|
define_method(method_name) do |*args, &block|
appropriate_connection(method_name, args) do |con|
con.send(method_name, *args, &block)
end
end

ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
end
end

def send_to_all(*method_names)
method_names.each do |method_name|
define_method method_name do |*args|
send_to_all method_name, *args
define_method(method_name) do |*args|
send_to_all(method_name, *args)
end

ruby2_keywords method_name if Module.private_method_defined?(:ruby2_keywords)
end
end
end
Expand Down Expand Up @@ -97,27 +101,25 @@ def strategy_class_for(strategy_name)

def method_missing(m, *args, &block)
if METHOD_MISSING_SKIP.include?(m)
return super(m, *args, &block)
return super
end

any_connection do |con|
if con.respond_to?(m)
con.public_send(m, *args, &block)
elsif con.respond_to?(m, true)
con.__send__(m, *args, &block)
if con.respond_to?(m, true)
con.send(m, *args, &block)
else
super(m, *args, &block)
super
end
end
end

class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def respond_to#{RUBY_VERSION.to_s =~ /^1.8/ ? nil : '_missing'}?(m, include_private = false)
any_connection do |con|
con._makara_connection.respond_to?(m, true)
end
ruby2_keywords :method_missing if Module.private_method_defined?(:ruby2_keywords)

def respond_to_missing?(m, include_private = false)
any_connection do |con|
con._makara_connection.respond_to?(m, true)
end
RUBY_EVAL
end

def graceful_connection_for(config)
fake_wrapper = Makara::ConnectionWrapper.new(self, nil, config)
Expand All @@ -138,7 +140,6 @@ def disconnect!

protected


def send_to_all(method_name, *args)
# slave pool must run first to allow for slave-->master failover without running operations on master twice.
handling_an_all_execution(method_name) do
Expand All @@ -147,6 +148,8 @@ def send_to_all(method_name, *args)
end
end

ruby2_keywords :send_to_all if Module.private_method_defined?(:ruby2_keywords)

def any_connection
@master_pool.provide do |con|
yield con
Expand Down
2 changes: 1 addition & 1 deletion makara.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
gem.homepage = "https://github.com/taskrabbit/makara"
gem.licenses = ['MIT']
gem.metadata = {
source_code_uri: 'https://github.com/taskrabbit/makara'
'source_code_uri' => 'https://github.com/taskrabbit/makara'
}

gem.files = `git ls-files`.split($\)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,13 @@

con = connection.slave_pool.connections.first
if (ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR <= 0)
expect(con).to receive(:execute).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
expect(con).to receive(:execute) do |query|
expect(query).to match(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/)
end.once.and_call_original
else
expect(con).to receive(:exec_query).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
expect(con).to receive(:exec_query) do |query|
expect(query).to match(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/)
end.once.and_call_original
end
Test::User.exists?
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,13 @@
con = connection.slave_pool.connections.first
if (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 2) ||
(ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR <= 0)
expect(con).to receive(:exec_no_cache).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
expect(con).to receive(:exec_no_cache) do |query|
expect(query).to match(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/)
end.once.and_call_original
else
expect(con).to receive(:exec_query).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
expect(con).to receive(:exec_query) do |query|
expect(query).to match(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/)
end.once.and_call_original
end
Test::User.exists?
end
Expand Down
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
rescue LoadError
end

if RUBY_VERSION >= "2.7.0"
Warning[:deprecated] = true
end

RSpec.configure do |config|
config.run_all_when_everything_filtered = true
config.filter_run :focus
Expand Down