methodmissing-mysqlplus_adapter 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +1 -1
- data/VERSION.yml +1 -1
- data/lib/active_record/connection_adapters/mysqlplus_adapter.rb +2 -2
- data/lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/macro.rb +50 -5
- data/lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/result.rb +2 -2
- data/test/deferrable/macro_test.rb +32 -0
- data/test/helper.rb +11 -6
- data/test/models/mysql_user.rb +3 -0
- data/test/models/mysql_user_info.rb +6 -0
- metadata +5 -3
- data/test/deferrable_test.rb +0 -15
data/README.textile
CHANGED
@@ -82,7 +82,7 @@ Since ActiveRecord 2.1 preloading favors multiple efficient queries to cumbersom
|
|
82
82
|
|
83
83
|
h2. Garbage Collection
|
84
84
|
|
85
|
-
There's some experimental GC patches "available":http://github.com/oldmoe/mysqlplus/tree/with_async_validation - the mysql ruby gem forces GC every 20 queries, that's a guaranteed GC cycle every 5th request for a request with a 4 query overhead.
|
85
|
+
There's some experimental GC patches "available":http://github.com/oldmoe/mysqlplus/tree/with_async_validation - the mysql ruby gem forces GC every 20 queries, that's a guaranteed GC cycle every 5th request for a request with a 4 query overhead.This adapter will automatically detect the presence of those patches and disable the forced GC runs.
|
86
86
|
|
87
87
|
h2. Stability
|
88
88
|
|
data/VERSION.yml
CHANGED
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
begin
|
13
13
|
require_library_or_gem('fastthread')
|
14
|
-
rescue
|
14
|
+
rescue LoadError
|
15
15
|
$stderr.puts "'gem install fastthread' for better performance"
|
16
16
|
end
|
17
17
|
|
@@ -36,7 +36,7 @@ module ActiveRecord
|
|
36
36
|
if skip_logging
|
37
37
|
@connection.c_async_query( sql )
|
38
38
|
else
|
39
|
-
log("(Socket #{socket.to_s}) #{sql}",name) do
|
39
|
+
log("(Socket #{socket.to_s}, Thread #{Thread.current.object_id.to_s}) #{sql}",name) do
|
40
40
|
@connection.c_async_query( sql )
|
41
41
|
end
|
42
42
|
end
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
def install!
|
8
8
|
ActiveRecord::Base.send :extend, SingletonMethods
|
9
9
|
ar_eigenclass::VALID_FIND_OPTIONS << :defer
|
10
|
-
alias_deferred :find, :find_by_sql, :preload_associations
|
10
|
+
alias_deferred :find, :find_by_sql, :preload_associations, :find_every
|
11
11
|
end
|
12
12
|
|
13
13
|
private
|
@@ -35,13 +35,27 @@ module ActiveRecord
|
|
35
35
|
# connection.
|
36
36
|
#
|
37
37
|
# ....
|
38
|
-
# Record.find(:first, :include => [:other
|
38
|
+
# Record.find(:first, :include => [:other, :another], :defer => true)
|
39
39
|
# ....
|
40
40
|
#
|
41
41
|
def preload_associations_with_defer(records, associations, preload_options={})
|
42
|
-
if
|
43
|
-
|
44
|
-
|
42
|
+
if preload_deferred?( associations )
|
43
|
+
associations.delete(:defer)
|
44
|
+
records = [records].flatten.compact.uniq
|
45
|
+
return if records.empty?
|
46
|
+
case associations
|
47
|
+
when Array then associations.each {|association| ActiveRecord::Deferrable::Result.new{ preload_associations_without_defer(records, association, preload_options) } }
|
48
|
+
when Symbol, String then ActiveRecord::Deferrable::Result.new{ preload_one_association(records, associations.to_sym, preload_options) }
|
49
|
+
when Hash then
|
50
|
+
associations.each do |parent, child|
|
51
|
+
raise "parent must be an association name" unless parent.is_a?(String) || parent.is_a?(Symbol)
|
52
|
+
preload_associations(records, parent, preload_options)
|
53
|
+
reflection = reflections[parent]
|
54
|
+
parents = records.map {|record| record.send(reflection.name)}.flatten.compact
|
55
|
+
unless parents.empty?
|
56
|
+
parents.first.class.preload_associations(parents, child)
|
57
|
+
end
|
58
|
+
end
|
45
59
|
end
|
46
60
|
else
|
47
61
|
preload_associations_without_defer(records, associations, preload_options)
|
@@ -91,6 +105,37 @@ module ActiveRecord
|
|
91
105
|
with_scope( { :find => { :defer => true } }, :merge, &block )
|
92
106
|
end
|
93
107
|
|
108
|
+
def find_every_with_defer(options) #:nodoc:
|
109
|
+
include_associations = merge_includes(scope(:find, :include), options[:include])
|
110
|
+
if include_associations.any? && references_eager_loaded_tables?(options)
|
111
|
+
records = find_with_associations(options)
|
112
|
+
else
|
113
|
+
records = find_by_sql(construct_finder_sql(options))
|
114
|
+
if include_associations.any?
|
115
|
+
preload_associations(records, preload_deferred_includes( include_associations, options ))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
records.each { |record| record.readonly! } if options[:readonly]
|
120
|
+
|
121
|
+
records
|
122
|
+
end
|
123
|
+
|
124
|
+
def preload_deferred_includes( include_associations, options ) #:nodoc:
|
125
|
+
options[:defer] ? (Array(include_associations) << :defer) : include_associations
|
126
|
+
end
|
127
|
+
|
128
|
+
def preload_deferred?( associations ) #:nodoc:
|
129
|
+
begin
|
130
|
+
associations.respond_to?(:include?) && associations.include?(:defer)
|
131
|
+
rescue TypeError
|
132
|
+
#failing test cases :
|
133
|
+
# * test_eager_with_valid_association_as_string_not_symbol(EagerAssociationTest) &&
|
134
|
+
# * test_eager_with_invalid_association_reference(EagerAssociationTest)
|
135
|
+
false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
94
139
|
end
|
95
140
|
|
96
141
|
end
|
@@ -15,7 +15,7 @@ module ActiveRecord
|
|
15
15
|
# back in on completion.
|
16
16
|
#
|
17
17
|
def defer!( deferrable )
|
18
|
-
@result = Thread.new( deferrable ) do |deferrable|
|
18
|
+
@result = ::Thread.new( deferrable ) do |deferrable|
|
19
19
|
begin
|
20
20
|
deferrable.call
|
21
21
|
rescue => exception
|
@@ -38,7 +38,7 @@ module ActiveRecord
|
|
38
38
|
# Re-raise any Exceptions from the background Thread.
|
39
39
|
#
|
40
40
|
def validate!
|
41
|
-
raise @_result if @_result.is_a?( Exception )
|
41
|
+
raise @_result if @_result.is_a?( ::Exception )
|
42
42
|
end
|
43
43
|
|
44
44
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../helper"
|
2
|
+
|
3
|
+
Mysqlplus::Test.prepare!
|
4
|
+
|
5
|
+
class MacroTest < ActiveSupport::TestCase
|
6
|
+
|
7
|
+
def teardown
|
8
|
+
ActiveRecord::Base.clear_all_connections!
|
9
|
+
ActiveRecord::Base.establish_connection( Mysqlplus::Test::CONNECTION_SPEC )
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_be_able_to_find_records_in_a_background_thread
|
14
|
+
ActiveRecord::Base.connection_pool.expects(:release_connection).twice
|
15
|
+
assert_equal MysqlUser.find(:first, :defer => true), MysqlUser.find(:first)
|
16
|
+
assert_instance_of MysqlUser, MysqlUser.find(:first, :defer => true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_be_able_to_find_records_by_sql_background_thread
|
20
|
+
ActiveRecord::Base.connection_pool.expects(:release_connection).once
|
21
|
+
assert_equal MysqlUser.find_by_sql("SELECT * FROM mysql.user WHERE User = 'root'", true), MysqlUser.find(:all, :conditions => ['user.User = ?', 'root'])
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_be_able_to_preload_related_records_on_multiple_connections
|
25
|
+
ActiveRecord::Base.connection_pool.expects(:release_connection).twice
|
26
|
+
assert_instance_of MysqlUser, MysqlUser.find( :first, :defer => true, :include => :mysql_user_info)
|
27
|
+
sleep(0.5)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
Thread.list.each{|t| t.join unless t == Thread.main }
|
data/test/helper.rb
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'mocha'
|
2
3
|
require 'active_support'
|
4
|
+
require 'active_support/test_case'
|
3
5
|
require 'activerecord'
|
6
|
+
|
4
7
|
ActiveRecord.load_all!
|
5
8
|
|
6
9
|
module Mysqlplus
|
7
10
|
class Test
|
8
11
|
|
12
|
+
CONNECTION_SPEC = { :adapter => 'mysqlplus',
|
13
|
+
:username => 'root',
|
14
|
+
:database => 'mysql',
|
15
|
+
:pool => 5,
|
16
|
+
:warmup => true }
|
17
|
+
|
9
18
|
MODELS_DIR = "#{File.dirname(__FILE__)}/models".freeze
|
10
19
|
|
11
20
|
class << self
|
@@ -32,17 +41,13 @@ module Mysqlplus
|
|
32
41
|
end
|
33
42
|
|
34
43
|
def test_files
|
35
|
-
glob( "#{File.dirname(__FILE__)}
|
44
|
+
glob( "#{File.dirname(__FILE__)}/**/*_test.rb" )
|
36
45
|
end
|
37
46
|
|
38
47
|
private
|
39
48
|
|
40
49
|
def connect!
|
41
|
-
::ActiveRecord::Base.establish_connection(
|
42
|
-
:username => 'root',
|
43
|
-
:database => 'mysql',
|
44
|
-
:pool => 5,
|
45
|
-
:warmup => true )
|
50
|
+
::ActiveRecord::Base.establish_connection( CONNECTION_SPEC )
|
46
51
|
end
|
47
52
|
|
48
53
|
def require_models
|
data/test/models/mysql_user.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: methodmissing-mysqlplus_adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Lourens Naud\xC3\xA9"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-02-
|
12
|
+
date: 2009-02-09 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -35,10 +35,12 @@ files:
|
|
35
35
|
- test/connections
|
36
36
|
- test/connections/mysqlplus
|
37
37
|
- test/connections/mysqlplus/connection.rb
|
38
|
-
- test/
|
38
|
+
- test/deferrable
|
39
|
+
- test/deferrable/macro_test.rb
|
39
40
|
- test/helper.rb
|
40
41
|
- test/models
|
41
42
|
- test/models/mysql_user.rb
|
43
|
+
- test/models/mysql_user_info.rb
|
42
44
|
has_rdoc: true
|
43
45
|
homepage: http://github.com/methodmissing/mysqplus_adapter
|
44
46
|
post_install_message:
|
data/test/deferrable_test.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/helper"
|
2
|
-
Mysqlplus::Test.prepare!
|
3
|
-
|
4
|
-
class DeferrableTest < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_should_be_able_to_find_records_in_a_background_thread
|
7
|
-
assert_equal MysqlUser.find(:first, :defer => true), MysqlUser.find(:first)
|
8
|
-
assert_instance_of MysqlUser, MysqlUser.find(:first, :defer => true)
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_should_be_able_to_find_records_by_sql_background_thread
|
12
|
-
assert_equal MysqlUser.find_by_sql("SELECT * FROM mysql.user WHERE User = 'root'", true), MysqlUser.find(:all, :conditions => ['user.User = ?', 'root'])
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|