methodmissing-scrooge 2.2.1 → 2.2.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/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 1
3
- :major: 2
4
2
  :minor: 2
3
+ :patch: 2
4
+ :major: 2
@@ -1,21 +1,30 @@
1
- class Hash
2
-
3
- # TODO: Circumvent this hack
4
- alias_method :update_without_scrooge, :update
5
- def update(other)
6
- update_without_scrooge(other.to_hash)
7
- end
8
-
9
- end
10
-
11
1
  module Scrooge
12
2
  module Optimizations
13
3
  module Columns
14
- class AttributesProxy < Hash
15
-
16
- # Hash like Proxy container for attributes
4
+ class UnscroogedAttributes < Hash
5
+
6
+ # Hash container for attributes when scrooge is not used
17
7
  #
8
+
9
+ def self.setup(record)
10
+ new.replace(record)
11
+ end
12
+
13
+ # Must call to_hash - other hash may be ScroogedAttributes and
14
+ # must be fully fetched if so
15
+ #
16
+ def update(hash)
17
+ super(hash.to_hash)
18
+ end
19
+
20
+ alias_method :merge!, :update
21
+ end
22
+
23
+ class ScroogedAttributes < Hash
18
24
 
25
+ # Hash container for attributes with scrooge monitoring of attribute access
26
+ #
27
+
19
28
  attr_accessor :callsite_signature, :scrooge_columns, :fully_fetched, :klass
20
29
 
21
30
  def self.setup(record, scrooge_columns, klass, callsite_signature)
@@ -88,7 +97,7 @@ module Scrooge
88
97
 
89
98
  def update(hash)
90
99
  @fully_fetched = true
91
- super
100
+ super(hash.to_hash)
92
101
  end
93
102
 
94
103
  alias_method :merge!, :update
@@ -107,17 +116,15 @@ module Scrooge
107
116
 
108
117
  def fetch_remaining!( columns_to_fetch )
109
118
  begin
110
- new_object = fetch_record_with_remaining_columns( columns_to_fetch )
119
+ remaining_attributes = fetch_record_with_remaining_columns( columns_to_fetch )
111
120
  rescue ActiveRecord::RecordNotFound
112
121
  raise ActiveRecord::MissingAttributeError, "scrooge cannot fetch missing attribute(s) #{columns_to_fetch.to_a.join(', ')} because record went away"
113
122
  end
114
- replace(new_object.instance_variable_get(:@attributes).merge(self))
123
+ replace(remaining_attributes.merge(self))
115
124
  end
116
125
 
117
126
  def fetch_record_with_remaining_columns( columns_to_fetch )
118
- @klass.send(:with_exclusive_scope) do
119
- @klass.find(self[@klass.primary_key], :select=>@klass.scrooge_select_sql(columns_to_fetch))
120
- end
127
+ @klass.scrooge_reload(self[@klass.primary_key], columns_to_fetch)
121
128
  end
122
129
 
123
130
  def interesting_for_scrooge?( attr_s )
@@ -51,6 +51,14 @@ module Scrooge
51
51
  Marshal.load(str)
52
52
  end
53
53
 
54
+ # Efficient reloading - get the hash with missing attributes directly from the
55
+ # underlying connection.
56
+ #
57
+ def scrooge_reload( p_key, missing_columns )
58
+ attributes = connection.send( :select, "SELECT #{scrooge_select_sql(missing_columns)} FROM #{quoted_table_name} WHERE #{quoted_table_name}.#{primary_key} = '#{p_key}'" ).first
59
+ attributes ? attributes : raise( ActiveRecord::RecordNotFound )
60
+ end
61
+
54
62
  private
55
63
 
56
64
  # Only scope n-1 rows by default.
@@ -68,10 +76,16 @@ module Scrooge
68
76
  callsite_set = scrooge_callsite(callsite_signature).columns
69
77
  sql = sql.gsub(scrooge_select_regex, "SELECT #{scrooge_select_sql(callsite_set)} FROM")
70
78
  result = connection.select_all(sanitize_sql(sql), "#{name} Load Scrooged").collect! do |record|
71
- instantiate( Scrooge::Optimizations::Columns::AttributesProxy.setup(record, callsite_set, self, callsite_signature) )
79
+ instantiate( Scrooge::Optimizations::Columns::ScroogedAttributes.setup(record, callsite_set, self, callsite_signature) )
72
80
  end
73
81
  end
74
82
 
83
+ def find_by_sql_without_scrooge( sql )
84
+ result = connection.select_all(sanitize_sql(sql), "#{name} Load").collect! do |record|
85
+ instantiate( Scrooge::Optimizations::Columns::UnscroogedAttributes.setup(record) )
86
+ end
87
+ end
88
+
75
89
  # Generate a regex that respects the table name as well to catch
76
90
  # verbose SQL from JOINS etc.
77
91
  #
@@ -88,17 +102,18 @@ module Scrooge
88
102
  end
89
103
 
90
104
  module InstanceMethods
91
-
105
+
92
106
  def self.included( base )
93
107
  base.alias_method_chain :delete, :scrooge
94
108
  base.alias_method_chain :destroy, :scrooge
95
109
  base.alias_method_chain :respond_to?, :scrooge
110
+ base.alias_method_chain :attributes_from_column_definition, :scrooge
96
111
  end
97
112
 
98
113
  # Is this instance being handled by scrooge?
99
114
  #
100
115
  def scrooged?
101
- @attributes.is_a?(Scrooge::Optimizations::Columns::AttributesProxy)
116
+ @attributes.is_a?(Scrooge::Optimizations::Columns::ScroogedAttributes)
102
117
  end
103
118
 
104
119
  # Delete should fully load all the attributes before the @attributes hash is frozen
@@ -178,6 +193,12 @@ module Scrooge
178
193
  def scrooge_fetch_remaining
179
194
  @attributes.fetch_remaining if scrooged?
180
195
  end
196
+
197
+ # New objects should get an UnscroogedAttributes as their @attributes hash
198
+ #
199
+ def attributes_from_column_definition_with_scrooge
200
+ UnscroogedAttributes.setup(attributes_from_column_definition_without_scrooge)
201
+ end
181
202
 
182
203
  end
183
204
 
data/lib/scrooge.rb CHANGED
@@ -16,7 +16,6 @@ module ActiveRecord
16
16
  # Determine if a given SQL string is a candidate for callsite <=> columns
17
17
  # optimization.
18
18
  #
19
- alias :find_by_sql_without_scrooge :find_by_sql
20
19
  def find_by_sql(sql)
21
20
  if scope_with_scrooge?(sql)
22
21
  find_by_sql_with_scrooge(sql)
@@ -1,4 +1,8 @@
1
1
  class MysqlUser < ActiveRecord::Base
2
2
  set_table_name 'user'
3
3
  set_primary_key 'User'
4
+
5
+ def after_initialize
6
+ max_connections if @attributes.has_key?("max_user_connections")
7
+ end
4
8
  end
data/test/scrooge_test.rb CHANGED
@@ -63,6 +63,11 @@ class ScroogeTest < ActiveSupport::TestCase
63
63
  user.User
64
64
  end
65
65
 
66
+ test "should only fire after_initialize once" do
67
+ # should not raise ActiveRecord::MissingAttributeError
68
+ [:max_connections, :max_user_connections].each {|f| MysqlUser.find(:first).read_attribute(f)}
69
+ end
70
+
66
71
  def first_callsite
67
72
  MysqlUser.scrooge_callsites.to_a.flatten.first
68
73
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: methodmissing-scrooge
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Lourens Naud\xC3\xA9"
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-03-15 00:00:00 -07:00
13
+ date: 2009-03-16 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -20,8 +20,9 @@ executables: []
20
20
 
21
21
  extensions: []
22
22
 
23
- extra_rdoc_files: []
24
-
23
+ extra_rdoc_files:
24
+ - README
25
+ - README.textile
25
26
  files:
26
27
  - Rakefile
27
28
  - README