hari 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +15 -0
  2. data/.travis.yml +15 -0
  3. data/LICENSE +15 -19
  4. data/README.md +22 -0
  5. data/hari.gemspec +2 -1
  6. data/lib/hari.rb +56 -1
  7. data/lib/hari/entity.rb +8 -11
  8. data/lib/hari/entity/property.rb +2 -2
  9. data/lib/hari/entity/property/builder.rb +9 -1
  10. data/lib/hari/entity/repository.rb +3 -2
  11. data/lib/hari/entity/serialization/float.rb +2 -0
  12. data/lib/hari/entity/serialization/integer.rb +3 -10
  13. data/lib/hari/node.rb +20 -3
  14. data/lib/hari/node/queries.rb +33 -0
  15. data/lib/hari/node/queries/list.rb +147 -0
  16. data/lib/hari/node/queries/relation.rb +100 -0
  17. data/lib/hari/node/queries/relation/backend/list.rb +35 -0
  18. data/lib/hari/node/queries/relation/backend/sorted_set.rb +95 -0
  19. data/lib/hari/node/queries/relation/runnable.rb +24 -0
  20. data/lib/hari/node/queries/relation/start.rb +19 -0
  21. data/lib/hari/node/queries/relation/step.rb +17 -0
  22. data/lib/hari/node/queries/set.rb +116 -0
  23. data/lib/hari/node/queries/sorted_set.rb +130 -0
  24. data/lib/hari/node/repository.rb +24 -0
  25. data/lib/hari/node/serialization.rb +24 -0
  26. data/lib/hari/relation.rb +72 -0
  27. data/lib/hari/relation/linked_list.rb +16 -0
  28. data/lib/hari/relation/sorted_set.rb +16 -0
  29. data/lib/hari/version.rb +1 -1
  30. data/spec/hari/configuration_spec.rb +5 -0
  31. data/spec/hari/entity/repository_spec.rb +4 -4
  32. data/spec/hari/entity/serialization_spec.rb +2 -2
  33. data/spec/hari/node/lists_spec.rb +126 -0
  34. data/spec/hari/node/sets_spec.rb +85 -0
  35. data/spec/hari/node/sorted_sets_spec.rb +89 -0
  36. data/spec/hari/node_spec.rb +79 -0
  37. data/spec/hari_spec.rb +37 -0
  38. data/spec/spec_helper.rb +11 -1
  39. metadata +48 -32
  40. data/lib/hari/relationship.rb +0 -72
  41. data/lib/hari/relationship/linked_list.rb +0 -22
  42. data/lib/hari/relationship/sorted_set.rb +0 -22
  43. data/lib/hari/scripts.rb +0 -26
@@ -0,0 +1,24 @@
1
+ module Hari
2
+ class Node < Entity
3
+ module Repository
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+
8
+ def find_one(id, options = {})
9
+ id = "#{node_type}##{id}" unless id.to_s.include?('#')
10
+ super id, options
11
+ end
12
+
13
+ def find_many(ids, options = {})
14
+ ids = ids.map do |id|
15
+ id.to_s.include?('#') ? id : "#{node_type}##{id}"
16
+ end
17
+
18
+ super ids, options
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Hari
2
+ class Node < Entity
3
+ module Serialization
4
+
5
+ def from_source(source)
6
+ return if source.blank?
7
+
8
+ hash = Yajl::Parser.parse(source)
9
+ klass = hash['id'].split('#').first.camelize.constantize
10
+
11
+ attrs = hash.inject({}) do |buffer, (key, value)|
12
+ if prop = klass.properties.find { |p| p.name == key }
13
+ buffer[key] = prop.desserialize(value)
14
+ end
15
+
16
+ buffer
17
+ end
18
+
19
+ klass.new attrs
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,72 @@
1
+ require 'hari/relation/linked_list'
2
+ require 'hari/relation/sorted_set'
3
+
4
+ module Hari
5
+ class Relation < Entity
6
+
7
+ DIRECTIONS = %w(in out)
8
+
9
+ attr_accessor :label, :start_node_id, :end_node_id
10
+
11
+ validates :label, :start_node_id, :end_node_id, presence: true
12
+
13
+ def start_node
14
+ @start_node ||= Hari::Node.find(start_node_id)
15
+ end
16
+
17
+ def end_node
18
+ @end_node ||= Hari::Node.find(end_node_id)
19
+ end
20
+
21
+ def key(direction = nil)
22
+ case direction.try :to_s
23
+ when nil then "#{start_node_id}:#{label}:#{end_node_id}"
24
+ when 'out' then "#{start_node_id}:#{label}:out"
25
+ when 'in' then "#{end_node_id}:#{label}:in"
26
+ end
27
+ end
28
+
29
+ alias :generate_id :key
30
+
31
+ def self.create(label, start_node, end_node, attrs = {})
32
+ new(attrs).tap do |r|
33
+ r.label = label
34
+ r.start_node_id = Hari.node_key(start_node)
35
+ r.end_node_id = Hari.node_key(end_node)
36
+ r.save
37
+ end
38
+ end
39
+
40
+ def self.use!(backend)
41
+ @backend = backend.kind_of?(Module) ? backend
42
+ : "Hari::Relation::#{backend.to_s.camelize}".constantize
43
+ end
44
+
45
+ def self.backend
46
+ @backend ||= Hari::Relation::SortedSet
47
+ end
48
+
49
+ def backend
50
+ self.class.backend
51
+ end
52
+
53
+ def weight(direction)
54
+ ::Time.now.to_f
55
+ end
56
+
57
+ private
58
+
59
+ def create
60
+ super
61
+ backend.create self
62
+ self
63
+ end
64
+
65
+ def delete
66
+ backend.delete self
67
+ super
68
+ self
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,16 @@
1
+ module Hari
2
+ class Relation < Entity
3
+ module LinkedList
4
+ extend self
5
+
6
+ def create(rel)
7
+ Relation::DIRECTIONS.each { |d| Hari.redis.lpush rel.key(d), rel.id }
8
+ end
9
+
10
+ def delete(rel)
11
+ Relation::DIRECTIONS.each { |d| Hari.redis.lrem rel.key(d), 1, rel.id }
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Hari
2
+ class Relation < Entity
3
+ module SortedSet
4
+ extend self
5
+
6
+ def create(rel)
7
+ Relation::DIRECTIONS.each { |d| Hari.redis.zadd rel.key(d), rel.weight(d), rel.id }
8
+ end
9
+
10
+ def delete(rel)
11
+ Relation::DIRECTIONS.each { |d| Hari.redis.zrem rel.key(d), rel.id }
12
+ end
13
+
14
+ end
15
+ end
16
+ end
data/lib/hari/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hari
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.3'
3
3
  end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Configuration do
4
+
5
+ end
@@ -3,19 +3,19 @@ require 'spec_helper'
3
3
  describe Hari::Entity::Repository do
4
4
 
5
5
  specify '.create, .find' do
6
- model = TestModel.create(name: 'Ze', birth: '2012-04-20', points: '300')
6
+ model = TestEntity.create(name: 'Ze', birth: '2012-04-20', points: '300')
7
7
  model.id.should be
8
8
 
9
- found = TestModel.find(model.id)
9
+ found = TestEntity.find(model.id)
10
10
  found.birth.year.should == 2012
11
11
  found.birth.month.should == 4
12
12
  found.birth.day.should == 20
13
13
  found.points.should == 300
14
14
  found.name.should == 'Ze'
15
15
 
16
- model2 = TestModel.create(name: 'Jo', birth: '2009-03-21', points: '404')
16
+ model2 = TestEntity.create(name: 'Jo', birth: '2009-03-21', points: '404')
17
17
 
18
- founds = TestModel.find(model.id, model2.id)
18
+ founds = TestEntity.find(model.id, model2.id)
19
19
  founds.size.should == 2
20
20
  end
21
21
 
@@ -4,7 +4,7 @@ describe Hari::Entity::Serialization do
4
4
 
5
5
  describe '#to_json' do
6
6
  it 'serializes instance to json' do
7
- model = TestModel.new(name: 'Ze',
7
+ model = TestEntity.new(name: 'Ze',
8
8
  birth: Date.new(1986, 01, 23),
9
9
  points: '200')
10
10
 
@@ -14,7 +14,7 @@ describe Hari::Entity::Serialization do
14
14
 
15
15
  describe '.from_json' do
16
16
  it 'desserializes instance from json' do
17
- model = TestModel.from_json('{"name":"Ze","birth":"1986-01-23","points":200}')
17
+ model = TestEntity.from_json('{"name":"Ze","birth":"1986-01-23","points":200}')
18
18
  model.name.should == 'Ze'
19
19
  model.birth.should == Date.new(1986, 01, 23)
20
20
  model.points.should == 200
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Node::Queries::List do
4
+
5
+ let(:node) { Hari.node user: 10 }
6
+ subject { node.list :friends }
7
+
8
+ before { subject.add 10, 20, 30, 40, 50, 60 }
9
+
10
+ specify '#name' do
11
+ subject.name.should eq(:friends)
12
+ end
13
+
14
+ specify '#range + #members + #list! + ' +
15
+ '#[i] + #[i, j], + #[i..j] + ' +
16
+ '#at + #index + #from + #to' do
17
+ node.list!(:friends).should eq %w(10 20 30 40 50 60)
18
+ subject.members.should eq %w(10 20 30 40 50 60)
19
+ subject.range.should eq %w(10 20 30 40 50 60)
20
+
21
+ subject.range(1, 3).should eq %w(20 30 40)
22
+ subject[1, 3].should eq %w(20 30 40)
23
+ subject[1..3].should eq %w(20 30 40)
24
+ subject[1].should eq('20')
25
+
26
+ subject.at(1).should eq('20')
27
+ subject.index(1).should eq('20')
28
+ subject.from(2).should eq %w(30 40 50 60)
29
+ subject.to(3).should eq %w(10 20 30 40)
30
+ end
31
+
32
+ specify '#include? + #member?' do
33
+ subject.include?('20').should be_true
34
+ subject.member?('20').should be_true
35
+ subject.include?('70').should be_false
36
+ end
37
+
38
+ specify '#count + #size + #length' do
39
+ subject.count.should eq(6)
40
+ subject.size.should eq(6)
41
+ subject.length.should eq(6)
42
+ end
43
+
44
+ specify '#one? + #many?' do
45
+ subject.should_not be_one
46
+ subject.should be_many
47
+
48
+ list = node.list(:enemies)
49
+ list.add 90
50
+ list.should be_one
51
+ list.should_not be_many
52
+ end
53
+
54
+ specify '#empty?' do
55
+ subject.should_not be_empty
56
+ node.list(:wtfs).should be_empty
57
+ end
58
+
59
+ specify '#delete' do
60
+ subject.delete 30
61
+ subject.members.should eq %w(10 20 40 50 60)
62
+ end
63
+
64
+ specify '#<<' do
65
+ subject << 90
66
+ subject.include?('90').should be_true
67
+ subject.pop.should eq('90')
68
+ end
69
+
70
+ specify '#pop + #rpop + #shift + #lpop' do
71
+ subject.pop.should eq('60')
72
+ subject.count.should eq(5)
73
+ subject.include?('60').should be_false
74
+
75
+ subject.rpop.should eq('50')
76
+ subject.count.should eq(4)
77
+ subject.include?('50').should be_false
78
+
79
+ subject.lpop.should eq('10')
80
+ subject.count.should eq(3)
81
+ subject.include?('10').should be_false
82
+
83
+ subject.shift.should eq('20')
84
+ subject.count.should eq(2)
85
+ subject.include?('20').should be_false
86
+ end
87
+
88
+ specify '#<< + #push + #rpush + #add + #lpush + #first + #last' do
89
+ subject << 80
90
+ subject.last.should eq('80')
91
+
92
+ subject.push 90
93
+ subject.last.should eq('90')
94
+
95
+ subject.rpush 100
96
+ subject.last.should eq('100')
97
+
98
+ subject.add 200
99
+ subject.last.should eq('200')
100
+
101
+ subject.lpush 300
102
+ subject.first.should eq('300')
103
+ end
104
+
105
+ specify '#[]=' do
106
+ subject[1] = 77
107
+ subject.members.should eq %w(10 77 30 40 50 60)
108
+ end
109
+
110
+ specify '#trim' do
111
+ subject.trim 2, 4
112
+ subject.members.should eq %w(30 40 50)
113
+ end
114
+
115
+ specify '#insert + #insert_before + #insert_after' do
116
+ subject.insert '20', '55'
117
+ subject.members.should eq %w(10 20 55 30 40 50 60)
118
+
119
+ subject.insert_after '40', '66'
120
+ subject.members.should eq %w(10 20 55 30 40 66 50 60)
121
+
122
+ subject.insert_before '66', '99'
123
+ subject.members.should eq %w(10 20 55 30 40 99 66 50 60)
124
+ end
125
+
126
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Node::Queries::Set do
4
+
5
+ let(:node) { Hari.node user: 10 }
6
+ subject { node.set :friends }
7
+
8
+ before { subject.add 10, 20, 30 }
9
+
10
+ specify '#name' do
11
+ subject.name.should eq(:friends)
12
+ end
13
+
14
+ specify '#members + #set!' do
15
+ node.set!(:friends).should eq %w(10 20 30)
16
+ subject.members.should eq %w(10 20 30)
17
+ end
18
+
19
+ specify '#include? + #member?' do
20
+ subject.include?(20).should be_true
21
+ subject.member?(20).should be_true
22
+ subject.include?(40).should be_false
23
+ end
24
+
25
+ specify '#count + #size + #length' do
26
+ subject.count.should eq(3)
27
+ subject.size.should eq(3)
28
+ subject.length.should eq(3)
29
+ end
30
+
31
+ specify '#one? + #many?' do
32
+ subject.should_not be_one
33
+ subject.should be_many
34
+
35
+ set = node.set(:enemies)
36
+ set.add 90
37
+ set.should be_one
38
+ set.should_not be_many
39
+ end
40
+
41
+ specify '#empty?' do
42
+ subject.should_not be_empty
43
+ node.set(:wtfs).should be_empty
44
+ end
45
+
46
+ specify '#delete' do
47
+ subject.delete 30, 40
48
+ subject.members.should eq %w(10 20)
49
+ end
50
+
51
+ specify '#<<' do
52
+ subject << 40
53
+ subject.include?(40).should be_true
54
+ end
55
+
56
+ specify '#rand' do
57
+ %w(10 20 30).include?(subject.rand.first).should be_true
58
+ subject.rand(3).sort.should eq %w(10 20 30)
59
+ subject.count.should eq(3)
60
+ end
61
+
62
+ specify '#intersect + #&' do
63
+ other_friends = Hari.node(user: 20).set(:friends)
64
+ other_friends.add 20, 30, 40, 50
65
+
66
+ (subject & other_friends).sort.should eq %w(20 30)
67
+ subject.intersect(other_friends).sort.should eq %w(20 30)
68
+ end
69
+
70
+ specify '#diff + #-' do
71
+ other_friends = Hari.node(user: 20).set(:friends)
72
+ other_friends.add 20, 30, 40, 50
73
+
74
+ (subject - other_friends).sort.should eq %w(10)
75
+ subject.diff(other_friends).sort.should eq %w(10)
76
+ end
77
+
78
+ specify '#pop' do
79
+ member = subject.pop
80
+ %w(10 20 30).include?(member).should be_true
81
+ subject.count.should eq(2)
82
+ subject.members.include?(member).should be_false
83
+ end
84
+
85
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Node::Queries::SortedSet do
4
+
5
+ let(:node) { Hari.node user: 10 }
6
+ subject { node.sorted_set :friends }
7
+
8
+ before { subject.add 10, 'john', 30, 'bill', 50, 'jack' }
9
+
10
+ specify '#name' do
11
+ subject.name.should eq(:friends)
12
+ end
13
+
14
+ specify '#range + #range_with_scores + #members + #sorted_set!' do
15
+ node.sorted_set!(:friends).should eq %w(john bill jack)
16
+ subject.members.should eq %w(john bill jack)
17
+ subject.range.should eq %w(john bill jack)
18
+
19
+ subject.range(0, 1).should eq %w(john bill)
20
+
21
+ subject.range_with_scores.should eq [['john', 10.0], ['bill', 30.0], ['jack', 50.0]]
22
+ subject.range(0, 1, with_scores: true).should eq [['john', 10.0], ['bill', 30.0]]
23
+
24
+ subject.revrange(0, 1).should eq %w(jack bill)
25
+ subject.revrange.should eq %w(jack bill john)
26
+ subject.reverse_range.should eq %w(jack bill john)
27
+ subject.desc_range.should eq %w(jack bill john)
28
+
29
+ subject.revrange_with_scores.should eq [['jack', 50.0], ['bill', 30.0], ['john', 10.0]]
30
+ end
31
+
32
+ specify '#include? + #member?' do
33
+ subject.include?('jack').should be_true
34
+ subject.member?('bill').should be_true
35
+ subject.include?('steve').should be_false
36
+ end
37
+
38
+ specify '#count + #size + #length' do
39
+ subject.count.should eq(3)
40
+ subject.size.should eq(3)
41
+ subject.length.should eq(3)
42
+ end
43
+
44
+ specify '#one? + #many?' do
45
+ subject.should_not be_one
46
+ subject.should be_many
47
+
48
+ zset = node.sorted_set(:enemies)
49
+ zset.add 70, 'jill'
50
+ zset.should be_one
51
+ zset.should_not be_many
52
+ end
53
+
54
+ specify '#empty?' do
55
+ subject.should_not be_empty
56
+ node.sorted_set(:wtfs).should be_empty
57
+ end
58
+
59
+ specify '#delete' do
60
+ subject.delete 'jack', 'bill', 'jill'
61
+ subject.members.should eq %w(john)
62
+ end
63
+
64
+ specify '#score' do
65
+ subject.score('john').should eq(10.0)
66
+ subject.score('steve').should_not be
67
+ end
68
+
69
+ specify '#rank + #revrank' do
70
+ subject.rank('john').should eq(0)
71
+ subject.ranking('bill').should eq(1)
72
+ subject.position('jack').should eq(2)
73
+
74
+ subject.revrank('john').should eq(2)
75
+ subject.reverse_ranking('bill').should eq(1)
76
+ subject.reverse_position('jack').should eq(0)
77
+ end
78
+
79
+ specify '#trim_by_rank' do
80
+ subject.trim_by_rank 1, 1
81
+ subject.members.should eq %w(john jack)
82
+ end
83
+
84
+ specify '#trim_by_score' do
85
+ subject.trim_by_score 5, 15
86
+ subject.members.should eq %w(bill jack)
87
+ end
88
+
89
+ end