forest_liana 7.8.0 → 7.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/services/forest_liana/stat_getter.rb +9 -1
- data/app/services/forest_liana/value_stat_getter.rb +7 -6
- data/lib/forest_liana/version.rb +1 -1
- data/spec/services/forest_liana/line_stat_getter_spec.rb +13 -0
- data/spec/services/forest_liana/pie_stat_getter_spec.rb +90 -67
- data/spec/services/forest_liana/value_stat_getter_spec.rb +78 -55
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c535f5719b2f62c0ff1e2bde402a0c57b099f4120b5c6b3232d8ea0343c84eaf
|
4
|
+
data.tar.gz: b609b22af960f63d0b03e8a99597cf6d202da15414826d6dca1b836b7a672676
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 502270b809bf91474ce0bd977a767ee93325c70cfb7aa2ccc0b807ec54fb70a2c447e58eac44a9beca1b9bde7720e214c855f794834c9ec46eb871c60b259a7a
|
7
|
+
data.tar.gz: 581fe22c160e4f10a2ed8a866261b2362a31ffb03b5817433794d19f4c1a3a55878a9350e81b95088aeaf4f2b8d6c58a69ad4c1179b8252f6070afb077d52f85
|
@@ -6,7 +6,15 @@ module ForestLiana
|
|
6
6
|
@resource = resource
|
7
7
|
@params = params
|
8
8
|
@user = forest_user
|
9
|
-
|
9
|
+
|
10
|
+
validate_params
|
11
|
+
compute_includes
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_params
|
15
|
+
if @params.key?(:aggregate) && !%w[count sum avg max min].include?(@params[:aggregate].downcase)
|
16
|
+
raise ForestLiana::Errors::HTTP422Error.new('Invalid aggregate function')
|
17
|
+
end
|
10
18
|
end
|
11
19
|
|
12
20
|
def get_resource
|
@@ -19,24 +19,25 @@ module ForestLiana
|
|
19
19
|
end
|
20
20
|
|
21
21
|
@record = Model::Stat.new(value: {
|
22
|
-
countCurrent:
|
23
|
-
countPrevious: previous_value ?
|
22
|
+
countCurrent: aggregate(resource),
|
23
|
+
countPrevious: previous_value ? aggregate(previous_value) : nil
|
24
24
|
})
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
-
def
|
30
|
-
|
29
|
+
def aggregate(value)
|
30
|
+
aggregator = @params[:aggregate].downcase
|
31
|
+
uniq = aggregator == 'count'
|
31
32
|
|
32
33
|
if Rails::VERSION::MAJOR >= 4
|
33
34
|
if uniq
|
34
35
|
# NOTICE: uniq is deprecated since Rails 5.0
|
35
36
|
value = Rails::VERSION::MAJOR >= 5 ? value.distinct : value.uniq
|
36
37
|
end
|
37
|
-
value.send(
|
38
|
+
value.send(aggregator, aggregate_field)
|
38
39
|
else
|
39
|
-
value.send(
|
40
|
+
value.send(aggregator, aggregate_field, distinct: uniq)
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
data/lib/forest_liana/version.rb
CHANGED
@@ -10,6 +10,19 @@ module ForestLiana
|
|
10
10
|
Owner.delete_all
|
11
11
|
end
|
12
12
|
|
13
|
+
describe 'with not allowed aggregator' do
|
14
|
+
it 'should raise an error' do
|
15
|
+
expect {
|
16
|
+
LineStatGetter.new(Owner, {
|
17
|
+
timezone: "Europe/Paris",
|
18
|
+
aggregate: "eval",
|
19
|
+
time_range: "Week",
|
20
|
+
group_by_date_field: "`ls`",
|
21
|
+
}, user)
|
22
|
+
}.to raise_error(ForestLiana::Errors::HTTP422Error, 'Invalid aggregate function')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
13
26
|
describe 'Check client_timezone function' do
|
14
27
|
describe 'with a SQLite database' do
|
15
28
|
it 'should return false' do
|
@@ -23,90 +23,113 @@ module ForestLiana
|
|
23
23
|
}
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
{
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
describe 'with not allowed aggregator' do
|
27
|
+
let(:scopes) { { } }
|
28
|
+
let(:model) { Tree }
|
29
|
+
let(:collection) { 'trees' }
|
30
|
+
let(:params) {
|
31
|
+
{
|
32
|
+
type: 'Pie',
|
33
|
+
collection: collection,
|
34
|
+
timezone: 'Europe/Paris',
|
35
|
+
aggregate: 'eval',
|
36
|
+
group_by_field: '`ls`'
|
37
|
+
}
|
35
38
|
}
|
36
|
-
}
|
37
39
|
|
38
|
-
|
40
|
+
it 'should raise an error' do
|
41
|
+
expect {
|
42
|
+
PieStatGetter.new(model, params, user)
|
43
|
+
}.to raise_error(ForestLiana::Errors::HTTP422Error, 'Invalid aggregate function')
|
44
|
+
end
|
45
|
+
end
|
39
46
|
|
40
|
-
describe 'with
|
41
|
-
let(:
|
47
|
+
describe 'with valid aggregate function' do
|
48
|
+
let(:model) { Tree }
|
49
|
+
let(:collection) { 'trees' }
|
50
|
+
let(:params) {
|
51
|
+
{
|
52
|
+
type: 'Pie',
|
53
|
+
collection: collection,
|
54
|
+
timezone: 'Europe/Paris',
|
55
|
+
aggregate: 'Count',
|
56
|
+
group_by_field: group_by_field
|
57
|
+
}
|
58
|
+
}
|
42
59
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
60
|
+
subject { PieStatGetter.new(model, params, user) }
|
61
|
+
|
62
|
+
describe 'with empty scopes' do
|
63
|
+
let(:scopes) { { } }
|
64
|
+
|
65
|
+
describe 'with an aggregate on the name field' do
|
66
|
+
let(:group_by_field) { 'name' }
|
67
|
+
|
68
|
+
it 'should be as many categories as records count' do
|
69
|
+
subject.perform
|
70
|
+
expect(subject.record.value).to match_array([
|
71
|
+
{:key => "Old Tree n1", :value => 1},
|
72
|
+
{:key => "Old Tree n2", :value => 1},
|
73
|
+
{:key => "Old Tree n3", :value => 1},
|
74
|
+
{:key => "Old Tree n4", :value => 1},
|
75
|
+
{:key => "Young Tree n1", :value => 1},
|
76
|
+
{:key => "Young Tree n2", :value => 1},
|
77
|
+
{:key => "Young Tree n3", :value => 1},
|
78
|
+
{:key => "Young Tree n4", :value => 1},
|
79
|
+
{:key => "Young Tree n5", :value => 1}
|
80
|
+
])
|
81
|
+
end
|
59
82
|
end
|
60
|
-
end
|
61
83
|
|
62
|
-
|
63
|
-
|
84
|
+
describe 'with an aggregate on the age field' do
|
85
|
+
let(:group_by_field) { 'age' }
|
64
86
|
|
65
|
-
|
66
|
-
|
67
|
-
|
87
|
+
it 'should be as many categories as different ages among records' do
|
88
|
+
subject.perform
|
89
|
+
expect(subject.record.value).to eq [{ :key => 3, :value => 5}, { :key => 15, :value => 4 }]
|
90
|
+
end
|
68
91
|
end
|
69
92
|
end
|
70
|
-
end
|
71
93
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
94
|
+
describe 'with scopes' do
|
95
|
+
let(:scopes) {
|
96
|
+
{
|
97
|
+
'Tree' => {
|
98
|
+
'scope'=> {
|
99
|
+
'filter'=> {
|
100
|
+
'aggregator' => 'and',
|
101
|
+
'conditions' => [
|
102
|
+
{ 'field' => 'age', 'operator' => 'less_than', 'value' => 10 }
|
103
|
+
]
|
104
|
+
},
|
105
|
+
'dynamicScopesValues' => { }
|
106
|
+
}
|
84
107
|
}
|
85
108
|
}
|
86
109
|
}
|
87
|
-
}
|
88
110
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
111
|
+
describe 'with an aggregate on the name field' do
|
112
|
+
let(:group_by_field) { 'name' }
|
113
|
+
|
114
|
+
it 'should be as many categories as records inside the scope' do
|
115
|
+
subject.perform
|
116
|
+
expect(subject.record.value).to match_array([
|
117
|
+
{:key => "Young Tree n1", :value => 1},
|
118
|
+
{:key => "Young Tree n2", :value => 1},
|
119
|
+
{:key => "Young Tree n3", :value => 1},
|
120
|
+
{:key => "Young Tree n4", :value => 1},
|
121
|
+
{:key => "Young Tree n5", :value => 1}
|
122
|
+
])
|
123
|
+
end
|
101
124
|
end
|
102
|
-
end
|
103
125
|
|
104
|
-
|
105
|
-
|
126
|
+
describe 'with an aggregate on the age field' do
|
127
|
+
let(:group_by_field) { 'age' }
|
106
128
|
|
107
|
-
|
108
|
-
|
109
|
-
|
129
|
+
it 'should be only one category' do
|
130
|
+
subject.perform
|
131
|
+
expect(subject.record.value).to eq [{ :key => 3, :value => 5}]
|
132
|
+
end
|
110
133
|
end
|
111
134
|
end
|
112
135
|
end
|
@@ -15,80 +15,103 @@ module ForestLiana
|
|
15
15
|
Tree.create!(name: 'Tree n3', age: 4, island: island, owner: king, cutter: villager)
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
{
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
describe 'with not allowed aggregator' do
|
19
|
+
let(:model) { User }
|
20
|
+
let(:collection) { 'users' }
|
21
|
+
let(:scopes) { { } }
|
22
|
+
let(:params) {
|
23
|
+
{
|
24
|
+
type: "Value",
|
25
|
+
collection: collection,
|
26
|
+
timezone: "Europe/Paris",
|
27
|
+
aggregate: "eval",
|
28
|
+
aggregate_field: "`ls`"
|
29
|
+
}
|
25
30
|
}
|
26
|
-
}
|
27
31
|
|
28
|
-
|
32
|
+
it 'should raise an error' do
|
33
|
+
expect {
|
34
|
+
ValueStatGetter.new(model, params, user)
|
35
|
+
}.to raise_error(ForestLiana::Errors::HTTP422Error, 'Invalid aggregate function')
|
36
|
+
end
|
37
|
+
end
|
29
38
|
|
30
|
-
describe 'with
|
31
|
-
let(:
|
39
|
+
describe 'with valid aggregate function' do
|
40
|
+
let(:params) {
|
41
|
+
{
|
42
|
+
type: "Value",
|
43
|
+
collection: collection,
|
44
|
+
timezone: "Europe/Paris",
|
45
|
+
aggregate: "Count",
|
46
|
+
filters: filters
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
subject { ValueStatGetter.new(model, params, user) }
|
32
51
|
|
33
|
-
describe 'with
|
34
|
-
let(:
|
35
|
-
let(:collection) { 'users' }
|
36
|
-
let(:filters) { { field: 'name', operator: 'in', value: ['Merry', 'Pippin'] }.to_json }
|
52
|
+
describe 'with empty scopes' do
|
53
|
+
let(:scopes) { { } }
|
37
54
|
|
38
|
-
|
39
|
-
|
40
|
-
|
55
|
+
describe 'with a simple filter matching no entries' do
|
56
|
+
let(:model) { User }
|
57
|
+
let(:collection) { 'users' }
|
58
|
+
let(:filters) { { field: 'name', operator: 'in', value: ['Merry', 'Pippin'] }.to_json }
|
59
|
+
|
60
|
+
it 'should have a countCurrent of 0' do
|
61
|
+
subject.perform
|
62
|
+
expect(subject.record.value[:countCurrent]).to eq 0
|
63
|
+
end
|
41
64
|
end
|
42
|
-
end
|
43
65
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
66
|
+
describe 'with a filter on a belongs_to string field' do
|
67
|
+
let(:model) { Tree }
|
68
|
+
let(:collection) { 'trees' }
|
69
|
+
let(:filters) { { field: 'owner:name', operator: 'equal', value: 'Aragorn' }.to_json }
|
48
70
|
|
49
|
-
|
50
|
-
|
51
|
-
|
71
|
+
it 'should have a countCurrent of 2' do
|
72
|
+
subject.perform
|
73
|
+
expect(subject.record.value[:countCurrent]).to eq 2
|
74
|
+
end
|
52
75
|
end
|
53
|
-
end
|
54
76
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
77
|
+
describe 'with a filter on a belongs_to enum field' do
|
78
|
+
let(:model) { Tree }
|
79
|
+
let(:collection) { 'trees' }
|
80
|
+
let(:filters) { { field: 'owner:title', operator: 'equal', value: 'villager' }.to_json }
|
59
81
|
|
60
|
-
|
61
|
-
|
62
|
-
|
82
|
+
it 'should have a countCurrent of 1' do
|
83
|
+
subject.perform
|
84
|
+
expect(subject.record.value[:countCurrent]).to eq 1
|
85
|
+
end
|
63
86
|
end
|
64
87
|
end
|
65
|
-
end
|
66
88
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
89
|
+
describe 'with scopes' do
|
90
|
+
let(:scopes) {
|
91
|
+
{
|
92
|
+
'User' => {
|
93
|
+
'scope'=> {
|
94
|
+
'filter'=> {
|
95
|
+
'aggregator' => 'and',
|
96
|
+
'conditions' => [
|
97
|
+
{ 'field' => 'title', 'operator' => 'not_equal', 'value' => 'villager' }
|
98
|
+
]
|
99
|
+
},
|
100
|
+
'dynamicScopesValues' => { }
|
101
|
+
}
|
79
102
|
}
|
80
103
|
}
|
81
104
|
}
|
82
|
-
}
|
83
105
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
106
|
+
describe 'with a filter on a belongs_to enum field' do
|
107
|
+
let(:model) { User }
|
108
|
+
let(:collection) { 'users' }
|
109
|
+
let(:filters) { { field: 'title', operator: 'equal', value: 'villager' }.to_json }
|
88
110
|
|
89
|
-
|
90
|
-
|
91
|
-
|
111
|
+
it 'should have a countCurrent of 0' do
|
112
|
+
subject.perform
|
113
|
+
expect(subject.record.value[:countCurrent]).to eq 0
|
114
|
+
end
|
92
115
|
end
|
93
116
|
end
|
94
117
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forest_liana
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.8.
|
4
|
+
version: 7.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sandro Munda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|