hari 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/hari.gemspec +10 -2
- data/lib/hari.rb +8 -4
- data/lib/hari/configuration/redis.rb +6 -2
- data/lib/hari/entity.rb +10 -20
- data/lib/hari/entity/property.rb +19 -4
- data/lib/hari/entity/property/builder.rb +18 -3
- data/lib/hari/entity/repository.rb +11 -3
- data/lib/hari/entity/serialization.rb +53 -9
- data/lib/hari/entity/serialization/array.rb +21 -0
- data/lib/hari/entity/serialization/hash.rb +31 -0
- data/lib/hari/keys.rb +5 -0
- data/lib/hari/keys/hash.rb +67 -0
- data/lib/hari/keys/key.rb +24 -3
- data/lib/hari/keys/list.rb +10 -8
- data/lib/hari/keys/set.rb +8 -8
- data/lib/hari/keys/sorted_set.rb +20 -8
- data/lib/hari/node.rb +19 -2
- data/lib/hari/node/index.rb +152 -0
- data/lib/hari/node/queries.rb +32 -17
- data/lib/hari/node/queries/relation.rb +14 -1
- data/lib/hari/node/queries/relation/backend/sorted_set.rb +41 -90
- data/lib/hari/node/queries/relation/backend/sorted_set/count_step.rb +16 -0
- data/lib/hari/node/queries/relation/backend/sorted_set/node_step.rb +91 -0
- data/lib/hari/node/queries/type.rb +69 -4
- data/lib/hari/node/repository.rb +36 -0
- data/lib/hari/node/serialization.rb +11 -10
- data/lib/hari/object.rb +6 -0
- data/lib/hari/serialization.rb +3 -0
- data/lib/hari/version.rb +1 -1
- data/spec/hari/entity/repository_spec.rb +17 -0
- data/spec/hari/entity/serialization/hash_spec.rb +16 -0
- data/spec/hari/entity/serialization_spec.rb +14 -4
- data/spec/hari/keys/hash_spec.rb +55 -0
- data/spec/hari/keys/lists_spec.rb +27 -0
- data/spec/hari/node/index_spec.rb +199 -0
- data/spec/hari/node_spec.rb +84 -0
- data/spec/hari/serialization_spec.rb +41 -0
- data/spec/spec_helper.rb +6 -2
- metadata +27 -4
data/lib/hari/keys/key.rb
CHANGED
@@ -2,10 +2,10 @@ module Hari
|
|
2
2
|
module Keys
|
3
3
|
class Key
|
4
4
|
|
5
|
-
attr_reader :node, :name
|
5
|
+
attr_reader :node, :name, :options
|
6
6
|
|
7
|
-
def initialize(node = nil)
|
8
|
-
@node = node
|
7
|
+
def initialize(node = nil, options = {})
|
8
|
+
@node, @options = node, options
|
9
9
|
end
|
10
10
|
|
11
11
|
def key
|
@@ -43,6 +43,27 @@ module Hari
|
|
43
43
|
Hari.redis.ttl key
|
44
44
|
end
|
45
45
|
|
46
|
+
def serialize(value)
|
47
|
+
type = options[:type]
|
48
|
+
|
49
|
+
if type.nil? || value.nil?
|
50
|
+
value
|
51
|
+
else
|
52
|
+
value.kind_of?(Enumerable) ? value.map(&:to_json) : value.to_json
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def desserialize(value)
|
57
|
+
type = options[:type]
|
58
|
+
|
59
|
+
if type.nil? || value.nil?
|
60
|
+
value
|
61
|
+
else
|
62
|
+
value.kind_of?(Enumerable) ? value.map { |v| type.from_json(v) }
|
63
|
+
: type.from_json(value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
46
67
|
end
|
47
68
|
end
|
48
69
|
end
|
data/lib/hari/keys/list.rb
CHANGED
@@ -33,11 +33,11 @@ module Hari
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def []=(index, member)
|
36
|
-
Hari.redis.lset key, index, member
|
36
|
+
Hari.redis.lset key, index, serialize(member)
|
37
37
|
end
|
38
38
|
|
39
39
|
def range(start = 0, stop = -1)
|
40
|
-
Hari.redis.lrange
|
40
|
+
desserialize Hari.redis.lrange(key, start, stop)
|
41
41
|
end
|
42
42
|
|
43
43
|
alias :members :range
|
@@ -52,7 +52,7 @@ module Hari
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def at(index)
|
55
|
-
Hari.redis.lindex
|
55
|
+
desserialize Hari.redis.lindex(key, index)
|
56
56
|
end
|
57
57
|
|
58
58
|
alias :index :at
|
@@ -81,20 +81,22 @@ module Hari
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def include?(member)
|
84
|
-
range.include? member
|
84
|
+
range.include? serialize(member)
|
85
85
|
end
|
86
86
|
|
87
87
|
alias :member? :include?
|
88
88
|
|
89
89
|
def push(*members)
|
90
|
-
|
90
|
+
return if Array(members).empty?
|
91
|
+
|
92
|
+
Hari.redis.rpush key, serialize(members)
|
91
93
|
end
|
92
94
|
|
93
95
|
alias :rpush :push
|
94
96
|
alias :add :push
|
95
97
|
|
96
98
|
def lpush(*members)
|
97
|
-
Hari.redis.lpush key, members
|
99
|
+
Hari.redis.lpush key, serialize(members)
|
98
100
|
end
|
99
101
|
|
100
102
|
def <<(member)
|
@@ -116,13 +118,13 @@ module Hari
|
|
116
118
|
end
|
117
119
|
|
118
120
|
def pop
|
119
|
-
Hari.redis.rpop
|
121
|
+
desserialize Hari.redis.rpop(key)
|
120
122
|
end
|
121
123
|
|
122
124
|
alias :rpop :pop
|
123
125
|
|
124
126
|
def shift
|
125
|
-
Hari.redis.lpop
|
127
|
+
desserialize Hari.redis.lpop(key)
|
126
128
|
end
|
127
129
|
|
128
130
|
alias :lpop :shift
|
data/lib/hari/keys/set.rb
CHANGED
@@ -13,11 +13,11 @@ module Hari
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def members
|
16
|
-
Hari.redis.smembers
|
16
|
+
desserialize Hari.redis.smembers(key)
|
17
17
|
end
|
18
18
|
|
19
19
|
def rand(count = 1)
|
20
|
-
Hari.redis.srandmember
|
20
|
+
desserialize Hari.redis.srandmember(key, count)
|
21
21
|
end
|
22
22
|
|
23
23
|
def count
|
@@ -40,13 +40,13 @@ module Hari
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def include?(member)
|
43
|
-
Hari.redis.sismember key, member
|
43
|
+
Hari.redis.sismember key, serialize(member)
|
44
44
|
end
|
45
45
|
|
46
46
|
alias :member? :include?
|
47
47
|
|
48
48
|
def add(*members)
|
49
|
-
Hari.redis.sadd key, members
|
49
|
+
Hari.redis.sadd key, serialize(members)
|
50
50
|
end
|
51
51
|
|
52
52
|
def <<(member)
|
@@ -54,15 +54,15 @@ module Hari
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def delete(*members)
|
57
|
-
Hari.redis.srem key, members
|
57
|
+
Hari.redis.srem key, serialize(members)
|
58
58
|
end
|
59
59
|
|
60
60
|
def pop
|
61
|
-
Hari.redis.spop
|
61
|
+
desserialize Hari.redis.spop(key)
|
62
62
|
end
|
63
63
|
|
64
64
|
def intersect(*set_queries)
|
65
|
-
Hari.redis.sinter
|
65
|
+
desserialize Hari.redis.sinter(key, set_query_keys(set_queries))
|
66
66
|
end
|
67
67
|
|
68
68
|
def &(other_set_query)
|
@@ -70,7 +70,7 @@ module Hari
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def diff(*set_queries)
|
73
|
-
Hari.redis.sdiff
|
73
|
+
desserialize Hari.redis.sdiff(key, set_query_keys(set_queries))
|
74
74
|
end
|
75
75
|
|
76
76
|
def -(other_set_query)
|
data/lib/hari/keys/sorted_set.rb
CHANGED
@@ -15,7 +15,10 @@ module Hari
|
|
15
15
|
def range(start = 0, stop = -1, options = {})
|
16
16
|
return revrange(start, stop, options) if options[:desc]
|
17
17
|
|
18
|
-
Hari.redis.zrange key, start, stop,
|
18
|
+
result = Hari.redis.zrange key, start, stop,
|
19
|
+
options.slice(:with_scores)
|
20
|
+
|
21
|
+
desserialize result
|
19
22
|
end
|
20
23
|
|
21
24
|
alias :members :range
|
@@ -25,7 +28,10 @@ module Hari
|
|
25
28
|
end
|
26
29
|
|
27
30
|
def revrange(start = 0, stop = -1, options = {})
|
28
|
-
Hari.redis.zrevrange key, start, stop,
|
31
|
+
result = Hari.redis.zrevrange key, start, stop,
|
32
|
+
options.slice(:with_scores)
|
33
|
+
|
34
|
+
desserialize result
|
29
35
|
end
|
30
36
|
|
31
37
|
alias :reverse_range :revrange
|
@@ -38,11 +44,17 @@ module Hari
|
|
38
44
|
def range_by_score(min, max, options = {})
|
39
45
|
return revrange_by_score(min, max, options) if options[:desc]
|
40
46
|
|
41
|
-
Hari.redis.zrangebyscore key, min, max,
|
47
|
+
result = Hari.redis.zrangebyscore key, min, max,
|
48
|
+
options.slice(:with_scores, :limit)
|
49
|
+
|
50
|
+
desserialize result
|
42
51
|
end
|
43
52
|
|
44
53
|
def revrange_by_score(min, max, options = {})
|
45
|
-
Hari.redis.zrevrangebyscore key, max, min,
|
54
|
+
result = Hari.redis.zrevrangebyscore key, max, min,
|
55
|
+
options.slice(:with_scores, :limit)
|
56
|
+
|
57
|
+
desserialize result
|
46
58
|
end
|
47
59
|
|
48
60
|
def rank(member, options = {})
|
@@ -55,7 +67,7 @@ module Hari
|
|
55
67
|
alias :position :rank
|
56
68
|
|
57
69
|
def revrank(member)
|
58
|
-
Hari.redis.zrevrank key, member
|
70
|
+
Hari.redis.zrevrank key, serialize(member)
|
59
71
|
end
|
60
72
|
|
61
73
|
alias :reverse_ranking :revrank
|
@@ -87,11 +99,11 @@ module Hari
|
|
87
99
|
alias :member? :include?
|
88
100
|
|
89
101
|
def score(member)
|
90
|
-
Hari.redis.zscore key, member
|
102
|
+
Hari.redis.zscore key, serialize(member)
|
91
103
|
end
|
92
104
|
|
93
105
|
def add(*score_members)
|
94
|
-
Hari.redis.zadd key, score_members.to_a.flatten
|
106
|
+
Hari.redis.zadd key, serialize(score_members.to_a.flatten)
|
95
107
|
end
|
96
108
|
|
97
109
|
def <<(*score_members)
|
@@ -99,7 +111,7 @@ module Hari
|
|
99
111
|
end
|
100
112
|
|
101
113
|
def delete(*members)
|
102
|
-
Hari.redis.zrem key, members
|
114
|
+
Hari.redis.zrem key, serialize(members)
|
103
115
|
end
|
104
116
|
|
105
117
|
def trim_by_rank(start, stop)
|
data/lib/hari/node.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'hari/node/repository'
|
2
2
|
require 'hari/node/queries'
|
3
3
|
require 'hari/node/serialization'
|
4
|
+
require 'hari/node/index'
|
4
5
|
|
5
6
|
module Hari
|
6
7
|
class Node < Entity
|
@@ -15,10 +16,22 @@ module Hari
|
|
15
16
|
super
|
16
17
|
end
|
17
18
|
|
19
|
+
after_update { reindex }
|
20
|
+
after_create { reindex force_index: true }
|
21
|
+
after_destroy { remove_from_indexes }
|
22
|
+
|
18
23
|
def generate_id
|
19
|
-
|
24
|
+
unless model_id.present?
|
25
|
+
begin
|
26
|
+
self.model_id = SecureRandom.hex(8)
|
27
|
+
end until !Hari.redis.exists(node_key)
|
28
|
+
end
|
29
|
+
|
30
|
+
node_key
|
31
|
+
end
|
20
32
|
|
21
|
-
|
33
|
+
def node_key
|
34
|
+
"#{node_type}##{model_id}"
|
22
35
|
end
|
23
36
|
|
24
37
|
def node_type
|
@@ -29,5 +42,9 @@ module Hari
|
|
29
42
|
self.to_s.underscore
|
30
43
|
end
|
31
44
|
|
45
|
+
def self.indexed_properties
|
46
|
+
properties.select { |p| p.options[:index] }
|
47
|
+
end
|
48
|
+
|
32
49
|
end
|
33
50
|
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Hari
|
2
|
+
class Node
|
3
|
+
class Index
|
4
|
+
|
5
|
+
attr_accessor :property, :value, :indexes, :options
|
6
|
+
|
7
|
+
attr_writer :start, :stop
|
8
|
+
|
9
|
+
def initialize(property, value)
|
10
|
+
@property, @value = property, value
|
11
|
+
@indexes, @options = [], {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(node)
|
15
|
+
Hari.redis.zadd key, Time.now.to_f, node.model_id
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete(node)
|
19
|
+
Hari.redis.zrem key, node.model_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def append(index)
|
23
|
+
self.indexes << index
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def start
|
29
|
+
@start ||= 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop
|
33
|
+
@stop ||= -1
|
34
|
+
end
|
35
|
+
|
36
|
+
def limit(page = nil, per_page = nil)
|
37
|
+
if page.present? && per_page.present?
|
38
|
+
self.start = page * per_page
|
39
|
+
self.stop = start + per_page - 1
|
40
|
+
end
|
41
|
+
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def from(score, direction = nil)
|
46
|
+
direction ||= :up
|
47
|
+
options[:from] = { score: score.to_f, direction: direction.to_s }
|
48
|
+
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def count
|
53
|
+
return count_intersect unless indexes.empty?
|
54
|
+
|
55
|
+
from = options[:from]
|
56
|
+
limit = stop == -1 ? stop : stop - start + 1
|
57
|
+
|
58
|
+
if from.present? && from[:direction] == 'up'
|
59
|
+
Hari.redis.zrevrangebyscore(key, '+inf', from[:score]).size
|
60
|
+
elsif from.present? && from[:direction] == 'down'
|
61
|
+
Hari.redis.zrevrangebyscore(key, from[:score], '-inf').size
|
62
|
+
else
|
63
|
+
Hari.redis.zcard key
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def count_intersect
|
68
|
+
intersect
|
69
|
+
|
70
|
+
from = options[:from]
|
71
|
+
limit = stop == -1 ? stop : stop - start + 1
|
72
|
+
|
73
|
+
count = if from.present? && from[:direction] == 'up'
|
74
|
+
Hari.redis.zrevrangebyscore(intersect_key, '+inf', from[:score]).size
|
75
|
+
elsif from.present? && from[:direction] == 'down'
|
76
|
+
Hari.redis.zrevrangebyscore(intersect_key, from[:score], '-inf').size
|
77
|
+
else
|
78
|
+
Hari.redis.zcard intersect_key
|
79
|
+
end
|
80
|
+
|
81
|
+
Hari.redis.del intersect_key
|
82
|
+
|
83
|
+
count
|
84
|
+
end
|
85
|
+
|
86
|
+
def list
|
87
|
+
return list_intersect unless indexes.empty?
|
88
|
+
|
89
|
+
from = options[:from]
|
90
|
+
limit = stop == -1 ? stop : stop - start + 1
|
91
|
+
|
92
|
+
ids = if from.present? && from[:direction] == 'up'
|
93
|
+
Hari.redis.zrevrangebyscore key, '+inf', from[:score], limit: [start, limit]
|
94
|
+
elsif from.present? && from[:direction] == 'down'
|
95
|
+
Hari.redis.zrevrangebyscore key, from[:score], '-inf', limit: [start, limit]
|
96
|
+
else
|
97
|
+
Hari.redis.zrevrange key, start, stop
|
98
|
+
end
|
99
|
+
|
100
|
+
property.entity.find_many ids
|
101
|
+
end
|
102
|
+
|
103
|
+
def list_intersect
|
104
|
+
intersect
|
105
|
+
|
106
|
+
from = options[:from]
|
107
|
+
limit = stop == -1 ? stop : stop - start + 1
|
108
|
+
|
109
|
+
ids = if from.present? && from[:direction] == 'up'
|
110
|
+
Hari.redis.zrevrangebyscore intersect_key, '+inf', from[:score], limit: [start, limit]
|
111
|
+
elsif from.present? && from[:direction] == 'down'
|
112
|
+
Hari.redis.zrevrangebyscore intersect_key, from[:score], '-inf', limit: [start, limit]
|
113
|
+
else
|
114
|
+
Hari.redis.zrevrange intersect_key, start, stop
|
115
|
+
end
|
116
|
+
|
117
|
+
Hari.redis.del intersect_key
|
118
|
+
|
119
|
+
property.entity.find_many ids
|
120
|
+
end
|
121
|
+
|
122
|
+
alias :to_a :list
|
123
|
+
alias :result :list
|
124
|
+
|
125
|
+
def key
|
126
|
+
"#{property.entity.node_type}|#{property.name}:#{digest(value)}"
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def digest(value)
|
132
|
+
case value = value.to_s.strip
|
133
|
+
when ''
|
134
|
+
'_NULL_'
|
135
|
+
when /^[[:alnum:]]+$/
|
136
|
+
value
|
137
|
+
else
|
138
|
+
Digest::MD5.hexdigest value
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def intersect
|
143
|
+
Hari.redis.zinterstore intersect_key, [key] + indexes.map(&:key), aggregate: 'max'
|
144
|
+
end
|
145
|
+
|
146
|
+
def intersect_key
|
147
|
+
"inter:#{key}:#{indexes.map(&:key).join(':')}"
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/lib/hari/node/queries.rb
CHANGED
@@ -1,34 +1,49 @@
|
|
1
|
+
require 'hari/node/queries/relation'
|
2
|
+
require 'hari/node/queries/type'
|
3
|
+
|
1
4
|
module Hari
|
2
5
|
class Node < Entity
|
3
6
|
module Queries
|
4
|
-
|
5
|
-
autoload :Type, 'hari/node/queries/type'
|
7
|
+
extend ActiveSupport::Concern
|
6
8
|
|
7
9
|
delegate :in, :out, to: :relation_query
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
delegate :list, :list!, to: :list_query
|
12
|
-
delegate :string, :string!, to: :string_query
|
11
|
+
Keys::TYPES.each do |key|
|
12
|
+
query_builder = Keys.const_get(key.camelize)
|
13
13
|
|
14
|
-
|
14
|
+
define_method key do |name = nil, options = {}|
|
15
|
+
return super() unless name
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
query = query_builder.new(query_node, options)
|
18
|
+
query.send key, name
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
define_method "#{key}!" do |name, options = {}|
|
22
|
+
query = query_builder.new(query_node, options)
|
23
|
+
query.send "#{key}!", name
|
24
|
+
end
|
22
25
|
end
|
23
26
|
|
24
|
-
|
25
|
-
Keys::
|
26
|
-
|
27
|
+
included do
|
28
|
+
Keys::TYPES.each do |key|
|
29
|
+
define_singleton_method key do |name = nil, options = {}|
|
30
|
+
return super() unless name
|
27
31
|
|
28
|
-
|
29
|
-
|
32
|
+
define_method(name) { send key, name, options }
|
33
|
+
define_method("#{name}!") { send "#{key}!", name, options }
|
34
|
+
|
35
|
+
define_method "#{name}=" do |value|
|
36
|
+
data = send(name)
|
37
|
+
data.delete!
|
38
|
+
|
39
|
+
data.add *value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
30
43
|
end
|
31
44
|
|
45
|
+
private
|
46
|
+
|
32
47
|
def relation_query
|
33
48
|
Queries::Relation::Start.new query_node
|
34
49
|
end
|