trifle-stats 0.2.1 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64e5b8835413e4d664240d8b3bcb30f66bc886c139870c5849a1ef0d48ddcdc6
4
- data.tar.gz: 8e499def09294e6b76ec07ea8f906d1b210145a305a82ffabf65665d777786d9
3
+ metadata.gz: 532f2b7afd34d3f6a1d634578157b4a12396d5e6b2d5ab679a792dc7245928be
4
+ data.tar.gz: 482944111799367469b5c831f2703a0f80f50b252301f03a60401d08752ae0ae
5
5
  SHA512:
6
- metadata.gz: e4e9c33a1921fed870c398370e1fc0eeeb1c4f1d33ad1e030ef8a1555cdc5930a4541e2aeae2409ef0738c4b76437a16c195a019cdc8e73752e8e5ae9fda8a78
7
- data.tar.gz: 7b76bf3d1900c3db9c5038ec6c6a4245cfb0ea056385f3dc77f552f6b08f5f0f90816692b21c0763fa91d9ad85c44c0820e85f7824c9b895ed6ecbb54f2adc24
6
+ metadata.gz: 16805ed32667f648efd688bb8be1ea03fa6f04abe837bd0f483bb53fb9d730563932fd4036bfa36e93d1a35a01a802557303beec0835dbe3d17de486d75b396f
7
+ data.tar.gz: 13044b35325c973667c73827fce1b3146a51846ac186f9b8e6e8a5631653afe2f07e7ae461068729d19c8be81c311c44a5a1e10119534c093c723c438956309e
@@ -9,29 +9,28 @@ name: Ruby
9
9
 
10
10
  on:
11
11
  push:
12
- branches: [ main ]
12
+ branches: [main]
13
13
  pull_request:
14
- branches: [ main ]
14
+ branches: [main]
15
15
 
16
16
  jobs:
17
17
  test:
18
-
19
18
  runs-on: ubuntu-latest
20
19
  strategy:
21
20
  matrix:
22
- ruby-version: ['2.6', '2.7', '3.0']
21
+ ruby-version: ["3.0"]
23
22
 
24
23
  steps:
25
- - uses: actions/checkout@v2
26
- - name: Set up Ruby
27
- # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
- # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
- # uses: ruby/setup-ruby@v1
30
- uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
31
- with:
32
- ruby-version: ${{ matrix.ruby-version }}
33
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
34
- - name: Rspec
35
- run: bundle exec rspec
36
- - name: Rubocop
37
- run: bundle exec rubocop
24
+ - uses: actions/checkout@v2
25
+ - name: Set up Ruby
26
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
27
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
28
+ # uses: ruby/setup-ruby@v1
29
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
30
+ with:
31
+ ruby-version: ${{ matrix.ruby-version }}
32
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
33
+ - name: Rspec
34
+ run: bundle exec rspec
35
+ - name: Rubocop
36
+ run: bundle exec rubocop
data/Gemfile.lock CHANGED
@@ -1,7 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- trifle-stats (0.2.1)
4
+ trifle-stats (0.4.1)
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,27 +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
19
20
  end
20
21
  end
21
22
 
22
23
  def set(key:, **values)
23
24
  self.class.pack(hash: values).each do |k, c|
24
- d = @data.fetch(key, {})
25
+ d = @data.fetch(key.join(@separator), {})
25
26
  d[k] = c
26
- @data[key] = d
27
+ @data[key.join(@separator)] = d
27
28
  end
28
29
  end
29
30
 
30
31
  def get(key:)
31
32
  self.class.unpack(
32
- hash: @data.fetch(key, {})
33
+ hash: @data.fetch(key.join(@separator), {})
33
34
  )
34
35
  end
35
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.1'
5
+ VERSION = '0.4.1'
6
6
  end
7
7
  end
data/trifle-stats.gemspec CHANGED
@@ -12,7 +12,8 @@ Gem::Specification.new do |spec|
12
12
  'that helps you track custom metrics. Automatically '\
13
13
  'increments counters for each enabled range. '\
14
14
  'It supports timezones and different week beginning.'
15
- spec.homepage = "https://trifle.io"
15
+ spec.homepage = 'https://trifle.io'
16
+ spec.licenses = ['MIT']
16
17
  spec.required_ruby_version = Gem::Requirement.new('>= 2.6')
17
18
 
18
19
  spec.metadata['homepage_uri'] = spec.homepage
@@ -33,6 +34,9 @@ Gem::Specification.new do |spec|
33
34
  spec.add_development_dependency('rake', '~> 13.0')
34
35
  spec.add_development_dependency('rspec', '~> 3.2')
35
36
  spec.add_development_dependency('rubocop', '1.0.0')
37
+
38
+ spec.add_runtime_dependency('mongo', '>= 2.14.0')
39
+ spec.add_runtime_dependency('pg', '>= 1.2')
36
40
  spec.add_runtime_dependency('redis', '>= 4.2')
37
41
  spec.add_runtime_dependency('tzinfo', '~> 2.0')
38
42
  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.1
4
+ version: 0.4.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: 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
@@ -160,7 +190,8 @@ files:
160
190
  - lib/trifle/stats/version.rb
161
191
  - trifle-stats.gemspec
162
192
  homepage: https://trifle.io
163
- licenses: []
193
+ licenses:
194
+ - MIT
164
195
  metadata:
165
196
  homepage_uri: https://trifle.io
166
197
  source_code_uri: https://github.com/trifle-io/trifle-stats