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.
- checksums.yaml +8 -8
- data/Gemfile.lock +30 -18
- data/README.md +6 -36
- data/lib/mongoid/report/attach_proxy.rb +26 -5
- data/lib/mongoid/report/batches.rb +41 -0
- data/lib/mongoid/report/collection.rb +4 -3
- data/lib/mongoid/report/collections.rb +16 -0
- data/lib/mongoid/report/input.rb +17 -0
- data/lib/mongoid/report/merger.rb +29 -0
- data/lib/mongoid/report/output.rb +32 -0
- data/lib/mongoid/report/queries_builder.rb +14 -16
- data/lib/mongoid/report/report_proxy.rb +16 -4
- data/lib/mongoid/report/scope.rb +123 -17
- data/lib/mongoid/report/scope_collection.rb +16 -10
- data/lib/mongoid/report/version.rb +1 -1
- data/lib/mongoid/report.rb +180 -61
- data/spec/mongoid/report/aggregation_spec.rb +72 -57
- data/spec/mongoid/report/attach_to_spec.rb +16 -0
- data/spec/mongoid/report/collection_spec.rb +12 -7
- data/spec/mongoid/report/column_spec.rb +1 -1
- data/spec/mongoid/report/dynamic_attach_to_spec.rb +86 -0
- data/spec/mongoid/report/integration_spec.rb +129 -0
- data/spec/mongoid/report/module_configuration_spec.rb +35 -0
- data/spec/mongoid/report/out_spec.rb +122 -0
- data/spec/mongoid/report/queries_builder_spec.rb +54 -16
- data/spec/mongoid/report/set_spec.rb +3 -3
- data/spec/mongoid/report/summary_spec.rb +87 -16
- data/spec/mongoid/report/threads_spec.rb +132 -4
- data/spec/mongoid/report_spec.rb +58 -34
- data/spec/spec_helper.rb +2 -0
- metadata +17 -2
@@ -10,8 +10,12 @@ module Mongoid
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def scopes
|
13
|
-
@scopes ||=
|
14
|
-
|
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
|
data/lib/mongoid/report.rb
CHANGED
@@ -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 =
|
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
|
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.
|
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
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
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(
|
51
|
-
report_module_settings[
|
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
|
55
|
-
report_module_settings[
|
116
|
+
def batches(report_module, report_name)
|
117
|
+
report_module_settings[report_module][:reports][report_name][:batches]
|
56
118
|
end
|
57
119
|
|
58
|
-
|
59
|
-
|
60
|
-
|
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(
|
75
|
-
|
76
|
-
|
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
|
80
|
-
define_report_method(*fields) do |_, report_name,
|
81
|
-
|
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
|
-
|
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,
|
100
|
-
columns.each do |
|
101
|
-
|
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.
|
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.
|
218
|
+
self.set_settings(report_module, report_name, :mapping, mapping)
|
122
219
|
end
|
123
220
|
end
|
124
221
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
134
|
-
|
135
|
-
.
|
136
|
-
|
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(:
|
146
|
-
options.delete(:
|
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
|
-
|
149
|
-
|
150
|
-
|
151
|
-
options.delete(:
|
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(
|
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,
|
263
|
+
yield fields, report_module, report_name, options || {}
|
159
264
|
end
|
160
265
|
|
161
|
-
def initialize_settings_by(
|
162
|
-
|
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
|
-
|
165
|
-
fields:
|
270
|
+
reports: {},
|
271
|
+
fields: [],
|
166
272
|
group_by: [],
|
167
|
-
|
273
|
+
batches: {},
|
168
274
|
columns: {},
|
169
275
|
mapping: {},
|
170
|
-
|
276
|
+
# needs to be cloned
|
277
|
+
queries: [],
|
171
278
|
}
|
172
279
|
end
|
173
|
-
end
|
174
280
|
|
175
|
-
|
176
|
-
|
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
|
|