mongoid-report 0.1.3 → 0.1.5
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 +1 -1
- data/lib/mongoid/report/collection.rb +13 -5
- data/lib/mongoid/report/config.rb +11 -0
- data/lib/mongoid/report/queries_builder.rb +1 -7
- data/lib/mongoid/report/scope.rb +21 -12
- data/lib/mongoid/report/scope_collection.rb +23 -3
- data/lib/mongoid/report/version.rb +1 -1
- data/lib/mongoid/report.rb +16 -2
- data/spec/mongoid/report/aggregation_spec.rb +15 -9
- data/spec/mongoid/report/column_spec.rb +1 -1
- data/spec/mongoid/report/config_spec.rb +9 -0
- data/spec/mongoid/report/queries_builder_spec.rb +3 -3
- data/spec/mongoid/report/summary_spec.rb +24 -0
- data/spec/mongoid/report/threads_spec.rb +40 -0
- data/spec/mongoid/report_spec.rb +42 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NDE4Y2Y5ODExNDhkNTdmMWNlNzIwMTg1MWU0OTcwYWJlZTg0YTIzYw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzBhN2ZiY2RhMDhjOTcwZDA2ZjBkNjQ4NDEzN2I2MDZhNmVhZjZhOQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MzY3ZDQ5ZTI2YjJmNmE4OWU2Y2JmZWRkMTkzMzYwNmQ0NzJlNGFjNGI3OTY4
|
10
|
+
Mzc3MjBiNGE3ZjRiMTJjZDY3Nzk1NWFlNzBkMmM4YjA4YzM3MWM3NDQzMDhk
|
11
|
+
MWRiMTRhMzNkZDg1NDk3ZjUxOTdiMDAxZWZkNmNiMGU0ZGZiOWY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
M2NkYmJlYTU0YjcyZmRhODE3OTY5Yjg0Y2MzMmRhYzU0NTc5YmVkZTc0M2Zh
|
14
|
+
OWE4MWJjNWY5YjZkMjZkMGZmZGVkZTBkZjIwNzVjM2E4M2FhZTE1MjViYzhk
|
15
|
+
NTAzYTU5NGJhYjY4MGRkYjA3ZTc5YmQ3NjdiOGFlZWRiZjk5OTc=
|
data/Gemfile.lock
CHANGED
@@ -4,12 +4,18 @@ module Mongoid
|
|
4
4
|
module Report
|
5
5
|
|
6
6
|
class Collection < SimpleDelegator
|
7
|
-
def initialize(rows, fields, columns)
|
7
|
+
def initialize(context, rows, fields, columns)
|
8
|
+
@context = context
|
8
9
|
@rows = rows
|
9
10
|
@fields = fields
|
10
11
|
@columns = columns
|
12
|
+
|
13
|
+
# Apply dyncamic columns in context of row and apply indifferent access
|
14
|
+
# for the rows.
|
15
|
+
rows = compile_dynamic_fields(rows, columns)
|
16
|
+
|
17
|
+
# Collection should behave like Array using delegator method.
|
11
18
|
super(rows)
|
12
|
-
compile_dynamic_fields(columns)
|
13
19
|
end
|
14
20
|
|
15
21
|
def summary
|
@@ -24,11 +30,13 @@ module Mongoid
|
|
24
30
|
|
25
31
|
private
|
26
32
|
|
27
|
-
def compile_dynamic_fields(columns)
|
28
|
-
|
33
|
+
def compile_dynamic_fields(rows, columns)
|
34
|
+
rows.map do |row|
|
29
35
|
@columns.each do |name, function|
|
30
|
-
row[name] = function.call(row)
|
36
|
+
row[name] = function.call(@context, row)
|
31
37
|
end
|
38
|
+
|
39
|
+
row.with_indifferent_access
|
32
40
|
end
|
33
41
|
end
|
34
42
|
end
|
data/lib/mongoid/report/scope.rb
CHANGED
@@ -19,23 +19,32 @@ module Mongoid
|
|
19
19
|
|
20
20
|
def all
|
21
21
|
self.yield unless yielded?
|
22
|
-
|
23
|
-
|
22
|
+
|
23
|
+
aggregation_queries = compile_queries
|
24
|
+
rows = klass.collection.aggregate(aggregation_queries)
|
25
|
+
|
26
|
+
Collection.new(context, rows, fields, columns)
|
24
27
|
end
|
25
28
|
|
26
29
|
private
|
27
30
|
|
28
31
|
def compile_queries
|
29
|
-
queries.
|
30
|
-
query
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
compiled = queries.map do |query|
|
33
|
+
next query unless query.has_key?("$match")
|
34
|
+
|
35
|
+
query.deep_dup.tap do |new_query|
|
36
|
+
new_query.each do |function_name, values|
|
37
|
+
values.each do |name, value|
|
38
|
+
if value.respond_to?(:call)
|
39
|
+
value = value.call(context)
|
40
|
+
end
|
41
|
+
new_query[function_name][name] = value
|
42
|
+
end
|
34
43
|
end
|
35
44
|
end
|
36
|
-
|
37
|
-
query
|
38
45
|
end
|
46
|
+
|
47
|
+
compiled
|
39
48
|
end
|
40
49
|
|
41
50
|
def yielded?
|
@@ -47,17 +56,17 @@ module Mongoid
|
|
47
56
|
end
|
48
57
|
|
49
58
|
def klass
|
50
|
-
context.
|
59
|
+
context.report_module_settings[report_name][:for]
|
51
60
|
end
|
52
61
|
|
53
62
|
def fields
|
54
63
|
# We need to use here only output field names it could be different
|
55
64
|
# than defined colunms, Example: field1: 'report-field-name'
|
56
|
-
context.
|
65
|
+
context.report_module_settings[report_name][:fields].values
|
57
66
|
end
|
58
67
|
|
59
68
|
def columns
|
60
|
-
context.
|
69
|
+
context.report_module_settings[report_name][:columns]
|
61
70
|
end
|
62
71
|
end
|
63
72
|
|
@@ -1,7 +1,14 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
1
3
|
module Mongoid
|
2
4
|
module Report
|
3
5
|
|
4
6
|
ScopeCollection = Struct.new(:context) do
|
7
|
+
def initialize(context)
|
8
|
+
@mutex = Mutex.new
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
5
12
|
def scopes
|
6
13
|
@scopes ||= modules.map do |key|
|
7
14
|
Scope.new(context, key)
|
@@ -23,9 +30,22 @@ module Mongoid
|
|
23
30
|
end
|
24
31
|
|
25
32
|
def all
|
26
|
-
|
27
|
-
|
28
|
-
|
33
|
+
{}.tap do |hash|
|
34
|
+
if Mongoid::Report::Config.use_threads_on_aggregate
|
35
|
+
scopes.map do |scope|
|
36
|
+
Thread.new do
|
37
|
+
rows = scope.all
|
38
|
+
|
39
|
+
@mutex.synchronize do
|
40
|
+
hash[scope.report_name] = rows
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end.map(&:join)
|
44
|
+
else
|
45
|
+
scopes.each do |scope|
|
46
|
+
hash[scope.report_name] = scope.all
|
47
|
+
end
|
48
|
+
end
|
29
49
|
end
|
30
50
|
end
|
31
51
|
|
data/lib/mongoid/report.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
require 'active_support/core_ext/class/attribute'
|
3
3
|
|
4
|
+
require_relative 'report/config'
|
4
5
|
require_relative 'report/queries_builder'
|
5
6
|
require_relative 'report/attach_proxy'
|
6
7
|
require_relative 'report/collection'
|
@@ -19,8 +20,20 @@ module Mongoid
|
|
19
20
|
|
20
21
|
self.settings = {}
|
21
22
|
|
23
|
+
def self.inherited(subclass)
|
24
|
+
subclass.settings = self.settings.dup
|
25
|
+
end
|
26
|
+
|
27
|
+
# Variable for copying internal class settings to the instance because of
|
28
|
+
# possible modifications in case of using filters with lambda
|
29
|
+
# expressions.
|
30
|
+
attr_reader :report_module_settings
|
31
|
+
|
22
32
|
def initialize_report_module
|
23
|
-
|
33
|
+
# Lets store settings under created instance.
|
34
|
+
@report_module_settings = self.class.settings.dup
|
35
|
+
|
36
|
+
@report_module_settings.each do |klass, configuration|
|
24
37
|
builder = QueriesBuilder.new(configuration)
|
25
38
|
|
26
39
|
# Prepare group queries depends on the configuration in the included
|
@@ -35,7 +48,7 @@ module Mongoid
|
|
35
48
|
alias :initialize :initialize_report_module
|
36
49
|
|
37
50
|
def queries(klass)
|
38
|
-
|
51
|
+
report_module_settings[klass][:queries]
|
39
52
|
end
|
40
53
|
|
41
54
|
# We should pass here mongoid document
|
@@ -140,6 +153,7 @@ module Mongoid
|
|
140
153
|
fields: ActiveSupport::OrderedHash.new,
|
141
154
|
group_by: [],
|
142
155
|
queries: [],
|
156
|
+
compiled: false,
|
143
157
|
columns: ActiveSupport::OrderedHash.new,
|
144
158
|
}
|
145
159
|
end
|
@@ -7,19 +7,25 @@ describe Mongoid::Report do
|
|
7
7
|
let(:two_days_ago) { Date.parse("18-12-2004") }
|
8
8
|
|
9
9
|
describe '.aggregate_for' do
|
10
|
-
it 'aggregates fields by
|
11
|
-
|
12
|
-
|
13
|
-
instance3 = klass.create!(day: yesterday , field1: 1)
|
10
|
+
it 'aggregates fields by app' do
|
11
|
+
Report = Class.new do
|
12
|
+
include Mongoid::Report
|
14
13
|
|
15
|
-
|
14
|
+
attach_to Model do
|
15
|
+
aggregation_field :field1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
klass.create!(field1: 1)
|
20
|
+
klass.create!(field1: 1)
|
21
|
+
klass.create!(field1: 1)
|
22
|
+
|
23
|
+
example = Report.new
|
16
24
|
rows = example.aggregate_for(klass)
|
17
25
|
rows = rows.all
|
18
26
|
|
19
|
-
expect(rows.size).to eq(
|
20
|
-
expect(rows[0]['field1']).to eq(
|
21
|
-
expect(rows[1]['field1']).to eq(1)
|
22
|
-
expect(rows[2]['field1']).to eq(1)
|
27
|
+
expect(rows.size).to eq(1)
|
28
|
+
expect(rows[0]['field1']).to eq(3)
|
23
29
|
end
|
24
30
|
|
25
31
|
it 'aggregates field by defined field of the mode' do
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongoid::Report::Config do
|
4
|
+
it 'allows to set aggregation threads' do
|
5
|
+
expect(Mongoid::Report::Config.use_threads_on_aggregate).to eq(false)
|
6
|
+
Mongoid::Report::Config.use_threads_on_aggregate = true
|
7
|
+
expect(Mongoid::Report::Config.use_threads_on_aggregate).to eq(true)
|
8
|
+
end
|
9
|
+
end
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe Mongoid::Report::QueriesBuilder do
|
4
4
|
|
5
5
|
describe '.queries' do
|
6
|
-
it 'builds queries for aggregation
|
6
|
+
it 'builds queries for aggregation' do
|
7
7
|
queries = Report1.new.queries(Model)
|
8
8
|
expect(queries.size).to eq(3)
|
9
9
|
expect(queries[0]).to eq(
|
@@ -13,12 +13,12 @@ describe Mongoid::Report::QueriesBuilder do
|
|
13
13
|
})
|
14
14
|
expect(queries[1]).to eq(
|
15
15
|
'$group' => {
|
16
|
-
:_id => {
|
16
|
+
:_id => { },
|
17
17
|
:field1 => { '$sum' => '$field1' },
|
18
18
|
})
|
19
19
|
expect(queries[2]).to eq(
|
20
20
|
'$project' => {
|
21
|
-
:_id =>
|
21
|
+
:_id => 0,
|
22
22
|
:field1 => '$field1',
|
23
23
|
})
|
24
24
|
end
|
@@ -20,6 +20,30 @@ describe Mongoid::Report do
|
|
20
20
|
expect(rows.summary[:field1]).to eq(3)
|
21
21
|
expect(rows.summary['field1']).to eq(3)
|
22
22
|
end
|
23
|
+
|
24
|
+
it 'should support dynamic columns as well' do
|
25
|
+
Report = Class.new do
|
26
|
+
include Mongoid::Report
|
27
|
+
|
28
|
+
report 'example' do
|
29
|
+
attach_to Model do
|
30
|
+
aggregation_field :field1
|
31
|
+
column 'new-field1' => ->(context, row) { row['field1'] * 10 }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
klass.create!(field1: 1)
|
37
|
+
klass.create!(field1: 1)
|
38
|
+
klass.create!(field1: 1)
|
39
|
+
|
40
|
+
example = Report.new
|
41
|
+
rows = example.aggregate_for('example-models')
|
42
|
+
rows = rows.all
|
43
|
+
|
44
|
+
expect(rows[0]['field1']).to eq(3)
|
45
|
+
expect(rows[0]['new-field1']).to eq(30)
|
46
|
+
end
|
23
47
|
end
|
24
48
|
|
25
49
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
describe Mongoid::Report do
|
5
|
+
let(:klass) { Model }
|
6
|
+
|
7
|
+
it 'aggregates fields by app in threads' do
|
8
|
+
Report = Class.new do
|
9
|
+
include Mongoid::Report
|
10
|
+
|
11
|
+
attach_to Model, as: 'field1-aggregation' do
|
12
|
+
aggregation_field :field1
|
13
|
+
end
|
14
|
+
|
15
|
+
attach_to Model, as: 'field2-aggregation' do
|
16
|
+
aggregation_field :field2
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
30000.times { klass.create!(field1: 1, field2: 1) }
|
21
|
+
|
22
|
+
report = Report.new
|
23
|
+
scoped = report.aggregate
|
24
|
+
|
25
|
+
Mongoid::Report::Config.use_threads_on_aggregate = true
|
26
|
+
time1 = Benchmark.measure do
|
27
|
+
rows = scoped.all
|
28
|
+
end
|
29
|
+
|
30
|
+
Mongoid::Report::Config.use_threads_on_aggregate = false
|
31
|
+
time2 = Benchmark.measure do
|
32
|
+
rows = scoped.all
|
33
|
+
end
|
34
|
+
|
35
|
+
puts time2
|
36
|
+
puts time1
|
37
|
+
|
38
|
+
time2.real.should > time1.real
|
39
|
+
end
|
40
|
+
end
|
data/spec/mongoid/report_spec.rb
CHANGED
@@ -88,4 +88,46 @@ describe Mongoid::Report do
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
|
92
|
+
describe 'two report classes' do
|
93
|
+
it 'should have different settings' do
|
94
|
+
ReportKlass1 = Class.new do
|
95
|
+
include Mongoid::Report
|
96
|
+
|
97
|
+
attach_to Model do
|
98
|
+
aggregation_field :field1
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
ReportKlass2 = Class.new do
|
103
|
+
include Mongoid::Report
|
104
|
+
|
105
|
+
attach_to Model do
|
106
|
+
aggregation_field :field2
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
expect(ReportKlass1.settings).not_to eq(ReportKlass2.settings)
|
111
|
+
end
|
112
|
+
|
113
|
+
class ReportKlass
|
114
|
+
include Mongoid::Report
|
115
|
+
end
|
116
|
+
|
117
|
+
class ReportKlass1 < ReportKlass
|
118
|
+
attach_to Model do
|
119
|
+
aggregation_field :field1
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class ReportKlass2 < ReportKlass
|
124
|
+
attach_to Model do
|
125
|
+
aggregation_field :field2
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should have different settings for inherited classes' do
|
130
|
+
expect(ReportKlass1.fields(Model)).not_to eq(ReportKlass2.fields(Model))
|
131
|
+
end
|
132
|
+
end
|
91
133
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-report
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexandr Korsak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mongoid
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/mongoid/report.rb
|
75
75
|
- lib/mongoid/report/attach_proxy.rb
|
76
76
|
- lib/mongoid/report/collection.rb
|
77
|
+
- lib/mongoid/report/config.rb
|
77
78
|
- lib/mongoid/report/queries_builder.rb
|
78
79
|
- lib/mongoid/report/report_proxy.rb
|
79
80
|
- lib/mongoid/report/scope.rb
|
@@ -82,8 +83,10 @@ files:
|
|
82
83
|
- mongoid-report.gemspec
|
83
84
|
- spec/mongoid/report/aggregation_spec.rb
|
84
85
|
- spec/mongoid/report/column_spec.rb
|
86
|
+
- spec/mongoid/report/config_spec.rb
|
85
87
|
- spec/mongoid/report/queries_builder_spec.rb
|
86
88
|
- spec/mongoid/report/summary_spec.rb
|
89
|
+
- spec/mongoid/report/threads_spec.rb
|
87
90
|
- spec/mongoid/report_spec.rb
|
88
91
|
- spec/spec_helper.rb
|
89
92
|
- spec/support/models.rb
|
@@ -114,8 +117,10 @@ summary: Easily build mongoid reports using aggregation framework
|
|
114
117
|
test_files:
|
115
118
|
- spec/mongoid/report/aggregation_spec.rb
|
116
119
|
- spec/mongoid/report/column_spec.rb
|
120
|
+
- spec/mongoid/report/config_spec.rb
|
117
121
|
- spec/mongoid/report/queries_builder_spec.rb
|
118
122
|
- spec/mongoid/report/summary_spec.rb
|
123
|
+
- spec/mongoid/report/threads_spec.rb
|
119
124
|
- spec/mongoid/report_spec.rb
|
120
125
|
- spec/spec_helper.rb
|
121
126
|
- spec/support/models.rb
|