rpc-mapper 0.1.6 → 0.2.0
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/lib/rpc_mapper/association.rb +162 -0
- data/lib/rpc_mapper/association_preload.rb +50 -0
- data/lib/rpc_mapper/associations/common.rb +11 -11
- data/lib/rpc_mapper/associations/external.rb +16 -58
- data/lib/rpc_mapper/base.rb +7 -4
- data/lib/rpc_mapper/cacheable.rb +3 -2
- data/lib/rpc_mapper/errors.rb +9 -0
- data/lib/rpc_mapper/relation/finder_methods.rb +2 -2
- data/lib/rpc_mapper/relation/query_methods.rb +13 -5
- data/lib/rpc_mapper/relation.rb +8 -3
- data/lib/rpc_mapper/version.rb +2 -2
- metadata +6 -4
@@ -0,0 +1,162 @@
|
|
1
|
+
module RPCMapper::Association; end
|
2
|
+
|
3
|
+
module RPCMapper::Association
|
4
|
+
|
5
|
+
class Base
|
6
|
+
attr_accessor :source_klass, :id, :options
|
7
|
+
|
8
|
+
def initialize(klass, id, options={})
|
9
|
+
self.source_klass = klass
|
10
|
+
self.id = id.to_sym
|
11
|
+
self.options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
raise NotImplementedError, "You must define the type in subclasses."
|
16
|
+
end
|
17
|
+
|
18
|
+
def polymorphic?
|
19
|
+
raise NotImplementedError, "You must define how your association is polymorphic in subclasses."
|
20
|
+
end
|
21
|
+
|
22
|
+
def collection?
|
23
|
+
raise NotImplementedError, "You must define collection? in subclasses."
|
24
|
+
end
|
25
|
+
|
26
|
+
def primary_key
|
27
|
+
options[:primary_key] || :id
|
28
|
+
end
|
29
|
+
|
30
|
+
def foreign_key
|
31
|
+
options[:foreign_key]
|
32
|
+
end
|
33
|
+
|
34
|
+
def target_klass(object=nil)
|
35
|
+
klass = if options[:polymorphic]
|
36
|
+
eval [options[:polymorphic_namespace], object.send("#{id}_type")].compact.join('::') if object
|
37
|
+
else
|
38
|
+
raise(ArgumentError, ":class_name option required for association declaration.") unless options[:class_name]
|
39
|
+
options[:class_name] = "::#{options[:class_name]}" unless options[:class_name] =~ /^::/
|
40
|
+
eval(options[:class_name])
|
41
|
+
end
|
42
|
+
|
43
|
+
RPCMapper::Base.resolve_leaf_klass klass
|
44
|
+
end
|
45
|
+
|
46
|
+
def scope(object)
|
47
|
+
raise NotImplementedError, "You must define scope in subclasses"
|
48
|
+
end
|
49
|
+
|
50
|
+
# TRP: Only eager loadable if association query does not depend on instance data
|
51
|
+
def eager_loadable?
|
52
|
+
RPCMapper::Relation::FINDER_OPTIONS.inject(true) { |condition, key| condition && !options[key].respond_to?(:call) }
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def base_scope(object)
|
58
|
+
target_klass(object).scoped.apply_finder_options base_finder_options(object)
|
59
|
+
end
|
60
|
+
|
61
|
+
def base_finder_options(object)
|
62
|
+
RPCMapper::Relation::FINDER_OPTIONS.inject({}) do |sum, key|
|
63
|
+
value = self.options[key]
|
64
|
+
sum.merge!(key => value.respond_to?(:call) ? value.call(object) : value) if value
|
65
|
+
sum
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
class BelongsTo < Base
|
73
|
+
|
74
|
+
def type
|
75
|
+
:belongs_to
|
76
|
+
end
|
77
|
+
|
78
|
+
def collection?
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def foreign_key
|
83
|
+
super || "#{id}_id".to_sym
|
84
|
+
end
|
85
|
+
|
86
|
+
def polymorphic?
|
87
|
+
!!options[:polymorphic]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns a scope on the target containing this association
|
91
|
+
#
|
92
|
+
# Builds conditions on top of the base_scope generated from any finder options set with the association
|
93
|
+
#
|
94
|
+
# belongs_to :foo, :foreign_key => :foo_id
|
95
|
+
#
|
96
|
+
# In addition to any finder options included with the association options the following scope will be added:
|
97
|
+
# where(:id => source[:foo_id])
|
98
|
+
def scope(object)
|
99
|
+
base_scope(object).where(self.primary_key => object[self.foreign_key]) if object[self.foreign_key]
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
class Has < Base
|
106
|
+
|
107
|
+
def foreign_key
|
108
|
+
super || (self.polymorphic? ? "#{options[:as]}_id" : "#{RPCMapper::Base.base_class_name(source_klass).downcase}_id").to_sym
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# Returns a scope on the target containing this association
|
113
|
+
#
|
114
|
+
# Builds conditions on top of the base_scope generated from any finder options set with the association
|
115
|
+
#
|
116
|
+
# has_many :widgets, :class_name => "Widget", :foreign_key => :widget_id
|
117
|
+
# has_many :comments, :as => :parent
|
118
|
+
#
|
119
|
+
# In addition to any finder options included with the association options the following will be added:
|
120
|
+
# where(widget_id => source[:id])
|
121
|
+
# Or for the polymorphic :comments association:
|
122
|
+
# where(:parent_id => source[:id], :parent_type => source.class)
|
123
|
+
def scope(object)
|
124
|
+
s = base_scope(object).where(self.foreign_key => object[self.primary_key]) if object[self.primary_key]
|
125
|
+
s = s.where(:"#{options[:as]}_type" => RPCMapper::Base.base_class_name(object.class)) if s && polymorphic?
|
126
|
+
s
|
127
|
+
end
|
128
|
+
|
129
|
+
def polymorphic?
|
130
|
+
!!options[:as]
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
class HasMany < Has
|
137
|
+
|
138
|
+
def collection?
|
139
|
+
true
|
140
|
+
end
|
141
|
+
|
142
|
+
def type
|
143
|
+
:has_many
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
class HasOne < Has
|
150
|
+
|
151
|
+
def collection?
|
152
|
+
false
|
153
|
+
end
|
154
|
+
|
155
|
+
def type
|
156
|
+
:has_one
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module RPCMapper::AssociationPreload
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
def eager_load_associations(original_results, relation)
|
5
|
+
relation.includes_values.each do |association_id|
|
6
|
+
association = self.defined_associations[association_id.to_sym]
|
7
|
+
options = association.options
|
8
|
+
|
9
|
+
unless association.eager_loadable?
|
10
|
+
raise RPCMapper::AssociationPreloadNotSupported,
|
11
|
+
"delayed execution options (block options) cannot be used for eager loaded associations"
|
12
|
+
end
|
13
|
+
|
14
|
+
case association.type
|
15
|
+
when :has_many, :has_one
|
16
|
+
fks = original_results.collect { |record| record.send(association.primary_key) }.compact
|
17
|
+
|
18
|
+
pre_records = association.target_klass.where(association.foreign_key => fks).all
|
19
|
+
|
20
|
+
original_results.each do |record|
|
21
|
+
pk = record.send(association.primary_key)
|
22
|
+
relevant_records = pre_records.select { |r| r.send(association.foreign_key) == pk }
|
23
|
+
relevant_records = association.collection? ? relevant_records : relevant_records.first
|
24
|
+
record.send("#{association.id}=", relevant_records)
|
25
|
+
end
|
26
|
+
|
27
|
+
when :belongs_to
|
28
|
+
fks = original_results.collect { |record| record.send(association.foreign_key) }.compact
|
29
|
+
|
30
|
+
pre_records = association.target_klass.where(association.primary_key => fks).all
|
31
|
+
|
32
|
+
original_results.each do |record|
|
33
|
+
fk = record.send(association.foreign_key)
|
34
|
+
relevant_records = pre_records.select { |r| r.send(association.primary_key) == fk }.first
|
35
|
+
record.send("#{association.id}=", relevant_records)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
module InstanceMethods
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.included(receiver)
|
47
|
+
receiver.extend ClassMethods
|
48
|
+
receiver.send :include, InstanceMethods
|
49
|
+
end
|
50
|
+
end
|
@@ -3,6 +3,15 @@ module RPCMapper::Associations
|
|
3
3
|
module Common
|
4
4
|
module ClassMethods
|
5
5
|
|
6
|
+
def base_class_name(klass)
|
7
|
+
klass.to_s.split("::").last
|
8
|
+
end
|
9
|
+
|
10
|
+
# TRP: This will return the most recent extension of klass or klass if it is a leaf node in the hierarchy
|
11
|
+
def resolve_leaf_klass(klass)
|
12
|
+
extension_map[klass].empty? ? klass : resolve_leaf_klass(extension_map[klass].last)
|
13
|
+
end
|
14
|
+
|
6
15
|
protected
|
7
16
|
|
8
17
|
def extension_map
|
@@ -13,15 +22,6 @@ module RPCMapper::Associations
|
|
13
22
|
self.extension_map[old_klass] += [new_klass] if base_class_name(old_klass) == base_class_name(new_klass)
|
14
23
|
end
|
15
24
|
|
16
|
-
# TRP: This will return the most recent extension of klass or klass if it is a leaf node in the hierarchy
|
17
|
-
def resolve_leaf_klass(klass)
|
18
|
-
extension_map[klass].empty? ? klass : resolve_leaf_klass(extension_map[klass].last)
|
19
|
-
end
|
20
|
-
|
21
|
-
def base_class_name(klass)
|
22
|
-
klass.to_s.split("::").last
|
23
|
-
end
|
24
|
-
|
25
25
|
end
|
26
26
|
|
27
27
|
module InstanceMethods
|
@@ -32,9 +32,9 @@ module RPCMapper::Associations
|
|
32
32
|
klass = if options[:polymorphic]
|
33
33
|
eval [options[:polymorphic_namespace], self.send("#{association}_type")].compact.join('::')
|
34
34
|
else
|
35
|
-
raise(ArgumentError, ":class_name
|
35
|
+
raise(ArgumentError, ":class_name option required for association declaration.") unless options[:class_name]
|
36
36
|
options[:class_name] = "::#{options[:class_name]}" unless options[:class_name] =~ /^::/
|
37
|
-
|
37
|
+
eval(options[:class_name])
|
38
38
|
end
|
39
39
|
|
40
40
|
self.class.send :resolve_leaf_klass, klass
|
@@ -1,47 +1,38 @@
|
|
1
1
|
require 'rpc_mapper/associations/common'
|
2
|
+
require 'rpc_mapper/association'
|
2
3
|
|
3
4
|
module RPCMapper::Associations
|
4
5
|
|
5
6
|
module External
|
6
7
|
module ClassMethods
|
7
8
|
|
8
|
-
def belongs_to(
|
9
|
-
create_external_association(
|
9
|
+
def belongs_to(id, options={})
|
10
|
+
create_external_association RPCMapper::Association::BelongsTo.new(self, id, options)
|
10
11
|
end
|
11
12
|
|
12
|
-
def has_one(
|
13
|
-
create_external_association(
|
13
|
+
def has_one(id, options={})
|
14
|
+
create_external_association RPCMapper::Association::HasOne.new(self, id, options)
|
14
15
|
end
|
15
16
|
|
16
|
-
def has_many(
|
17
|
-
create_external_association(
|
17
|
+
def has_many(id, options={})
|
18
|
+
create_external_association RPCMapper::Association::HasMany.new(self, id, options)
|
18
19
|
end
|
19
20
|
|
20
21
|
protected
|
21
22
|
|
22
|
-
def create_external_association(
|
23
|
-
cache_ivar = "@association_#{association}"
|
24
|
-
self.
|
23
|
+
def create_external_association(association)
|
24
|
+
cache_ivar = "@association_#{association.id}"
|
25
|
+
self.defined_associations[association.id] = association
|
25
26
|
|
26
|
-
define_method(association) do
|
27
|
-
type = self.class.declared_associations[association].first
|
28
|
-
options = self.class.declared_associations[association].last.dup
|
29
|
-
options = options.is_a?(Proc) ? options.call(self) : options
|
30
|
-
klass = klass_from_association_options(association, options)
|
27
|
+
define_method(association.id) do
|
31
28
|
cached_value = instance_variable_get(cache_ivar)
|
32
29
|
|
33
|
-
options[:primary_key] = (options[:primary_key] || "id").to_sym
|
34
|
-
options[:foreign_key] = (options[:foreign_key] || ((type == :belongs) ? "#{association}_id" : "#{self.class.name.split('::').last.downcase}_id")).to_sym
|
35
|
-
|
36
30
|
# TRP: Logic for actually pulling setting the value
|
37
31
|
unless cached_value
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
when :many
|
43
|
-
klass.apply_finder_options(query_options) if query_options[:conditions] # TRP: Only apply scopes if conditions is not nil
|
44
|
-
end
|
32
|
+
scoped = association.scope(self)
|
33
|
+
|
34
|
+
cached_value = association.collection? ? scoped : scoped.first if scoped && !scoped.where_values.empty?
|
35
|
+
|
45
36
|
instance_variable_set(cache_ivar, cached_value)
|
46
37
|
end
|
47
38
|
|
@@ -49,7 +40,7 @@ module RPCMapper::Associations
|
|
49
40
|
end
|
50
41
|
|
51
42
|
# TRP: Allow eager loading of the association without having to load it through the normal accessor
|
52
|
-
define_method("#{association}=") do |value|
|
43
|
+
define_method("#{association.id}=") do |value|
|
53
44
|
instance_variable_set(cache_ivar, value)
|
54
45
|
end
|
55
46
|
end
|
@@ -57,39 +48,6 @@ module RPCMapper::Associations
|
|
57
48
|
end
|
58
49
|
|
59
50
|
module InstanceMethods
|
60
|
-
|
61
|
-
protected
|
62
|
-
|
63
|
-
def build_query_options_for_external_association(type, options)
|
64
|
-
as = options[:as]
|
65
|
-
as_type = self.class.send(:base_class_name, self.class) if as
|
66
|
-
|
67
|
-
pk = options[:primary_key].to_sym
|
68
|
-
fk = (as ? "#{as}_id" : options[:foreign_key]).to_sym
|
69
|
-
|
70
|
-
default_query_options = case type
|
71
|
-
when :belongs
|
72
|
-
{ :conditions => (self[fk] ? { pk => self[fk] } : nil) } # TRP: Only add conditions if the fk is not nil
|
73
|
-
when :one, :many
|
74
|
-
# TRP: Only add conditions if the pk is not nil
|
75
|
-
if self[pk]
|
76
|
-
conditions = { fk => self[pk] }
|
77
|
-
conditions.merge!(:"#{as}_type" => as_type) if as
|
78
|
-
{ :conditions => conditions }
|
79
|
-
else
|
80
|
-
{}
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
configured_query_options = {}
|
85
|
-
RPCMapper::Relation::FINDER_OPTIONS.each do |key|
|
86
|
-
value = options[key]
|
87
|
-
configured_query_options.merge!({ key => value.respond_to?(:call) ? value.call(self) : value }) if value
|
88
|
-
end
|
89
|
-
|
90
|
-
default_query_options.deep_merge(configured_query_options)
|
91
|
-
end
|
92
|
-
|
93
51
|
end
|
94
52
|
|
95
53
|
def self.included(receiver)
|
data/lib/rpc_mapper/base.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'rpc_mapper/errors'
|
3
3
|
require 'rpc_mapper/associations/contains'
|
4
4
|
require 'rpc_mapper/associations/external'
|
5
|
+
require 'rpc_mapper/association_preload'
|
5
6
|
require 'rpc_mapper/cacheable'
|
6
7
|
require 'rpc_mapper/serialization'
|
7
8
|
require 'rpc_mapper/relation'
|
@@ -12,16 +13,17 @@ require 'rpc_mapper/adapters'
|
|
12
13
|
class RPCMapper::Base
|
13
14
|
include RPCMapper::Associations::Contains
|
14
15
|
include RPCMapper::Associations::External
|
16
|
+
include RPCMapper::AssociationPreload
|
15
17
|
include RPCMapper::Serialization
|
16
18
|
include RPCMapper::Scopes
|
17
19
|
|
18
20
|
attr_accessor :attributes, :new_record, :read_options, :write_options
|
19
21
|
alias :new_record? :new_record
|
20
22
|
|
21
|
-
class_inheritable_accessor :read_adapter, :write_adapter, :cacheable, :defined_attributes, :scoped_methods, :
|
23
|
+
class_inheritable_accessor :read_adapter, :write_adapter, :cacheable, :defined_attributes, :scoped_methods, :defined_associations
|
22
24
|
|
23
25
|
self.cacheable = false
|
24
|
-
self.
|
26
|
+
self.defined_associations = {}
|
25
27
|
self.defined_attributes = []
|
26
28
|
|
27
29
|
def initialize(attributes={})
|
@@ -88,8 +90,9 @@ class RPCMapper::Base
|
|
88
90
|
|
89
91
|
protected
|
90
92
|
|
91
|
-
def fetch_records(
|
92
|
-
|
93
|
+
def fetch_records(relation)
|
94
|
+
options = relation.to_hash
|
95
|
+
self.read_adapter.read(options).collect { |hash| self.new_from_data_store(hash) }.compact.tap { |result| eager_load_associations(result, relation) }
|
93
96
|
end
|
94
97
|
|
95
98
|
def read_with(adapter_type)
|
data/lib/rpc_mapper/cacheable.rb
CHANGED
@@ -20,7 +20,8 @@ module RPCMapper::Cacheable
|
|
20
20
|
|
21
21
|
protected
|
22
22
|
|
23
|
-
def fetch_records_with_caching(
|
23
|
+
def fetch_records_with_caching(relation)
|
24
|
+
options = relation.to_hash
|
24
25
|
key = Digest::MD5.hexdigest(self.to_s + options.to_a.sort { |a,b| a.to_s.first <=> b.to_s.first }.inspect)
|
25
26
|
cache_hit = self.cache_store.read(key)
|
26
27
|
get_fresh = options.delete(:fresh)
|
@@ -30,7 +31,7 @@ module RPCMapper::Cacheable
|
|
30
31
|
cache_hit.each { |fv| fv.fresh = false.freeze }
|
31
32
|
cache_hit
|
32
33
|
else
|
33
|
-
fresh_value = fetch_records_without_caching(
|
34
|
+
fresh_value = fetch_records_without_caching(relation)
|
34
35
|
|
35
36
|
# TRP: Only store in cache if record count is below the cache_record_count_threshold (if it is set)
|
36
37
|
if !self.cache_record_count_threshold || fresh_value.size <= self.cache_record_count_threshold
|
data/lib/rpc_mapper/errors.rb
CHANGED
@@ -12,4 +12,13 @@ module RPCMapper
|
|
12
12
|
class RecordNotSaved < RPCMapperError
|
13
13
|
end
|
14
14
|
|
15
|
+
# Raised when trying to eager load an association that relies on instance level data.
|
16
|
+
# class Article < RPCMapper::Base
|
17
|
+
# has_many :comments, :conditions => lambda { |article| ... }
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Article.recent.includes(:comments) # Raises AssociationPreloadNotSupported
|
21
|
+
class AssociationPreloadNotSupported < RPCMapperError
|
22
|
+
end
|
23
|
+
|
15
24
|
end
|
@@ -18,11 +18,11 @@ module RPCMapper::FinderMethods
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def all(options={})
|
21
|
-
self.apply_finder_options(options).
|
21
|
+
self.apply_finder_options(options).to_a
|
22
22
|
end
|
23
23
|
|
24
24
|
def first(options={})
|
25
|
-
self.apply_finder_options(options).limit(1).
|
25
|
+
self.apply_finder_options(options).limit(1).to_a.first
|
26
26
|
end
|
27
27
|
|
28
28
|
def search(options={})
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module RPCMapper::QueryMethods
|
2
2
|
# TRP: Define each of the variables the query options will be stored in.
|
3
|
-
attr_accessor :select_values, :group_values, :order_values, :joins_values, :where_values,
|
4
|
-
:
|
5
|
-
:fresh_value
|
3
|
+
attr_accessor :select_values, :group_values, :order_values, :joins_values, :includes_values, :where_values, :having_values,
|
4
|
+
:limit_value, :offset_value, :from_value,
|
5
|
+
:raw_sql_value, :fresh_value
|
6
6
|
|
7
7
|
def select(*args)
|
8
8
|
if block_given?
|
@@ -24,8 +24,13 @@ module RPCMapper::QueryMethods
|
|
24
24
|
clone.tap { |r| r.joins_values += args if args && !args.empty? }
|
25
25
|
end
|
26
26
|
|
27
|
+
def includes(*args)
|
28
|
+
args.reject! { |a| a.nil? }
|
29
|
+
clone.tap { |r| r.includes_values += (r.includes_values + args).flatten.uniq if args && !args.empty? }
|
30
|
+
end
|
31
|
+
|
27
32
|
def where(*args)
|
28
|
-
clone.tap { |r| r.where_values += args if args && !args.empty? }
|
33
|
+
clone.tap { |r| r.where_values += args.compact.reject(&:empty?) if args && !args.empty? }
|
29
34
|
end
|
30
35
|
|
31
36
|
def having(*args)
|
@@ -45,7 +50,10 @@ module RPCMapper::QueryMethods
|
|
45
50
|
end
|
46
51
|
|
47
52
|
def fresh(val=true)
|
48
|
-
clone.tap
|
53
|
+
clone.tap do |r|
|
54
|
+
r.fresh_value = val
|
55
|
+
r.instance_variable_set(:@records, nil) if r.fresh_value
|
56
|
+
end
|
49
57
|
end
|
50
58
|
|
51
59
|
def sql(raw_sql)
|
data/lib/rpc_mapper/relation.rb
CHANGED
@@ -5,8 +5,9 @@ require 'rpc_mapper/relation/finder_methods'
|
|
5
5
|
# => http://github.com/rails/rails
|
6
6
|
# Used to achieve the chainability of scopes -- methods are delegated back and forth from BM::Base and BM::Relation
|
7
7
|
class RPCMapper::Relation
|
8
|
+
attr_reader :klass
|
8
9
|
SINGLE_VALUE_METHODS = [:limit, :offset, :from, :fresh]
|
9
|
-
MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :where, :having]
|
10
|
+
MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :includes, :where, :having]
|
10
11
|
|
11
12
|
FINDER_OPTIONS = SINGLE_VALUE_METHODS + MULTI_VALUE_METHODS + [:conditions, :search, :sql]
|
12
13
|
|
@@ -38,7 +39,7 @@ class RPCMapper::Relation
|
|
38
39
|
|
39
40
|
def to_hash
|
40
41
|
# TRP: If present pass :sql option alone as it trumps all other options
|
41
|
-
if self.raw_sql_value
|
42
|
+
@hash ||= if self.raw_sql_value
|
42
43
|
{ :sql => raw_sql_value }
|
43
44
|
else
|
44
45
|
hash = SINGLE_VALUE_METHODS.inject({}) do |h, option|
|
@@ -64,6 +65,10 @@ class RPCMapper::Relation
|
|
64
65
|
@records ||= fetch_records
|
65
66
|
end
|
66
67
|
|
68
|
+
def eager_load?
|
69
|
+
@includes_values && !@includes_values.empty?
|
70
|
+
end
|
71
|
+
|
67
72
|
def inspect
|
68
73
|
to_a.inspect
|
69
74
|
end
|
@@ -119,7 +124,7 @@ class RPCMapper::Relation
|
|
119
124
|
end
|
120
125
|
|
121
126
|
def fetch_records
|
122
|
-
@klass.send(:fetch_records,
|
127
|
+
@klass.send(:fetch_records, self)
|
123
128
|
end
|
124
129
|
|
125
130
|
end
|
data/lib/rpc_mapper/version.rb
CHANGED
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Travis Petticrew
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-22 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -127,6 +127,8 @@ files:
|
|
127
127
|
- lib/rpc_mapper/adapters/bertrpc_adapter.rb
|
128
128
|
- lib/rpc_mapper/adapters/restful_http_adapter.rb
|
129
129
|
- lib/rpc_mapper/adapters.rb
|
130
|
+
- lib/rpc_mapper/association.rb
|
131
|
+
- lib/rpc_mapper/association_preload.rb
|
130
132
|
- lib/rpc_mapper/associations/common.rb
|
131
133
|
- lib/rpc_mapper/associations/contains.rb
|
132
134
|
- lib/rpc_mapper/associations/external.rb
|