counter_culture 1.7.0 → 1.8.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
  SHA1:
3
- metadata.gz: abf23aa3efb1a2f3257bbf6892182ce3ae4ce928
4
- data.tar.gz: dba604aa21f0c043169ff3b7f49050450b74f870
3
+ metadata.gz: d2851375f488ec2d44fad34f75bc463cc7b6d30e
4
+ data.tar.gz: e8cee5f97368554bd04a0acc97b9feffb7e9fe5c
5
5
  SHA512:
6
- metadata.gz: fa34f25d6de4af563033c744e84b82a6ba2b45a14115f74245fa73b40e09e51a3882634863b0aa1d94bb6c7b004b73392c5f7b11180f6c55f47825d27af00c6f
7
- data.tar.gz: 2a317f9b84e3d1f47b6a686cf3d53360514796905fcba622f19c897569fd17b806f99f7e563434ef4759d0d22212dd15db5134217d116debfc4849e3aef3fddc
6
+ metadata.gz: b6af5865d97f22a07be30100266b5b2ee67778c9447c3e74e45c82d21e268912f83d295431cc4ad5ed26d3cc86eee95277a846044b9247ef61b238e6b98ac411
7
+ data.tar.gz: f8ac7e975612ddb98bb955b090db7d29511b602797fa3d684a1743a1d000f95e8a5bd8d2c0b6092c8a6cec236cd932a7437517e2da33c2e39c5e64e69d21fbca
@@ -1,3 +1,9 @@
1
+ ## 1.8.0 (August 30, 2017)
2
+
3
+ Improvements:
4
+ - Quote all table names to work correctly with PostgreSQL schemata
5
+ - Use ActiveRecord version, not Rails version, to make things work for projects that use ActiveRecord but not Rails
6
+
1
7
  ## 1.7.0 (June 12, 2017)
2
8
 
3
9
  Improvements:
@@ -5,7 +11,7 @@ Improvements:
5
11
 
6
12
  ## 1.6.2 (April 26, 2017)
7
13
 
8
- Bugfixes;
14
+ Bugfixes:
9
15
  - Restore compatibility with older Rails versions
10
16
 
11
17
  ## 1.6.1 (April 26, 2017)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.7.0
1
+ 1.8.0
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: counter_culture 1.7.0 ruby lib
5
+ # stub: counter_culture 1.8.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "counter_culture"
9
- s.version = "1.7.0"
9
+ s.version = "1.8.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Magnus von Koeller"]
14
- s.date = "2017-06-12"
14
+ s.date = "2017-08-30"
15
15
  s.description = "counter_culture provides turbo-charged counter caches that are kept up-to-date not just on create and destroy, that support multiple levels of indirection through relationships, allow dynamic column names and that avoid deadlocks by updating in the after_commit callback."
16
16
  s.email = "magnus@vonkoeller.de"
17
17
  s.extra_rdoc_files = [
@@ -1,6 +1,7 @@
1
1
  module CounterCulture
2
2
  class Counter
3
3
  CONFIG_OPTIONS = [ :column_names, :counter_cache_name, :delta_column, :foreign_key_values, :touch, :delta_magnitude, :execute_after_commit ]
4
+ ACTIVE_RECORD_VERSION = Gem.loaded_specs["activerecord"].version
4
5
 
5
6
  attr_reader :model, :relation, *CONFIG_OPTIONS
6
7
 
@@ -197,7 +198,7 @@ module CounterCulture
197
198
  end
198
199
 
199
200
  def attribute_changed?(obj, attr)
200
- if Rails.version >= "5.1.0"
201
+ if ACTIVE_RECORD_VERSION >= Gem::Version.new("5.1.0")
201
202
  obj.saved_changes[attr].present?
202
203
  else
203
204
  obj.send(:attribute_changed?, attr)
@@ -260,9 +261,9 @@ module CounterCulture
260
261
  def previous_model(obj)
261
262
  prev = obj.dup
262
263
 
263
- changes_method = Rails.version >= "5.1.0" ? :saved_changes : :changed_attributes
264
+ changes_method = ACTIVE_RECORD_VERSION >= Gem::Version.new("5.1.0") ? :saved_changes : :changed_attributes
264
265
  obj.public_send(changes_method).each do |key, value|
265
- old_value = Rails.version >= "5.1.0" ? value.first : value
266
+ old_value = ACTIVE_RECORD_VERSION >= Gem::Version.new("5.1.0") ? value.first : value
266
267
  prev.public_send("#{key}=", old_value)
267
268
  end
268
269
 
@@ -280,7 +281,7 @@ module CounterCulture
280
281
 
281
282
  def attribute_was(obj, attr)
282
283
  changes_method =
283
- if Rails.version >= "5.1.0"
284
+ if ACTIVE_RECORD_VERSION >= Gem::Version.new("5.1.0")
284
285
  "_before_last_save"
285
286
  else
286
287
  "_was"
@@ -75,27 +75,19 @@ module CounterCulture
75
75
 
76
76
  # iterate over all the possible counter cache column names
77
77
  counter_column_names.each do |where, column_name|
78
- # if the column name is nil, that means those records don't affect
79
- # counts; we don't need to do anything in that case. but we allow
80
- # specifying that condition regardless to make the syntax less
81
- # confusing
82
- next unless column_name
78
+ # if the column name is nil, that means those records don't affect
79
+ # counts; we don't need to do anything in that case. but we allow
80
+ # specifying that condition regardless to make the syntax less
81
+ # confusing
82
+ next unless column_name
83
+
84
+ relation_class_table_name = quote_table_name(relation_class.table_name)
83
85
 
84
86
  # select join column and count (from above) as well as cache column ('column_name') for later comparison
85
- counts_query = scope.select("#{relation_class.table_name}.#{relation_class.primary_key}, #{relation_class.table_name}.#{relation_reflect(relation).association_primary_key(relation_class)}, #{count_select} AS count, #{relation_class.table_name}.#{column_name}")
87
+ counts_query = scope.select("#{relation_class_table_name}.#{relation_class.primary_key}, #{relation_class_table_name}.#{relation_reflect(relation).association_primary_key(relation_class)}, #{count_select} AS count, #{relation_class_table_name}.#{column_name}")
86
88
 
87
89
  # we need to join together tables until we get back to the table this class itself lives in
88
- # conditions must also be applied to the join on which we are counting
89
- join_clauses.each_with_index do |join, index|
90
- if index == join_clauses.size - 1
91
- if where
92
- join += " AND (#{model.send(:sanitize_sql_for_conditions, where)})"
93
- end
94
- # respect the deleted_at column if it exists
95
- if model.column_names.include?('deleted_at')
96
- join += " AND #{model.table_name}.deleted_at IS NULL"
97
- end
98
- end
90
+ join_clauses(where).each do |join|
99
91
  counts_query = counts_query.joins(join)
100
92
  end
101
93
 
@@ -144,16 +136,17 @@ module CounterCulture
144
136
  end
145
137
 
146
138
  def self_table_name
147
- @self_table_name ||= if relation_class.table_name == model.table_name
148
- "#{model.table_name}_#{model.table_name}"
149
- else
150
- model.table_name
139
+ return @self_table_name if @self_table_name
140
+
141
+ @self_table_name = parameterize(model.table_name)
142
+ if relation_class.table_name == model.table_name
143
+ @self_table_name = "#{@self_table_name}_#{@self_table_name}"
151
144
  end
145
+ @self_table_name = quote_table_name(@self_table_name)
146
+ @self_table_name
152
147
  end
153
148
 
154
- def join_clauses
155
- return @join_clauses if defined?(@join_clauses)
156
-
149
+ def join_clauses(where)
157
150
  # we need to work our way back from the end-point of the relation to
158
151
  # this class itself; make a list of arrays pointing to the
159
152
  # second-to-last, third-to-last, etc.
@@ -162,14 +155,15 @@ module CounterCulture
162
155
 
163
156
  # store joins in an array so that we can later apply column-specific
164
157
  # conditions
165
- @join_clauses = reverse_relation.map do |cur_relation|
158
+ join_clauses = reverse_relation.each_with_index.map do |cur_relation, index|
166
159
  reflect = relation_reflect(cur_relation)
167
160
 
168
- target_table_alias = target_table = reflect.active_record.table_name
169
- if relation_class.table_name == target_table
161
+ target_table = quote_table_name(reflect.active_record.table_name)
162
+ target_table_alias = parameterize(target_table)
163
+ if relation_class.table_name == reflect.active_record.table_name
170
164
  # join with alias to avoid ambiguous table name in
171
165
  # self-referential models
172
- target_table_alias += "_#{target_table}"
166
+ target_table_alias += "_#{target_table_alias}"
173
167
  end
174
168
 
175
169
  if polymorphic?
@@ -180,6 +174,7 @@ module CounterCulture
180
174
  association_primary_key = reflect.association_primary_key
181
175
  source_table = reflect.table_name
182
176
  end
177
+ source_table = quote_table_name(source_table)
183
178
 
184
179
  source_table_key = association_primary_key
185
180
  target_table_key = reflect.foreign_key
@@ -204,10 +199,34 @@ module CounterCulture
204
199
  # NB only works for one-level relations
205
200
  joins_sql += " AND #{target_table}.#{reflect.foreign_type} = '#{relation_class.name}'"
206
201
  end
202
+ if index == reverse_relation.size - 1
203
+ # conditions must be applied to the join on which we are counting
204
+ if where
205
+ joins_sql += " AND (#{model.send(:sanitize_sql_for_conditions, where)})"
206
+ end
207
+ # respect the deleted_at column if it exists
208
+ if model.column_names.include?('deleted_at')
209
+ joins_sql += " AND #{target_table_alias}.deleted_at IS NULL"
210
+ end
211
+ end
207
212
  joins_sql
208
213
  end
209
214
  end
210
215
 
216
+ # This is only needed in relatively unusal cases, for example if you are
217
+ # using Postgres with schema-namespaced tables. But then it's required,
218
+ # and otherwise it's just a no-op, so why not do it?
219
+ def quote_table_name(table_name)
220
+ relation_class.connection.quote_table_name(table_name)
221
+ end
222
+
223
+ def parameterize(string)
224
+ if Rails.version < '5.0'
225
+ string.parameterize('_')
226
+ else
227
+ string.parameterize(separator: '_')
228
+ end
229
+ end
211
230
  end
212
231
  end
213
232
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: counter_culture
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Magnus von Koeller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-12 00:00:00.000000000 Z
11
+ date: 2017-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: after_commit_action