redis_model 0.1.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +187 -0
- data/Rakefile +15 -0
- data/lib/redis_model/adapters/paperclip.rb +51 -0
- data/lib/redis_model/attribute.rb +124 -0
- data/lib/redis_model/base.rb +67 -0
- data/lib/redis_model/belonged_to.rb +27 -0
- data/lib/redis_model/class_attribute.rb +50 -0
- data/lib/redis_model/configurations.rb +15 -0
- data/lib/redis_model/helpers/sorted_set_paginator.rb +80 -0
- data/lib/redis_model/intersected.rb +17 -0
- data/lib/redis_model/schema.rb +114 -0
- data/lib/redis_model/types/base.rb +32 -0
- data/lib/redis_model/types/base_value.rb +26 -0
- data/lib/redis_model/types/counter.rb +25 -0
- data/lib/redis_model/types/float.rb +17 -0
- data/lib/redis_model/types/hash.rb +53 -0
- data/lib/redis_model/types/integer.rb +17 -0
- data/lib/redis_model/types/list.rb +40 -0
- data/lib/redis_model/types/set.rb +59 -0
- data/lib/redis_model/types/sorted_set.rb +184 -0
- data/lib/redis_model/types/string.rb +11 -0
- data/lib/redis_model/types/timestamp.rb +26 -0
- data/lib/redis_model/version.rb +3 -0
- data/lib/redis_model.rb +37 -0
- data/redis_model.gemspec +28 -0
- data/spec/redis_model/attribute_spec.rb +77 -0
- data/spec/redis_model/base_spec.rb +34 -0
- data/spec/redis_model/class_attribute_spec.rb +16 -0
- data/spec/redis_model/helpers/sorted_set_paginator_spec.rb +33 -0
- data/spec/redis_model/schema_spec.rb +118 -0
- data/spec/redis_model/types/base_spec.rb +28 -0
- data/spec/redis_model/types/counter_spec.rb +32 -0
- data/spec/redis_model/types/float_spec.rb +20 -0
- data/spec/redis_model/types/hash_spec.rb +55 -0
- data/spec/redis_model/types/integer_spec.rb +22 -0
- data/spec/redis_model/types/list_spec.rb +55 -0
- data/spec/redis_model/types/set_spec.rb +62 -0
- data/spec/redis_model/types/sorted_set_spec.rb +303 -0
- data/spec/redis_model/types/string_spec.rb +28 -0
- data/spec/redis_model/types/timestamp_spec.rb +22 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/dynamic_class.rb +5 -0
- metadata +190 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
module RedisModel
|
2
|
+
# Public: Schema information for RedisModel::Base-derived classes. It
|
3
|
+
# contains information required to manipulate Redis data including data type
|
4
|
+
# and key label.
|
5
|
+
class Schema
|
6
|
+
attr_reader :klass, :data_type, :data_type_module
|
7
|
+
|
8
|
+
# Public: Data type label and their corresponding module responsible for
|
9
|
+
# specified type.
|
10
|
+
DATA_TYPES = {
|
11
|
+
value: RedisModel::Types::Counter,
|
12
|
+
counter: RedisModel::Types::Counter,
|
13
|
+
list: RedisModel::Types::List,
|
14
|
+
sorted_set: RedisModel::Types::SortedSet,
|
15
|
+
float: RedisModel::Types::Float,
|
16
|
+
set: RedisModel::Types::Set,
|
17
|
+
hash: RedisModel::Types::Hash,
|
18
|
+
string: RedisModel::Types::String,
|
19
|
+
timestamp: RedisModel::Types::Timestamp,
|
20
|
+
integer: RedisModel::Types::Integer
|
21
|
+
}
|
22
|
+
|
23
|
+
# Public: Exception class indicating some class tried to initiate data_type
|
24
|
+
# when one of its direct ancestors already have initiated.
|
25
|
+
class DuplicateDefinition < StandardError ; end
|
26
|
+
|
27
|
+
# Public: Exception raised when invalid data_type label is provided.
|
28
|
+
class UnknownType < StandardError ; end
|
29
|
+
|
30
|
+
# Public: Global index of RedisModel::Schema objects.
|
31
|
+
#
|
32
|
+
# Returns the Hash of global schema index.
|
33
|
+
def self.collection
|
34
|
+
@collection ||= {}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Public: Find schema information for specified class. It could be schema
|
38
|
+
# defined for one of ancestors of the class.
|
39
|
+
#
|
40
|
+
# klass - Class to find schema.
|
41
|
+
#
|
42
|
+
# Returns RedisModel::Schema object for given class, nil if it does not
|
43
|
+
# exist.
|
44
|
+
def self.find(klass)
|
45
|
+
collection[(klass.ancestors - klass.included_modules).detect do |parent_klass|
|
46
|
+
collection[parent_klass]
|
47
|
+
end]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Public: Register schema for specified class.
|
51
|
+
#
|
52
|
+
# klass - Class to register schema.
|
53
|
+
# options - Additional options for schema.
|
54
|
+
# :data_type - Data type of Redis value.
|
55
|
+
#
|
56
|
+
# Returns the Module corresponding to data type of the class.
|
57
|
+
def self.register(klass, options = {})
|
58
|
+
raise DuplicateDefinition.new if find(klass)
|
59
|
+
|
60
|
+
(collection[klass] = new(options.merge(klass: klass))).data_type_module
|
61
|
+
end
|
62
|
+
|
63
|
+
# Public: Initializes a Schema.
|
64
|
+
#
|
65
|
+
# options - Options for schema.
|
66
|
+
# :klass - Class being specified for the schema.
|
67
|
+
# :data_type - Data type of Redis value.
|
68
|
+
#
|
69
|
+
# Returns newly initialized Schema object.
|
70
|
+
def initialize(options = {})
|
71
|
+
raise UnknownType.new unless DATA_TYPES[options[:data_type]]
|
72
|
+
|
73
|
+
@klass = options[:klass]
|
74
|
+
@data_type = options[:data_type]
|
75
|
+
@data_type_module = DATA_TYPES[@data_type]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Public: Key label of Redis value associated with instance of classes
|
79
|
+
# inherit RedisModel::Base.
|
80
|
+
#
|
81
|
+
# object - Instance of RedisModel::Base-derived class.
|
82
|
+
#
|
83
|
+
# Returns String containing label for specified object.
|
84
|
+
def key_label(object)
|
85
|
+
[base_key_label, @custom_key_label_proc && @custom_key_label_proc.call(object)].compact.join(':')
|
86
|
+
end
|
87
|
+
|
88
|
+
# Public: Defines custom part of key label by passing a block having arity
|
89
|
+
# of 1 to this method.
|
90
|
+
#
|
91
|
+
# block - Block or proc that converts object into custom label string
|
92
|
+
#
|
93
|
+
# Examples:
|
94
|
+
#
|
95
|
+
# schema.custom_key_label do |object|
|
96
|
+
# object.id
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# Returns nothing.
|
100
|
+
def custom_key_label(&block)
|
101
|
+
@custom_key_label_proc = block
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
|
106
|
+
# Internal: Retrieves string used for label for Redis value associated with
|
107
|
+
# the schema. Base label can be
|
108
|
+
#
|
109
|
+
# Returns String containing base label.
|
110
|
+
def base_key_label
|
111
|
+
@key_label_base ||= [RedisModel::Configurations.instance.app_name, RedisModel::Configurations.instance.environment, @klass.name.underscore].compact.join(':')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Provides methods for Redis commands related to plain key
|
4
|
+
# operations and helpers.
|
5
|
+
module Base
|
6
|
+
# Public: Asserts existence of Redis key having the label using Redis
|
7
|
+
# command ExiSTS.
|
8
|
+
#
|
9
|
+
# Returns true if key exists, false otherwise.
|
10
|
+
def exists?
|
11
|
+
connection.exists(key_label)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Removes Redis value associated with the key using Redis command
|
15
|
+
# DEL.
|
16
|
+
#
|
17
|
+
# Returns 1 if key is deleted, 0 otherwise.
|
18
|
+
def del
|
19
|
+
connection.del(key_label)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :clear, :del
|
23
|
+
|
24
|
+
# Public: Helper method for global Redis connection.
|
25
|
+
#
|
26
|
+
# Returns global Redis connection object.
|
27
|
+
def connection
|
28
|
+
RedisModel::Base.connection
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Base methods for helper types based on basic key-value pairs.
|
4
|
+
module BaseValue
|
5
|
+
include RedisModel::Types::Base
|
6
|
+
|
7
|
+
# Public: Reads value of string stored in Redis using GET command.
|
8
|
+
#
|
9
|
+
# Returns String contained in Redis. nil if it does not exist.
|
10
|
+
def get
|
11
|
+
@cached_value ||= RedisModel::Base.connection.get(key_label)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Sets value of string stored in Redis using SEt command.
|
15
|
+
#
|
16
|
+
# value - Value to set.
|
17
|
+
#
|
18
|
+
# Returns String contained in Redis. nil if it does not exist.
|
19
|
+
def set(value, options = {})
|
20
|
+
@cached_value = nil
|
21
|
+
|
22
|
+
RedisModel::Base.connection.set(key_label, value, options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods needed for counter data type.
|
4
|
+
module Counter
|
5
|
+
include RedisModel::Types::BaseValue
|
6
|
+
|
7
|
+
# Public: Atomically increments counter value using Redis command INCR or
|
8
|
+
# INCRBY.
|
9
|
+
#
|
10
|
+
# by - Amount to increment by (default: 1).
|
11
|
+
#
|
12
|
+
# Returns Integer value of counter after increment.
|
13
|
+
def incr(by = nil)
|
14
|
+
by ? connection.incrby(key_label, by) : connection.incr(key_label)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Public: Retrieves Integer value of counter.
|
18
|
+
#
|
19
|
+
# Returns Integer value of counter.
|
20
|
+
def to_i
|
21
|
+
(get || 0).to_i
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods needed for Float data type.
|
4
|
+
module Float
|
5
|
+
include RedisModel::Types::BaseValue
|
6
|
+
|
7
|
+
# Public: Retrieves Float value stored in the key.
|
8
|
+
#
|
9
|
+
# Returns Float value stored in the key. nil if it does not exist.
|
10
|
+
def to_f
|
11
|
+
get && get.to_f
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :to_value, :to_f
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods for hash type of key in Redis.
|
4
|
+
module Hash
|
5
|
+
include Base
|
6
|
+
|
7
|
+
# Public: Sets a key in Hash using Redis HSET command.
|
8
|
+
#
|
9
|
+
# key - Key to set.
|
10
|
+
# value - Value to set.
|
11
|
+
#
|
12
|
+
# Returns new value.
|
13
|
+
def []=(key, value)
|
14
|
+
result = connection.hset(key_label, key.to_s, value)
|
15
|
+
|
16
|
+
@cached_hash = nil
|
17
|
+
|
18
|
+
value
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Retrieves a key in Hash using Redis HGET command.
|
22
|
+
#
|
23
|
+
# key - Key to retrieve.
|
24
|
+
#
|
25
|
+
# Returns retrieved value.
|
26
|
+
def [](key)
|
27
|
+
connection.hget(key_label, key.to_s)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: Increments a key in Hash using Redis HINCRBY command.
|
31
|
+
#
|
32
|
+
# key - Key to increment.
|
33
|
+
# by - Amount for increment (default: 1)
|
34
|
+
#
|
35
|
+
# Returns incremented value.
|
36
|
+
def incr(key, by = 1)
|
37
|
+
result = connection.hincrby(key_label, key, by)
|
38
|
+
|
39
|
+
@cached_hash = nil
|
40
|
+
|
41
|
+
result.to_i
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
@cached_hash ||= connection.hgetall(key_label)
|
46
|
+
end
|
47
|
+
|
48
|
+
def keys
|
49
|
+
connection.hkeys(key_label)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods needed for Integer type.
|
4
|
+
module Integer
|
5
|
+
include RedisModel::Types::BaseValue
|
6
|
+
|
7
|
+
# Public: Retrieves value stored in Redis key as Integer.
|
8
|
+
#
|
9
|
+
# Returns Integer value stored in Redis key, nil if it does not exist.
|
10
|
+
def to_i
|
11
|
+
get && get.to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :to_value, :to_i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods needed for List type.
|
4
|
+
module List
|
5
|
+
include RedisModel::Types::Base
|
6
|
+
|
7
|
+
# Public: Fetches elements in Redis list as Array using LRANGE command.
|
8
|
+
#
|
9
|
+
# Returns Array containing elements in the list.
|
10
|
+
def to_a
|
11
|
+
connection.lrange key_label, 0, -1
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Retrieves length of Redis list using LLEN command.
|
15
|
+
#
|
16
|
+
# Returns Integer containing length of the list.
|
17
|
+
def count
|
18
|
+
connection.llen key_label
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :length, :count
|
22
|
+
|
23
|
+
# Public: Retrieves a element in the list using LINDEX command.
|
24
|
+
#
|
25
|
+
# Returns String containing value of the specified element.
|
26
|
+
def [](index)
|
27
|
+
connection.lindex key_label, index
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: Pushes a element into the list using RPUSH command.
|
31
|
+
#
|
32
|
+
# Returns true.
|
33
|
+
def <<(value)
|
34
|
+
connection.rpush key_label, value
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :push, :<<
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods needed for Set type.
|
4
|
+
module Set
|
5
|
+
include RedisModel::Types::Base
|
6
|
+
|
7
|
+
# Public: Fetches elements in Redis set as Array using SMEMBERS command.
|
8
|
+
#
|
9
|
+
# Returns Array containing elements in the set.
|
10
|
+
def to_a
|
11
|
+
connection.smembers key_label
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Retrieves length of Redis set using SCARD command.
|
15
|
+
#
|
16
|
+
# Returns Integer containing cardinality of the set.
|
17
|
+
def count
|
18
|
+
connection.scard key_label
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :length, :count
|
22
|
+
|
23
|
+
# Public: Pushes a element into the set using SADD command.
|
24
|
+
#
|
25
|
+
# Returns true.
|
26
|
+
def <<(value)
|
27
|
+
connection.sadd key_label, value
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: Removes a element from the set using SREM command.
|
31
|
+
#
|
32
|
+
# Returns true.
|
33
|
+
def remove(value)
|
34
|
+
connection.srem key_label, value
|
35
|
+
end
|
36
|
+
|
37
|
+
# Public: Picks a member among elements in the set using SRANDMEMBER
|
38
|
+
# command.
|
39
|
+
#
|
40
|
+
# count - Number of elements to pick.
|
41
|
+
#
|
42
|
+
# Returns Array containing elements in the set randomly selected.
|
43
|
+
def pick(count)
|
44
|
+
RedisModel::Base.connection.pipelined do
|
45
|
+
count.times do
|
46
|
+
connection.srandmember(key_label)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Public: Asserts value is included in the set using SISMEMBER command.
|
52
|
+
#
|
53
|
+
# Returns true if value is included in the set, false otherwise.
|
54
|
+
def include?(value)
|
55
|
+
connection.sismember key_label, value.to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods needed for Sorted Set type. Note that it assumes
|
4
|
+
# elements are sorted in descending order of score as default because the
|
5
|
+
# module is implemented for leaderboard feature. Future releases will
|
6
|
+
# revert this decision and will use default order of Redis.
|
7
|
+
module SortedSet
|
8
|
+
include RedisModel::Types::Base
|
9
|
+
|
10
|
+
# Public: Fetches elements in the sorted set as Array.
|
11
|
+
#
|
12
|
+
# Returns Array containing elements in the set.
|
13
|
+
def to_a
|
14
|
+
get_range('-inf', '+inf', include_boundaries: true)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Public: Counts number of elements in (from, to) interval using ZCOUNT
|
18
|
+
# command.
|
19
|
+
#
|
20
|
+
# from - Beginning point of the interval.
|
21
|
+
# to - Ending point of the interval.
|
22
|
+
#
|
23
|
+
# Returns Integer containing number of elements in the interval.
|
24
|
+
def count_range(from, to)
|
25
|
+
connection.zcount(key_label, from, to)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Public: Asserts value is included in the set.
|
29
|
+
#
|
30
|
+
# Returns true if value is included in the set, false otherwise.
|
31
|
+
def include?(value)
|
32
|
+
!!connection.zrank(key_label, value)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public: Retrieves elements in [from, to] index interval. Elements are
|
36
|
+
# arranged in descending order of score. ZREVRANGE command is used.
|
37
|
+
#
|
38
|
+
# from - Beginning point of the index interval.
|
39
|
+
# to - Ending point of the index interval.
|
40
|
+
# options - Additional options for retrieval.
|
41
|
+
# :withscores - If it is set to true, returned array
|
42
|
+
# contains values and corresponding scores
|
43
|
+
# of elements.
|
44
|
+
#
|
45
|
+
# Returns Integer containing number of elements in the interval.
|
46
|
+
def get_range_by_rank(from, to, options = {})
|
47
|
+
connection.zrevrange(key_label, from, to, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Public: Retrieves elements in (from, to) index interval. Elements are
|
51
|
+
# arranged in ascending order of score. ZRANGE command is used.
|
52
|
+
#
|
53
|
+
# from - Beginning point of the index interval.
|
54
|
+
# to - Ending point of the index interval.
|
55
|
+
# options - Additional options for retrieval.
|
56
|
+
# :withscores - If it is set to true, returned array
|
57
|
+
# contains values and corresponding scores
|
58
|
+
# of elements.
|
59
|
+
#
|
60
|
+
# Returns Integer containing number of elements in the interval.
|
61
|
+
def get_range_by_reverse_rank(from, to, options = {})
|
62
|
+
connection.zrange(key_label, from, to, options)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Public: Retrieves index of element in the sorted set. Elements are
|
66
|
+
# arranged in descending order of score. ZREVRANK command is used.
|
67
|
+
#
|
68
|
+
# from - Beginning point of the index interval.
|
69
|
+
# to - Ending point of the index interval.
|
70
|
+
# options - Additional options for retrieval.
|
71
|
+
# :withscores - If it is set to true, returned array
|
72
|
+
# contains values and corresponding scores
|
73
|
+
# of elements.
|
74
|
+
#
|
75
|
+
# Returns Integer containing number of elements in the interval.
|
76
|
+
def get_rank(key)
|
77
|
+
connection.zrevrank(key_label, key)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Public: Retrieves score of element having specified value using ZSCORE
|
81
|
+
# command.
|
82
|
+
#
|
83
|
+
# value - Value of the element in concern.
|
84
|
+
#
|
85
|
+
# Returns score of element.
|
86
|
+
def score(value)
|
87
|
+
connection.zscore(key_label, value)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Public: Retrieves length of Redis sorted set using ZCARD command.
|
91
|
+
#
|
92
|
+
# Returns Integer containing cardinality of the sorted set.
|
93
|
+
def count
|
94
|
+
connection.zcard(key_label)
|
95
|
+
end
|
96
|
+
|
97
|
+
alias_method :length, :count
|
98
|
+
|
99
|
+
# Public: Retrieves elements in the sorted set in (from, to) interval
|
100
|
+
# using ZREVRANGEBYSCORE command.
|
101
|
+
#
|
102
|
+
# from - Beginning point of the interval.
|
103
|
+
# to - Ending point of the interval.
|
104
|
+
# options - Additional options for retrieval.
|
105
|
+
# :include_boundaries - If it is set to true, elements on
|
106
|
+
# beginning/ending points are included.
|
107
|
+
# :withscores - If it is set to true, returned array
|
108
|
+
# contains values and corresponding scores
|
109
|
+
# of elements.
|
110
|
+
#
|
111
|
+
# Returns Array of element values or value/score pairs.
|
112
|
+
def get_range(from, to, options = {})
|
113
|
+
if options.delete(:include_boundaries)
|
114
|
+
connection.zrevrangebyscore(key_label, to, from, options)
|
115
|
+
else
|
116
|
+
connection.zrevrangebyscore(key_label, "(#{to}", "(#{from}", options)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Public: Puts an element in sorted set using ZADD command.
|
121
|
+
#
|
122
|
+
# score - Score for the element.
|
123
|
+
# value - Value for the element.
|
124
|
+
#
|
125
|
+
# Returns true.
|
126
|
+
def put(score, value)
|
127
|
+
connection.zadd(key_label, score, value)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Public: Removes an element from the sorted set using ZREM command.
|
131
|
+
#
|
132
|
+
# value - Value to remove.
|
133
|
+
#
|
134
|
+
# Returns true.
|
135
|
+
def remove(value)
|
136
|
+
connection.zrem(key_label, value)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Public: Removes elements of the sorted set in specified interval using
|
140
|
+
# ZREMRANGEBYSCORE command.
|
141
|
+
#
|
142
|
+
# from - Beginning point of the interval (default: '-inf').
|
143
|
+
# to - Ending point of the interval (default: '+inf').
|
144
|
+
#
|
145
|
+
# Returns true.
|
146
|
+
def remove_range(from = '-inf', to = '+inf')
|
147
|
+
connection.zremrangebyscore(key_label, from, to)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Public: Duplicates the sorted set with new key label using ZUNIONSTORE
|
151
|
+
# command.
|
152
|
+
#
|
153
|
+
# Returns true if duplication was successful, false otherwise.
|
154
|
+
def duplicate(new_key_label)
|
155
|
+
connection.zunionstore(new_key_label, [key_label]) if exists?
|
156
|
+
end
|
157
|
+
|
158
|
+
# Public: Generates intersected sorted set with another sorted set or set
|
159
|
+
# and perform operations on the new intersected set optionally.
|
160
|
+
#
|
161
|
+
# set - Another set to perform intersection with the sorted set.
|
162
|
+
# options - Additional options for the intersection.
|
163
|
+
# :seed - Seed for the new key label used to avoid naming
|
164
|
+
# confliction.
|
165
|
+
# block - An optional block that performs RedisModel commands with the
|
166
|
+
# intersected sorted set. If the block is given, intersected
|
167
|
+
# sorted set is removed after commands are completed.
|
168
|
+
#
|
169
|
+
# Returns RedisModel::Intersected object resulted from intersection if
|
170
|
+
# block was not given. If block was given, result of block is returned.
|
171
|
+
def intersect(set, options = {}, &block)
|
172
|
+
result = intersected = RedisModel::Intersected.new([self, set], options[:seed])
|
173
|
+
|
174
|
+
if block_given?
|
175
|
+
intersected.generate
|
176
|
+
result = yield(intersected)
|
177
|
+
intersected.clear
|
178
|
+
end
|
179
|
+
|
180
|
+
result
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RedisModel
|
2
|
+
module Types
|
3
|
+
# Internal: Methods needed for timestamp type.
|
4
|
+
module Timestamp
|
5
|
+
include RedisModel::Types::BaseValue
|
6
|
+
|
7
|
+
# Public: Reads value on Redis and converts it to timestamp.
|
8
|
+
#
|
9
|
+
# Returns Time object.
|
10
|
+
def to_time
|
11
|
+
Time.parse(get) rescue nil
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :to_value, :to_time
|
15
|
+
|
16
|
+
# Public: Sets ISO 8601 string of timestamp to Redis.
|
17
|
+
#
|
18
|
+
# timestamp - Timestamp to store.
|
19
|
+
#
|
20
|
+
# Returns nothing.
|
21
|
+
def set(timestamp)
|
22
|
+
super(timestamp.utc.iso8601)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/redis_model.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
require 'redis'
|
5
|
+
require 'active_support/inflector'
|
6
|
+
|
7
|
+
require "redis_model/version"
|
8
|
+
require 'redis_model/configurations'
|
9
|
+
require 'redis_model/types/base'
|
10
|
+
require 'redis_model/types/base_value'
|
11
|
+
require 'redis_model/types/string'
|
12
|
+
require 'redis_model/types/counter'
|
13
|
+
require 'redis_model/types/list'
|
14
|
+
require 'redis_model/types/sorted_set'
|
15
|
+
require 'redis_model/types/float'
|
16
|
+
require 'redis_model/types/set'
|
17
|
+
require 'redis_model/types/hash'
|
18
|
+
require 'redis_model/types/timestamp'
|
19
|
+
require 'redis_model/types/integer'
|
20
|
+
require 'redis_model/schema'
|
21
|
+
require 'redis_model/base'
|
22
|
+
require 'redis_model/belonged_to'
|
23
|
+
require 'redis_model/attribute'
|
24
|
+
require 'redis_model/class_attribute'
|
25
|
+
require 'redis_model/intersected'
|
26
|
+
|
27
|
+
# Public: RedisModel provides various types of interfaces to handle values on
|
28
|
+
# Redis from applications, mostly with ORM including ActiveRecord. RedisModel
|
29
|
+
# is highly customizable and tries to avoid polluting name space of previously
|
30
|
+
# defined classes and modules.
|
31
|
+
module RedisModel
|
32
|
+
def self.config
|
33
|
+
(@configurations ||= RedisModel::Configurations.instance).tap do |configurations|
|
34
|
+
yield configurations if block_given?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/redis_model.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'redis_model/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'redis_model'
|
8
|
+
spec.version = RedisModel::VERSION
|
9
|
+
spec.authors = ['Inbeom Hwang']
|
10
|
+
spec.email = ['hwanginbeom@gmail.com']
|
11
|
+
spec.summary = %q{Interfaces for Redis values.}
|
12
|
+
spec.description = %q{RedisModel provides various types of interfaces to handle values on Redis}
|
13
|
+
spec.homepage = 'http://gitlab.ultracaption.net/inbeom/redis_model'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'redis'
|
22
|
+
spec.add_dependency 'activesupport'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rspec'
|
27
|
+
spec.add_development_dependency 'kaminari'
|
28
|
+
end
|