mm_eager_includer 0.0.1

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.
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: []