lifesaver 0.0.1 → 0.1.0
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.
- data/.rspec +1 -0
- data/.travis.yml +3 -1
- data/CHANGELOG.md +7 -0
- data/Gemfile +4 -0
- data/README.md +33 -13
- data/lib/lifesaver.rb +34 -11
- data/lib/lifesaver/config.rb +16 -0
- data/lib/lifesaver/index_worker.rb +10 -10
- data/lib/lifesaver/indexing/enqueuer.rb +37 -0
- data/lib/lifesaver/indexing/indexer.rb +40 -0
- data/lib/lifesaver/indexing/model_additions.rb +55 -0
- data/lib/lifesaver/notification/eager_loader.rb +48 -0
- data/lib/lifesaver/notification/enqueuer.rb +24 -0
- data/lib/lifesaver/notification/indexing_graph.rb +91 -0
- data/lib/lifesaver/notification/model_additions.rb +104 -0
- data/lib/lifesaver/notification/notifiable_associations.rb +49 -0
- data/lib/lifesaver/notification/traversal_queue.rb +48 -0
- data/lib/lifesaver/railtie.rb +4 -3
- data/lib/lifesaver/serialized_model.rb +3 -0
- data/lib/lifesaver/version.rb +1 -1
- data/lib/lifesaver/visitor_worker.rb +8 -4
- data/spec/integration/lifesaver_spec.rb +78 -0
- data/spec/spec_helper.rb +12 -10
- data/spec/support/active_record.rb +3 -3
- data/spec/support/test_models.rb +8 -6
- data/spec/support/tire_helper.rb +37 -0
- data/spec/unit/config_spec.rb +17 -0
- data/spec/unit/indexing/indexer_spec.rb +51 -0
- data/spec/unit/indexing/model_addtions_spec.rb +53 -0
- data/spec/unit/notification/eager_loader_spec.rb +64 -0
- data/spec/unit/notification/enqueuer_spec.rb +39 -0
- data/spec/unit/notification/indexing_graph_spec.rb +73 -0
- data/spec/unit/notification/model_additions_spec.rb +69 -0
- data/spec/unit/notification/notifiable_associations_spec.rb +75 -0
- data/spec/unit/notification/traversal_queue_spec.rb +67 -0
- metadata +40 -14
- data/lib/lifesaver/index_graph.rb +0 -53
- data/lib/lifesaver/marshal.rb +0 -43
- data/lib/lifesaver/model_additions.rb +0 -133
- data/spec/lifesaver/index_graph_spec.rb +0 -64
- data/spec/lifesaver/marshal_spec.rb +0 -80
- data/spec/lifesaver/model_additions_spec.rb +0 -91
- data/spec/lifesaver_spec.rb +0 -111
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Lifesaver::Marshal do
|
4
|
-
describe ".is_serialized?" do
|
5
|
-
it "returns true if Hash has :id and :class" do
|
6
|
-
obj = { class: :post, id: 1 }
|
7
|
-
expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(true)
|
8
|
-
end
|
9
|
-
|
10
|
-
it "returns true if Hash has 'id' and 'class'" do
|
11
|
-
obj = { "class" => "post", "id" => "1" }
|
12
|
-
expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(true)
|
13
|
-
end
|
14
|
-
|
15
|
-
it "returns false if Hash does not have id and class keys" do
|
16
|
-
obj = { some_key: 1, id: 4 }
|
17
|
-
expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(false)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "returns false if passed an non-Hash object" do
|
21
|
-
obj = Post.new
|
22
|
-
expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(false)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe ".sanitize" do
|
27
|
-
it "returns symbolized version of the Hash'" do
|
28
|
-
obj = { "class" => "post", "id" => "1", "status" => "updated" }
|
29
|
-
out = { class: :post, id: 1, status: :updated }
|
30
|
-
expect(Lifesaver::Marshal.sanitize(obj)).to eql(out)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "rejects non-Hashes" do
|
34
|
-
obj = Post.new
|
35
|
-
expect { Lifesaver::Marshal.sanitize(obj) }.to raise_error
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe ".load" do
|
40
|
-
before(:all) do
|
41
|
-
Post.create(title: "Test Post")
|
42
|
-
end
|
43
|
-
|
44
|
-
it "loads a serialized object from ActiveRecord" do
|
45
|
-
obj = { class: :post, id: 1 }
|
46
|
-
expect(Lifesaver::Marshal.load(obj)).to eql([Post.find(1), {}])
|
47
|
-
end
|
48
|
-
|
49
|
-
it "returns nil if model not found" do
|
50
|
-
obj = { class: :post, id: 12 }
|
51
|
-
expect(Lifesaver::Marshal.load(obj)).to eql(nil)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "returns options if they were passed" do
|
55
|
-
obj = { class: :post, id: 1, status: :notified }
|
56
|
-
m = Lifesaver::Marshal.load(obj)
|
57
|
-
expect(m).to eql([Post.find(1), {status: :notified}])
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
it "rejects bad input" do
|
62
|
-
obj = Post.new
|
63
|
-
expect { Lifesaver::Marshal.load(obj) }.to raise_error
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
describe ".dump" do
|
68
|
-
it "decomposes an object to a Hash" do
|
69
|
-
obj = Post.create(title: "Test Post")
|
70
|
-
out = { class: :post, id: 2 }
|
71
|
-
expect(Lifesaver::Marshal.dump(obj)).to eql(out)
|
72
|
-
end
|
73
|
-
|
74
|
-
it "adds additional key, value pairs if passed" do
|
75
|
-
obj = Post.create(title: "Test Post")
|
76
|
-
out = { status: :updated, class: :post, id: 2 }
|
77
|
-
expect(Lifesaver::Marshal.dump(obj, {status: :updated})).to eql(out)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Lifesaver::ModelAdditions do
|
4
|
-
Lifesaver.suppress_indexing
|
5
|
-
|
6
|
-
describe ".notifies_for_indexing" do
|
7
|
-
after(:each) do
|
8
|
-
Post.send(:notifies_for_indexing, only_on_change: :authorships)
|
9
|
-
end
|
10
|
-
it "should return a Hash of models for notification on save and notify" do
|
11
|
-
Post.send(:notifies_for_indexing, :comments,
|
12
|
-
only_on_change: :authorships,
|
13
|
-
only_on_notify: :authors
|
14
|
-
)
|
15
|
-
exp_hash = { on_change: [], on_notify: [] }
|
16
|
-
exp_hash[:on_change] << :comments
|
17
|
-
exp_hash[:on_change] << :authorships
|
18
|
-
exp_hash[:on_notify] << :comments
|
19
|
-
exp_hash[:on_notify] << :authors
|
20
|
-
expect(Post.notifiable_associations).to eql(exp_hash)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "#association_models" do
|
25
|
-
before(:each) do
|
26
|
-
@post = Post.create(title: "Some post")
|
27
|
-
affiliate = Affiliate.create(name: "Some place")
|
28
|
-
@author = Author.create(name: "Some guy", affiliate_id: affiliate.id)
|
29
|
-
Authorship.create(post: @post, author: @author)
|
30
|
-
end
|
31
|
-
after(:all) do
|
32
|
-
Post.destroy_all
|
33
|
-
Author.destroy_all
|
34
|
-
Authorship.destroy_all
|
35
|
-
Affiliate.destroy_all
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should return an array of models for multiple association" do
|
39
|
-
association = @post.association_models(:authorships)
|
40
|
-
expect(association[0]).to be_a_kind_of(Authorship)
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should return an array of one model for a singular association" do
|
44
|
-
association = @author.association_models(:affiliate)
|
45
|
-
expect(association[0]).to be_a_kind_of(Affiliate)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
Lifesaver.unsuppress_indexing
|
50
|
-
|
51
|
-
describe "#indexing_suppressed?" do
|
52
|
-
let(:post) { Post.new(title: "Test Post") }
|
53
|
-
|
54
|
-
it "should be false by default" do
|
55
|
-
expect(post.send(:suppress_indexing?)).to eql(false)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should be true if overridden locally" do
|
59
|
-
Lifesaver.suppress_indexing
|
60
|
-
expect(post.send(:suppress_indexing?)).to eql(true)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should be false if override is cancelled" do
|
64
|
-
Lifesaver.unsuppress_indexing
|
65
|
-
expect(post.send(:suppress_indexing?)).to eql(false)
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should be true if set individually" do
|
69
|
-
post.suppress_indexing
|
70
|
-
expect(post.send(:suppress_indexing?)).to eql(true)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should be false if unset individually" do
|
74
|
-
post.unsuppress_indexing
|
75
|
-
expect(post.send(:suppress_indexing?)).to eql(false)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe "#dependent_association_map" do
|
80
|
-
it "returns an empty Hash when there are no dependent associations" do
|
81
|
-
expect(Comment.new.send(:dependent_association_map)).to eql({})
|
82
|
-
end
|
83
|
-
|
84
|
-
it "returns a Hash with the keys of dependent_association" do
|
85
|
-
dependent_map = Author.new.send(:dependent_association_map)
|
86
|
-
expect(dependent_map).to eql({authorships: true})
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
data/spec/lifesaver_spec.rb
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Lifesaver do
|
4
|
-
before(:all) do
|
5
|
-
Lifesaver.suppress_indexing
|
6
|
-
Post.destroy_all
|
7
|
-
Author.destroy_all
|
8
|
-
Authorship.destroy_all
|
9
|
-
Affiliate.destroy_all
|
10
|
-
Comment.destroy_all
|
11
|
-
Lifesaver.unsuppress_indexing
|
12
|
-
end
|
13
|
-
before(:each) do
|
14
|
-
[Author, Post].each do |klass|
|
15
|
-
klass.tire.index.delete
|
16
|
-
klass.tire.create_elasticsearch_index
|
17
|
-
end
|
18
|
-
|
19
|
-
Lifesaver.suppress_indexing
|
20
|
-
|
21
|
-
@posts = []
|
22
|
-
@posts << Post.create(
|
23
|
-
title: "Lifesavers are my favorite candy",
|
24
|
-
content: "Lorem ipsum",
|
25
|
-
tags: %w(candy stuff opinions)
|
26
|
-
)
|
27
|
-
@posts << Post.create(
|
28
|
-
title: "Birds are the best animal",
|
29
|
-
content: "Lorem ipsum",
|
30
|
-
tags: %w(animals stuff facts)
|
31
|
-
)
|
32
|
-
@posts << Post.create(
|
33
|
-
title: "Chicago Cubs have a winning season",
|
34
|
-
content: "Lorem ipsum",
|
35
|
-
tags: %w(sports stuff jokes)
|
36
|
-
)
|
37
|
-
@comments = []
|
38
|
-
@comments << Comment.create(
|
39
|
-
post: @posts.last,
|
40
|
-
text: "We love this!"
|
41
|
-
)
|
42
|
-
@comments << Comment.create(
|
43
|
-
post: @posts.last,
|
44
|
-
text: "We lied. Didn't realize it was a joke."
|
45
|
-
)
|
46
|
-
@authors = []
|
47
|
-
@authors << Author.create(name: "Paul Sorensen")
|
48
|
-
@authors << Author.create(name: "Paul Sorensen's Ghost Writer")
|
49
|
-
@authors << Author.create(name: "Theo Epstein")
|
50
|
-
@affiliates = []
|
51
|
-
@affiliates << Affiliate.create(name: "Prosper Forebearer")
|
52
|
-
@affiliates << Affiliate.create(name: "Chicago Cubs")
|
53
|
-
@authors[0].affiliate_id = @affiliates.first.id
|
54
|
-
@authors[1].affiliate_id = @affiliates.first.id
|
55
|
-
@authors[2].affiliate_id = @affiliates.last.id
|
56
|
-
@authors.each { |a| a.save! }
|
57
|
-
Authorship.create(post: @posts[0], author: @authors[0])
|
58
|
-
Authorship.create(post: @posts[1], author: @authors[0])
|
59
|
-
Authorship.create(post: @posts[1], author: @authors[1])
|
60
|
-
Authorship.create(post: @posts[2], author: @authors[2])
|
61
|
-
|
62
|
-
Lifesaver.unsuppress_indexing
|
63
|
-
|
64
|
-
[Author, Post].each do |klass|
|
65
|
-
klass.all.each { |k| k.tire.update_index }
|
66
|
-
klass.tire.index.refresh
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
after(:each) do
|
71
|
-
Post.destroy_all
|
72
|
-
Author.destroy_all
|
73
|
-
Authorship.destroy_all
|
74
|
-
Affiliate.destroy_all
|
75
|
-
Comment.destroy_all
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should traverse the provided graph" do
|
79
|
-
models = Lifesaver::IndexGraph.generate([{"class"=>"author", "id"=>1, "status"=>"changed"}])
|
80
|
-
expect(models.size).to eql(2)
|
81
|
-
end
|
82
|
-
|
83
|
-
it "should reindex on destroy" do
|
84
|
-
@authors[2].destroy
|
85
|
-
sleep(1.seconds)
|
86
|
-
expect(Author.search(query: "Theo Epstein").to_a.size).to eql(0)
|
87
|
-
end
|
88
|
-
|
89
|
-
it "should reindex on update" do
|
90
|
-
@authors[2].name = "Harry Carry"
|
91
|
-
@authors[2].save!
|
92
|
-
sleep(1.seconds) # need to wait for elasticsearch to update
|
93
|
-
expect(Author.search(query: "Harry Carry").to_a.size).to eql(1)
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should update distant related indexes" do
|
97
|
-
@posts[0].tags << 'werd'
|
98
|
-
@posts[0].save!
|
99
|
-
sleep(1.seconds)
|
100
|
-
expect(Author.search(query: "werd").to_a.size).to eql(1)
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should update related indexes if saved model doesn't have index" do
|
104
|
-
@comments[0].text = "We hate this!"
|
105
|
-
@comments[0].save!
|
106
|
-
sleep(1.seconds)
|
107
|
-
result = Post.search(query: "Chicago").to_a.first
|
108
|
-
comment_text = result.comments.first.text
|
109
|
-
expect(comment_text).to eql("We hate this!")
|
110
|
-
end
|
111
|
-
end
|