trifle-stats 1.0.0 → 1.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43ed8b8a05c933e5397b59bce9dc18eaee146ac62d2df67eccfbd9a53caad619
4
- data.tar.gz: 59f6d4ceba6de8977fcedf6f153fd621bd78a7055102080475c0d1f0e98f952f
3
+ metadata.gz: d2ab7e87008ccd472bcbb2f821db69a304c0d2be078827150d828459c62b9ffa
4
+ data.tar.gz: 7e6b5b77c70845d2c2d7b5b29f7a9811bba32f166f3a6204fb13e931c29ab90e
5
5
  SHA512:
6
- metadata.gz: 3a6fc973aaedd3167ea5c1b4d2f2cb7ebd8376de153f212005aae43320e59acb992d1034f8a83c5d6063e9b314f916603cd98714ecb9d0a66b02e4dd8dc8fb33
7
- data.tar.gz: adfbb9e6625f1f05b20c7f420c6a029b94086882ebd7e02fb3223449fbbc22c6b42c2ad49218b76ad8406570b1c9e2263b677ae93150fe1a6200e00dadddc8e1
6
+ metadata.gz: 49870c3899c775ce1a91a857cc39f9cc92c05b6bb7ffe211ecf52adf033436942f5db44942cd4e2f84143b8111e586b25254f88f4d9c4cf8c9123adac20503e8
7
+ data.tar.gz: 3dee093eed89e39a2dbc0c867dba0529359a9cba84f11c021fad8a78246e2e0d1115119ee896658e8ed917546757423432078faece8c582f559923b973170938
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- trifle-stats (1.0.0)
4
+ trifle-stats (1.1.1)
5
5
  tzinfo (~> 2.0)
6
6
 
7
7
  GEM
@@ -6,12 +6,13 @@ module Trifle
6
6
  module Stats
7
7
  class Configuration
8
8
  attr_writer :driver
9
- attr_accessor :track_ranges, :time_zone, :beginning_of_week
9
+ attr_accessor :track_ranges, :time_zone, :beginning_of_week, :designator
10
10
 
11
11
  def initialize
12
12
  @ranges = %i[minute hour day week month quarter year]
13
13
  @beginning_of_week = :monday
14
14
  @time_zone = 'GMT'
15
+ @designator = nil
15
16
  end
16
17
 
17
18
  def tz
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trifle
4
+ module Stats
5
+ class Designator
6
+ class Custom
7
+ attr_reader :buckets
8
+
9
+ def initialize(buckets:)
10
+ @buckets = buckets.sort
11
+ end
12
+
13
+ def designate(value:)
14
+ return buckets.first.to_s if value <= buckets.first
15
+ return "#{buckets.last}+" if value > buckets.last
16
+
17
+ (buckets.find { |b| value.ceil < b }).to_s
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trifle
4
+ module Stats
5
+ class Designator
6
+ class Geometric
7
+ attr_reader :min, :max
8
+
9
+ def initialize(min:, max:)
10
+ @min = min.negative? ? 0 : min
11
+ @max = max
12
+ end
13
+
14
+ def designate(value:) # rubocop:disable Metrics/AbcSize
15
+ return min.to_f.to_s if value <= min
16
+ return "#{max.to_f}+" if value > max
17
+ return (10**value.floor.to_s.length).to_f.to_s if value > 1
18
+ return 1.0.to_s if value > 0.1 # ugh?
19
+
20
+ (1.0 / 10**value.to_s.gsub('0.', '').split(/[1-9]/).first.length).to_s
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trifle
4
+ module Stats
5
+ class Designator
6
+ class Linear
7
+ attr_reader :min, :max, :step
8
+
9
+ def initialize(min:, max:, step:)
10
+ @min = min
11
+ @max = max
12
+ @step = step.to_i
13
+ end
14
+
15
+ def designate(value:) # rubocop:disable Metrics/AbcSize
16
+ return min.to_s if value <= min
17
+ return "#{max}+" if value > max
18
+
19
+ (value.ceil / step * step + ((value.ceil % step).zero? ? 0 : step)).to_s
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,8 +2,8 @@
2
2
 
3
3
  Driver is a wrapper class that persists and retrieves values from backend. It needs to implement:
4
4
 
5
- - `inc(key:, **values)` method increment values
6
- - `set(key:, **values)` method set values
5
+ - `inc(keys:, **values)` method increment values
6
+ - `set(keys:, **values)` method set values
7
7
  - `get(keys:)` method to retrieve values
8
8
 
9
9
  ## Documentation
@@ -16,24 +16,27 @@ module Trifle
16
16
  @separator = '::'
17
17
  end
18
18
 
19
- def inc(key:, **values)
20
- pkey = key.join(separator)
19
+ def inc(keys:, **values)
20
+ data = self.class.pack(hash: { data: values })
21
21
 
22
22
  collection.bulk_write(
23
- [upsert_operation('$inc', pkey: pkey, values: values)]
23
+ keys.map do |key|
24
+ upsert_operation('$inc', pkey: key.join(separator), data: data)
25
+ end
24
26
  )
25
27
  end
26
28
 
27
- def set(key:, **values)
28
- pkey = key.join(separator)
29
+ def set(keys:, **values)
30
+ data = self.class.pack(hash: { data: values })
29
31
 
30
32
  collection.bulk_write(
31
- [upsert_operation('$set', pkey: pkey, values: values)]
33
+ keys.map do |key|
34
+ upsert_operation('$set', pkey: key.join(separator), data: data)
35
+ end
32
36
  )
33
37
  end
34
38
 
35
- def upsert_operation(operation, pkey:, values:)
36
- data = self.class.pack(hash: { data: values })
39
+ def upsert_operation(operation, pkey:, data:)
37
40
  {
38
41
  update_many: {
39
42
  filter: { key: pkey },
@@ -16,11 +16,13 @@ module Trifle
16
16
  @separator = '::'
17
17
  end
18
18
 
19
- def inc(key:, **values)
20
- pkey = key.join(separator)
19
+ def inc(keys:, **values)
20
+ keys.map do |key|
21
+ pkey = key.join(separator)
21
22
 
22
- self.class.pack(hash: values).each do |k, c|
23
- _inc_one(key: pkey, name: k, value: c)
23
+ self.class.pack(hash: values).each do |k, c|
24
+ _inc_one(key: pkey, name: k, value: c)
25
+ end
24
26
  end
25
27
  end
26
28
 
@@ -31,10 +33,12 @@ module Trifle
31
33
  client.exec(query)
32
34
  end
33
35
 
34
- def set(key:, **values)
35
- pkey = key.join(separator)
36
+ def set(keys:, **values)
37
+ keys.map do |key|
38
+ pkey = key.join(separator)
36
39
 
37
- _set_all(key: pkey, **values)
40
+ _set_all(key: pkey, **values)
41
+ end
38
42
  end
39
43
 
40
44
  def _set_all(key:, **values)
@@ -12,19 +12,23 @@ module Trifle
12
12
  @separator = '::'
13
13
  end
14
14
 
15
- def inc(key:, **values)
16
- self.class.pack(hash: values).each do |k, c|
17
- d = @data.fetch(key.join(@separator), {})
18
- d[k] = d[k].to_i + c
19
- @data[key.join(@separator)] = d
15
+ def inc(keys:, **values)
16
+ keys.map do |key|
17
+ self.class.pack(hash: values).each do |k, c|
18
+ d = @data.fetch(key.join(@separator), {})
19
+ d[k] = d[k].to_i + c
20
+ @data[key.join(@separator)] = d
21
+ end
20
22
  end
21
23
  end
22
24
 
23
- def set(key:, **values)
24
- self.class.pack(hash: values).each do |k, c|
25
- d = @data.fetch(key.join(@separator), {})
26
- d[k] = c
27
- @data[key.join(@separator)] = d
25
+ def set(keys:, **values)
26
+ keys.map do |key|
27
+ self.class.pack(hash: values).each do |k, c|
28
+ d = @data.fetch(key.join(@separator), {})
29
+ d[k] = c
30
+ @data[key.join(@separator)] = d
31
+ end
28
32
  end
29
33
  end
30
34
 
@@ -16,18 +16,22 @@ module Trifle
16
16
  @separator = '::'
17
17
  end
18
18
 
19
- def inc(key:, **values)
20
- pkey = ([prefix] + key).join(separator)
19
+ def inc(keys:, **values)
20
+ keys.map do |key|
21
+ pkey = ([prefix] + key).join(separator)
21
22
 
22
- self.class.pack(hash: values).each do |k, c|
23
- client.hincrby(pkey, k, c)
23
+ self.class.pack(hash: values).each do |k, c|
24
+ client.hincrby(pkey, k, c)
25
+ end
24
26
  end
25
27
  end
26
28
 
27
- def set(key:, **values)
28
- pkey = ([prefix] + key).join(separator)
29
+ def set(keys:, **values)
30
+ keys.map do |key|
31
+ pkey = ([prefix] + key).join(separator)
29
32
 
30
- client.hmset(pkey, *self.class.pack(hash: values))
33
+ client.hmset(pkey, *self.class.pack(hash: values))
34
+ end
31
35
  end
32
36
 
33
37
  def get(keys:)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trifle
4
+ module Stats
5
+ module Operations
6
+ module Timeseries
7
+ class Classify
8
+ attr_reader :key, :values
9
+
10
+ def initialize(**keywords)
11
+ @key = keywords.fetch(:key)
12
+ @at = keywords.fetch(:at)
13
+ @values = keywords.fetch(:values)
14
+ @config = keywords[:config]
15
+ end
16
+
17
+ def config
18
+ @config || Trifle::Stats.default
19
+ end
20
+
21
+ def deep_classify(hash)
22
+ hash.transform_values do |value|
23
+ next deep_classify(value) if value.is_a?(Hash)
24
+
25
+ { classify(value) => 1 }
26
+ end
27
+ end
28
+
29
+ def classify(value)
30
+ config.designator.designate(value: value).to_s.gsub('.', '_')
31
+ end
32
+
33
+ def key_for(range:)
34
+ at = Nocturnal.new(@at, config: config).send(range)
35
+ [key, range, at.to_i]
36
+ end
37
+
38
+ def perform
39
+ config.driver.inc(
40
+ keys: config.ranges.map { |range| key_for(range: range) },
41
+ **deep_classify(values)
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -18,14 +18,16 @@ module Trifle
18
18
  @config || Trifle::Stats.default
19
19
  end
20
20
 
21
+ def key_for(range:)
22
+ at = Nocturnal.new(@at, config: config).send(range)
23
+ [key, range, at.to_i]
24
+ end
25
+
21
26
  def perform
22
- config.ranges.map do |range|
23
- at = Nocturnal.new(@at, config: config).send(range)
24
- config.driver.inc(
25
- key: [key, range, at.to_i],
26
- **values
27
- )
28
- end
27
+ config.driver.inc(
28
+ keys: config.ranges.map { |range| key_for(range: range) },
29
+ **values
30
+ )
29
31
  end
30
32
  end
31
33
  end
@@ -18,14 +18,16 @@ module Trifle
18
18
  @config || Trifle::Stats.default
19
19
  end
20
20
 
21
+ def key_for(range:)
22
+ at = Nocturnal.new(@at, config: config).send(range)
23
+ [key, range, at.to_i]
24
+ end
25
+
21
26
  def perform
22
- config.ranges.map do |range|
23
- at = Nocturnal.new(@at, config: config).send(range)
24
- config.driver.set(
25
- key: [key, range, at.to_i],
26
- **values
27
- )
28
- end
27
+ config.driver.set(
28
+ keys: config.ranges.map { |range| key_for(range: range) },
29
+ **values
30
+ )
29
31
  end
30
32
  end
31
33
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Trifle
4
4
  module Stats
5
- VERSION = '1.0.0'
5
+ VERSION = '1.1.1'
6
6
  end
7
7
  end
data/lib/trifle/stats.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'trifle/stats/designator/custom'
4
+ require 'trifle/stats/designator/geometric'
5
+ require 'trifle/stats/designator/linear'
3
6
  require 'trifle/stats/driver/mongo'
4
7
  require 'trifle/stats/driver/postgres'
5
8
  require 'trifle/stats/driver/process'
@@ -7,6 +10,7 @@ require 'trifle/stats/driver/redis'
7
10
  require 'trifle/stats/mixins/packer'
8
11
  require 'trifle/stats/nocturnal'
9
12
  require 'trifle/stats/configuration'
13
+ require 'trifle/stats/operations/timeseries/classify'
10
14
  require 'trifle/stats/operations/timeseries/increment'
11
15
  require 'trifle/stats/operations/timeseries/set'
12
16
  require 'trifle/stats/operations/timeseries/values'
@@ -45,6 +49,15 @@ module Trifle
45
49
  ).perform
46
50
  end
47
51
 
52
+ def self.assort(key:, at:, values:, config: nil)
53
+ Trifle::Stats::Operations::Timeseries::Classify.new(
54
+ key: key,
55
+ at: at,
56
+ values: values,
57
+ config: config
58
+ ).perform
59
+ end
60
+
48
61
  def self.values(key:, from:, to:, range:, config: nil)
49
62
  Trifle::Stats::Operations::Timeseries::Values.new(
50
63
  key: key,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trifle-stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jozef Vaclavik
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-18 00:00:00.000000000 Z
11
+ date: 2022-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -183,6 +183,9 @@ files:
183
183
  - bin/setup
184
184
  - lib/trifle/stats.rb
185
185
  - lib/trifle/stats/configuration.rb
186
+ - lib/trifle/stats/designator/custom.rb
187
+ - lib/trifle/stats/designator/geometric.rb
188
+ - lib/trifle/stats/designator/linear.rb
186
189
  - lib/trifle/stats/driver/README.md
187
190
  - lib/trifle/stats/driver/mongo.rb
188
191
  - lib/trifle/stats/driver/postgres.rb
@@ -190,6 +193,7 @@ files:
190
193
  - lib/trifle/stats/driver/redis.rb
191
194
  - lib/trifle/stats/mixins/packer.rb
192
195
  - lib/trifle/stats/nocturnal.rb
196
+ - lib/trifle/stats/operations/timeseries/classify.rb
193
197
  - lib/trifle/stats/operations/timeseries/increment.rb
194
198
  - lib/trifle/stats/operations/timeseries/set.rb
195
199
  - lib/trifle/stats/operations/timeseries/values.rb