multirow_counter 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-