multirow_counter 0.0.2 → 0.0.3

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 250181796c25350c1166b39ab8d0ff56f0f4ed2b
4
+ data.tar.gz: 878c3644f5bccacb41e4c006f1ab80613284ae69
5
+ SHA512:
6
+ metadata.gz: ddbbb2213381c12d5251289070ddb23b4981b7dfc60d2c5fcc2ee62df5d632309ed27aa0c6b6d226c945546d144c8bbe57206c593ddbfb114cf64e96e7ecabc8
7
+ data.tar.gz: f4cf08244e0f71a4ae5fd0c5bbf7c2677353e822dc77ff939cb19ed3aa59c697a31d86086313427732f93e1367b442d639eb9ffe3bbab080553fdd781b174d94
Binary file
Binary file
@@ -1,25 +1,14 @@
1
1
  class Add<%= counter_name.classify %>CounterTo<%= model_name.classify %> < ActiveRecord::Migration
2
2
 
3
3
  def self.up
4
- create_table :<%= [model_name, counter_name].join('_').tableize %> do |t|
5
- t.integer :id
6
- t.integer :<%= model_name %>_id
7
- t.integer :counter_id
8
- t.integer :value
9
- end
10
-
11
- add_index :<%= [model_name, counter_name].join('_').tableize %>, :<%= model_name %>_id
12
-
13
- # You may want to consider moving this into a background task if it takes too long
14
- <%= model_name.classify %>.find_each do |<%= model_name %>|
15
- 1.upto(<%= number_of_counter_rows %>) do |num|
16
- MultirowCounter::<%= model_name.classify %><%= counter_name.classify %>.create! do |row|
17
- row.<%= model_name %>_id = <%= model_name %>.id
18
- row.counter_id = num
19
- row.value = 0
20
- end
21
- end
22
- end
4
+ execute <<-SQL
5
+ CREATE TABLE <%= [model_name, counter_name].join('_').tableize %> (
6
+ <%= model_name %>_id INT NOT NULL,
7
+ counter_id TINYINT NOT NULL,
8
+ value INT NOT NULL,
9
+ PRIMARY KEY (<%= model_name %>_id, counter_id)
10
+ )
11
+ SQL
23
12
  end
24
13
 
25
14
  def self.down
@@ -1,4 +1,3 @@
1
1
  require 'multirow_counter/extension'
2
- require 'multirow_counter/counter_model_creator'
3
2
  require 'multirow_counter/railtie' if defined?(Rails)
4
3
 
@@ -4,25 +4,54 @@ module MultirowCounter
4
4
  num_rows = options[:rows] || raise(ArgumentError, "You need to specify how many rows will be used eg. :rows => 3")
5
5
  class_name = self.name
6
6
 
7
- creator = CounterModelCreator.new(counter_name.to_s, class_name)
8
- const = creator.create
7
+ assoc = class_name.foreign_key
8
+ table_name = [class_name, counter_name.to_s.camelize].join.tableize
9
9
 
10
10
  # define getter method
11
11
  getter = lambda do
12
- counter_relation = const.where(class_name.foreign_key => id)
13
- counter_relation.sum(:value)
12
+ ivar_name = "@#{counter_name}"
13
+ if x = instance_variable_get(ivar_name)
14
+ return x
15
+ else
16
+ val = ActiveRecord::Base.connection.select_value <<-SQL
17
+ SELECT IFNULL(SUM(value),0) FROM #{table_name} WHERE #{assoc}=#{self.id}
18
+ SQL
19
+ instance_variable_set(ivar_name, val.to_i)
20
+ end
14
21
  end
15
22
 
16
23
  define_method(counter_name, &getter)
17
24
  define_method("multirow_counter_#{counter_name}", &getter)
18
25
 
19
26
  # define increment method
20
- define_method("increment_#{counter_name}") do |incr = 1|
21
- counter_relation = const.where(class_name.foreign_key => id)
27
+ define_method("new_#{counter_name}!") do |incr = 1|
28
+ ivar_name = "@#{counter_name}"
29
+ if x = instance_variable_get(ivar_name)
30
+ instance_variable_set(ivar_name, x + incr)
31
+ end
32
+
22
33
  randomly_selected_counter_row = rand(num_rows) + 1
23
34
 
24
- counter_relation.where(:counter_id => randomly_selected_counter_row).limit(1).update_all("value = value+#{Integer(incr)}")
35
+ num_changed = ActiveRecord::Base.connection.update <<-SQL
36
+ UPDATE #{table_name} SET value=value+#{Integer(incr)}
37
+ WHERE #{assoc}=#{self.id} AND counter_id=#{randomly_selected_counter_row}
38
+ SQL
39
+
40
+ if num_changed == 0 # row doesn't exist. We create it instead.
41
+ ActiveRecord::Base.connection.execute <<-SQL
42
+ INSERT INTO #{table_name} (#{assoc}, counter_id, value)
43
+ VALUES (#{self.id}, #{randomly_selected_counter_row}, #{Integer(incr)})
44
+ ON DUPLICATE KEY UPDATE value=value+#{Integer(incr)};
45
+ SQL
46
+ end
25
47
  end
48
+
49
+ define_method("reload_with_#{counter_name}_reset") do
50
+ instance_variable_set("@#{counter_name}", nil)
51
+ send("reload_without_#{counter_name}_reset")
52
+ end
53
+
54
+ alias_method_chain :reload, "#{counter_name}_reset".to_sym
26
55
  end
27
56
  end
28
57
  end
@@ -1,6 +1,8 @@
1
1
  require 'helper'
2
2
 
3
3
  describe MultirowCounter do
4
+ include MultirowCounterTables
5
+
4
6
  before do
5
7
  reset_tables
6
8
  end
@@ -14,30 +16,30 @@ describe MultirowCounter do
14
16
  end
15
17
 
16
18
  it "should allow incrementing" do
17
- @shop.increment_version
19
+ @shop.new_version!
18
20
  assert_equal 1, @shop.version
19
21
  end
20
22
 
21
23
  it "supports many increments" do
22
- 10.times { @shop.increment_version }
24
+ 10.times { @shop.new_version! }
23
25
  assert_equal 10, @shop.version
24
26
  end
25
27
 
26
28
  it "supports batch increments" do
27
- @shop.increment_version(10)
29
+ @shop.new_version!(10)
28
30
  assert_equal 10, @shop.version
29
31
  end
30
32
 
31
33
  it "should not send all increments to the same row" do
32
- 10.times { @shop.increment_version }
34
+ 10.times { @shop.new_version! }
33
35
 
34
- shop_versions = MultirowCounter::ShopVersion.where(:shop_id => @shop.id)
36
+ shop_versions = ShopVersion.where(:shop_id => @shop.id)
35
37
  refute shop_versions.any? { |v| v.value == 10 }
36
38
  end
37
39
 
38
40
  it "requires the number of rows to be specified" do
39
41
  class Foo < ActiveRecord::Base
40
- lambda {
42
+ lambda {
41
43
  multirow_counter :the_count, :random => 'oops'
42
44
  }.must_raise ArgumentError
43
45
  end
@@ -46,5 +48,15 @@ describe MultirowCounter do
46
48
  it "defines a second obscure getter" do
47
49
  @shop.multirow_counter_version.must_equal @shop.version
48
50
  end
51
+
52
+ it "resets the memoized value when reloading" do
53
+ @shop.new_version!
54
+ @other_instance = Shop.find(@shop.id)
55
+ @other_instance.new_version!
56
+
57
+ @shop.reload
58
+
59
+ assert_equal @shop.version, @other_instance.version
60
+ end
49
61
  end
50
62
 
metadata CHANGED
@@ -1,38 +1,93 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multirow_counter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.3
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jesse Storimer
9
8
  autorequire:
10
9
  bindir: bin
11
- cert_chain: []
12
- date: 2012-07-17 00:00:00.000000000 Z
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQ8wDQYDVQQDDAZhZG1p
14
+ bnMxFzAVBgoJkiaJk/IsZAEZFgdzaG9waWZ5MRMwEQYKCZImiZPyLGQBGRYDY29t
15
+ MB4XDTE0MDUxNTIwMzM0OFoXDTE1MDUxNTIwMzM0OFowPzEPMA0GA1UEAwwGYWRt
16
+ aW5zMRcwFQYKCZImiZPyLGQBGRYHc2hvcGlmeTETMBEGCgmSJomT8ixkARkWA2Nv
17
+ bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL0/81O3e1vh5smcwp2G
18
+ MpLQ6q0kejQLa65bPYPxdzWA1SYOKyGfw+yR9LdFzsuKpwWzKq6zX35lj1IckWS4
19
+ bNBEQzxmufUxU0XPM02haFB8fOfDJzdXsWte9Ge4IFwahwn68gpMqN+BvxL+KMYz
20
+ Iut9YmN44d4LZdsENEIO5vmybuG2vYDz7R56qB0PA+Q2P2CdhymsBad2DQs69FBo
21
+ uico9V6VMYYctL9lCYdzu9IXrOYNTt88suKIVzzAlHOKeN0Ng5qdztFoTR8sfxDr
22
+ Ydg3KHl5n47wlpgd8R0f/4b5gGxW+v9pyJCgQnLlRu7DedVSvv7+GMtj3g9r3nhJ
23
+ KqECAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFI/o
24
+ maf34HXbUOQsdoLHacEKQgunMB0GA1UdEQQWMBSBEmFkbWluc0BzaG9waWZ5LmNv
25
+ bTAdBgNVHRIEFjAUgRJhZG1pbnNAc2hvcGlmeS5jb20wDQYJKoZIhvcNAQEFBQAD
26
+ ggEBADkK9aj5T0HPExsov4EoMWFnO+G7RQ28C30VAfKxnL2UxG6i4XMHVs6Xi94h
27
+ qXFw1ec9Y2eDUqaolT3bviOk9BB197+A8Vz/k7MC6ci2NE+yDDB7HAC8zU6LAx8Y
28
+ Iqvw7B/PSZ/pz4bUVFlTATif4mi1vO3lidRkdHRtM7UePSn2rUpOi0gtXBP3bLu5
29
+ YjHJN7wx5cugMEyroKITG5gL0Nxtu21qtOlHX4Hc4KdE2JqzCPOsS4zsZGhgwhPs
30
+ fl3hbtVFTqbOlwL9vy1fudXcolIE/ZTcxQ+er07ZFZdKCXayR9PPs64heamfn0fp
31
+ TConQSX2BnZdhIEYW+cKzEC/bLc=
32
+ -----END CERTIFICATE-----
33
+ date: 2014-06-23 00:00:00.000000000 Z
13
34
  dependencies:
14
35
  - !ruby/object:Gem::Dependency
15
36
  name: activerecord
16
- requirement: &2180916380 !ruby/object:Gem::Requirement
17
- none: false
37
+ requirement: !ruby/object:Gem::Requirement
18
38
  requirements:
19
- - - ! '>='
39
+ - - ">="
20
40
  - !ruby/object:Gem::Version
21
41
  version: '0'
22
42
  type: :runtime
23
43
  prerelease: false
24
- version_requirements: *2180916380
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
25
49
  - !ruby/object:Gem::Dependency
26
50
  name: mysql2
27
- requirement: &2180915820 !ruby/object:Gem::Requirement
28
- none: false
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rake
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
29
73
  requirements:
30
- - - ! '>='
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ - !ruby/object:Gem::Dependency
78
+ name: minitest
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
31
82
  - !ruby/object:Gem::Version
32
83
  version: '0'
33
84
  type: :development
34
85
  prerelease: false
35
- version_requirements: *2180915820
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
36
91
  description: Typically SQL is not a great place to store a counter that is incremented
37
92
  often. For instance if you're counting the number of visits to a page by incrementing
38
93
  a SQL column and that page gets popular then there's a good chance that the SQL
@@ -47,34 +102,32 @@ extra_rdoc_files: []
47
102
  files:
48
103
  - lib/generators/multirow_counter_generator.rb
49
104
  - lib/generators/templates/multirow_counter_migration.rb
50
- - lib/multirow_counter/counter_model_creator.rb
105
+ - lib/multirow_counter.rb
51
106
  - lib/multirow_counter/extension.rb
52
107
  - lib/multirow_counter/railtie.rb
53
- - lib/multirow_counter.rb
54
108
  - test/multirow_counter_test.rb
55
- homepage: http://github.com/Shopify/multirow-counter
109
+ homepage: http://github.com/Shopify/multirow_counter
56
110
  licenses: []
111
+ metadata: {}
57
112
  post_install_message:
58
113
  rdoc_options: []
59
114
  require_paths:
60
115
  - lib
61
116
  required_ruby_version: !ruby/object:Gem::Requirement
62
- none: false
63
117
  requirements:
64
- - - ! '>='
118
+ - - ">="
65
119
  - !ruby/object:Gem::Version
66
120
  version: '0'
67
121
  required_rubygems_version: !ruby/object:Gem::Requirement
68
- none: false
69
122
  requirements:
70
- - - ! '>='
123
+ - - ">="
71
124
  - !ruby/object:Gem::Version
72
125
  version: '0'
73
126
  requirements: []
74
127
  rubyforge_project:
75
- rubygems_version: 1.8.11
128
+ rubygems_version: 2.2.2
76
129
  signing_key:
77
- specification_version: 3
130
+ specification_version: 4
78
131
  summary: Encapsulates a multi-row counter for SQL.
79
132
  test_files:
80
133
  - test/multirow_counter_test.rb
@@ -0,0 +1,3 @@
1
+ x �e�G ���7y���&Z��\�����y�I������˄@�X8����n����ez���:m��Y��H��_x�.�t;�^�K���כ�� ��ٜt�c�O,��劅?_n�:y�����T:���lҡyг�
2
+ ��,���]���c�Є�K��tČ����){MId�*�a�¥���OU�3����y���D��8;����NyZ�rS�.����� ���G�a}uً��P��qt4�]
3
+ ,=ul�Ǜ��F7�
@@ -1,9 +0,0 @@
1
- class CounterModelCreator < Struct.new(:counter_name, :class_name)
2
- def create
3
- counter_class = Class.new(ActiveRecord::Base)
4
- const_name = [class_name, counter_name.classify].join
5
- MultirowCounter.const_set(const_name, counter_class)
6
- end
7
- end
8
-
9
-