hari 0.0.1 → 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.
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