redis_counters-dumpers 1.1.0 → 1.2.3

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
  SHA1:
3
- metadata.gz: a60e1ec26471d5763627a8a3ab246e67ef0e9953
4
- data.tar.gz: e67d6186b99f2a423fc58ac4e3573aa273541f98
3
+ metadata.gz: b0cf08857a7fe296b1ccb59f5472630235414c22
4
+ data.tar.gz: 2739dfa6ab87472f73c49e745c5a17934669e81d
5
5
  SHA512:
6
- metadata.gz: 60efde8a403440f3c6748ad59937ae3bd4d9c748c30e77e5bb531dd915ed30ffea1b2dab5654536bc07611007c7e2084a7d94e5a3dba9809d2652bd883dd4e9d
7
- data.tar.gz: ecaf2c8adc08a8bec2e48fa312bd58b7f015141c96c7d063580a410c3088f3f2c7b071fa37a34fd37fbfb83db95cde447a2d1d2d038efc9c7f5db13f64044853
6
+ metadata.gz: e4a6bf161dd2330d8e6a2324ea6ae3ae7d8e4e6dd67bdcc9e27f42798749e3e403ade710f90ab991f6bb1aaf36b68623cd127508aeff8b0e77db3bf975f92015
7
+ data.tar.gz: 66f74d188bb8ed737efcdc9f07ad5e3a8f416f7463b2ef02a9d7dca9f0898617930f09360d377c44a2e8d724b2e9cb44e31d12694b72aa2aff494945fedbc512
data/.drone.yml CHANGED
@@ -1,21 +1,86 @@
1
- build:
2
- test:
3
- image: abakpress/dind-testing
4
- pull: true
5
- privileged: true
6
- volumes:
7
- - /home/data/drone/images:/images
8
- - /home/data/drone/gems:/bundle
1
+ name: build
2
+
3
+ kind: pipeline
4
+ type: docker
5
+
6
+ volumes:
7
+ - name: rubygems
8
+ host:
9
+ path: /home/data/drone/rubygems
10
+ - name: images
11
+ host:
12
+ path: /home/data/drone/images
13
+ - name: bundle
14
+ host:
15
+ path: /home/data/drone/gems
16
+ - name: keys
17
+ host:
18
+ path: /home/data/drone/key_cache
19
+
20
+ spec_step_common: &spec_step_common
21
+ image: abakpress/dind-testing:1.0.3
22
+ pull: if-not-exists
23
+ privileged: true
24
+ volumes:
25
+ - name: images
26
+ path: /images
27
+ - name: bundle
28
+ path: /bundle
29
+ - name: keys
30
+ path: /ssh_keys
31
+ commands:
32
+ - prepare-build
33
+
34
+ - fetch-images
35
+ --image whilp/ssh-agent
36
+ --image abakpress/ruby-app:$RUBY_IMAGE_TAG
37
+ --image abakpress/postgres-db:$POSTGRES_IMAGE_TAG
38
+ --image redis:$REDIS_IMAGE_TAG
39
+
40
+ - dip ssh add -T -v /ssh_keys -k /ssh_keys/id_rsa
41
+ - dip provision
42
+ - dip rspec
43
+
44
+ steps:
45
+ - name: Tests Ruby 2.2
9
46
  environment:
10
- - COMPOSE_FILE_EXT=drone
11
- - POSTGRES_IMAGE_TAG=9.6-latest
12
- - RUBY_IMAGE_TAG=2.2-latest
13
- commands:
14
- - wrapdocker docker -v
47
+ COMPOSE_FILE_EXT: drone
48
+ DOCKER_RUBY_VERSION: 2.2
49
+ RUBY_IMAGE_TAG: 2.2-latest
50
+ POSTGRES_IMAGE_TAG: 9.6-latest
51
+ REDIS_IMAGE_TAG: 4-alpine
52
+ RAILS_ENV: test
53
+ <<: *spec_step_common
54
+
55
+ - name: Tests Ruby 2.3
56
+ environment:
57
+ COMPOSE_FILE_EXT: drone
58
+ DOCKER_RUBY_VERSION: 2.3
59
+ RUBY_IMAGE_TAG: 2.3-latest
60
+ POSTGRES_IMAGE_TAG: 9.6-latest
61
+ REDIS_IMAGE_TAG: 4-alpine
62
+ RAILS_ENV: test
63
+ <<: *spec_step_common
15
64
 
16
- - fetch-images
17
- --image abakpress/ruby-app:$RUBY_IMAGE_TAG
18
- --image abakpress/postgres-db:$POSTGRES_IMAGE_TAG
65
+ - name: Tests Ruby 2.4
66
+ environment:
67
+ COMPOSE_FILE_EXT: drone
68
+ DOCKER_RUBY_VERSION: 2.4
69
+ RUBY_IMAGE_TAG: 2.4-latest
70
+ POSTGRES_IMAGE_TAG: 9.6-latest
71
+ REDIS_IMAGE_TAG: 4-alpine
72
+ RAILS_ENV: test
73
+ <<: *spec_step_common
19
74
 
20
- - dip provision
21
- - dip rspec
75
+ - name: release
76
+ image: abakpress/gem-publication:latest
77
+ pull: if-not-exists
78
+ when:
79
+ event: push
80
+ branch: master
81
+ status: success
82
+ volumes:
83
+ - name: rubygems
84
+ path: /root/.gem
85
+ commands:
86
+ - release-gem --public
data/.gitignore CHANGED
@@ -14,3 +14,4 @@
14
14
  *.o
15
15
  *.a
16
16
  mkmf.log
17
+ /.idea/
data/Appraisals CHANGED
@@ -1,14 +1,11 @@
1
- appraise 'rails3.2' do
2
- gem 'activesupport', '~> 3.2.14'
3
- gem 'activerecord', '~> 3.2.14'
1
+ if RUBY_VERSION < '2.4'
2
+ appraise 'rails4.0' do
3
+ gem 'activesupport', '~> 4.0.0'
4
+ gem 'activerecord', '~> 4.0.0'
5
+ end
4
6
  end
5
7
 
6
- appraise 'rails4.0' do
7
- gem 'activesupport', '~> 4.0.0'
8
- gem 'activerecord', '~> 4.0.0'
9
- end
10
-
11
- appraise 'rails4.1' do
12
- gem 'activesupport', '~> 4.1.0'
13
- gem 'activerecord', '~> 4.1.0'
8
+ appraise 'rails4.2' do
9
+ gem 'activesupport', '~> 4.2.0'
10
+ gem 'activerecord', '~> 4.2.0'
14
11
  end
data/CHANGELOG.md CHANGED
@@ -1,8 +1,55 @@
1
+ # v1.2.3
1
2
 
2
- #### [Current]
3
- * 2015-09-10 [1f96c39](../../commit/1f96c39) - __(Zhidkov Denis)__ feat: add source_conditions method
4
- * 2015-02-19 [8885300](../../commit/8885300) - __(bibendi)__ add group_by method
3
+ * 2021-08-06 [fb93322](../../commit/fb93322) - __(TamarinEA)__ chore: add rubygems volume
4
+ * 2021-08-05 [ea4350e](../../commit/ea4350e) - __(TamarinEA)__ Release 1.2.3
5
+ * 2021-08-05 [06cc372](../../commit/06cc372) - __(TamarinEA)__ chore: add ruby 2.4 support
5
6
 
6
- #### v0.0.1
7
- * 2015-01-26 [86918bd](../../commit/86918bd) - __(bibendi)__ initial code base
8
- * 2015-01-26 [a238032](../../commit/a238032) - __(bibendi)__ initial
7
+ # v1.2.2
8
+
9
+ * 2018-12-21 [6dd9509](../../commit/6dd9509) - __(Oleg Perminov)__ fix: add type text to updating expression
10
+ https://jira.railsc.ru/browse/CRM-4532
11
+
12
+ * 2018-12-13 [b197e2a](../../commit/b197e2a) - __(Oleg Perminov)__ feature: add flexibility to persistent types
13
+ https://jira.railsc.ru/browse/CRM-4532
14
+
15
+ # v1.2.1
16
+
17
+ * 2018-12-27 [dca67bc](../../commit/dca67bc) - __(Andrew N. Shalaev)__ feature: add autopublication to rubygems.org
18
+ * 2018-12-26 [21b57c8](../../commit/21b57c8) - __(Andrew N. Shalaev)__ fix: constraint pg gem
19
+ * 2018-12-21 [2f4ceab](../../commit/2f4ceab) - __(Andrew N. Shalaev)__ feature: add support for redis >= v4
20
+
21
+ # v1.2.0
22
+
23
+ * 2017-11-13 [bd94a94](../../commit/bd94a94) - __(Artem Napolskih)__ fix: specs for redis_counters 1.5
24
+ * 2017-11-13 [5641228](../../commit/5641228) - __(Artem Napolskih)__ chore: remove hstore dependency
25
+
26
+ # v1.1.0
27
+
28
+ Ограничение activesupport нужно, чтобы собрался бандл.
29
+
30
+ * 2017-06-21 [fc29058](../../commit/fc29058) - __(Pavel Galkin)__ feat: matching_expr option for destination
31
+ https://jira.railsc.ru/browse/CK-862 - пункт 4.
32
+
33
+ * 2017-06-20 [d21a7d8](../../commit/d21a7d8) - __(Pavel Galkin)__ chore: update infrastructure
34
+
35
+ # v1.0.0
36
+
37
+ * 2016-10-14 [704ad6d](../../commit/704ad6d) - __(Semyon Pupkov)__ Bump version
38
+ * 2016-09-05 [0bf4850](../../commit/0bf4850) - __(vadshalamov)__ feature: позволит не задавать increment_fields
39
+ * 2016-08-31 [b5c9bd9](../../commit/b5c9bd9) - __(vadshalamov)__ feature: добавит hstore в список возможных полей
40
+ * 2016-08-31 [3b0235c](../../commit/3b0235c) - __(vadshalamov)__ feature: позволит передавать набор аргументов для дампа
41
+ * 2016-07-18 [caa913e](../../commit/caa913e) - __(Stanislav Gordanov)__ feat: добавит enum тип в список возможных полей
42
+ * 2016-05-27 [bbb7119](../../commit/bbb7119) - __(Michail Merkushin)__ fix: Remove CTE favor temp table
43
+ https://jira.railsc.ru/browse/PC4-17052
44
+
45
+ # v0.1.0
46
+
47
+ * 2015-09-10 [1f96c39](../../commit/1f96c39) - __(Zhidkov Denis)__ feat: add source_conditions method
48
+ Adds ability to specify WHERE-clause for select query from source tmp-table
49
+
50
+ * 2015-02-19 [8885300](../../commit/8885300) - __(bibendi)__ add group_by method
51
+
52
+ # v0.0.1
53
+
54
+ * 2015-01-26 [86918bd](../../commit/86918bd) - __(bibendi)__ initial code base
55
+ * 2015-01-26 [a238032](../../commit/a238032) - __(bibendi)__ initial
data/Gemfile CHANGED
@@ -1,3 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'activerecord-postgres-hstore', require: false
4
+ gem 'simple_hstore_accessor', '~> 0.2', require: false
5
+ gem 'pg', '~> 0.11'
6
+
3
7
  gemspec
data/dip.yml CHANGED
@@ -1,9 +1,10 @@
1
1
  version: '1'
2
2
 
3
3
  environment:
4
- DOCKER_RUBY_VERSION: 2.2
5
- RUBY_IMAGE_TAG: 2.2-latest
4
+ DOCKER_RUBY_VERSION: 2.4
5
+ RUBY_IMAGE_TAG: 2.4-latest
6
6
  POSTGRES_IMAGE_TAG: 9.6-latest
7
+ REDIS_IMAGE_TAG: 4-alpine
7
8
  COMPOSE_FILE_EXT: development
8
9
 
9
10
  compose:
@@ -42,5 +43,6 @@ interaction:
42
43
  provision:
43
44
  - docker volume create --name bundler_data
44
45
  - dip bundle config --local https://gems.railsc.ru/ ${APRESS_GEMS_CREDENTIALS}
45
- - dip bundle install --full-index
46
+ - dip clean
47
+ - dip bundle install
46
48
  - dip appraisal install
data/docker-compose.yml CHANGED
@@ -9,11 +9,17 @@ services:
9
9
  - TEST_DB_HOST=db
10
10
  - TEST_DB_NAME=docker
11
11
  - TEST_DB_USERNAME=postgres
12
+ - TEST_REDIS_HOST=redis
12
13
  command: bash
13
14
  depends_on:
14
15
  - db
16
+ - redis
15
17
 
16
18
  db:
17
19
  image: abakpress/postgres-db:$POSTGRES_IMAGE_TAG
18
20
  environment:
19
21
  - POSTGRES_DB=docker
22
+
23
+ redis:
24
+ image: redis:$REDIS_IMAGE_TAG
25
+ command: 'redis-server --bind 0.0.0.0'
@@ -18,6 +18,8 @@ module RedisCounters
18
18
  extend Forwardable
19
19
  include ::RedisCounters::Dumpers::Dsl::Destination
20
20
 
21
+ VALUE_DELIMITER = ','.freeze
22
+
21
23
  # Ссылка на родительский движек - дампер.
22
24
  attr_accessor :engine
23
25
 
@@ -76,6 +78,9 @@ module RedisCounters
76
78
  # Returns String
77
79
  attr_accessor :matching_expr
78
80
 
81
+ # Разделитель значений, String.
82
+ attr_accessor :value_delimiter
83
+
79
84
  def initialize(engine)
80
85
  @engine = engine
81
86
  @fields_map = HashWithIndifferentAccess.new
@@ -174,7 +179,16 @@ module RedisCounters
174
179
  end
175
180
 
176
181
  def updating_expression
177
- increment_fields.map { |field| "#{field} = COALESCE(target.#{field}, 0) + source.#{field}" }.join(', ')
182
+ increment_fields.map do |field|
183
+ case model.columns_hash[field.to_s].type
184
+ when :datetime, :date
185
+ "#{field} = source.#{field}"
186
+ when :text, :string
187
+ "#{field} = array_to_string(ARRAY[source.#{field}, target.#{field}], '#{delimiter}')"
188
+ else
189
+ "#{field} = COALESCE(target.#{field}, 0) + source.#{field}"
190
+ end
191
+ end.join(', ')
178
192
  end
179
193
 
180
194
  def matching_expression
@@ -197,6 +211,10 @@ module RedisCounters
197
211
 
198
212
  "WHERE #{source_conditions.map { |source_condition| "(#{source_condition})" }.join(' AND ')}"
199
213
  end
214
+
215
+ def delimiter
216
+ value_delimiter || VALUE_DELIMITER
217
+ end
200
218
  end
201
219
  end
202
220
  end
@@ -13,6 +13,7 @@ module RedisCounters
13
13
 
14
14
  setter :model
15
15
  setter :matching_expr
16
+ setter :value_delimiter
16
17
 
17
18
  varags_setter :fields
18
19
  varags_setter :key_fields
@@ -234,10 +234,16 @@ module RedisCounters
234
234
  end
235
235
 
236
236
  def redis_session
237
- @redis_session ||= begin
238
- redis = ::Redis.new(counter.redis.client.options)
239
- ::Redis::Namespace.new(counter.redis.namespace, :redis => redis)
240
- end
237
+ return @redis_session if defined?(@redis_session)
238
+
239
+ client = if Gem::Version.new(::Redis::VERSION) < Gem::Version.new('4')
240
+ counter.redis.client
241
+ else
242
+ counter.redis._client
243
+ end
244
+ redis = ::Redis.new(client.options)
245
+
246
+ @redis_session = ::Redis::Namespace.new(counter.redis.namespace, redis: redis)
241
247
  end
242
248
 
243
249
  def create_temp_table
@@ -1,5 +1,5 @@
1
1
  module RedisCounters
2
2
  module Dumpers
3
- VERSION = '1.1.0'.freeze
3
+ VERSION = '1.2.3'.freeze
4
4
  end
5
5
  end
@@ -18,21 +18,17 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.add_runtime_dependency 'activesupport', '>= 3.0', '< 5'
20
20
  spec.add_runtime_dependency 'activerecord', '>= 3.0'
21
- spec.add_runtime_dependency 'pg'
22
21
  spec.add_runtime_dependency 'redis', '>= 3.0'
23
22
  spec.add_runtime_dependency 'redis-namespace', '>= 1.3'
24
23
  spec.add_runtime_dependency 'callbacks_rb', '>= 0.0.1'
25
24
  spec.add_runtime_dependency 'redis_counters', '>= 1.3'
26
- spec.add_runtime_dependency 'activerecord-postgres-hstore'
27
- spec.add_runtime_dependency 'simple_hstore_accessor', '~> 0.2'
28
25
 
29
26
  spec.add_development_dependency 'bundler', '>= 1.7'
30
27
  spec.add_development_dependency 'rake', '>= 10.0'
31
28
  spec.add_development_dependency 'rspec', '>= 3.2'
32
- spec.add_development_dependency 'rspec-rails', '>= 3.2'
29
+ spec.add_development_dependency 'rspec-rails', '~> 3.9.1'
33
30
  spec.add_development_dependency 'appraisal', '>= 1.0.2'
34
31
  spec.add_development_dependency 'mock_redis'
35
32
  spec.add_development_dependency 'combustion'
36
33
  spec.add_development_dependency 'pry-byebug'
37
- spec.add_development_dependency 'test-unit'
38
34
  end
@@ -0,0 +1,2 @@
1
+ class RealtimeStat < ActiveRecord::Base
2
+ end
@@ -27,7 +27,7 @@ ActiveRecord::Schema.define do
27
27
  t.hstore :params
28
28
  end
29
29
 
30
- add_index :stats_by_days, [:record_id, :column_id, :date], unique: true
30
+ add_index :stats_by_days, [:record_id, :column_id, :date, :params], unique: true, name: :uq
31
31
 
32
32
  create_table :stats_totals do |t|
33
33
  t.integer :record_id, null: false
@@ -37,7 +37,7 @@ ActiveRecord::Schema.define do
37
37
  t.hstore :params
38
38
  end
39
39
 
40
- add_index :stats_totals, [:record_id, :column_id], unique: true
40
+ add_index :stats_totals, [:record_id, :column_id, :params], unique: true
41
41
 
42
42
  create_table :stats_agg_totals do |t|
43
43
  t.integer :record_id, null: false
@@ -52,4 +52,12 @@ ActiveRecord::Schema.define do
52
52
  t.integer :value, null: false, default: 0
53
53
  t.string :payload
54
54
  end
55
+
56
+ create_table :realtime_stats do |t|
57
+ t.integer :record_id, null: false
58
+ t.integer :column_id, null: false
59
+ t.integer :hits, null: false, default: 0
60
+ t.timestamp :date
61
+ t.string :params
62
+ end
55
63
  end
@@ -26,6 +26,7 @@ describe RedisCounters::Dumpers::Engine do
26
26
  key_fields :record_id, :column_id, :params
27
27
  increment_fields :hits
28
28
  map :hits, to: :value
29
+ map :params, to: "COALESCE(params, '')"
29
30
  end
30
31
 
31
32
  destination do
@@ -59,105 +60,241 @@ describe RedisCounters::Dumpers::Engine do
59
60
  end
60
61
 
61
62
  before do
62
- allow(dumper).to receive(:redis_session).and_return(MockRedis.new)
63
+ allow(dumper).to receive(:redis_session).and_return(Redis.new(host: ENV['TEST_REDIS_HOST']))
63
64
  end
64
65
 
65
66
  describe '#process!' do
66
67
  context 'when increment_fields specified' do
67
- before do
68
- counter.increment(date: prev_date_s, record_id: 1, column_id: 100, subject: '', params: '')
69
- counter.increment(date: prev_date_s, record_id: 1, column_id: 200, subject: '', params: '')
70
- counter.increment(date: prev_date_s, record_id: 1, column_id: 200, subject: '', params: '')
71
- counter.increment(date: prev_date_s, record_id: 2, column_id: 100, subject: nil, params: '')
68
+ context 'without source conditions' do
69
+ before do
70
+ counter.increment(date: prev_date_s, record_id: 1, column_id: 100, subject: '', params: '')
71
+ counter.increment(date: prev_date_s, record_id: 1, column_id: 200, subject: '', params: '')
72
+ counter.increment(date: prev_date_s, record_id: 1, column_id: 200, subject: '', params: '')
73
+ counter.increment(date: prev_date_s, record_id: 2, column_id: 100, subject: nil, params: '')
72
74
 
73
- params = {a: 1}.stringify_keys.to_s[1..-2]
74
- counter.increment(date: prev_date_s, record_id: 3, column_id: 300, subject: nil, params: params)
75
+ params = {a: 1}.stringify_keys.to_s[1..-2]
76
+ counter.increment(date: prev_date_s, record_id: 3, column_id: 300, subject: nil, params: params)
75
77
 
76
- dumper.process!(counter, date: prev_date)
78
+ dumper.process!(counter, date: prev_date)
77
79
 
78
- counter.increment(date: date_s, record_id: 1, column_id: 100, subject: '', params: '')
79
- counter.increment(date: date_s, record_id: 1, column_id: 200, subject: '', params: '')
80
- counter.increment(date: date_s, record_id: 1, column_id: 200, subject: '', params: '')
81
- counter.increment(date: date_s, record_id: 2, column_id: 100, subject: nil, params: '')
80
+ counter.increment(date: date_s, record_id: 1, column_id: 100, subject: '', params: '')
81
+ counter.increment(date: date_s, record_id: 1, column_id: 200, subject: '', params: '')
82
+ counter.increment(date: date_s, record_id: 1, column_id: 200, subject: '', params: '')
83
+ counter.increment(date: date_s, record_id: 2, column_id: 100, subject: nil, params: '')
82
84
 
83
- dumper.process!(counter, date: date)
84
- end
85
+ dumper.process!(counter, date: date)
86
+ end
85
87
 
86
- it { expect(StatsByDay.count).to eq 7 }
87
- it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: prev_date).first.hits).to eq 1 }
88
- it { expect(StatsByDay.where(record_id: 1, column_id: 200, date: prev_date).first.hits).to eq 2 }
89
- it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: prev_date).first.hits).to eq 1 }
90
- it { expect(StatsByDay.where(record_id: 3, column_id: 300, date: prev_date).first.params).to eq("a" => "1") }
91
- it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: date).first.hits).to eq 1 }
92
- it { expect(StatsByDay.where(record_id: 1, column_id: 200, date: date).first.hits).to eq 2 }
93
- it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: date).first.hits).to eq 1 }
88
+ it { expect(StatsByDay.count).to eq 7 }
89
+ it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: prev_date).first.hits).to eq 1 }
90
+ it { expect(StatsByDay.where(record_id: 1, column_id: 200, date: prev_date).first.hits).to eq 2 }
91
+ it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: prev_date).first.hits).to eq 1 }
92
+ it { expect(StatsByDay.where(record_id: 3, column_id: 300, date: prev_date).first.params).to eq("a" => "1") }
93
+ it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: date).first.hits).to eq 1 }
94
+ it { expect(StatsByDay.where(record_id: 1, column_id: 200, date: date).first.hits).to eq 2 }
95
+ it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: date).first.hits).to eq 1 }
94
96
 
95
- it { expect(StatsTotal.count).to eq 4 }
96
- it { expect(StatsTotal.where(record_id: 1, column_id: 100).first.hits).to eq 2 }
97
- it { expect(StatsTotal.where(record_id: 1, column_id: 200).first.hits).to eq 4 }
98
- it { expect(StatsTotal.where(record_id: 2, column_id: 100).first.hits).to eq 2 }
97
+ it { expect(StatsTotal.count).to eq 4 }
98
+ it { expect(StatsTotal.where(record_id: 1, column_id: 100).first.hits).to eq 2 }
99
+ it { expect(StatsTotal.where(record_id: 1, column_id: 200).first.hits).to eq 4 }
100
+ it { expect(StatsTotal.where(record_id: 2, column_id: 100).first.hits).to eq 2 }
99
101
 
100
- it { expect(StatsAggTotal.count).to eq 3 }
101
- it { expect(StatsAggTotal.where(record_id: 1).first.hits).to eq 6 }
102
- it { expect(StatsAggTotal.where(record_id: 2).first.hits).to eq 2 }
102
+ it { expect(StatsAggTotal.count).to eq 3 }
103
+ it { expect(StatsAggTotal.where(record_id: 1).first.hits).to eq 6 }
104
+ it { expect(StatsAggTotal.where(record_id: 2).first.hits).to eq 2 }
105
+ end
103
106
 
104
107
  context 'with source conditions' do
108
+ context 'when incremented field class is integer' do
109
+ let(:dumper) do
110
+ RedisCounters::Dumpers::Engine.build do
111
+ name :stats_totals
112
+ fields record_id: :integer,
113
+ column_id: :integer,
114
+ value: :integer,
115
+ date: :date
116
+
117
+ destination do
118
+ model StatsByDay
119
+ take :record_id, :column_id, :hits, :date
120
+ key_fields :record_id, :column_id, :date
121
+ increment_fields :hits
122
+ map :hits, to: :value
123
+ condition 'target.date = :date'
124
+ source_condition 'column_id = 100'
125
+ end
126
+
127
+ destination do
128
+ model StatsTotal
129
+ take :record_id, :column_id, :hits
130
+ key_fields :record_id, :column_id
131
+ increment_fields :hits
132
+ map :hits, to: :value
133
+ source_condition 'column_id = 100'
134
+ end
135
+
136
+ destination do
137
+ model StatsAggTotal
138
+ take :record_id, :hits
139
+ key_fields :record_id
140
+ increment_fields :hits
141
+ map :hits, to: 'sum(value)'
142
+ group_by :record_id
143
+ source_condition 'column_id = 100'
144
+ end
145
+
146
+ on_before_merge do |dumper, _connection|
147
+ dumper.common_params = {date: dumper.args[:date].strftime('%Y-%m-%d')}
148
+ end
149
+ end
150
+ end
151
+
152
+ before do
153
+ counter.increment(date: prev_date_s, record_id: 1, column_id: 100, subject: '', params: '')
154
+ counter.increment(date: prev_date_s, record_id: 1, column_id: 200, subject: '', params: '')
155
+ counter.increment(date: prev_date_s, record_id: 1, column_id: 200, subject: '', params: '')
156
+ counter.increment(date: prev_date_s, record_id: 2, column_id: 100, subject: nil, params: '')
157
+
158
+ params = {a: 1}.stringify_keys.to_s[1..-2]
159
+ counter.increment(date: prev_date_s, record_id: 3, column_id: 300, subject: nil, params: params)
160
+
161
+ dumper.process!(counter, date: prev_date)
162
+
163
+ counter.increment(date: date_s, record_id: 1, column_id: 100, subject: '', params: '')
164
+ counter.increment(date: date_s, record_id: 1, column_id: 200, subject: '', params: '')
165
+ counter.increment(date: date_s, record_id: 1, column_id: 200, subject: '', params: '')
166
+ counter.increment(date: date_s, record_id: 2, column_id: 100, subject: nil, params: '')
167
+
168
+ dumper.process!(counter, date: date)
169
+ end
170
+
171
+ it { expect(StatsByDay.count).to eq 4 }
172
+ it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: prev_date).first.hits).to eq 1 }
173
+ it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: prev_date).first.hits).to eq 1 }
174
+ it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: date).first.hits).to eq 1 }
175
+ it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: date).first.hits).to eq 1 }
176
+
177
+ it { expect(StatsTotal.count).to eq 2 }
178
+ it { expect(StatsTotal.where(record_id: 1, column_id: 100).first.hits).to eq 2 }
179
+ it { expect(StatsTotal.where(record_id: 2, column_id: 100).first.hits).to eq 2 }
180
+
181
+ it { expect(StatsAggTotal.count).to eq 2 }
182
+ it { expect(StatsAggTotal.where(record_id: 1).first.hits).to eq 2 }
183
+ it { expect(StatsAggTotal.where(record_id: 2).first.hits).to eq 2 }
184
+ end
185
+ end
186
+
187
+ context 'when incremented field class is string' do
105
188
  let(:dumper) do
106
189
  RedisCounters::Dumpers::Engine.build do
107
- name :stats_totals
190
+ name :realtime_stats
108
191
  fields record_id: :integer,
109
192
  column_id: :integer,
110
193
  value: :integer,
111
- date: :date
194
+ params: :string,
195
+ date: :timestamp
112
196
 
113
197
  destination do
114
- model StatsByDay
115
- take :record_id, :column_id, :hits, :date
116
- key_fields :record_id, :column_id, :date
117
- increment_fields :hits
198
+ model RealtimeStat
199
+ take :record_id, :column_id, :date, :hits, :params
200
+ key_fields :record_id, :column_id
201
+ increment_fields :hits, :params
202
+ value_delimiter '; '
118
203
  map :hits, to: :value
119
- condition 'target.date = :date'
120
- source_condition 'column_id = 100'
204
+ condition 'target.date::date = :date::date'
121
205
  end
206
+ end
207
+ end
208
+
209
+ before do
210
+ counter.increment(date: date, record_id: 1, column_id: 100, subject: '', params: 'abc')
211
+ dumper.common_params = {date: date, params: 'abc'}
212
+ dumper.process!(counter, date: date)
213
+
214
+ counter.increment(date: date, record_id: 1, column_id: 100, subject: '', params: 'xyz')
215
+ dumper.common_params = {date: date, params: 'xyz'}
216
+ dumper.process!(counter, date: date)
217
+ end
218
+
219
+ it do
220
+ expect(RealtimeStat.count).to eq 1
221
+ expect(RealtimeStat.first.params).to eq 'xyz; abc'
222
+ end
223
+ end
224
+
225
+ context 'when incremented field class is text' do
226
+ let(:dumper) do
227
+ RedisCounters::Dumpers::Engine.build do
228
+ name :realtime_stats
229
+ fields record_id: :integer,
230
+ column_id: :integer,
231
+ value: :integer,
232
+ params: :text,
233
+ date: :timestamp
122
234
 
123
235
  destination do
124
- model StatsTotal
125
- take :record_id, :column_id, :hits
236
+ model RealtimeStat
237
+ take :record_id, :column_id, :date, :hits, :params
126
238
  key_fields :record_id, :column_id
127
- increment_fields :hits
239
+ increment_fields :hits, :params
128
240
  map :hits, to: :value
129
- source_condition 'column_id = 100'
241
+ condition 'target.date::date = :date::date'
130
242
  end
243
+ end
244
+ end
131
245
 
132
- destination do
133
- model StatsAggTotal
134
- take :record_id, :hits
135
- key_fields :record_id
136
- increment_fields :hits
137
- map :hits, to: 'sum(value)'
138
- group_by :record_id
139
- source_condition 'column_id = 100'
140
- end
246
+ before do
247
+ counter.increment(date: date, record_id: 1, column_id: 100, subject: '', params: 'abc')
248
+ dumper.common_params = {date: date, params: 'abc'}
249
+ dumper.process!(counter, date: date)
250
+
251
+ counter.increment(date: date, record_id: 1, column_id: 100, subject: '', params: 'xyz')
252
+ dumper.common_params = {date: date, params: 'xyz'}
253
+ dumper.process!(counter, date: date)
254
+ end
255
+
256
+ it do
257
+ expect(RealtimeStat.count).to eq 1
258
+ expect(RealtimeStat.first.params).to eq 'xyz,abc'
259
+ end
260
+ end
261
+
262
+ context 'when incremented field class is date or time' do
263
+ let(:current_time) { Date.today.to_time }
264
+ let(:dumper) do
265
+ RedisCounters::Dumpers::Engine.build do
266
+ name :realtime_stats
267
+ fields record_id: :integer,
268
+ column_id: :integer,
269
+ value: :integer,
270
+ params: :string,
271
+ date: :timestamp
141
272
 
142
- on_before_merge do |dumper, _connection|
143
- dumper.common_params = {date: dumper.args[:date].strftime('%Y-%m-%d')}
273
+ destination do
274
+ model RealtimeStat
275
+ take :record_id, :column_id, :hits, :params, :date
276
+ key_fields :record_id, :column_id
277
+ increment_fields :hits, :date
278
+ map :hits, to: :value
279
+ condition 'target.date::date = :date::date'
144
280
  end
145
281
  end
146
282
  end
147
283
 
148
- it { expect(StatsByDay.count).to eq 4 }
149
- it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: prev_date).first.hits).to eq 1 }
150
- it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: prev_date).first.hits).to eq 1 }
151
- it { expect(StatsByDay.where(record_id: 1, column_id: 100, date: date).first.hits).to eq 1 }
152
- it { expect(StatsByDay.where(record_id: 2, column_id: 100, date: date).first.hits).to eq 1 }
284
+ before do
285
+ counter.increment(date: date, record_id: 1, column_id: 100, subject: '', params: '')
286
+ dumper.common_params = {date: current_time}
287
+ dumper.process!(counter, date: date)
153
288
 
154
- it { expect(StatsTotal.count).to eq 2 }
155
- it { expect(StatsTotal.where(record_id: 1, column_id: 100).first.hits).to eq 2 }
156
- it { expect(StatsTotal.where(record_id: 2, column_id: 100).first.hits).to eq 2 }
289
+ counter.increment(date: date, record_id: 1, column_id: 100, subject: '', params: '')
290
+ dumper.common_params = {date: current_time}
291
+ dumper.process!(counter, date: date)
292
+ end
157
293
 
158
- it { expect(StatsAggTotal.count).to eq 2 }
159
- it { expect(StatsAggTotal.where(record_id: 1).first.hits).to eq 2 }
160
- it { expect(StatsAggTotal.where(record_id: 2).first.hits).to eq 2 }
294
+ it 'update incremented date' do
295
+ expect(RealtimeStat.count).to eq 1
296
+ expect(RealtimeStat.first.date).to eq current_time
297
+ end
161
298
  end
162
299
  end
163
300
 
data/spec/spec_helper.rb CHANGED
@@ -1,19 +1,13 @@
1
1
  require 'redis_counters/dumpers'
2
2
 
3
- if ::ActiveRecord::VERSION::MAJOR < 4
4
- require 'activerecord-postgres-hstore'
5
- require 'simple_hstore_accessor'
6
- end
7
-
8
3
  require 'combustion'
9
4
  Combustion.initialize! :active_record
10
5
 
11
6
  require 'rspec/rails'
12
7
  require 'pry-byebug'
13
8
 
14
- require 'mock_redis'
15
9
  require 'redis'
16
- Redis.current = MockRedis.new
10
+ Redis.current = Redis.new(host: ENV['TEST_REDIS_HOST'])
17
11
 
18
12
  RSpec.configure do |config|
19
13
  config.use_transactional_fixtures = true
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_counters-dumpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Merkushin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-11 00:00:00.000000000 Z
11
+ date: 2021-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -44,20 +44,6 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: '3.0'
47
- - !ruby/object:Gem::Dependency
48
- name: pg
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: '0'
61
47
  - !ruby/object:Gem::Dependency
62
48
  name: redis
63
49
  requirement: !ruby/object:Gem::Requirement
@@ -114,34 +100,6 @@ dependencies:
114
100
  - - ">="
115
101
  - !ruby/object:Gem::Version
116
102
  version: '1.3'
117
- - !ruby/object:Gem::Dependency
118
- name: activerecord-postgres-hstore
119
- requirement: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - ">="
122
- - !ruby/object:Gem::Version
123
- version: '0'
124
- type: :runtime
125
- prerelease: false
126
- version_requirements: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - ">="
129
- - !ruby/object:Gem::Version
130
- version: '0'
131
- - !ruby/object:Gem::Dependency
132
- name: simple_hstore_accessor
133
- requirement: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - "~>"
136
- - !ruby/object:Gem::Version
137
- version: '0.2'
138
- type: :runtime
139
- prerelease: false
140
- version_requirements: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - "~>"
143
- - !ruby/object:Gem::Version
144
- version: '0.2'
145
103
  - !ruby/object:Gem::Dependency
146
104
  name: bundler
147
105
  requirement: !ruby/object:Gem::Requirement
@@ -188,16 +146,16 @@ dependencies:
188
146
  name: rspec-rails
189
147
  requirement: !ruby/object:Gem::Requirement
190
148
  requirements:
191
- - - ">="
149
+ - - "~>"
192
150
  - !ruby/object:Gem::Version
193
- version: '3.2'
151
+ version: 3.9.1
194
152
  type: :development
195
153
  prerelease: false
196
154
  version_requirements: !ruby/object:Gem::Requirement
197
155
  requirements:
198
- - - ">="
156
+ - - "~>"
199
157
  - !ruby/object:Gem::Version
200
- version: '3.2'
158
+ version: 3.9.1
201
159
  - !ruby/object:Gem::Dependency
202
160
  name: appraisal
203
161
  requirement: !ruby/object:Gem::Requirement
@@ -254,20 +212,6 @@ dependencies:
254
212
  - - ">="
255
213
  - !ruby/object:Gem::Version
256
214
  version: '0'
257
- - !ruby/object:Gem::Dependency
258
- name: test-unit
259
- requirement: !ruby/object:Gem::Requirement
260
- requirements:
261
- - - ">="
262
- - !ruby/object:Gem::Version
263
- version: '0'
264
- type: :development
265
- prerelease: false
266
- version_requirements: !ruby/object:Gem::Requirement
267
- requirements:
268
- - - ">="
269
- - !ruby/object:Gem::Version
270
- version: '0'
271
215
  description:
272
216
  email:
273
217
  - bibendi@bk.ru
@@ -298,6 +242,7 @@ files:
298
242
  - lib/redis_counters/dumpers/version.rb
299
243
  - redis_counters-dumpers.gemspec
300
244
  - spec/internal/app/models/nullable_stat.rb
245
+ - spec/internal/app/models/realtime_stat.rb
301
246
  - spec/internal/app/models/stat.rb
302
247
  - spec/internal/app/models/stats_agg_total.rb
303
248
  - spec/internal/app/models/stats_by_day.rb
@@ -326,12 +271,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
326
271
  version: '0'
327
272
  requirements: []
328
273
  rubyforge_project:
329
- rubygems_version: 2.4.6
274
+ rubygems_version: 2.6.1
330
275
  signing_key:
331
276
  specification_version: 4
332
277
  summary: Dump statistics from Redis to DB
333
278
  test_files:
334
279
  - spec/internal/app/models/nullable_stat.rb
280
+ - spec/internal/app/models/realtime_stat.rb
335
281
  - spec/internal/app/models/stat.rb
336
282
  - spec/internal/app/models/stats_agg_total.rb
337
283
  - spec/internal/app/models/stats_by_day.rb