mongoid-report 0.1.9 → 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.
- 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
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NzMwZDY2MzQxNmI5ZmJmYjUxZjhkZTJkM2VlOTg2OGI2YTBmNTBmNA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZTg4NzljZmFjNDRmOWNkZTExYWY0N2U3MGUxMTIwOTBkNzc0OTkxYw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NzNiYzA4NmU2YTg1MjQyMDQxNzEwYmIwNzk1ZmRjZGYxOTNkODFjYTI0YWYy
|
10
|
+
MjU4MGU2YjQwZWZjOTUxZjdiMWZkMWE4OWRkYzIyZjFkMzEzMDdjYzZkMTJi
|
11
|
+
ZGRhNjFmOTc2ZWVjZTM5Y2MwMTJjNWJmYWUxMmYzMDNkNTdlODk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NDMwMzRjMTg0YjE1NTE1ZTcwMmE1OTYxZTUxMTE3NmY1ZmMwNjM0MDAzNTk3
|
14
|
+
NjhlMzAxZjFiYTljMmI2MTQ2Y2Q5NWUyODIxNDYzOTczMGI1ZDgyNjAxNjFh
|
15
|
+
YmY3YTMzYWIwOTUyNmQ4ZjQyMTZlNjFmNDFiMDdjYzE0OGY3ZjM=
|
data/Gemfile.lock
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mongoid-report (0.
|
4
|
+
mongoid-report (0.2.0)
|
5
5
|
mongoid (> 3.0.1)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (
|
11
|
-
activesupport (=
|
12
|
-
builder (~> 3.
|
13
|
-
activesupport (
|
14
|
-
i18n (~> 0.6, >= 0.6.
|
15
|
-
|
16
|
-
|
10
|
+
activemodel (4.1.4)
|
11
|
+
activesupport (= 4.1.4)
|
12
|
+
builder (~> 3.1)
|
13
|
+
activesupport (4.1.4)
|
14
|
+
i18n (~> 0.6, >= 0.6.9)
|
15
|
+
json (~> 1.7, >= 1.7.7)
|
16
|
+
minitest (~> 5.1)
|
17
|
+
thread_safe (~> 0.1)
|
18
|
+
tzinfo (~> 1.1)
|
19
|
+
bson (2.3.0)
|
20
|
+
builder (3.2.2)
|
17
21
|
celluloid (0.15.2)
|
18
22
|
timers (~> 1.1.0)
|
19
23
|
celluloid-io (0.15.0)
|
@@ -21,6 +25,7 @@ GEM
|
|
21
25
|
nio4r (>= 0.5.0)
|
22
26
|
coderay (1.1.0)
|
23
27
|
columnize (0.3.6)
|
28
|
+
connection_pool (2.0.0)
|
24
29
|
debugger (1.6.6)
|
25
30
|
columnize (>= 0.3.1)
|
26
31
|
debugger-linecache (~> 1.2.0)
|
@@ -42,7 +47,8 @@ GEM
|
|
42
47
|
guard-rspec (4.2.8)
|
43
48
|
guard (~> 2.1)
|
44
49
|
rspec (>= 2.14, < 4.0)
|
45
|
-
i18n (0.6.
|
50
|
+
i18n (0.6.11)
|
51
|
+
json (1.8.1)
|
46
52
|
listen (2.7.1)
|
47
53
|
celluloid (>= 0.15.2)
|
48
54
|
celluloid-io (>= 0.15.0)
|
@@ -50,15 +56,19 @@ GEM
|
|
50
56
|
rb-inotify (>= 0.9)
|
51
57
|
lumberjack (1.0.5)
|
52
58
|
method_source (0.8.2)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
minitest (5.4.0)
|
60
|
+
mongoid (4.0.0)
|
61
|
+
activemodel (~> 4.0)
|
62
|
+
moped (~> 2.0.0)
|
63
|
+
origin (~> 2.1)
|
64
|
+
tzinfo (>= 0.3.37)
|
65
|
+
moped (2.0.0)
|
66
|
+
bson (~> 2.2)
|
67
|
+
connection_pool (~> 2.0)
|
68
|
+
optionable (~> 0.2.0)
|
60
69
|
nio4r (1.0.0)
|
61
|
-
|
70
|
+
optionable (0.2.0)
|
71
|
+
origin (2.1.1)
|
62
72
|
pry (0.9.12.6)
|
63
73
|
coderay (~> 1.0)
|
64
74
|
method_source (~> 0.8)
|
@@ -84,8 +94,10 @@ GEM
|
|
84
94
|
rspec-support (3.0.0)
|
85
95
|
slop (3.5.0)
|
86
96
|
thor (0.19.1)
|
97
|
+
thread_safe (0.3.4)
|
87
98
|
timers (1.1.0)
|
88
|
-
tzinfo (
|
99
|
+
tzinfo (1.2.1)
|
100
|
+
thread_safe (~> 0.1)
|
89
101
|
|
90
102
|
PLATFORMS
|
91
103
|
ruby
|
data/README.md
CHANGED
@@ -14,6 +14,7 @@ framework.
|
|
14
14
|
include Mongoid::Document
|
15
15
|
|
16
16
|
field :field1, type: Integer, default: 0
|
17
|
+
field :field2, type: Integer, default: 0
|
17
18
|
|
18
19
|
field :day, type: Date
|
19
20
|
end
|
@@ -21,42 +22,11 @@ framework.
|
|
21
22
|
class Report1
|
22
23
|
include Mongoid::Report
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
attach_to Model do
|
31
|
-
column :field1
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class Report3
|
36
|
-
include Mongoid::Report
|
37
|
-
|
38
|
-
group_by :day, for: Model
|
39
|
-
|
40
|
-
column :field1, for: Model
|
41
|
-
end
|
42
|
-
|
43
|
-
class Report4
|
44
|
-
include Mongoid::Report
|
45
|
-
|
46
|
-
attach_to Model do
|
47
|
-
group_by :day
|
48
|
-
|
49
|
-
column :field1
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class Report5
|
54
|
-
include Mongoid::Report
|
55
|
-
|
56
|
-
attach_to Model, as: 'summary-report' do
|
57
|
-
group_by :day
|
58
|
-
|
59
|
-
column :field1
|
25
|
+
report 'example' do
|
26
|
+
attach_to Model do
|
27
|
+
group_by :day
|
28
|
+
column :field1, collection: Model
|
29
|
+
end
|
60
30
|
end
|
61
31
|
end
|
62
32
|
```
|
@@ -2,12 +2,21 @@ module Mongoid
|
|
2
2
|
module Report
|
3
3
|
|
4
4
|
AttachProxy = Struct.new(:context, :collection, :options) do
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :report_name
|
6
6
|
|
7
7
|
def initialize(context, collection, options)
|
8
8
|
# Lets remove as option because of passing to the next blocks options
|
9
|
-
|
10
|
-
|
9
|
+
report_name = options.delete(:as)
|
10
|
+
|
11
|
+
if collection
|
12
|
+
report_name ||= Collections.name(collection)
|
13
|
+
end
|
14
|
+
|
15
|
+
options.merge!(
|
16
|
+
report_name: report_name,
|
17
|
+
collection: collection,
|
18
|
+
)
|
19
|
+
|
11
20
|
super(context, collection, options)
|
12
21
|
end
|
13
22
|
|
@@ -35,10 +44,22 @@ module Mongoid
|
|
35
44
|
context.group_by(*fields, proxy_options)
|
36
45
|
end
|
37
46
|
|
38
|
-
def
|
47
|
+
def match(*fields)
|
48
|
+
proxy_options = fields.extract_options!
|
49
|
+
proxy_options.merge!(options)
|
50
|
+
context.match(*fields, proxy_options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def query(*fields)
|
54
|
+
proxy_options = fields.extract_options!
|
55
|
+
proxy_options.merge!(options)
|
56
|
+
context.query(*fields, proxy_options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def batches(*fields)
|
39
60
|
proxy_options = fields.extract_options!
|
40
61
|
proxy_options.merge!(options)
|
41
|
-
context.
|
62
|
+
context.batches(*fields, proxy_options)
|
42
63
|
end
|
43
64
|
end
|
44
65
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Report
|
3
|
+
|
4
|
+
# Split the queries into threads.
|
5
|
+
Batches = Struct.new(:settings, :conditions) do
|
6
|
+
DEFAULT_THREAD_POOL_SIZE = 5
|
7
|
+
|
8
|
+
def initialize(settings = {}, conditions = {})
|
9
|
+
if settings.nil? || settings.empty?
|
10
|
+
settings = { 'pool_size' => DEFAULT_THREAD_POOL_SIZE }
|
11
|
+
end
|
12
|
+
|
13
|
+
super(settings, conditions)
|
14
|
+
end
|
15
|
+
|
16
|
+
def field
|
17
|
+
conditions.keys[0]
|
18
|
+
end
|
19
|
+
|
20
|
+
def range
|
21
|
+
conditions.values[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def map
|
25
|
+
range.each_slice(size.ceil).map do |r|
|
26
|
+
yield r
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def size
|
31
|
+
range.count.to_f / settings['pool_size'].to_f
|
32
|
+
end
|
33
|
+
|
34
|
+
def present?
|
35
|
+
settings['pool_size'].present? &&
|
36
|
+
conditions.present?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -3,7 +3,7 @@ require 'delegate'
|
|
3
3
|
module Mongoid
|
4
4
|
module Report
|
5
5
|
|
6
|
-
class Collection
|
6
|
+
class Collection
|
7
7
|
def initialize(context, rows, fields, columns, mapping)
|
8
8
|
@context = context
|
9
9
|
@rows = rows
|
@@ -15,7 +15,7 @@ module Mongoid
|
|
15
15
|
|
16
16
|
class Rows < SimpleDelegator ; end
|
17
17
|
|
18
|
-
attr_reader :rows
|
18
|
+
attr_reader :context, :rows
|
19
19
|
|
20
20
|
def headers
|
21
21
|
@fields
|
@@ -29,13 +29,14 @@ module Mongoid
|
|
29
29
|
# all summaried mongo columns and then apply dynamic columns
|
30
30
|
# calculations.
|
31
31
|
next if @columns.has_key?(field)
|
32
|
+
next unless row[field].is_a?(Fixnum) || row[field].is_a?(Float)
|
32
33
|
summary[field] += row[field]
|
33
34
|
end
|
34
35
|
|
35
36
|
# Apply dynamic columns for summarized row
|
36
37
|
@columns.each do |name, function|
|
37
38
|
next unless @fields.include?(name)
|
38
|
-
summary[name] = function.call(@context,
|
39
|
+
summary[name] = function.call(@context, summary, { mapping: @mapping, summary: true })
|
39
40
|
end
|
40
41
|
|
41
42
|
summary
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Report
|
3
|
+
|
4
|
+
class Collections
|
5
|
+
def self.get(collection_name)
|
6
|
+
Mongoid.session(:default)[collection_name]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.name(model)
|
10
|
+
model && model.respond_to?(:collection) ?
|
11
|
+
model.collection.name : model
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Report
|
3
|
+
|
4
|
+
class Input
|
5
|
+
attr_accessor :collection_name
|
6
|
+
|
7
|
+
def present?
|
8
|
+
collection_name.present?
|
9
|
+
end
|
10
|
+
|
11
|
+
def collection
|
12
|
+
@collection ||= Mongoid::Report::Collections.get(collection_name)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Report
|
3
|
+
|
4
|
+
# We are using this class to combine results by group by fields.
|
5
|
+
Merger = Struct.new(:groups) do
|
6
|
+
def do(rows)
|
7
|
+
# Merge by groups.
|
8
|
+
rows
|
9
|
+
.group_by { |row| groups.map { |group| row[group] }.join('-') }
|
10
|
+
.values
|
11
|
+
.map { |array_row| combine(array_row) }
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def combine(rows)
|
17
|
+
rows.inject(Hash.new {|h,k| h[k] = 0}) do |row, lines|
|
18
|
+
lines.each do |key, value|
|
19
|
+
next row[key] = value if groups.include?(key)
|
20
|
+
row[key] += value
|
21
|
+
end
|
22
|
+
|
23
|
+
row
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Report
|
3
|
+
|
4
|
+
class Output
|
5
|
+
attr_accessor :collection_name, :options
|
6
|
+
|
7
|
+
def do(rows)
|
8
|
+
drop()
|
9
|
+
collection.insert(rows)
|
10
|
+
end
|
11
|
+
|
12
|
+
def present?
|
13
|
+
collection_name.present?
|
14
|
+
end
|
15
|
+
|
16
|
+
def drop
|
17
|
+
return collection.drop() unless options[:drop].present?
|
18
|
+
|
19
|
+
# We will use custom way for dropping the collection or removing the
|
20
|
+
# records partially
|
21
|
+
collection.find(options[:drop]).remove_all()
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def collection
|
27
|
+
@collection ||= Collections.get(collection_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Report
|
3
3
|
|
4
|
-
QueriesBuilder = Struct.new(:
|
4
|
+
QueriesBuilder = Struct.new(:configuration) do
|
5
5
|
def do
|
6
6
|
[].tap do |queries|
|
7
7
|
queries.concat([{ '$project' => project_query }])
|
@@ -13,26 +13,22 @@ module Mongoid
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def groups
|
16
|
-
|
16
|
+
configuration[:group_by]
|
17
17
|
end
|
18
18
|
|
19
19
|
def fields
|
20
|
-
@fields ||=
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def in_fields
|
26
|
-
@in_fields ||= fields.keys
|
27
|
-
end
|
20
|
+
@fields ||= begin
|
21
|
+
columns = configuration[:columns].keys
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
configuration[:fields].select do |field|
|
24
|
+
!columns.include?(field.to_sym)
|
25
|
+
end
|
26
|
+
end
|
31
27
|
end
|
32
28
|
|
33
29
|
def all_fields
|
34
30
|
[:_id]
|
35
|
-
.concat(
|
31
|
+
.concat(fields)
|
36
32
|
.concat(groups)
|
37
33
|
end
|
38
34
|
|
@@ -52,7 +48,8 @@ module Mongoid
|
|
52
48
|
hash.merge!(group => GROUP_TEMPLATE % group)
|
53
49
|
end
|
54
50
|
|
55
|
-
|
51
|
+
fields.inject(query) do |hash, field|
|
52
|
+
next hash if groups.include?(field)
|
56
53
|
hash.merge!(field => { '$sum' => GROUP_TEMPLATE % field })
|
57
54
|
end
|
58
55
|
end
|
@@ -71,8 +68,9 @@ module Mongoid
|
|
71
68
|
end
|
72
69
|
end
|
73
70
|
|
74
|
-
fields.inject(query) do |hash,
|
75
|
-
hash.
|
71
|
+
fields.inject(query) do |hash, field|
|
72
|
+
next hash if groups.include?(field)
|
73
|
+
hash.merge!(field => "$#{field}")
|
76
74
|
end
|
77
75
|
end
|
78
76
|
end
|
@@ -1,13 +1,25 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module Mongoid
|
2
4
|
module Report
|
3
5
|
|
4
6
|
ReportProxy = Struct.new(:context, :name) do
|
5
|
-
def
|
6
|
-
|
7
|
+
def attach_proxy
|
8
|
+
@attach_proxy ||= begin
|
9
|
+
AttachProxy.new(context, nil, report_module: name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
delegate :column, :columns, :mapping, :group_by, :match,
|
13
|
+
:batches, :query, to: :attach_proxy
|
14
|
+
|
15
|
+
def attach_to(*fields, &block)
|
16
|
+
options = fields.extract_options!
|
17
|
+
model = fields[0]
|
7
18
|
|
8
|
-
options.
|
19
|
+
report_name = options.delete(:as) || Collections.name(model)
|
20
|
+
options.merge!(report_module: name, as: report_name)
|
9
21
|
|
10
|
-
context.attach_to(
|
22
|
+
context.attach_to(*fields, options, &block)
|
11
23
|
end
|
12
24
|
end
|
13
25
|
|
data/lib/mongoid/report/scope.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module Mongoid
|
2
4
|
module Report
|
3
5
|
|
4
|
-
Scope = Struct.new(:context, :report_name) do
|
6
|
+
Scope = Struct.new(:context, :report_module, :report_name) do
|
5
7
|
def query(conditions = {})
|
6
8
|
queries.concat([conditions]) unless conditions.empty?
|
7
9
|
self
|
@@ -11,41 +13,112 @@ module Mongoid
|
|
11
13
|
def yield
|
12
14
|
return self if @yielded
|
13
15
|
|
14
|
-
queries.concat(context.queries(report_name))
|
16
|
+
queries.concat(context.queries(report_module, report_name))
|
15
17
|
@yielded = true
|
16
18
|
|
17
19
|
self
|
18
20
|
end
|
19
21
|
|
22
|
+
def out(collection_name, options = {})
|
23
|
+
output.collection_name = collection_name
|
24
|
+
output.options = options
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def in(collection_name)
|
29
|
+
input.collection_name = collection_name
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def all_in_batches(aggregation_queries)
|
34
|
+
# Lets assume we have only one field for making splits for the
|
35
|
+
# aggregation queries.
|
36
|
+
rows = []
|
37
|
+
|
38
|
+
threads = batches.map do |r|
|
39
|
+
# For now we are supporting only data fields for splitting up the
|
40
|
+
# queries.
|
41
|
+
range_match = r.map { |time| time.to_date.mongoize }
|
42
|
+
|
43
|
+
Thread.new do
|
44
|
+
q =
|
45
|
+
['$match' => { batches.field => { '$gte' => range_match.first, '$lte' => range_match.last } }] +
|
46
|
+
aggregation_queries
|
47
|
+
|
48
|
+
# if groups == [batch.field]
|
49
|
+
rows.concat(Array(collection.aggregate(q)))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
threads.map(&:join)
|
53
|
+
|
54
|
+
merger = Mongoid::Report::Merger.new(groups)
|
55
|
+
merger.do(rows)
|
56
|
+
end
|
57
|
+
|
58
|
+
def all_inline(aggregation_queries)
|
59
|
+
Array(collection.aggregate(aggregation_queries))
|
60
|
+
end
|
61
|
+
|
20
62
|
def all
|
21
63
|
self.yield unless yielded?
|
22
64
|
|
23
65
|
aggregation_queries = compile_queries
|
24
|
-
|
66
|
+
|
67
|
+
rows = if batches.present?
|
68
|
+
all_in_batches(aggregation_queries)
|
69
|
+
else
|
70
|
+
all_inline(aggregation_queries)
|
71
|
+
end
|
72
|
+
|
73
|
+
# in case if we want to store rows to collection
|
74
|
+
if output.present?
|
75
|
+
output.do(rows)
|
76
|
+
end
|
25
77
|
|
26
78
|
Collection.new(context, rows, fields, columns, mapping)
|
27
79
|
end
|
28
80
|
|
81
|
+
def in_batches(conditions)
|
82
|
+
batches.conditions = conditions
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
29
86
|
private
|
30
87
|
|
31
88
|
def compile_queries
|
32
|
-
compiled =
|
33
|
-
|
89
|
+
compiled = Set.new
|
90
|
+
|
91
|
+
queries.each do |query|
|
92
|
+
next compiled << query if query.has_key?("$project") || query.has_key?('$group')
|
34
93
|
|
35
94
|
query.deep_dup.tap do |new_query|
|
36
95
|
new_query.each do |function_name, values|
|
37
|
-
|
38
|
-
|
39
|
-
|
96
|
+
|
97
|
+
if values.respond_to?(:call)
|
98
|
+
new_query[function_name] = values.call(context)
|
99
|
+
else
|
100
|
+
values.each do |name, value|
|
101
|
+
if value.respond_to?(:call)
|
102
|
+
value = value.call(context)
|
103
|
+
end
|
104
|
+
|
105
|
+
unless value.present?
|
106
|
+
# In case we don't have value for applying match, lets skip
|
107
|
+
# this type of the queries.
|
108
|
+
new_query.delete(function_name)
|
109
|
+
else
|
110
|
+
new_query[function_name][name] = value
|
111
|
+
end
|
40
112
|
end
|
41
113
|
|
42
|
-
|
43
|
-
|
44
|
-
|
114
|
+
end # values.is_a?(Proc)
|
115
|
+
end # new_query.each
|
116
|
+
|
117
|
+
compiled << new_query if new_query.present?
|
45
118
|
end
|
46
119
|
end
|
47
120
|
|
48
|
-
compiled
|
121
|
+
compiled.to_a
|
49
122
|
end
|
50
123
|
|
51
124
|
def yielded?
|
@@ -56,22 +129,55 @@ module Mongoid
|
|
56
129
|
@queries ||= []
|
57
130
|
end
|
58
131
|
|
59
|
-
|
60
|
-
|
132
|
+
# Different usage for this method:
|
133
|
+
# - attach_to method contains collection name as first argument
|
134
|
+
# - attach_to method contains mongoid model
|
135
|
+
# - aggregate_for method contains attach_to proc option for calculating
|
136
|
+
# collection name.
|
137
|
+
def collection
|
138
|
+
@collection ||= begin
|
139
|
+
# In case if we are using dynamic collection name calculated by
|
140
|
+
# passing attach_to proc to the aggregate method.
|
141
|
+
if input.present?
|
142
|
+
# Using default session to mongodb we can automatically provide
|
143
|
+
# access to collection.
|
144
|
+
input.collection
|
145
|
+
else
|
146
|
+
klass = context.report_module_settings[report_module][:reports][report_name][:collection]
|
147
|
+
Collections.get(klass)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def batches
|
153
|
+
@batches ||= Mongoid::Report::Batches.new(
|
154
|
+
context.batches(report_module, report_name))
|
155
|
+
end
|
156
|
+
|
157
|
+
def output
|
158
|
+
@output ||= Mongoid::Report::Output.new
|
159
|
+
end
|
160
|
+
|
161
|
+
def input
|
162
|
+
@input ||= Mongoid::Report::Input.new
|
163
|
+
end
|
164
|
+
|
165
|
+
def groups
|
166
|
+
@groups ||= context.groups(report_module, report_name)
|
61
167
|
end
|
62
168
|
|
63
169
|
def fields
|
64
170
|
# We need to use here only output field names it could be different
|
65
171
|
# than defined colunms, Example: field1: 'report-field-name'
|
66
|
-
context.
|
172
|
+
context.fields(report_module, report_name)
|
67
173
|
end
|
68
174
|
|
69
175
|
def columns
|
70
|
-
context.
|
176
|
+
context.columns(report_module, report_name)
|
71
177
|
end
|
72
178
|
|
73
179
|
def mapping
|
74
|
-
context.
|
180
|
+
context.mapping(report_module, report_name)
|
75
181
|
end
|
76
182
|
end
|
77
183
|
|