mm_eager_includer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/mongo_mapper/eager_include.rb +194 -0
  2. metadata +47 -0
@@ -0,0 +1,194 @@
1
+ require 'mongo_mapper'
2
+
3
+ module MongoMapper
4
+ class EagerIncluder
5
+ class << self
6
+ def enabled?
7
+ (@enabled == true || @enabled == false) ? @enabled : true
8
+ end
9
+
10
+ def enabled=(bool)
11
+ @enabled = bool
12
+ end
13
+
14
+ def eager_include(record_or_records, *association_names, &block)
15
+ association_names.each do |association_name|
16
+ new(record_or_records, association_name).eager_include(&block)
17
+ end
18
+ end
19
+
20
+ def write_to_cache(object_id, association_name, value)
21
+ cache[association_name] ||= {}
22
+ cache[association_name][object_id] = value
23
+ end
24
+
25
+ def read_from_cache(object_id, association_name)
26
+ cache[association_name][object_id]
27
+ end
28
+
29
+ def clear_cache!
30
+ @cache = {}
31
+ end
32
+
33
+ private
34
+
35
+ def cache
36
+ @cache ||= {}
37
+ end
38
+ end
39
+
40
+ def initialize(record_or_records, association_name)
41
+ @records = Array(record_or_records)
42
+
43
+ if @records.length == 0
44
+ return
45
+ end
46
+
47
+ @association_name = association_name.to_sym
48
+ @association = @records.first.associations[association_name]
49
+ if !@association
50
+ raise "Could not find association `#{association_name}` on instance of #{@records.first.class}"
51
+ end
52
+
53
+ @proxy_class = @association.proxy_class
54
+ end
55
+
56
+ def enabled?
57
+ self.class.enabled?
58
+ end
59
+
60
+ def eager_include(&block)
61
+ return if !enabled?
62
+
63
+ if @records.length == 0
64
+ return
65
+ end
66
+
67
+ if @proxy_class == MongoMapper::Plugins::Associations::ManyDocumentsProxy
68
+ eager_include_has_many(&block)
69
+ elsif @proxy_class == MongoMapper::Plugins::Associations::BelongsToProxy
70
+ eager_include_belongs_to(&block)
71
+ elsif @proxy_class == MongoMapper::Plugins::Associations::OneProxy
72
+ eager_include_has_one(&block)
73
+ elsif @proxy_class == MongoMapper::Plugins::Associations::InArrayProxy
74
+ eager_include_has_many_in(&block)
75
+ else
76
+ raise NotImplementedError, "#{@proxy_class} not supported yet!"
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def setup_association(record, association_name, value)
83
+ association_name = association_name.to_sym
84
+
85
+ self.class.write_to_cache(record.object_id, association_name, value)
86
+
87
+ code = <<-CODE
88
+ def #{association_name}
89
+ MongoMapper::EagerIncluder.read_from_cache(object_id, :#{association_name})
90
+ end
91
+ CODE
92
+
93
+ record.instance_eval(code, __FILE__, __LINE__)
94
+ end
95
+
96
+ def foreign_keys
97
+ @association.options[:in]
98
+ end
99
+
100
+ def foreign_key
101
+ @association_name.to_s.foreign_key
102
+ end
103
+
104
+ def primary_key
105
+ @association.options[:foreign_key] || @records.first.class.name.foreign_key
106
+ end
107
+
108
+ def eager_include_has_many(&block)
109
+ ids = @records.map { |el| el.id }.uniq
110
+ proxy_records = @association.klass.where({
111
+ primary_key => {
112
+ '$in' => ids
113
+ }
114
+ }).all
115
+
116
+ @records.each do |record|
117
+ matching_proxy_records = proxy_records.select do |proxy_record|
118
+ record_or_records = proxy_record.send(primary_key)
119
+ if record_or_records.is_a?(Array)
120
+ record_or_records.include?(record.id)
121
+ else
122
+ record_or_records == record.id
123
+ end
124
+ end
125
+
126
+ setup_association(record, @association_name, matching_proxy_records)
127
+ end
128
+ end
129
+
130
+ def eager_include_has_one(&block)
131
+ ids = @records.map { |el| el.id }.uniq
132
+ proxy_records = @association.klass.where({
133
+ primary_key => ids
134
+ })
135
+
136
+ if block
137
+ proxy_records = block.call(proxy_records)
138
+ end
139
+
140
+ proxy_records = proxy_records.all
141
+
142
+ @records.each do |record|
143
+ matching_proxy_record = proxy_records.detect do |proxy_record|
144
+ proxy_record.send(primary_key) == record.id
145
+ end
146
+
147
+ setup_association(record, @association_name, matching_proxy_record)
148
+ end
149
+ end
150
+
151
+ def eager_include_belongs_to(&block)
152
+ ids = @records.map { |el| el.send(foreign_key) }.uniq
153
+
154
+ proxy_records = @association.klass.where({
155
+ :_id => {
156
+ '$in' => ids
157
+ }
158
+ })
159
+
160
+ if block
161
+ proxy_records = block.call(proxy_records)
162
+ end
163
+
164
+ proxy_records = proxy_records.all
165
+
166
+ @records.each do |record|
167
+ matching_proxy_record = proxy_records.detect do |proxy_record|
168
+ proxy_record.id == record.send(foreign_key)
169
+ end
170
+
171
+ setup_association(record, @association_name, matching_proxy_record)
172
+ end
173
+ end
174
+
175
+ def eager_include_has_many_in(&block)
176
+ ids = @records.map { |el| el.send(foreign_keys) }.flatten.uniq
177
+ proxy_records = @association.klass.where({
178
+ '_id' => {
179
+ '$in' => ids
180
+ }
181
+ }).all
182
+
183
+ @records.each do |record|
184
+ proxy_record_ids = record.send(foreign_keys)
185
+
186
+ matching_proxy_records = proxy_record_ids.map do |proxy_record_id|
187
+ proxy_records.detect { |proxy_record| proxy_record.id == proxy_record_id }
188
+ end
189
+
190
+ setup_association(record, @association_name, matching_proxy_records)
191
+ end
192
+ end
193
+ end
194
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mm_eager_includer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Scott Taylor
9
+ - Andrew Pariser
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2014-10-22 00:00:00.000000000 Z
14
+ dependencies: []
15
+ description: Eager include associations with mongo mapper
16
+ email: scott@railsnewbie.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/mongo_mapper/eager_include.rb
22
+ homepage: http://github.com/GoLearnUp/eager_include_mm
23
+ licenses:
24
+ - MIT
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.24
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: Eager include associations with mongo mapper
47
+ test_files: []