running_count 0.1.0 → 0.2.0

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: 281c3126d219fffe217bea334f4ee81b040bb875ea1d5b120a5443eff7db48fa
4
- data.tar.gz: b236cc36eaec448d824371484cb1c0505d7fc1170324ba105cd04722de566a15
3
+ metadata.gz: 17316e1fc11a06d992f032a266cfdd460e2398d9f2ea2cd012e12ccda8d6e6bf
4
+ data.tar.gz: 6c2c23a38cf332a8a164642b595b78bcbc7b895a26513b2244b2b4c2c3489089
5
5
  SHA512:
6
- metadata.gz: 0ce7b753f6c6d2a2a8b6334bb17aaed7b3856a499716a85a01d4c6af6df24896b043f6af381fc2d314c5c548dc191777ee186cb19fe9d9462e44ee4e4416f725
7
- data.tar.gz: afe63389d76ee143a0df841d4c6480e23e3560e913bddf7603c4f6f6555710f61fc62fe4ac993a677c7d2c7e7a5f21a45f210c99cabc17b6550497497fbcf944
6
+ metadata.gz: b2081c854ebba5b361c9c7e40fbc73a51de2201d76cb28a91efa4b70a508d71e88dc74bd516d770fa7c6d10deb05ab1bd8842c466b5c1c542f123adf178fd650
7
+ data.tar.gz: e8a44b425b3726484fd246bf171149329dffcd2da868573ce9e9ccac10b916c98e28b5ba1ff7c50cff9fc5eac98e4a36c2e9d7f62c6cd7cc9515f789b8ec037b
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- running_count (0.1.0)
5
- activesupport
4
+ running_count (0.2.0)
5
+ activesupport (~> 4.2.11)
6
6
  pg (= 0.20.0)
7
- redis-rails
7
+ redis-rails (~> 5.0)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
@@ -74,8 +74,6 @@ GEM
74
74
  pry-byebug (3.6.0)
75
75
  byebug (~> 10.0)
76
76
  pry (~> 0.10)
77
- pry-rails (0.3.9)
78
- pry (>= 0.10.4)
79
77
  rack (1.6.11)
80
78
  rack-test (0.6.3)
81
79
  rack (>= 1.0)
@@ -150,9 +148,8 @@ PLATFORMS
150
148
  ruby
151
149
 
152
150
  DEPENDENCIES
153
- database_cleaner
154
- pry-byebug
155
- pry-rails
151
+ database_cleaner (~> 1.7.0)
152
+ pry-byebug (~> 3.6.0)
156
153
  rails (~> 4.0)
157
154
  rake (~> 10.0)
158
155
  rspec (~> 3.0)
data/README.md CHANGED
@@ -1,28 +1,45 @@
1
- # RunningCount
1
+ # running_count
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/running_count`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Counter caches for Rails applications, including cached running counts.
6
4
 
7
5
  ## Installation
8
6
 
9
7
  Add this line to your application's Gemfile:
10
8
 
11
9
  ```ruby
12
- gem 'running_count'
10
+ gem 'running_count', '~> 0.2`
13
11
  ```
14
12
 
15
13
  And then execute:
16
14
 
17
15
  $ bundle
18
16
 
19
- Or install it yourself as:
17
+ ## Usage
20
18
 
21
- $ gem install running_count
19
+ ```
20
+ class Course < ActiveRecord::Base
21
+ belongs_to :user
22
22
 
23
- ## Usage
23
+ keep_running_count :user
24
+ end
25
+
26
+ class User
27
+ has_many :courses
28
+ end
29
+ ```
30
+
31
+ Tracks the number of Course records associated with the User model, saving them to the `courses_count` field in the 'users' table.
32
+
33
+ Also tracks a dynamic running count in the `running_courses_count` method on the `User` model.
34
+
35
+ ## Reconciling changes
36
+
37
+ ```
38
+ Course.reconcile_changes
39
+ ```
40
+
41
+ Will update the 'users' table with the number of associated courses in the `courses_count` field, and clear the dynamic cache.
24
42
 
25
- TODO: Write usage instructions here
26
43
 
27
44
  ## Development
28
45
 
@@ -5,28 +5,33 @@ module RunningCount
5
5
 
6
6
  extend ActiveSupport::Concern
7
7
 
8
- def enqueue_count
9
- Counter.enqueue_change(self, self.class._counter_data)
8
+ def enqueue_changes
9
+ Counter.enqueue_changes(self, self.class._counter_data)
10
10
  end
11
11
 
12
- def enqueue_sum
13
- Counter.enqueue_sum(self, self.class._counter_data)
12
+ def enqueue_deletion
13
+ Counter.enqueue_deletion(self, self.class._counter_data)
14
14
  end
15
15
 
16
16
  module ClassMethods
17
17
 
18
18
  def keep_running_count(relation, opts = {})
19
- Counter.add_callbacks(self, opts)
19
+ data = Counter.counter_data(self.name, self.table_name, relation, opts)
20
+ counter_column = data[:counter_column]
21
+
22
+ _counter_data[counter_column] = data
20
23
 
21
- @counter_data = Counter.counter_data(self.name, self.table_name, relation, opts)
24
+ Counter.add_callbacks(self, opts)
22
25
  end
23
26
 
24
27
  def reconcile_changes
25
- Counter.reconcile_changes(self._counter_data)
28
+ self._counter_data.values.each do |data|
29
+ Counter.reconcile_changes(data)
30
+ end
26
31
  end
27
32
 
28
33
  def _counter_data
29
- @counter_data
34
+ @counter_data ||= {}
30
35
  end
31
36
 
32
37
  end
@@ -5,6 +5,16 @@ module RunningCount
5
5
 
6
6
  class << self
7
7
 
8
+ def enqueue_changes(record, counter_data)
9
+ counter_data
10
+ .values
11
+ .partition { |data| data[:aggregated_field].present? }
12
+ .tap do |sums, counts|
13
+ sums.each { |data| Counter.enqueue_sum(record, data) }
14
+ counts.each { |data| Counter.enqueue_count(record, data) }
15
+ end
16
+ end
17
+
8
18
  def enqueue_sum(record, counter_data)
9
19
  aggregated_field = counter_data[:aggregated_field]
10
20
 
@@ -13,17 +23,35 @@ module RunningCount
13
23
  diff = record.previous_changes[aggregated_field].last.to_i - record.previous_changes[aggregated_field].first.to_i
14
24
 
15
25
  if diff != 0
16
- Counter.enqueue_change(record, counter_data.merge(amount: diff))
26
+ Counter.enqueue_count(record, counter_data.merge(amount: diff))
17
27
  end
18
28
  end
19
29
 
20
- def enqueue_change(record, counter_data)
30
+ def enqueue_count(record, counter_data)
31
+ if changed_field = counter_data[:changed_field]
32
+ return true unless record.previous_changes.has_key?(changed_field) && counter_data[:if].call(record)
33
+ end
34
+
21
35
  destination = record.send(counter_data[:relation])
22
36
  item = Format.item(destination)
23
37
 
24
38
  Storage.add_item(item, counter_data[:running_set_name], counter_data.fetch(:amount, 1))
25
- rescue StandardError => e
26
- binding.pry
39
+ end
40
+
41
+ def enqueue_deletion(record, counter_data)
42
+ counter_data
43
+ .values
44
+ .each do |data|
45
+ Counter.enqueue_single_delete(record, data)
46
+ end
47
+ end
48
+
49
+ def enqueue_single_delete(record, data)
50
+ destination = record.send(data[:relation])
51
+ item = Format.item(destination)
52
+ amount = amount_from_deleted_record(record, data)
53
+
54
+ Storage.add_item(item, data[:running_set_name], 0 - amount)
27
55
  end
28
56
 
29
57
  def reconcile_changes(counter_data)
@@ -73,21 +101,27 @@ module RunningCount
73
101
  statement: statement,
74
102
  release_sql: Statement.release_sql(statement),
75
103
  aggregated_field: opts[:aggregated_field],
104
+ changed_field: opts[:changed_field],
76
105
  statement_sql: sql,
77
106
  if: opts[:if],
78
107
  }
79
108
  end
80
109
 
81
110
  def add_callbacks(klass, opts)
82
- if opts[:aggregated_field]
83
- klass.after_commit :enqueue_sum, on: [:create, :update], if: opts[:if]
84
- else
85
- klass.after_commit :enqueue_count, on: [:create, :update], if: opts[:if]
86
- end
111
+ klass.after_commit :enqueue_changes, on: [:create, :update], if: opts[:if]
112
+ klass.after_commit :enqueue_deletion, on: [:destroy], if: opts[:if]
87
113
  end
88
114
 
89
115
  private
90
116
 
117
+ def amount_from_deleted_record(record, counter_data)
118
+ if counter_data[:aggregated_field]
119
+ record.send(counter_data[:aggregated_field])
120
+ else
121
+ counter_data.fetch(:amount, 1)
122
+ end
123
+ end
124
+
91
125
  def destination_class_name(relation, opts)
92
126
  opts[:class_name] ? opts[:class_name].to_s.constantize : relation.to_s.camelcase.constantize
93
127
  end
@@ -31,7 +31,6 @@ module RunningCount
31
31
 
32
32
  destination_id = Format.parse(item)
33
33
  ActiveRecord::Base.connection.exec_query("EXECUTE #{counter_data[:statement]}(#{destination_id})")
34
- rescue StandardError => e
35
34
  end
36
35
 
37
36
  private
@@ -56,7 +55,7 @@ module RunningCount
56
55
 
57
56
  def sum_inner_sql(table_name, relation, opts)
58
57
  %(
59
- SELECT SUM(#{opts[:aggregated_field]}) FROM "#{table_name}"
58
+ SELECT COALESCE(SUM(#{opts[:aggregated_field]}), 0) FROM "#{table_name}"
60
59
  WHERE "#{table_name}"."#{relation}_id" = $1
61
60
  #{extra_sql(opts)}
62
61
  )
@@ -1,3 +1,3 @@
1
1
  module RunningCount
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -36,14 +36,13 @@ Gem::Specification.new do |spec|
36
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
37
  spec.require_paths = ["lib"]
38
38
 
39
- spec.add_dependency "activesupport"
40
- spec.add_dependency "redis-rails"
39
+ spec.add_dependency "activesupport", "~> 4.2.11"
40
+ spec.add_dependency "redis-rails", "~> 5.0"
41
41
  spec.add_dependency "pg", "0.20.0"
42
42
 
43
43
  spec.add_development_dependency "rake", "~> 10.0"
44
44
  spec.add_development_dependency "rspec", "~> 3.0"
45
45
  spec.add_development_dependency "rails", "~> 4.0"
46
- spec.add_development_dependency "database_cleaner"
47
- spec.add_development_dependency "pry-rails"
48
- spec.add_development_dependency "pry-byebug"
46
+ spec.add_development_dependency "database_cleaner", "~> 1.7.0"
47
+ spec.add_development_dependency "pry-byebug", "~> 3.6.0"
49
48
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: running_count
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Isaac Priestley
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-31 00:00:00.000000000 Z
11
+ date: 2019-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 4.2.11
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 4.2.11
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: redis-rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '5.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '5.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pg
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -98,44 +98,30 @@ dependencies:
98
98
  name: database_cleaner
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: pry-rails
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
101
+ - - "~>"
116
102
  - !ruby/object:Gem::Version
117
- version: '0'
103
+ version: 1.7.0
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
107
  requirements:
122
- - - ">="
108
+ - - "~>"
123
109
  - !ruby/object:Gem::Version
124
- version: '0'
110
+ version: 1.7.0
125
111
  - !ruby/object:Gem::Dependency
126
112
  name: pry-byebug
127
113
  requirement: !ruby/object:Gem::Requirement
128
114
  requirements:
129
- - - ">="
115
+ - - "~>"
130
116
  - !ruby/object:Gem::Version
131
- version: '0'
117
+ version: 3.6.0
132
118
  type: :development
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
- - - ">="
122
+ - - "~>"
137
123
  - !ruby/object:Gem::Version
138
- version: '0'
124
+ version: 3.6.0
139
125
  description: Write a longer description or delete this line.
140
126
  email:
141
127
  - isaac@teachable.com