trifle-stats 2.4.0 → 2.5.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +20 -2
- data/lib/trifle/stats/driver/mysql.rb +33 -15
- data/lib/trifle/stats/driver/postgres.rb +66 -37
- data/lib/trifle/stats/driver/redis.rb +37 -30
- data/lib/trifle/stats/driver/sqlite.rb +75 -35
- data/lib/trifle/stats/nocturnal.rb +2 -2
- data/lib/trifle/stats/operations/timeseries/increment.rb +8 -1
- data/lib/trifle/stats/operations/timeseries/set.rb +8 -1
- data/lib/trifle/stats/operations/timeseries/values.rb +14 -1
- data/lib/trifle/stats/transponder/expression.rb +117 -0
- data/lib/trifle/stats/transponder/expression_engine.rb +356 -0
- data/lib/trifle/stats/version.rb +1 -1
- data/lib/trifle/stats.rb +2 -10
- metadata +4 -13
- data/lib/trifle/stats/nocturnal_legacy.rb +0 -161
- data/lib/trifle/stats/transponder/add.rb +0 -30
- data/lib/trifle/stats/transponder/divide.rb +0 -30
- data/lib/trifle/stats/transponder/max.rb +0 -31
- data/lib/trifle/stats/transponder/mean.rb +0 -31
- data/lib/trifle/stats/transponder/min.rb +0 -31
- data/lib/trifle/stats/transponder/multiply.rb +0 -30
- data/lib/trifle/stats/transponder/ratio.rb +0 -30
- data/lib/trifle/stats/transponder/standard_deviation.rb +0 -34
- data/lib/trifle/stats/transponder/subtract.rb +0 -30
- data/lib/trifle/stats/transponder/sum.rb +0 -28
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Nocturnal # rubocop:disable Metrics/ClassLength
|
|
6
|
-
UNIT_MAP = {
|
|
7
|
-
's' => :second,
|
|
8
|
-
'm' => :minute,
|
|
9
|
-
'h' => :hour,
|
|
10
|
-
'd' => :day,
|
|
11
|
-
'w' => :week,
|
|
12
|
-
'mo' => :month,
|
|
13
|
-
'q' => :quarter,
|
|
14
|
-
'y' => :year
|
|
15
|
-
}.freeze
|
|
16
|
-
|
|
17
|
-
DAYS_INTO_WEEK = {
|
|
18
|
-
sunday: 0, monday: 1, tuesday: 2, wednesday: 3,
|
|
19
|
-
thursday: 4, friday: 5, saturday: 6
|
|
20
|
-
}.freeze
|
|
21
|
-
|
|
22
|
-
def self.timeline(from:, to:, granularity:, config: nil)
|
|
23
|
-
list = []
|
|
24
|
-
from = new(from, config: config).send(granularity)
|
|
25
|
-
to = new(to, config: config).send(granularity)
|
|
26
|
-
item = from.dup
|
|
27
|
-
while item <= to
|
|
28
|
-
list << item
|
|
29
|
-
item = Nocturnal.new(item, config: config).send("next_#{granularity}")
|
|
30
|
-
end
|
|
31
|
-
list
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def initialize(at, config: nil)
|
|
35
|
-
@at = at
|
|
36
|
-
@config = config
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def config
|
|
40
|
-
@config || Trifle::Stats.default
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def change(**fractions)
|
|
44
|
-
Time.new(
|
|
45
|
-
fractions.fetch(:year, @at.year),
|
|
46
|
-
fractions.fetch(:month, @at.month),
|
|
47
|
-
fractions.fetch(:day, @at.day),
|
|
48
|
-
fractions.fetch(:hour, @at.hour),
|
|
49
|
-
fractions.fetch(:minute, @at.min),
|
|
50
|
-
fractions.fetch(:second, 0),
|
|
51
|
-
config.tz.utc_offset
|
|
52
|
-
)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def second
|
|
56
|
-
change(second: @at.sec)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def next_second
|
|
60
|
-
Nocturnal.new(
|
|
61
|
-
second + 1,
|
|
62
|
-
config: config
|
|
63
|
-
).second
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def minute
|
|
67
|
-
change(second: 0)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def next_minute
|
|
71
|
-
Nocturnal.new(
|
|
72
|
-
minute + 60,
|
|
73
|
-
config: config
|
|
74
|
-
).minute
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def hour
|
|
78
|
-
change(minute: 0)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def next_hour
|
|
82
|
-
Nocturnal.new(
|
|
83
|
-
hour + 60 * 60,
|
|
84
|
-
config: config
|
|
85
|
-
).hour
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def day
|
|
89
|
-
change(hour: 0, minute: 0)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def next_day
|
|
93
|
-
Nocturnal.new(
|
|
94
|
-
day + 60 * 60 * 24,
|
|
95
|
-
config: config
|
|
96
|
-
).day
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def week
|
|
100
|
-
today = day
|
|
101
|
-
|
|
102
|
-
(today.to_date - days_to_week_start).to_time
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def next_week
|
|
106
|
-
Nocturnal.new(
|
|
107
|
-
week + 60 * 60 * 24 * 7,
|
|
108
|
-
config: config
|
|
109
|
-
).week
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def days_to_week_start
|
|
113
|
-
start_day_number = DAYS_INTO_WEEK.fetch(
|
|
114
|
-
config.beginning_of_week
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
(@at.wday - start_day_number) % 7
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def month
|
|
121
|
-
change(day: 1, hour: 0, minute: 0)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def next_month
|
|
125
|
-
Nocturnal.new(
|
|
126
|
-
month + 60 * 60 * 24 * 31,
|
|
127
|
-
config: config
|
|
128
|
-
).month
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def quarter
|
|
132
|
-
first_quarter_month = @at.month - (2 + @at.month) % 3
|
|
133
|
-
|
|
134
|
-
change(
|
|
135
|
-
month: first_quarter_month,
|
|
136
|
-
day: 1,
|
|
137
|
-
hour: 0,
|
|
138
|
-
minute: 0
|
|
139
|
-
)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def next_quarter
|
|
143
|
-
Nocturnal.new(
|
|
144
|
-
quarter + 60 * 60 * 24 * 31 * 3,
|
|
145
|
-
config: config
|
|
146
|
-
).quarter
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def year
|
|
150
|
-
change(month: 1, day: 1, hour: 0, minute: 0)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def next_year
|
|
154
|
-
Nocturnal.new(
|
|
155
|
-
year + 60 * 60 * 24 * 31 * 12,
|
|
156
|
-
config: config
|
|
157
|
-
).year
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Add
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:add, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, left:, right:, response: 'add') # rubocop:disable Metrics/MethodLength
|
|
11
|
-
left_keys = left.to_s.split('.')
|
|
12
|
-
right_keys = right.to_s.split('.')
|
|
13
|
-
|
|
14
|
-
series[:values] = series[:values].map do |data|
|
|
15
|
-
dleft = data.dig(*left_keys)
|
|
16
|
-
dright = data.dig(*right_keys)
|
|
17
|
-
next data unless dleft && dright
|
|
18
|
-
|
|
19
|
-
dres = dleft + dright
|
|
20
|
-
signal = {
|
|
21
|
-
response => dres
|
|
22
|
-
}
|
|
23
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
24
|
-
end
|
|
25
|
-
series
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Divide
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:divide, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, left:, right:, response: 'divide') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
11
|
-
left_keys = left.to_s.split('.')
|
|
12
|
-
right_keys = right.to_s.split('.')
|
|
13
|
-
|
|
14
|
-
series[:values] = series[:values].map do |data|
|
|
15
|
-
dleft = data.dig(*left_keys)
|
|
16
|
-
dright = data.dig(*right_keys)
|
|
17
|
-
next data unless dleft && dright
|
|
18
|
-
|
|
19
|
-
dres = (dleft / dright)
|
|
20
|
-
signal = {
|
|
21
|
-
response => dres.nan? ? BigDecimal(0) : dres
|
|
22
|
-
}
|
|
23
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
24
|
-
end
|
|
25
|
-
series
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Max
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:max, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, paths:, response: 'max') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
11
|
-
path_keys = paths.map { |path| path.to_s.split('.') }
|
|
12
|
-
|
|
13
|
-
series[:values] = series[:values].map do |data|
|
|
14
|
-
dvalues = path_keys.map { |path_key| data.dig(*path_key) }
|
|
15
|
-
next data if dvalues.any?(&:nil?)
|
|
16
|
-
|
|
17
|
-
numeric_values = dvalues.select { |v| v.is_a?(Numeric) }
|
|
18
|
-
next data if numeric_values.empty?
|
|
19
|
-
|
|
20
|
-
dres = numeric_values.max
|
|
21
|
-
signal = {
|
|
22
|
-
response => dres
|
|
23
|
-
}
|
|
24
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
25
|
-
end
|
|
26
|
-
series
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Mean
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:mean, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, paths:, response: 'mean') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
11
|
-
path_keys = paths.map { |path| path.to_s.split('.') }
|
|
12
|
-
|
|
13
|
-
series[:values] = series[:values].map do |data|
|
|
14
|
-
dvalues = path_keys.map { |path_key| data.dig(*path_key) }
|
|
15
|
-
next data if dvalues.any?(&:nil?)
|
|
16
|
-
|
|
17
|
-
numeric_values = dvalues.select { |v| v.is_a?(Numeric) }
|
|
18
|
-
next data if numeric_values.empty?
|
|
19
|
-
|
|
20
|
-
dres = (numeric_values.sum.to_f / numeric_values.length)
|
|
21
|
-
signal = {
|
|
22
|
-
response => dres.nan? ? BigDecimal(0) : dres
|
|
23
|
-
}
|
|
24
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
25
|
-
end
|
|
26
|
-
series
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Min
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:min, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, paths:, response: 'min') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
11
|
-
path_keys = paths.map { |path| path.to_s.split('.') }
|
|
12
|
-
|
|
13
|
-
series[:values] = series[:values].map do |data|
|
|
14
|
-
dvalues = path_keys.map { |path_key| data.dig(*path_key) }
|
|
15
|
-
next data if dvalues.any?(&:nil?)
|
|
16
|
-
|
|
17
|
-
numeric_values = dvalues.select { |v| v.is_a?(Numeric) }
|
|
18
|
-
next data if numeric_values.empty?
|
|
19
|
-
|
|
20
|
-
dres = numeric_values.min
|
|
21
|
-
signal = {
|
|
22
|
-
response => dres
|
|
23
|
-
}
|
|
24
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
25
|
-
end
|
|
26
|
-
series
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Multiply
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:multiply, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, left:, right:, response: 'multiply') # rubocop:disable Metrics/MethodLength
|
|
11
|
-
left_keys = left.to_s.split('.')
|
|
12
|
-
right_keys = right.to_s.split('.')
|
|
13
|
-
|
|
14
|
-
series[:values] = series[:values].map do |data|
|
|
15
|
-
dleft = data.dig(*left_keys)
|
|
16
|
-
dright = data.dig(*right_keys)
|
|
17
|
-
next data unless dleft && dright
|
|
18
|
-
|
|
19
|
-
dres = dleft * dright
|
|
20
|
-
signal = {
|
|
21
|
-
response => dres
|
|
22
|
-
}
|
|
23
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
24
|
-
end
|
|
25
|
-
series
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Ratio
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:ratio, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, left:, right:, response: 'ratio') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
11
|
-
left_keys = left.to_s.split('.')
|
|
12
|
-
right_keys = right.to_s.split('.')
|
|
13
|
-
|
|
14
|
-
series[:values] = series[:values].map do |data|
|
|
15
|
-
dleft = data.dig(*left_keys)
|
|
16
|
-
dright = data.dig(*right_keys)
|
|
17
|
-
next data unless dleft && dright
|
|
18
|
-
|
|
19
|
-
dres = (dleft / dright) * 100
|
|
20
|
-
signal = {
|
|
21
|
-
response => dres.nan? ? BigDecimal(0) : dres
|
|
22
|
-
}
|
|
23
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
24
|
-
end
|
|
25
|
-
series
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class StandardDeviation
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:standard_deviation, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, left:, right:, square:, response: 'sd') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
11
|
-
left_keys = left.to_s.split('.')
|
|
12
|
-
right_keys = right.to_s.split('.')
|
|
13
|
-
square_keys = square.to_s.split('.')
|
|
14
|
-
|
|
15
|
-
series[:values] = series[:values].map do |data|
|
|
16
|
-
dright = data.dig(*right_keys)
|
|
17
|
-
dsquare = data.dig(*square_keys)
|
|
18
|
-
dleft = data.dig(*left_keys)
|
|
19
|
-
next data unless dright && dsquare && dleft
|
|
20
|
-
|
|
21
|
-
dres = Math.sqrt(
|
|
22
|
-
(dright * dsquare - dleft * dleft) / (dright * (dright - 1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
|
|
23
|
-
)
|
|
24
|
-
signal = {
|
|
25
|
-
response => dres.nan? ? BigDecimal(0) : dres
|
|
26
|
-
}
|
|
27
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
28
|
-
end
|
|
29
|
-
series
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Subtract
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:subtract, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, left:, right:, response: 'subtract') # rubocop:disable Metrics/MethodLength
|
|
11
|
-
left_keys = left.to_s.split('.')
|
|
12
|
-
right_keys = right.to_s.split('.')
|
|
13
|
-
|
|
14
|
-
series[:values] = series[:values].map do |data|
|
|
15
|
-
dleft = data.dig(*left_keys)
|
|
16
|
-
dright = data.dig(*right_keys)
|
|
17
|
-
next data unless dleft && dright
|
|
18
|
-
|
|
19
|
-
dres = dleft - dright
|
|
20
|
-
signal = {
|
|
21
|
-
response => dres
|
|
22
|
-
}
|
|
23
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
24
|
-
end
|
|
25
|
-
series
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Trifle
|
|
4
|
-
module Stats
|
|
5
|
-
class Transponder
|
|
6
|
-
class Sum
|
|
7
|
-
include Trifle::Stats::Mixins::Packer
|
|
8
|
-
Trifle::Stats::Series.register_transponder(:sum, self)
|
|
9
|
-
|
|
10
|
-
def transpond(series:, paths:, response: 'sum') # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
11
|
-
path_keys = paths.map { |path| path.to_s.split('.') }
|
|
12
|
-
|
|
13
|
-
series[:values] = series[:values].map do |data|
|
|
14
|
-
dvalues = path_keys.map { |path_key| data.dig(*path_key) }
|
|
15
|
-
next data if dvalues.any?(&:nil?)
|
|
16
|
-
|
|
17
|
-
dres = dvalues.sum { |v| v.is_a?(Numeric) ? v : 0 }
|
|
18
|
-
signal = {
|
|
19
|
-
response => dres
|
|
20
|
-
}
|
|
21
|
-
self.class.deep_merge(data, self.class.unpack(hash: signal))
|
|
22
|
-
end
|
|
23
|
-
series
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|