trifle-stats 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61ed8d636a39a6b304b1877d29f6c70b6653b59c0a0a4e18bf9099cf0c903c7d
4
- data.tar.gz: 99488122d8ac47e900dd3764cc61f3012a00a47433dd8b6a857185220fc72335
3
+ metadata.gz: 6a3916f479d04bbffdab357ec6562c37134f114bb74eb8274b8c8285256ace45
4
+ data.tar.gz: 30df5c2bf81b14fef07ad6fd5a31e130bec6183e589fbc6dd9b9e1a23e2f94bf
5
5
  SHA512:
6
- metadata.gz: 7e4885fb88963d054b811c68a717e7e77dc9ddad55c11a499f98d599531f2fda6c12dd14e8cb680c367a7260976a6a411f7008845913323813bcaa9d1854e1bb
7
- data.tar.gz: ca1153f0d6ea56daf21d1fd507e0603e82bcfda0670a2093e6148a199928350d31ca7a980067d90add1e8c810fb719024602596764e8b025a490b7f9e3970780
6
+ metadata.gz: f1427bd400037791d86dd1890bd8dde7f91e5482dd65119f4223cc0f235cee7563af9675b4bbc8f15243fb4313dfea9a5d70d4e986f3c5ff91a58900430d60c4
7
+ data.tar.gz: 637dcd3e31689fa0b62ea583d8343fbc93943afbb285daaa8203f0e25eb87b43f3f4ed78217923be01316c2eeefeb6650988588ac14b6dd40d5caac47980250b
data/Gemfile.lock CHANGED
@@ -1,7 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- trifle-stats (0.2.0)
4
+ trifle-stats (0.4.0)
5
+ mongo (>= 2.14.0)
6
+ pg (>= 1.2)
5
7
  redis (>= 4.2)
6
8
  tzinfo (~> 2.0)
7
9
 
@@ -9,16 +11,20 @@ GEM
9
11
  remote: https://rubygems.org/
10
12
  specs:
11
13
  ast (2.4.2)
14
+ bson (4.12.1)
12
15
  byebug (11.1.3)
13
- concurrent-ruby (1.1.8)
16
+ concurrent-ruby (1.1.9)
14
17
  diff-lcs (1.4.4)
15
18
  dotenv (2.7.6)
19
+ mongo (2.14.0)
20
+ bson (>= 4.8.2, < 5.0.0)
16
21
  parallel (1.20.1)
17
22
  parser (3.0.0.0)
18
23
  ast (~> 2.4.1)
24
+ pg (1.2.3)
19
25
  rainbow (3.0.0)
20
26
  rake (12.3.3)
21
- redis (4.2.5)
27
+ redis (4.3.1)
22
28
  regexp_parser (2.0.3)
23
29
  rexml (3.2.4)
24
30
  rspec (3.10.0)
data/lib/trifle/stats.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'trifle/stats/driver/redis'
3
+ require 'trifle/stats/driver/mongo'
4
+ require 'trifle/stats/driver/postgres'
4
5
  require 'trifle/stats/driver/process'
6
+ require 'trifle/stats/driver/redis'
5
7
  require 'trifle/stats/mixins/packer'
6
8
  require 'trifle/stats/nocturnal'
7
9
  require 'trifle/stats/configuration'
@@ -6,11 +6,9 @@ module Trifle
6
6
  module Stats
7
7
  class Configuration
8
8
  attr_writer :driver
9
- attr_accessor :track_ranges, :separator, :time_zone,
10
- :beginning_of_week
9
+ attr_accessor :track_ranges, :time_zone, :beginning_of_week
11
10
 
12
11
  def initialize
13
- @separator = '::'
14
12
  @ranges = %i[minute hour day week month quarter year]
15
13
  @beginning_of_week = :monday
16
14
  @time_zone = 'GMT'
@@ -2,7 +2,7 @@
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 add values
5
+ - `inc(key:, **values)` method increment values
6
6
  - `set(key:, **values)` method set values
7
7
  - `get(key:)` method to retrieve values
8
8
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongo'
4
+ require_relative '../mixins/packer'
5
+
6
+ module Trifle
7
+ module Stats
8
+ module Driver
9
+ class Mongo
10
+ include Mixins::Packer
11
+ attr_accessor :client, :collection_name, :separator
12
+
13
+ def initialize(client, collection_name: 'trifle_stats')
14
+ @client = client
15
+ @collection_name = collection_name
16
+ @separator = '::'
17
+ end
18
+
19
+ def inc(key:, **values)
20
+ pkey = key.join(separator)
21
+
22
+ collection.bulk_write(
23
+ [upsert_operation('$inc', pkey: pkey, values: values)]
24
+ )
25
+ end
26
+
27
+ def set(key:, **values)
28
+ pkey = key.join(separator)
29
+
30
+ collection.bulk_write(
31
+ [upsert_operation('$set', pkey: pkey, values: values)]
32
+ )
33
+ end
34
+
35
+ def upsert_operation(operation, pkey:, values:)
36
+ data = self.class.pack(hash: { data: values })
37
+ {
38
+ update_many: {
39
+ filter: { key: pkey },
40
+ update: { operation => data },
41
+ upsert: true
42
+ }
43
+ }
44
+ end
45
+
46
+ def get(key:)
47
+ pkey = key.join(separator)
48
+
49
+ data = collection.find(key: pkey).limit(1).first
50
+ return {} if data.nil? || data['data'].nil?
51
+
52
+ data['data']
53
+ end
54
+
55
+ private
56
+
57
+ def collection
58
+ client[collection_name]
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pg'
4
+ require_relative '../mixins/packer'
5
+
6
+ module Trifle
7
+ module Stats
8
+ module Driver
9
+ class Postgres
10
+ include Mixins::Packer
11
+ attr_accessor :client, :table_name, :separator
12
+
13
+ def initialize(client = PG::Connection.new, table_name: 'trifle_stats')
14
+ @client = client
15
+ @table_name = table_name
16
+ @separator = '::'
17
+ end
18
+
19
+ def inc(key:, **values)
20
+ pkey = key.join(separator)
21
+
22
+ self.class.pack(hash: values).each do |k, c|
23
+ _inc_one(key: pkey, name: k, value: c)
24
+ end
25
+ end
26
+
27
+ def _inc_one(key:, name:, value:)
28
+ data = { name => value }
29
+ query = "INSERT INTO trifle_stats(key, data) VALUES ('#{key}', '#{data.to_json}') ON CONFLICT (key) DO UPDATE SET data = jsonb_set(to_jsonb(trifle_stats.data), '{#{name}}', (COALESCE(trifle_stats.data->>'#{name}','0')::int + #{value})::text::jsonb)" # rubocop:disable Metric/LineLength
30
+
31
+ client.exec(query)
32
+ end
33
+
34
+ def set(key:, **values)
35
+ pkey = key.join(separator)
36
+
37
+ _set_all(key: pkey, **values)
38
+ end
39
+
40
+ def _set_all(key:, **values)
41
+ data = self.class.pack(hash: values)
42
+ query = "INSERT INTO trifle_stats(key, data) VALUES ('#{key}', '#{data.to_json}') ON CONFLICT (key) DO UPDATE SET data = '#{data.to_json}'" # rubocop:disable Metric/LineLength
43
+
44
+ client.exec(query)
45
+ end
46
+
47
+ def get(key:)
48
+ pkey = key.join(separator)
49
+
50
+ data = _get(key: pkey)
51
+ return {} if data.nil?
52
+
53
+ self.class.unpack(hash: data)
54
+ end
55
+
56
+ def _get(key:)
57
+ result = client.exec_params(
58
+ "SELECT * FROM #{table_name} WHERE key = $1 LIMIT 1;", [key]
59
+ ).to_a.first
60
+ return nil if result.nil?
61
+
62
+ JSON.parse(result.try(:fetch, 'data'))
63
+ rescue JSON::ParserError
64
+ nil
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -9,19 +9,28 @@ module Trifle
9
9
  include Mixins::Packer
10
10
  def initialize
11
11
  @data = {}
12
+ @separator = '::'
12
13
  end
13
14
 
14
15
  def inc(key:, **values)
15
16
  self.class.pack(hash: values).each do |k, c|
16
- d = @data.fetch(key, {})
17
+ d = @data.fetch(key.join(@separator), {})
17
18
  d[k] = d[k].to_i + c
18
- @data[key] = d
19
+ @data[key.join(@separator)] = d
20
+ end
21
+ end
22
+
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
19
28
  end
20
29
  end
21
30
 
22
31
  def get(key:)
23
32
  self.class.unpack(
24
- hash: @data.fetch(key, {})
33
+ hash: @data.fetch(key.join(@separator), {})
25
34
  )
26
35
  end
27
36
  end
@@ -8,32 +8,33 @@ module Trifle
8
8
  module Driver
9
9
  class Redis
10
10
  include Mixins::Packer
11
- attr_accessor :prefix
11
+ attr_accessor :client, :prefix, :separator
12
12
 
13
13
  def initialize(client = ::Redis.current, prefix: 'trfl')
14
14
  @client = client
15
15
  @prefix = prefix
16
+ @separator = '::'
16
17
  end
17
18
 
18
19
  def inc(key:, **values)
19
- pkey = [@prefix, key].join('::')
20
+ pkey = ([prefix] + key).join(separator)
20
21
 
21
22
  self.class.pack(hash: values).each do |k, c|
22
- @client.hincrby(pkey, k, c)
23
+ client.hincrby(pkey, k, c)
23
24
  end
24
25
  end
25
26
 
26
27
  def set(key:, **values)
27
- pkey = [@prefix, key].join('::')
28
+ pkey = ([prefix] + key).join(separator)
28
29
 
29
- @client.hmset(pkey, *self.class.pack(hash: values))
30
+ client.hmset(pkey, *self.class.pack(hash: values))
30
31
  end
31
32
 
32
33
  def get(key:)
33
- pkey = [@prefix, key].join('::')
34
+ pkey = ([prefix] + key).join(separator)
34
35
 
35
36
  self.class.unpack(
36
- hash: @client.hgetall(pkey)
37
+ hash: client.hgetall(pkey)
37
38
  )
38
39
  end
39
40
  end
@@ -22,7 +22,7 @@ module Trifle
22
22
  config.ranges.map do |range|
23
23
  at = Nocturnal.new(@at, config: config).send(range)
24
24
  config.driver.inc(
25
- key: [key, range, at.to_i].join(config.separator),
25
+ key: [key, range, at.to_i],
26
26
  **values
27
27
  )
28
28
  end
@@ -22,7 +22,7 @@ module Trifle
22
22
  config.ranges.map do |range|
23
23
  at = Nocturnal.new(@at, config: config).send(range)
24
24
  config.driver.set(
25
- key: [key, range, at.to_i].join(config.separator),
25
+ key: [key, range, at.to_i],
26
26
  **values
27
27
  )
28
28
  end
@@ -27,7 +27,7 @@ module Trifle
27
27
  timeline.map do |at|
28
28
  {
29
29
  at => config.driver.get(
30
- key: [key, range, at.to_i].join(config.separator)
30
+ key: [key, range, at.to_i]
31
31
  )
32
32
  }
33
33
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Trifle
4
4
  module Stats
5
- VERSION = '0.2.0'
5
+ VERSION = '0.4.0'
6
6
  end
7
7
  end
data/trifle-stats.gemspec CHANGED
@@ -33,6 +33,9 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency('rake', '~> 13.0')
34
34
  spec.add_development_dependency('rspec', '~> 3.2')
35
35
  spec.add_development_dependency('rubocop', '1.0.0')
36
+
37
+ spec.add_runtime_dependency('mongo', '>= 2.14.0')
38
+ spec.add_runtime_dependency('pg', '>= 1.2')
36
39
  spec.add_runtime_dependency('redis', '>= 4.2')
37
40
  spec.add_runtime_dependency('tzinfo', '~> 2.0')
38
41
  end
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: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jozef Vaclavik
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-14 00:00:00.000000000 Z
11
+ date: 2021-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
96
  version: 1.0.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: mongo
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.14.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 2.14.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: pg
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '1.2'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '1.2'
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: redis
99
127
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +178,8 @@ files:
150
178
  - lib/trifle/stats.rb
151
179
  - lib/trifle/stats/configuration.rb
152
180
  - lib/trifle/stats/driver/README.md
181
+ - lib/trifle/stats/driver/mongo.rb
182
+ - lib/trifle/stats/driver/postgres.rb
153
183
  - lib/trifle/stats/driver/process.rb
154
184
  - lib/trifle/stats/driver/redis.rb
155
185
  - lib/trifle/stats/mixins/packer.rb