mongoid-report 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,8 +10,12 @@ module Mongoid
10
10
  end
11
11
 
12
12
  def scopes
13
- @scopes ||= modules.map do |key|
14
- Scope.new(context, key)
13
+ @scopes ||= [].tap do |collection|
14
+ context.settings.each do |report_module, module_settings|
15
+ module_settings[:reports].each do |report_name, _report_settings|
16
+ collection << Scope.new(context, report_module, report_name)
17
+ end
18
+ end
15
19
  end
16
20
  end
17
21
 
@@ -29,31 +33,33 @@ module Mongoid
29
33
  self
30
34
  end
31
35
 
36
+ def in_batches(conditions)
37
+ scopes.each do |scope|
38
+ scope.in_batches(conditions)
39
+ end
40
+ self
41
+ end
42
+
32
43
  def all
33
- {}.tap do |hash|
44
+ Hash.new { |h, k| h[k] = {} }.tap do |hash|
34
45
  if Mongoid::Report::Config.use_threads_on_aggregate
35
46
  scopes.map do |scope|
36
47
  Thread.new do
37
48
  rows = scope.all
38
49
 
39
50
  @mutex.synchronize do
40
- hash[scope.report_name] = rows
51
+ hash[scope.report_module][scope.report_name] = rows
41
52
  end
42
53
  end
43
54
  end.map(&:join)
44
55
  else
45
56
  scopes.each do |scope|
46
- hash[scope.report_name] = scope.all
57
+ hash[scope.report_module][scope.report_name] = scope.all
47
58
  end
48
59
  end
49
60
  end
50
61
  end
51
62
 
52
- private
53
-
54
- def modules
55
- context.settings.keys
56
- end
57
63
  end
58
64
 
59
65
  end
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Report
3
- VERSION = "0.1.9"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
@@ -5,6 +5,11 @@ require_relative 'report/config'
5
5
  require_relative 'report/queries_builder'
6
6
  require_relative 'report/attach_proxy'
7
7
  require_relative 'report/collection'
8
+ require_relative 'report/batches'
9
+ require_relative 'report/merger'
10
+ require_relative 'report/collections'
11
+ require_relative 'report/output'
12
+ require_relative 'report/input'
8
13
  require_relative 'report/scope'
9
14
  require_relative 'report/scope_collection'
10
15
  require_relative 'report/report_proxy'
@@ -18,46 +23,116 @@ module Mongoid
18
23
 
19
24
  class_attribute :settings
20
25
 
26
+ # TODO: rewrite this module adding clone method for the all settings
27
+ # defined for the mongoid-report. for now it's creating the duplicates.
28
+ # check out the mongoid library for the best example.
21
29
  self.settings = {}
22
30
 
23
31
  def self.inherited(subclass)
24
- subclass.settings = self.settings.dup
32
+ subclass.settings = {}
25
33
  end
26
34
 
27
35
  # Variable for copying internal class settings to the instance because of
28
- # possible modifications in case of using filters with lambda
36
+ # possible modifications in case of using maches with lambda
29
37
  # expressions.
30
38
  attr_reader :report_module_settings
31
39
 
32
40
  def initialize_report_module
33
41
  # Lets store settings under created instance.
34
- @report_module_settings = self.class.settings.dup
42
+ @report_module_settings = self.settings.inject({}) do |hash_module, (report_module, module_settings)|
43
+ hash_module.merge!(
44
+ report_module =>
45
+ {
46
+ fields: module_settings[:fields],
47
+ group_by: module_settings[:group_by],
48
+ batches: module_settings[:batches],
49
+ columns: module_settings[:columns],
50
+ mapping: module_settings[:mapping],
51
+ queries: (module_settings[:queries] || []).dup,
52
+ reports: (module_settings[:reports] || {}).inject({}) do |hash_report, (report_name, report_settings)|
53
+ hash_report.merge!(
54
+ report_name => {
55
+ collection: report_settings[:collection],
56
+ fields: report_settings[:fields],
57
+ group_by: report_settings[:group_by],
58
+ batches: report_settings[:batches],
59
+ columns: report_settings[:columns],
60
+ mapping: report_settings[:mapping],
61
+ queries: (report_settings[:queries] || []).dup,
62
+ })
63
+ end
64
+ })
65
+ end
66
+
67
+ @report_module_settings.each do |report_module, module_configuration|
68
+ # Lets do not run queries builder in case of missing queries or group
69
+ # by parameters
70
+ unless module_configuration[:queries].empty? && module_configuration[:group_by].empty?
71
+ builder = QueriesBuilder.new(module_configuration)
72
+
73
+ # Prepare group queries depends on the configuration in the included
74
+ # class.
75
+ queries = builder.do
35
76
 
36
- @report_module_settings.each do |klass, configuration|
37
- builder = QueriesBuilder.new(configuration)
77
+ # Now we have access to compiled queries to run it in aggregation
78
+ # framework.
79
+ module_configuration[:queries] = module_configuration[:queries] + queries
80
+ end
81
+
82
+ # For now we are filtering by $match queries only.
83
+ matches = module_configuration[:queries].select do |query|
84
+ query['$match'].present?
85
+ end
38
86
 
39
- # Prepare group queries depends on the configuration in the included
40
- # class.
41
- @queries = builder.do
87
+ module_configuration[:reports].each do |report_name, report_configuration|
88
+ # Lets merge report and module settings together.
89
+ report_configuration[:fields] = report_configuration[:fields] | module_configuration[:fields]
90
+ report_configuration[:group_by] = report_configuration[:group_by] | module_configuration[:group_by]
91
+ report_configuration[:columns] = report_configuration[:columns].merge(module_configuration[:columns])
92
+ report_configuration[:mapping] = report_configuration[:mapping].merge(module_configuration[:mapping])
42
93
 
43
- # Now we have access to compiled queries to run it in aggregation
44
- # framework.
45
- configuration[:queries].concat(@queries)
94
+ builder = QueriesBuilder.new(report_configuration)
95
+
96
+ # Prepare group queries depends on the configuration in the included
97
+ # class.
98
+ queries = builder.do
99
+
100
+ # Now we have access to compiled queries to run it in aggregation
101
+ # framework.
102
+ report_configuration[:queries] = report_configuration[:queries] + matches + queries
103
+ end
46
104
  end
47
105
  end
48
106
  alias :initialize :initialize_report_module
49
107
 
50
- def queries(klass)
51
- report_module_settings[klass][:queries]
108
+ def queries(report_module, report_name)
109
+ report_module_settings[report_module][:reports][report_name][:queries]
110
+ end
111
+
112
+ def mapping(report_module, report_name)
113
+ report_module_settings[report_module][:reports][report_name][:mapping]
52
114
  end
53
115
 
54
- def mapping(klass)
55
- report_module_settings[klass][:mapping]
116
+ def batches(report_module, report_name)
117
+ report_module_settings[report_module][:reports][report_name][:batches]
56
118
  end
57
119
 
58
- # We should pass here mongoid document
59
- def aggregate_for(report_name)
60
- Scope.new(self, report_name)
120
+ def groups(report_module, report_name)
121
+ report_module_settings[report_module][:reports][report_name][:group_by]
122
+ end
123
+
124
+ def fields(report_module, report_name)
125
+ report_module_settings[report_module][:reports][report_name][:fields]
126
+ end
127
+
128
+ def columns(report_module, report_name)
129
+ report_module_settings[report_module][:reports][report_name][:columns]
130
+ end
131
+
132
+ # Method for preparing of aggregation scope where you can apply query,
133
+ # yield and other grouping methods.
134
+ def aggregate_for(report_module, report_name)
135
+ Scope.new(self, report_module, report_name)
61
136
  end
62
137
 
63
138
  def aggregate
@@ -71,14 +146,27 @@ module Mongoid
71
146
  proxy.instance_eval(&block)
72
147
  end
73
148
 
74
- def attach_to(collection, options = {}, &block)
75
- proxy = AttachProxy.new(self, collection, options)
76
- proxy.instance_eval(&block)
149
+ def attach_to(*fields, &block)
150
+ options = fields.extract_options!
151
+ collection = fields[0]
152
+
153
+ options.merge!(report_name: options[:as]) if options[:as]
154
+
155
+ define_report_method(options.merge(collection: collection)) do
156
+ proxy = AttachProxy.new(self, collection, options)
157
+ proxy.instance_eval(&block)
158
+ end
77
159
  end
78
160
 
79
- def filter(*fields)
80
- define_report_method(*fields) do |_, report_name, options|
81
- queries = self.settings_property(report_name, :queries)
161
+ def batches(*fields)
162
+ define_report_method(*fields) do |_, report_module, report_name, batches|
163
+ self.set_settings(report_module, report_name, :batches, batches.stringify_keys!)
164
+ end
165
+ end
166
+
167
+ def match(*fields)
168
+ define_report_method(*fields) do |_, report_module, report_name, options|
169
+ queries = self.get_settings(report_module, report_name, :queries)
82
170
 
83
171
  options.each do |key, value|
84
172
  queries
@@ -89,51 +177,62 @@ module Mongoid
89
177
  end
90
178
  end
91
179
 
180
+ def query(*fields)
181
+ define_report_method(*fields) do |_, report_module, report_name, options|
182
+ queries = self.get_settings(report_module, report_name, :queries)
183
+
184
+ options.each do |key, value|
185
+ queries.concat([{ key => value }])
186
+ end
187
+ end
188
+ end
189
+
92
190
  def group_by(*fields)
93
- define_report_method(*fields) do |groups, report_name, _|
94
- settings[report_name][:group_by] = groups.map(&:to_s)
191
+ define_report_method(*fields) do |groups, report_module, report_name, _|
192
+ self.set_settings(report_module, report_name, :group_by, groups.map(&:to_s))
95
193
  end
96
194
  end
97
195
 
98
196
  def column(*fields)
99
- define_report_method(*fields) do |columns, report_name, options|
100
- columns.each do |column|
101
- name = options.fetch(:as) { column }
102
- add_field(report_name, column, name)
197
+ define_report_method(*fields) do |columns, report_module, report_name, _|
198
+ columns.each do |field|
199
+ self.get_settings(report_module, report_name, :fields) << field.to_s
103
200
  end
104
201
  end
105
202
  end
106
203
 
107
204
  def columns(*fields)
108
- define_report_method(*fields) do |_, report_name, columns|
109
- self.settings[report_name][:columns] = columns.stringify_keys!
205
+ define_report_method(*fields) do |_, report_module, report_name, columns|
206
+ self.set_settings(report_module, report_name, :columns, columns.stringify_keys!)
110
207
  end
111
208
  end
112
209
 
113
210
  def mapping(*fields)
114
- define_report_method(*fields) do |_, report_name, mapping|
211
+ define_report_method(*fields) do |_, report_module, report_name, mapping|
115
212
  mapping.stringify_keys!
116
213
 
117
214
  mapping.each do |key, value|
118
215
  mapping[key] = value.to_s
119
216
  end
120
217
 
121
- self.settings[report_name][:mapping] = mapping
218
+ self.set_settings(report_module, report_name, :mapping, mapping)
122
219
  end
123
220
  end
124
221
 
125
- def fields(collection)
126
- settings_property(collection, :fields, {})
127
- end
128
-
129
- def groups(collection)
130
- settings_property(collection, :group_by, [])
222
+ def get_settings(report_module, report_name, field)
223
+ unless report_name
224
+ self.settings[report_module][field]
225
+ else
226
+ self.settings[report_module][:reports][report_name][field]
227
+ end
131
228
  end
132
229
 
133
- def settings_property(collection, key, default = [])
134
- settings
135
- .fetch(collection) { {} }
136
- .fetch(key) { default }
230
+ def set_settings(report_module, report_name, field, value)
231
+ unless report_name
232
+ self.settings[report_module][field] = value
233
+ else
234
+ self.settings[report_module][:reports][report_name][field] = value
235
+ end
137
236
  end
138
237
 
139
238
  private
@@ -142,38 +241,58 @@ module Mongoid
142
241
  options = fields.extract_options!
143
242
 
144
243
  # We should always specify model to attach fields, groups
145
- collection = options.fetch(:for)
146
- options.delete(:for)
244
+ collection = options.fetch(:collection)
245
+ options.delete(:collection)
246
+
247
+ # In case if user passed mongoid model we should get name of collection
248
+ # instead of using mongoid models. on deep_dup operations it will work
249
+ # find with strings.
250
+ collection = Collections.name(collection)
147
251
 
148
- # If user didn't pass as option to name the report we are using
149
- # collection class as key for settings.
150
- attach_name = options.fetch(:attach_name) { collection }
151
- options.delete(:attach_name)
252
+ report_module = options.delete(:report_module)
253
+ report_module ||= self.name
254
+
255
+ report_name = options.delete(:report_name)
256
+ report_name ||= Collections.name(collection)
152
257
 
153
258
  # We should always have for option
154
- initialize_settings_by(attach_name, collection)
259
+ initialize_settings_by(report_module, report_name, collection)
155
260
 
156
261
  # Because of modifying fields(usign exract options method of
157
262
  # ActiveSupport) lets pass fields to the next block with collection.
158
- yield fields, attach_name, options || {}
263
+ yield fields, report_module, report_name, options || {}
159
264
  end
160
265
 
161
- def initialize_settings_by(attach_name, collection)
162
- settings[attach_name] ||= settings.fetch(attach_name) do
266
+ def initialize_settings_by(report_module, report_name, collection)
267
+ # Global settings for the report block
268
+ settings[report_module] ||= settings.fetch(report_module) do
163
269
  {
164
- for: collection,
165
- fields: ActiveSupport::OrderedHash.new,
270
+ reports: {},
271
+ fields: [],
166
272
  group_by: [],
167
- queries: [],
273
+ batches: {},
168
274
  columns: {},
169
275
  mapping: {},
170
- compiled: false,
276
+ # needs to be cloned
277
+ queries: [],
171
278
  }
172
279
  end
173
- end
174
280
 
175
- def add_field(attach_name, field, name)
176
- settings[attach_name][:fields][field.to_s] = name.to_s
281
+ return unless report_name
282
+
283
+ settings[report_module][:reports][report_name] ||=
284
+ settings[report_module][:reports].fetch(report_name) do
285
+ {
286
+ collection: collection,
287
+ fields: [],
288
+ group_by: [],
289
+ batches: {},
290
+ columns: {},
291
+ mapping: {},
292
+ # needs to be cloned
293
+ queries: [],
294
+ }
295
+ end
177
296
  end
178
297
  end
179
298