activerecord-redundancy 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 +4 -4
- data/lib/redundancy.rb +28 -54
- data/lib/redundancy/update_base.rb +88 -0
- data/lib/redundancy/update_column.rb +19 -0
- data/lib/redundancy/update_method.rb +19 -0
- data/lib/redundancy/update_prev_column.rb +19 -0
- data/lib/redundancy/update_prev_method.rb +25 -0
- data/lib/redundancy/utils.rb +102 -0
- data/lib/redundancy/version.rb +1 -1
- data/test/{belongs_to_has_one_association_test.rb → cache_column/belongs_to_has_one_association_test.rb} +5 -3
- data/test/{has_many_belongs_to_association_test.rb → cache_column/has_many_belongs_to_association_test.rb} +4 -2
- data/test/{has_one_belongs_to_association_test.rb → cache_column/has_one_belongs_to_association_test.rb} +5 -1
- data/test/{options_test.rb → cache_column/options_test.rb} +0 -0
- data/test/cache_method/has_many_belongs_to_association_test.rb +70 -0
- data/test/fixtures/posts.yml +2 -0
- data/test/fixtures/users.yml +2 -0
- data/test/support/environment.rb +3 -0
- data/test/support/models/account.rb +2 -2
- data/test/support/models/post.rb +5 -2
- data/test/support/models/user.rb +9 -1
- data/test/test_helper.rb +2 -0
- metadata +33 -12
- data/lib/redundancy/cache_column.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: faa2836ac314098d90878058bf77c1260a99decc
|
4
|
+
data.tar.gz: b6494ce4bbfdaf61a9eb799ad9daf418eeb76483
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 078c06ecc0f44628b258e97c6ca3290f0ce209ad450e5f84eb2f419e62c8c387e93fb236727e77179e35880c34b9499733e5de3e4a1ece02b954e98a37df0d02
|
7
|
+
data.tar.gz: 2f0cb3ee7453469962e52b95104450a40cae0308616447f775237dea18bf875d6a51cb923a25982d0e9a16e31c608c3af5283d62d110309f25cab0367028c4db
|
data/lib/redundancy.rb
CHANGED
@@ -1,73 +1,47 @@
|
|
1
|
-
require 'redundancy/
|
1
|
+
require 'redundancy/utils'
|
2
2
|
|
3
3
|
module Redundancy
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
before_save :
|
7
|
+
before_save :update_redundacies_before_save
|
8
|
+
after_save :update_redundacies_after_save
|
8
9
|
end
|
9
10
|
|
10
11
|
private
|
11
12
|
|
12
|
-
def
|
13
|
-
self.class.
|
14
|
-
|
13
|
+
def update_redundacies_before_save
|
14
|
+
self.class.redundacies.each do |redundancy|
|
15
|
+
redundancy.before_save(self)
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
raise ArgumentError, "Unknown association :#{association}" unless reflection
|
24
|
-
raise ArgumentError, "BelongsTo or HasOne reflection needed" unless
|
25
|
-
[:has_one, :belongs_to].include? reflection.macro
|
26
|
-
|
27
|
-
inverse_associations = options[:inverse_of]
|
28
|
-
inverse_associations ||= [model_name.plural, model_name.singular].map(&:to_sym)
|
29
|
-
|
30
|
-
inverse_association = Array.wrap(inverse_associations).find do |inverse_association|
|
31
|
-
reflection.klass.reflect_on_association(inverse_association)
|
32
|
-
end
|
33
|
-
|
34
|
-
raise ArgumentError, "Could not find the inverse association for #{association} (#{inverse_associations.inspect} in #{reflection.klass})" unless inverse_association
|
35
|
-
|
36
|
-
foreign_key = reflection.foreign_key
|
37
|
-
cache_column = options[:cache_column] || :"#{association}_#{attribute}"
|
38
|
-
|
39
|
-
local_klass = self
|
40
|
-
remote_klass = reflection.klass
|
41
|
-
|
42
|
-
case reflection.macro
|
43
|
-
when :belongs_to
|
44
|
-
local_klass.cache_columns << CacheColumn.new({
|
45
|
-
source: { association: association, attribute: attribute },
|
46
|
-
dist: { association: nil, attribute: cache_column },
|
47
|
-
change_if: foreign_key, klass: local_klass
|
48
|
-
})
|
49
|
-
|
50
|
-
when :has_one
|
51
|
-
remote_klass.cache_columns << CacheColumn.new({
|
52
|
-
source: { association: nil, attribute: attribute },
|
53
|
-
dist: { association: inverse_association, attribute: cache_column },
|
54
|
-
change_if: foreign_key, nil_unless: foreign_key, klass: remote_klass,
|
55
|
-
set_prev_nil: { klass: local_klass, attribute: foreign_key }
|
56
|
-
})
|
57
|
-
|
58
|
-
end
|
19
|
+
def update_redundacies_after_save
|
20
|
+
self.class.redundacies.each do |redundancy|
|
21
|
+
redundancy.after_save(self)
|
22
|
+
end
|
23
|
+
end
|
59
24
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
25
|
+
def update_redundacies
|
26
|
+
self.class.redundacies.each do |redundancy|
|
27
|
+
redundancy.before_save(self)
|
28
|
+
redundancy.after_save(self)
|
29
|
+
end
|
30
|
+
end
|
65
31
|
|
32
|
+
module ClassMethods
|
33
|
+
def cache_column association, attribute, options = {}
|
34
|
+
options.assert_valid_keys(:cache_column, :inverse_of)
|
35
|
+
Utils.cache_column self, association, attribute, options
|
36
|
+
end
|
66
37
|
|
38
|
+
def cache_method association, attribute, options = {}
|
39
|
+
options.assert_valid_keys(:cache_column, :inverse_of)
|
40
|
+
Utils.cache_method self, association, attribute, options
|
67
41
|
end
|
68
42
|
|
69
|
-
def
|
70
|
-
@
|
43
|
+
def redundacies
|
44
|
+
@redundacies ||= []
|
71
45
|
end
|
72
46
|
|
73
47
|
end
|
@@ -77,4 +51,4 @@ end
|
|
77
51
|
# include in AR
|
78
52
|
ActiveSupport.on_load(:active_record) do
|
79
53
|
ActiveRecord::Base.send(:include, Redundancy)
|
80
|
-
end
|
54
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Redundancy
|
2
|
+
|
3
|
+
class UpdateBase
|
4
|
+
attr_reader :options
|
5
|
+
attr_reader :source, :dest, :klass
|
6
|
+
attr_reader :change_if, :update, :target, :value
|
7
|
+
|
8
|
+
def initialize options
|
9
|
+
@options = options
|
10
|
+
@source, @dest = options[:source], options[:dest]
|
11
|
+
@klass = options[:klass]
|
12
|
+
|
13
|
+
@change_if = options[:change_if]
|
14
|
+
@update = options[:update] || false
|
15
|
+
end
|
16
|
+
|
17
|
+
def before_save record
|
18
|
+
end
|
19
|
+
|
20
|
+
def after_save record
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_target_from_association record
|
24
|
+
@target = dest[:association] ? record.send(dest[:association]) : record
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_target_from_prev_id record
|
28
|
+
prev_id = record.send(:attribute_was, dest[:prev_id])
|
29
|
+
return unless prev_id
|
30
|
+
@target = dest[:klass].where(id: prev_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_target_from_relation_first_record
|
34
|
+
@target = @target.first if @target.kind_of? ActiveRecord::Relation
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_value_from_association record
|
38
|
+
@value = source[:association] ? record.send(source[:association]) : record
|
39
|
+
@value = value && source[:attribute] && value.send(source[:attribute])
|
40
|
+
@value = nil if source[:nil_unless] && !record.send(source[:nil_unless])
|
41
|
+
@value
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_value_from_source record
|
45
|
+
@value = source
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_value_from_target record
|
49
|
+
@value = target && source[:attribute] && target.send(source[:attribute])
|
50
|
+
end
|
51
|
+
|
52
|
+
def raise_if_class_mismatch record
|
53
|
+
raise ArgumentError, "record class mismatch, expected #{klass}, got #{record.class}" unless record.kind_of? klass
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_target record
|
57
|
+
case target
|
58
|
+
when ActiveRecord::Base
|
59
|
+
return if target.send(:read_attribute, dest[:attribute]) == value
|
60
|
+
log "#{ update ? "update" : "write" } #{target.class}(#{target.id})##{dest[:attribute]} with #{value.inspect}"
|
61
|
+
log "#{change_if}: #{record.send(change_if).inspect}, #{dest[:association]||"self"}.id: #{target.id}" if change_if
|
62
|
+
if update
|
63
|
+
target.send(:update_attribute, dest[:attribute], value)
|
64
|
+
else
|
65
|
+
target.send(:write_attribute, dest[:attribute], value)
|
66
|
+
end
|
67
|
+
when ActiveRecord::Relation
|
68
|
+
log "update #{target.class}##{dest[:attribute]} with #{value.inspect}"
|
69
|
+
target.send(:update_all, dest[:attribute] => value)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def force_update_target record
|
74
|
+
@update = true
|
75
|
+
update_target record
|
76
|
+
end
|
77
|
+
|
78
|
+
def need_update? record
|
79
|
+
!change_if || record.send(:attribute_changed?, change_if)
|
80
|
+
end
|
81
|
+
|
82
|
+
def log *message
|
83
|
+
# puts *message
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'redundancy/update_base'
|
2
|
+
|
3
|
+
module Redundancy
|
4
|
+
|
5
|
+
class UpdateColumn < UpdateBase
|
6
|
+
|
7
|
+
def before_save record
|
8
|
+
raise_if_class_mismatch record
|
9
|
+
return unless need_update? record
|
10
|
+
|
11
|
+
get_target_from_association record
|
12
|
+
get_value_from_association record
|
13
|
+
|
14
|
+
update_target record
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'redundancy/update_base'
|
2
|
+
|
3
|
+
module Redundancy
|
4
|
+
|
5
|
+
class UpdateMethod < UpdateBase
|
6
|
+
|
7
|
+
def after_save record
|
8
|
+
raise_if_class_mismatch record
|
9
|
+
return unless need_update? record
|
10
|
+
|
11
|
+
get_target_from_association record
|
12
|
+
get_value_from_target record
|
13
|
+
|
14
|
+
force_update_target record
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'redundancy/update_base'
|
2
|
+
|
3
|
+
module Redundancy
|
4
|
+
|
5
|
+
class UpdatePrevColumn < UpdateBase
|
6
|
+
|
7
|
+
def before_save record
|
8
|
+
raise_if_class_mismatch record
|
9
|
+
return unless need_update? record
|
10
|
+
|
11
|
+
get_target_from_prev_id record
|
12
|
+
get_value_from_source record
|
13
|
+
|
14
|
+
update_target record
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'redundancy/update_base'
|
2
|
+
|
3
|
+
module Redundancy
|
4
|
+
|
5
|
+
class UpdatePrevMethod < UpdateBase
|
6
|
+
|
7
|
+
def before_save record
|
8
|
+
raise_if_class_mismatch record
|
9
|
+
return unless need_update? record
|
10
|
+
|
11
|
+
get_target_from_prev_id record
|
12
|
+
end
|
13
|
+
|
14
|
+
def after_save record
|
15
|
+
return unless need_update? record
|
16
|
+
return unless target
|
17
|
+
|
18
|
+
get_target_from_relation_first_record
|
19
|
+
get_value_from_target record
|
20
|
+
force_update_target record
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'redundancy/update_column'
|
2
|
+
require 'redundancy/update_prev_column'
|
3
|
+
require 'redundancy/update_method'
|
4
|
+
require 'redundancy/update_prev_method'
|
5
|
+
|
6
|
+
module Redundancy
|
7
|
+
|
8
|
+
module Utils
|
9
|
+
|
10
|
+
def self.cache_column klass, association, attribute, options
|
11
|
+
local_klass = klass
|
12
|
+
|
13
|
+
reflection = get_reflection local_klass, association
|
14
|
+
raise ArgumentError, "BelongsTo or HasOne reflection required" unless
|
15
|
+
[:has_one, :belongs_to].include? reflection.macro
|
16
|
+
|
17
|
+
foreign_key = reflection.foreign_key
|
18
|
+
remote_klass = reflection.klass
|
19
|
+
|
20
|
+
inverse_association = get_inverse_association local_klass, remote_klass, options
|
21
|
+
|
22
|
+
cache_column = options[:cache_column] || :"#{association}_#{attribute}"
|
23
|
+
|
24
|
+
case reflection.macro
|
25
|
+
when :belongs_to
|
26
|
+
local_klass.redundacies << UpdateColumn.new(
|
27
|
+
source: { association: association, attribute: attribute },
|
28
|
+
dest: { association: nil, attribute: cache_column },
|
29
|
+
change_if: foreign_key, klass: local_klass
|
30
|
+
)
|
31
|
+
|
32
|
+
when :has_one
|
33
|
+
remote_klass.redundacies << UpdateColumn.new(
|
34
|
+
source: { association: nil, attribute: attribute, nil_unless: foreign_key },
|
35
|
+
dest: { association: inverse_association, attribute: cache_column },
|
36
|
+
change_if: foreign_key, klass: remote_klass
|
37
|
+
)
|
38
|
+
|
39
|
+
remote_klass.redundacies << UpdatePrevColumn.new(
|
40
|
+
source: options[:default],
|
41
|
+
dest: { klass: local_klass, prev_id: foreign_key, attribute: cache_column },
|
42
|
+
change_if: foreign_key, klass: remote_klass
|
43
|
+
)
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
remote_klass.redundacies << UpdateColumn.new(
|
48
|
+
source: { association: nil, attribute: attribute },
|
49
|
+
dest: { association: inverse_association, attribute: cache_column },
|
50
|
+
change_if: attribute, klass: remote_klass, update: true
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.cache_method klass, association, attribute, options
|
55
|
+
local_klass = klass
|
56
|
+
|
57
|
+
reflection = get_reflection local_klass, association
|
58
|
+
raise ArgumentError, "BelongsTo reflection required" unless
|
59
|
+
[:belongs_to].include? reflection.macro
|
60
|
+
|
61
|
+
foreign_key = reflection.foreign_key
|
62
|
+
remote_klass = reflection.klass
|
63
|
+
|
64
|
+
cache_method = options[:cache_method] || :"raw_#{attribute}"
|
65
|
+
|
66
|
+
local_klass.redundacies << UpdateMethod.new(
|
67
|
+
source: { attribute: cache_method },
|
68
|
+
dest: { association: association, attribute: attribute },
|
69
|
+
change_if: options[:change_if], klass: local_klass
|
70
|
+
)
|
71
|
+
|
72
|
+
local_klass.redundacies << UpdatePrevMethod.new(
|
73
|
+
source: { attribute: cache_method },
|
74
|
+
dest: { klass: remote_klass, prev_id: foreign_key, attribute: attribute },
|
75
|
+
change_if: foreign_key, klass: local_klass
|
76
|
+
)
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.get_reflection klass, association
|
81
|
+
reflection = klass.reflect_on_association(association)
|
82
|
+
raise ArgumentError, "Unknown association :#{association}" unless reflection
|
83
|
+
reflection
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.get_inverse_association klass, reflection_klass, options
|
87
|
+
model_name = klass.model_name
|
88
|
+
inverse_associations = options[:inverse_of]
|
89
|
+
inverse_associations ||= [model_name.plural, model_name.singular].map(&:to_sym)
|
90
|
+
|
91
|
+
inverse_association = Array.wrap(inverse_associations).find do |inverse_association|
|
92
|
+
reflection_klass.reflect_on_association(inverse_association)
|
93
|
+
end
|
94
|
+
|
95
|
+
raise ArgumentError, "Could not find the inverse association for #{association} (#{inverse_associations.inspect} in #{reflection_klass})" unless inverse_association
|
96
|
+
inverse_association
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
data/lib/redundancy/version.rb
CHANGED
@@ -21,6 +21,7 @@ class BelongsToHasOneAssociationTest < ActiveSupport::TestCase
|
|
21
21
|
|
22
22
|
account.update_attribute(:user, user)
|
23
23
|
assert_equal user.name, account.user_name
|
24
|
+
assert_equal user.name, account.reload.user_name
|
24
25
|
end
|
25
26
|
|
26
27
|
test "should update account.user_name when update account.user with nil" do
|
@@ -30,6 +31,7 @@ class BelongsToHasOneAssociationTest < ActiveSupport::TestCase
|
|
30
31
|
|
31
32
|
account.update_attribute(:user, nil)
|
32
33
|
assert_equal nil, account.user_name
|
34
|
+
assert_equal nil, account.reload.user_name
|
33
35
|
end
|
34
36
|
|
35
37
|
test "should update account.user_name when update account.user with other user" do
|
@@ -42,7 +44,8 @@ class BelongsToHasOneAssociationTest < ActiveSupport::TestCase
|
|
42
44
|
|
43
45
|
account.update_attribute(:user, other_user)
|
44
46
|
assert_equal other_user.name, account.user_name
|
45
|
-
assert_equal
|
47
|
+
assert_equal other_user.name, account.reload.user_name
|
48
|
+
assert_equal nil, other_account.user
|
46
49
|
assert_equal nil, other_account.reload.user_name
|
47
50
|
end
|
48
51
|
|
@@ -53,8 +56,7 @@ class BelongsToHasOneAssociationTest < ActiveSupport::TestCase
|
|
53
56
|
|
54
57
|
user.update_attribute(:name, "Other Name")
|
55
58
|
assert_equal user.name, user.account.user_name
|
56
|
-
|
57
59
|
assert_equal user.name, account.reload.user_name
|
58
60
|
end
|
59
61
|
|
60
|
-
end
|
62
|
+
end
|
@@ -3,6 +3,7 @@ require 'test_helper'
|
|
3
3
|
class HasManyBelongsToAssociationTest < ActiveSupport::TestCase
|
4
4
|
|
5
5
|
# has_many:belongs_to association
|
6
|
+
# cache_column
|
6
7
|
test "should update post.user_name when create post" do
|
7
8
|
user = users(:one)
|
8
9
|
post = Post.create(title: 'title', content: 'content', user: user)
|
@@ -21,6 +22,7 @@ class HasManyBelongsToAssociationTest < ActiveSupport::TestCase
|
|
21
22
|
|
22
23
|
post.update_attribute(:user, user)
|
23
24
|
assert_equal user.name, post.user_name
|
25
|
+
assert_equal user.name, post.reload.user_name
|
24
26
|
end
|
25
27
|
|
26
28
|
test "should update post.user_name when update post.user with nil" do
|
@@ -30,6 +32,7 @@ class HasManyBelongsToAssociationTest < ActiveSupport::TestCase
|
|
30
32
|
|
31
33
|
post.update_attribute(:user, nil)
|
32
34
|
assert_equal nil, post.user_name
|
35
|
+
assert_equal nil, post.reload.user_name
|
33
36
|
end
|
34
37
|
|
35
38
|
test "should update post.user_name when update post.user with other user" do
|
@@ -42,6 +45,7 @@ class HasManyBelongsToAssociationTest < ActiveSupport::TestCase
|
|
42
45
|
|
43
46
|
post.update_attribute(:user, other_user)
|
44
47
|
assert_equal other_user.name, post.user_name
|
48
|
+
assert_equal other_user.name, post.reload.user_name
|
45
49
|
end
|
46
50
|
|
47
51
|
test "should update post.user_name when update user.name" do
|
@@ -53,8 +57,6 @@ class HasManyBelongsToAssociationTest < ActiveSupport::TestCase
|
|
53
57
|
user.posts.each do |post|
|
54
58
|
assert_equal user.name, post.user_name
|
55
59
|
end
|
56
|
-
|
57
60
|
assert_equal user.name, post.reload.user_name
|
58
61
|
end
|
59
|
-
|
60
62
|
end
|
@@ -21,6 +21,7 @@ class HasOneBelongsToAssociationTest < ActiveSupport::TestCase
|
|
21
21
|
|
22
22
|
user.update_attribute(:account, account)
|
23
23
|
assert_equal account.email, user.account_email
|
24
|
+
assert_equal account.email, user.reload.account_email
|
24
25
|
end
|
25
26
|
|
26
27
|
test "should update user.account_email when update user.account with nil" do
|
@@ -30,6 +31,7 @@ class HasOneBelongsToAssociationTest < ActiveSupport::TestCase
|
|
30
31
|
|
31
32
|
user.update_attribute(:account, nil)
|
32
33
|
assert_equal nil, user.account_email
|
34
|
+
assert_equal nil, user.reload.account_email
|
33
35
|
end
|
34
36
|
|
35
37
|
test "should update user.account_email when update user.account with other account" do
|
@@ -42,8 +44,10 @@ class HasOneBelongsToAssociationTest < ActiveSupport::TestCase
|
|
42
44
|
|
43
45
|
user.update_attribute(:account, other_account)
|
44
46
|
assert_equal other_account.email, user.account_email
|
47
|
+
assert_equal other_account.email, user.reload.account_email
|
45
48
|
assert_equal other_account, other_user.account
|
46
49
|
assert_equal other_account.email, other_user.account_email
|
50
|
+
assert_equal other_account.email, other_user.reload.account_email
|
47
51
|
end
|
48
52
|
|
49
53
|
test "should update user.account_email when update account.email" do
|
@@ -57,4 +61,4 @@ class HasOneBelongsToAssociationTest < ActiveSupport::TestCase
|
|
57
61
|
assert_equal account.email, user.reload.account_email
|
58
62
|
end
|
59
63
|
|
60
|
-
end
|
64
|
+
end
|
File without changes
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class HasManyBelongsToAssociationTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
# has_many:belongs_to association
|
6
|
+
# cache_method
|
7
|
+
test "should update user.posts_count when create post" do
|
8
|
+
user = users(:one)
|
9
|
+
post = Post.create(title: 'title', content: 'content', user: user)
|
10
|
+
assert_equal user.raw_posts_count, user.posts_count
|
11
|
+
end
|
12
|
+
|
13
|
+
test "should update user.posts_star when create post" do
|
14
|
+
user = users(:one)
|
15
|
+
post = Post.create(title: 'title', content: 'content', user: user, star: 5)
|
16
|
+
assert_equal user.raw_posts_star, user.posts_star
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should update user.posts_star when create post without star" do
|
20
|
+
user = users(:one)
|
21
|
+
post = Post.create(title: 'title', content: 'content', user: user)
|
22
|
+
assert_equal user.raw_posts_star, user.posts_star
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should update nothing when create post without user" do
|
26
|
+
post = Post.create(title: 'title', content: 'content')
|
27
|
+
end
|
28
|
+
|
29
|
+
test "should update user.posts_star when update post.user" do
|
30
|
+
user = users(:one)
|
31
|
+
post = posts(:two)
|
32
|
+
assert_equal user.raw_posts_star, user.posts_star
|
33
|
+
|
34
|
+
post.update_attribute(:user, user)
|
35
|
+
assert_equal user.raw_posts_star, user.reload.posts_star
|
36
|
+
end
|
37
|
+
|
38
|
+
test "should update user.posts_star when update post.user with nil" do
|
39
|
+
user = users(:one)
|
40
|
+
post = posts(:one)
|
41
|
+
assert_equal user.raw_posts_star, user.posts_star
|
42
|
+
|
43
|
+
post.update_attribute(:user, nil)
|
44
|
+
assert_equal user.raw_posts_star, user.reload.posts_star
|
45
|
+
end
|
46
|
+
|
47
|
+
test "should update user.posts_star when update post.user with other user" do
|
48
|
+
user = users(:one)
|
49
|
+
other_user = users(:two)
|
50
|
+
post = posts(:one)
|
51
|
+
other_post = posts(:two)
|
52
|
+
assert_equal user.raw_posts_star, user.posts_star
|
53
|
+
assert_equal other_user.raw_posts_star, other_user.posts_star
|
54
|
+
|
55
|
+
post.update_attribute(:user, other_user)
|
56
|
+
assert_equal user.raw_posts_star, user.reload.posts_star
|
57
|
+
assert_equal other_user.raw_posts_star, other_user.reload.posts_star
|
58
|
+
end
|
59
|
+
|
60
|
+
test "should update user.posts_star when update post.star" do
|
61
|
+
user = users(:one)
|
62
|
+
post = posts(:one)
|
63
|
+
assert_equal user.raw_posts_star, user.posts_star
|
64
|
+
|
65
|
+
post.update_attribute(:star, 5)
|
66
|
+
assert_equal user.raw_posts_star, post.user.posts_star
|
67
|
+
assert_equal user.raw_posts_star, user.reload.posts_star
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/test/fixtures/posts.yml
CHANGED
data/test/fixtures/users.yml
CHANGED
data/test/support/environment.rb
CHANGED
@@ -22,6 +22,7 @@ ActiveRecord::Schema.define do
|
|
22
22
|
t.integer "user_id"
|
23
23
|
t.string "user_name"
|
24
24
|
t.string "username"
|
25
|
+
t.integer "star"
|
25
26
|
t.string "title"
|
26
27
|
t.text "content"
|
27
28
|
t.datetime "created_at"
|
@@ -33,6 +34,8 @@ ActiveRecord::Schema.define do
|
|
33
34
|
create_table "users", force: true do |t|
|
34
35
|
t.integer "account_id"
|
35
36
|
t.string "account_email"
|
37
|
+
t.integer "posts_count"
|
38
|
+
t.integer "posts_star"
|
36
39
|
t.string "name"
|
37
40
|
t.datetime "created_at"
|
38
41
|
t.datetime "updated_at"
|
data/test/support/models/post.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
class Post < ActiveRecord::Base
|
2
2
|
belongs_to :user
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
cache_column :user, :name
|
5
|
+
cache_column :user, :name, cache_column: :username
|
6
|
+
|
7
|
+
cache_method :user, :posts_count
|
8
|
+
cache_method :user, :posts_star
|
6
9
|
end
|
data/test/support/models/user.rb
CHANGED
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-redundancy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -58,6 +58,20 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: pry-stack_explorer
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
61
75
|
- !ruby/object:Gem::Dependency
|
62
76
|
name: rails
|
63
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,15 +97,21 @@ files:
|
|
83
97
|
- Rakefile
|
84
98
|
- lib/activerecord-redundancy.rb
|
85
99
|
- lib/redundancy.rb
|
86
|
-
- lib/redundancy/
|
100
|
+
- lib/redundancy/update_base.rb
|
101
|
+
- lib/redundancy/update_column.rb
|
102
|
+
- lib/redundancy/update_method.rb
|
103
|
+
- lib/redundancy/update_prev_column.rb
|
104
|
+
- lib/redundancy/update_prev_method.rb
|
105
|
+
- lib/redundancy/utils.rb
|
87
106
|
- lib/redundancy/version.rb
|
88
|
-
- test/belongs_to_has_one_association_test.rb
|
107
|
+
- test/cache_column/belongs_to_has_one_association_test.rb
|
108
|
+
- test/cache_column/has_many_belongs_to_association_test.rb
|
109
|
+
- test/cache_column/has_one_belongs_to_association_test.rb
|
110
|
+
- test/cache_column/options_test.rb
|
111
|
+
- test/cache_method/has_many_belongs_to_association_test.rb
|
89
112
|
- test/fixtures/accounts.yml
|
90
113
|
- test/fixtures/posts.yml
|
91
114
|
- test/fixtures/users.yml
|
92
|
-
- test/has_many_belongs_to_association_test.rb
|
93
|
-
- test/has_one_belongs_to_association_test.rb
|
94
|
-
- test/options_test.rb
|
95
115
|
- test/support/environment.rb
|
96
116
|
- test/support/models/account.rb
|
97
117
|
- test/support/models/post.rb
|
@@ -117,18 +137,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
137
|
version: '0'
|
118
138
|
requirements: []
|
119
139
|
rubyforge_project:
|
120
|
-
rubygems_version: 2.
|
140
|
+
rubygems_version: 2.4.6
|
121
141
|
signing_key:
|
122
142
|
specification_version: 4
|
123
143
|
summary: Redundancy for better performance, non painful
|
124
144
|
test_files:
|
125
|
-
- test/belongs_to_has_one_association_test.rb
|
145
|
+
- test/cache_column/belongs_to_has_one_association_test.rb
|
146
|
+
- test/cache_column/has_many_belongs_to_association_test.rb
|
147
|
+
- test/cache_column/has_one_belongs_to_association_test.rb
|
148
|
+
- test/cache_column/options_test.rb
|
149
|
+
- test/cache_method/has_many_belongs_to_association_test.rb
|
126
150
|
- test/fixtures/accounts.yml
|
127
151
|
- test/fixtures/posts.yml
|
128
152
|
- test/fixtures/users.yml
|
129
|
-
- test/has_many_belongs_to_association_test.rb
|
130
|
-
- test/has_one_belongs_to_association_test.rb
|
131
|
-
- test/options_test.rb
|
132
153
|
- test/support/environment.rb
|
133
154
|
- test/support/models/account.rb
|
134
155
|
- test/support/models/post.rb
|
@@ -1,59 +0,0 @@
|
|
1
|
-
module Redundancy
|
2
|
-
|
3
|
-
class CacheColumn
|
4
|
-
attr_reader :options
|
5
|
-
attr_reader :source, :dist, :klass
|
6
|
-
attr_reader :change_if, :nil_unless, :update, :set_prev_nil
|
7
|
-
|
8
|
-
def initialize options
|
9
|
-
@options = options
|
10
|
-
@source, @dist = options[:source], options[:dist]
|
11
|
-
@klass = options[:klass]
|
12
|
-
|
13
|
-
@change_if = options[:change_if]
|
14
|
-
@nil_unless = options[:nil_unless]
|
15
|
-
@update = options[:update] || false
|
16
|
-
@set_prev_nil = options[:set_prev_nil]
|
17
|
-
end
|
18
|
-
|
19
|
-
def update_record record
|
20
|
-
raise ArgumentError, "record class mismatch, expected #{klass}, got #{record.class}" unless record.kind_of? klass
|
21
|
-
return unless need_update?(record)
|
22
|
-
|
23
|
-
src = source[:association] ? record.send(source[:association]) : record
|
24
|
-
src = src && source[:attribute] && src.send(source[:attribute])
|
25
|
-
src = nil if nil_unless && !record.send(nil_unless)
|
26
|
-
|
27
|
-
dst = dist[:association] ? record.send(dist[:association]) : record
|
28
|
-
|
29
|
-
set_prev_nil[:klass].where(id: record.send(:attribute_was, set_prev_nil[:attribute]))
|
30
|
-
.update_all(dist[:attribute] => nil) if set_prev_nil
|
31
|
-
|
32
|
-
case dst
|
33
|
-
when ActiveRecord::Base
|
34
|
-
return if dst.send(:read_attribute, dist[:attribute]) == src
|
35
|
-
log "#{ update ? "update" : "write" } #{dst.class}(#{dst.id})##{dist[:attribute]} with #{src.inspect}"
|
36
|
-
log "#{change_if}: #{record.send(change_if).inspect}, #{dist[:association]||"self"}.id: #{dst.id}"
|
37
|
-
if update
|
38
|
-
dst.send(:update_attribute, dist[:attribute], src)
|
39
|
-
else
|
40
|
-
dst.send(:write_attribute, dist[:attribute], src)
|
41
|
-
end
|
42
|
-
when ActiveRecord::Relation
|
43
|
-
log "update #{dst.class}##{dist[:attribute]} with #{src.inspect}"
|
44
|
-
dst.send(:update_all, dist[:attribute] => src)
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
def need_update? record
|
50
|
-
record.send(:attribute_changed?, change_if)
|
51
|
-
end
|
52
|
-
|
53
|
-
def log *message
|
54
|
-
# puts *message
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|