kredis 1.4.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +76 -18
- data/lib/install/install.rb +2 -0
- data/lib/kredis/attributes.rb +42 -27
- data/lib/kredis/connections.rb +4 -4
- data/lib/kredis/default_values.rb +36 -0
- data/lib/kredis/log_subscriber.rb +2 -0
- data/lib/kredis/migration.rb +4 -2
- data/lib/kredis/namespace.rb +2 -0
- data/lib/kredis/railtie.rb +2 -0
- data/lib/kredis/type/boolean.rb +11 -0
- data/lib/kredis/type_casting.rb +5 -2
- data/lib/kredis/types/callbacks_proxy.rb +2 -0
- data/lib/kredis/types/counter.rb +11 -2
- data/lib/kredis/types/cycle.rb +2 -0
- data/lib/kredis/types/enum.rb +21 -4
- data/lib/kredis/types/flag.rb +9 -0
- data/lib/kredis/types/hash.rb +10 -1
- data/lib/kredis/types/list.rb +9 -0
- data/lib/kredis/types/ordered_set.rb +87 -0
- data/lib/kredis/types/proxy/failsafe.rb +2 -0
- data/lib/kredis/types/proxy.rb +12 -0
- data/lib/kredis/types/proxying.rb +10 -1
- data/lib/kredis/types/scalar.rb +10 -1
- data/lib/kredis/types/set.rb +9 -0
- data/lib/kredis/types/slots.rb +2 -0
- data/lib/kredis/types/unique_list.rb +3 -1
- data/lib/kredis/types.rb +19 -12
- data/lib/kredis/version.rb +1 -1
- data/lib/kredis.rb +3 -0
- data/lib/tasks/kredis/install.rake +2 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15ed6996059d28937ffa4f43a35e53d1e8fbc1894a30446575d9c00c390cd838
|
4
|
+
data.tar.gz: 296f80ea7719d69334d50240c9fce5969df4f8d976800013167c1fb0ebe6a0b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cae34ebe3f21fe7c0e9cc0da5fc14bdc0d15931436bf7f07c552c14090489806990779ffd219be054f050468c809e23bf79302365f59f2dfced4b6a054ad352c
|
7
|
+
data.tar.gz: 96513897d1badc12f4fc6b2e51e017958f7e5eeaa5730d06bcb9d9a12d71ae09a4eb8ce2661e70a70647f4c4d7e5543a30451ab64d290b91de20d47602f30398
|
data/README.md
CHANGED
@@ -21,11 +21,11 @@ integer.value = 5 # => SET myinteger "5"
|
|
21
21
|
5 == integer.value # => GET myinteger
|
22
22
|
|
23
23
|
decimal = Kredis.decimal "mydecimal" # accuracy!
|
24
|
-
decimal.value = "%.47f" % (1.0/10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045"
|
24
|
+
decimal.value = "%.47f" % (1.0 / 10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045"
|
25
25
|
BigDecimal("0.10000000000000000555111512312578270211815834045e0") == decimal.value # => GET mydecimal
|
26
26
|
|
27
27
|
float = Kredis.float "myfloat" # speed!
|
28
|
-
float.value = 1.0/10 # => SET myfloat "0.1"
|
28
|
+
float.value = 1.0 / 10 # => SET myfloat "0.1"
|
29
29
|
0.1 == float.value # => GET myfloat
|
30
30
|
|
31
31
|
boolean = Kredis.boolean "myboolean"
|
@@ -49,10 +49,10 @@ list = Kredis.list "mylist"
|
|
49
49
|
list << "hello world!" # => RPUSH mylist "hello world!"
|
50
50
|
[ "hello world!" ] == list.elements # => LRANGE mylist 0, -1
|
51
51
|
|
52
|
-
integer_list = Kredis.list "myintegerlist", typed: :integer
|
53
|
-
integer_list.append([
|
54
|
-
integer_list <<
|
55
|
-
[ 1, 2, 3, 4 ] == integer_list.elements
|
52
|
+
integer_list = Kredis.list "myintegerlist", typed: :integer, default: [ 1, 2, 3 ] # => EXISTS? myintegerlist, RPUSH myintegerlist "1" "2" "3"
|
53
|
+
integer_list.append([ 4, 5, 6 ]) # => RPUSH myintegerlist "4" "5" "6"
|
54
|
+
integer_list << 7 # => RPUSH myintegerlist "7"
|
55
|
+
[ 1, 2, 3, 4, 5, 6, 7 ] == integer_list.elements # => LRANGE myintegerlist 0 -1
|
56
56
|
|
57
57
|
unique_list = Kredis.unique_list "myuniquelist"
|
58
58
|
unique_list.append(%w[ 2 3 4 ]) # => LREM myuniquelist 0, "2" + LREM myuniquelist 0, "3" + LREM myuniquelist 0, "4" + RPUSH myuniquelist "2", "3", "4"
|
@@ -62,6 +62,14 @@ unique_list << "5" # => LREM myuniquelist 0, "5" + R
|
|
62
62
|
unique_list.remove(3) # => LREM myuniquelist 0, "3"
|
63
63
|
[ "4", "2", "1", "5" ] == unique_list.elements # => LRANGE myuniquelist 0, -1
|
64
64
|
|
65
|
+
ordered_set = Kredis.ordered_set "myorderedset"
|
66
|
+
ordered_set.append(%w[ 2 3 4 ]) # => ZADD myorderedset 1646131025.4953232 2 1646131025.495326 3 1646131025.4953272 4
|
67
|
+
ordered_set.prepend(%w[ 1 2 3 4 ]) # => ZADD myorderedset -1646131025.4957051 1 -1646131025.495707 2 -1646131025.4957082 3 -1646131025.4957092 4
|
68
|
+
ordered_set.append([])
|
69
|
+
ordered_set << "5" # => ZADD myorderedset 1646131025.4960442 5
|
70
|
+
ordered_set.remove(3) # => ZREM myorderedset 3
|
71
|
+
[ "4", "2", "1", "5" ] == ordered_set.elements # => ZRANGE myorderedset 0 -1
|
72
|
+
|
65
73
|
set = Kredis.set "myset", typed: :datetime
|
66
74
|
set.add(DateTime.tomorrow, DateTime.yesterday) # => SADD myset "2021-02-03 00:00:00 +0100" "2021-02-01 00:00:00 +0100"
|
67
75
|
set << DateTime.tomorrow # => SADD myset "2021-02-03 00:00:00 +0100"
|
@@ -155,15 +163,7 @@ sleep 0.6.seconds
|
|
155
163
|
false == flag.marked? #=> EXISTS myflag
|
156
164
|
```
|
157
165
|
|
158
|
-
|
159
|
-
|
160
|
-
```ruby
|
161
|
-
one_string = Kredis.string "mystring"
|
162
|
-
two_string = Kredis.string "mystring", config: :secondary
|
163
|
-
|
164
|
-
one_string.value = "just on shared"
|
165
|
-
two_string.value != one_string.value
|
166
|
-
```
|
166
|
+
### Models
|
167
167
|
|
168
168
|
You can use all these structures in models:
|
169
169
|
|
@@ -189,6 +189,29 @@ person.morning.value = "blue" # => SET people:5:morning
|
|
189
189
|
true == person.morning.blue? # => GET people:5:morning
|
190
190
|
```
|
191
191
|
|
192
|
+
### Default values
|
193
|
+
|
194
|
+
You can set a default value for all types. For example:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
list = Kredis.list "favorite_colors", default: [ "red", "green", "blue" ]
|
198
|
+
|
199
|
+
# or, in a model
|
200
|
+
class Person < ApplicationRecord
|
201
|
+
kredis_string :name, default: "Unknown"
|
202
|
+
kredis_list :favorite_colors, default: [ "red", "green", "blue" ]
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
206
|
+
There's a performance overhead to consider though. When you first read or write an attribute in a model, Kredis will
|
207
|
+
check if the underlying Redis key exists, while watching for concurrent changes, and if it does not,
|
208
|
+
write the specified default value.
|
209
|
+
|
210
|
+
This means that using default values in a typical Rails app additional Redis calls (WATCH, EXISTS, UNWATCH) will be
|
211
|
+
executed for each Kredis attribute with a default value read or written during a request.
|
212
|
+
|
213
|
+
### Callbacks
|
214
|
+
|
192
215
|
You can also define `after_change` callbacks that trigger on mutations:
|
193
216
|
|
194
217
|
```ruby
|
@@ -201,6 +224,18 @@ class Person < ApplicationRecord
|
|
201
224
|
end
|
202
225
|
```
|
203
226
|
|
227
|
+
### Multiple Redis servers
|
228
|
+
|
229
|
+
And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
one_string = Kredis.string "mystring"
|
233
|
+
two_string = Kredis.string "mystring", config: :secondary
|
234
|
+
|
235
|
+
one_string.value = "just on shared"
|
236
|
+
two_string.value != one_string.value
|
237
|
+
```
|
238
|
+
|
204
239
|
## Installation
|
205
240
|
|
206
241
|
1. Run `./bin/bundle add kredis`
|
@@ -220,14 +255,14 @@ If you need to connect to Redis with SSL, the recommended approach is to set you
|
|
220
255
|
|
221
256
|
```ruby
|
222
257
|
Kredis::Connections.connections[:shared] = Redis.new(
|
223
|
-
url: ENV[
|
258
|
+
url: ENV["REDIS_URL"],
|
224
259
|
ssl_params: {
|
225
260
|
cert_store: OpenSSL::X509::Store.new.tap { |store|
|
226
|
-
store.add_file(Rails.root.join(
|
261
|
+
store.add_file(Rails.root.join("config", "ca_cert.pem").to_s)
|
227
262
|
},
|
228
263
|
|
229
264
|
cert: OpenSSL::X509::Certificate.new(File.read(
|
230
|
-
Rails.root.join(
|
265
|
+
Rails.root.join("config", "client.crt")
|
231
266
|
)),
|
232
267
|
|
233
268
|
key: OpenSSL::PKey::RSA.new(
|
@@ -251,6 +286,29 @@ config.kredis.connector = ->(config) { SomeRedisProxy.new(config) }
|
|
251
286
|
|
252
287
|
By default Kredis will use `Redis.new(config)`.
|
253
288
|
|
289
|
+
## Development
|
290
|
+
|
291
|
+
A development console is available by running `bin/console`.
|
292
|
+
|
293
|
+
From there, you can experiment with Kredis. e.g.
|
294
|
+
|
295
|
+
```erb
|
296
|
+
>> str = Kredis.string "mystring"
|
297
|
+
Kredis (0.1ms) Connected to shared
|
298
|
+
=>
|
299
|
+
#<Kredis::Types::Scalar:0x0000000134c7d938
|
300
|
+
...
|
301
|
+
>> str.value = "hello, world"
|
302
|
+
Kredis Proxy (2.4ms) SET mystring ["hello, world"]
|
303
|
+
=> "hello, world"
|
304
|
+
>> str.value
|
305
|
+
```
|
306
|
+
|
307
|
+
Run tests with `bin/test`.
|
308
|
+
|
309
|
+
[`debug`](https://github.com/ruby/debug) can be used in the development console and in the test suite by inserting a
|
310
|
+
breakpoint, e.g. `debugger`.
|
311
|
+
|
254
312
|
## License
|
255
313
|
|
256
314
|
Kredis is released under the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/install/install.rb
CHANGED
data/lib/kredis/attributes.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kredis::Attributes
|
2
4
|
extend ActiveSupport::Concern
|
3
5
|
|
@@ -6,52 +8,56 @@ module Kredis::Attributes
|
|
6
8
|
kredis_connection_with __method__, name, key, config: config, after_change: after_change
|
7
9
|
end
|
8
10
|
|
9
|
-
def kredis_string(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
10
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
11
|
+
def kredis_string(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
12
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
11
13
|
end
|
12
14
|
|
13
|
-
def kredis_integer(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
14
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
15
|
+
def kredis_integer(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
16
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
15
17
|
end
|
16
18
|
|
17
|
-
def kredis_decimal(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
18
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
19
|
+
def kredis_decimal(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
20
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
19
21
|
end
|
20
22
|
|
21
|
-
def kredis_datetime(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
22
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
23
|
+
def kredis_datetime(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
24
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
23
25
|
end
|
24
26
|
|
25
|
-
def kredis_flag(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
26
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
27
|
+
def kredis_flag(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
28
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
27
29
|
|
28
30
|
define_method("#{name}?") do
|
29
31
|
send(name).marked?
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
def kredis_float(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
34
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
35
|
+
def kredis_float(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
36
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
35
37
|
end
|
36
38
|
|
37
39
|
def kredis_enum(name, key: nil, values:, default:, config: :shared, after_change: nil)
|
38
40
|
kredis_connection_with __method__, name, key, values: values, default: default, config: config, after_change: after_change
|
39
41
|
end
|
40
42
|
|
41
|
-
def kredis_json(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
42
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
43
|
+
def kredis_json(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
44
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
45
|
+
end
|
46
|
+
|
47
|
+
def kredis_list(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
|
48
|
+
kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
|
43
49
|
end
|
44
50
|
|
45
|
-
def
|
46
|
-
kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
|
51
|
+
def kredis_unique_list(name, limit: nil, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
|
52
|
+
kredis_connection_with __method__, name, key, default: default, limit: limit, typed: typed, config: config, after_change: after_change
|
47
53
|
end
|
48
54
|
|
49
|
-
def
|
50
|
-
kredis_connection_with __method__, name, key,
|
55
|
+
def kredis_set(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
|
56
|
+
kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
|
51
57
|
end
|
52
58
|
|
53
|
-
def
|
54
|
-
kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
|
59
|
+
def kredis_ordered_set(name, limit: nil, default: nil, key: nil, typed: :string, config: :shared, after_change: nil)
|
60
|
+
kredis_connection_with __method__, name, key, default: default, limit: limit, typed: typed, config: config, after_change: after_change
|
55
61
|
end
|
56
62
|
|
57
63
|
def kredis_slot(name, key: nil, config: :shared, after_change: nil)
|
@@ -62,16 +68,16 @@ module Kredis::Attributes
|
|
62
68
|
kredis_connection_with __method__, name, key, available: available, config: config, after_change: after_change
|
63
69
|
end
|
64
70
|
|
65
|
-
def kredis_counter(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
66
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
71
|
+
def kredis_counter(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
72
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
67
73
|
end
|
68
74
|
|
69
|
-
def kredis_hash(name, key: nil, typed: :string, config: :shared, after_change: nil)
|
70
|
-
kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
|
75
|
+
def kredis_hash(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
|
76
|
+
kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
|
71
77
|
end
|
72
78
|
|
73
|
-
def kredis_boolean(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
|
74
|
-
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
|
79
|
+
def kredis_boolean(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
80
|
+
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
|
75
81
|
end
|
76
82
|
|
77
83
|
private
|
@@ -84,6 +90,7 @@ module Kredis::Attributes
|
|
84
90
|
if instance_variable_defined?(ivar_symbol)
|
85
91
|
instance_variable_get(ivar_symbol)
|
86
92
|
else
|
93
|
+
options[:default] = kredis_default_evaluated(options[:default]) if options[:default]
|
87
94
|
new_type = Kredis.send(type, kredis_key_evaluated(key) || kredis_key_for_attribute(name), **options)
|
88
95
|
instance_variable_set ivar_symbol,
|
89
96
|
after_change ? enrich_after_change_with_record_access(new_type, after_change) : new_type
|
@@ -102,7 +109,7 @@ module Kredis::Attributes
|
|
102
109
|
end
|
103
110
|
|
104
111
|
def kredis_key_for_attribute(name)
|
105
|
-
"#{self.class.name.tableize.
|
112
|
+
"#{self.class.name.tableize.tr("/", ":")}:#{extract_kredis_id}:#{name}"
|
106
113
|
end
|
107
114
|
|
108
115
|
def extract_kredis_id
|
@@ -115,4 +122,12 @@ module Kredis::Attributes
|
|
115
122
|
when Symbol then Kredis::Types::CallbacksProxy.new(type, ->(_) { send(original_after_change) })
|
116
123
|
end
|
117
124
|
end
|
125
|
+
|
126
|
+
def kredis_default_evaluated(default)
|
127
|
+
case default
|
128
|
+
when Proc then Proc.new { default.call(self) }
|
129
|
+
when Symbol then send(default)
|
130
|
+
else default
|
131
|
+
end
|
132
|
+
end
|
118
133
|
end
|
data/lib/kredis/connections.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "redis"
|
2
4
|
|
3
5
|
module Kredis::Connections
|
@@ -6,10 +8,8 @@ module Kredis::Connections
|
|
6
8
|
mattr_accessor :connector, default: ->(config) { Redis.new(config) }
|
7
9
|
|
8
10
|
def configured_for(name)
|
9
|
-
connections[name] ||=
|
10
|
-
|
11
|
-
connector.call configurator.config_for("redis/#{name}")
|
12
|
-
end
|
11
|
+
connections[name] ||= Kredis.instrument :meta, message: "Connected to #{name}" do
|
12
|
+
connector.call configurator.config_for("redis/#{name}")
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kredis::DefaultValues
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
prepended do
|
7
|
+
attr_writer :default
|
8
|
+
|
9
|
+
proxying :watch, :unwatch, :exists?
|
10
|
+
|
11
|
+
def default
|
12
|
+
case @default
|
13
|
+
when Proc then @default.call
|
14
|
+
when Symbol then send(@default)
|
15
|
+
else @default
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def set_default
|
21
|
+
raise NotImplementedError, "Kredis type #{self.class} needs to define #set_default"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(...)
|
26
|
+
super
|
27
|
+
|
28
|
+
if default
|
29
|
+
watch do
|
30
|
+
set_default unless exists?
|
31
|
+
|
32
|
+
unwatch
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/kredis/migration.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/module/delegation"
|
2
4
|
|
3
5
|
class Kredis::Migration
|
@@ -33,10 +35,10 @@ class Kredis::Migration
|
|
33
35
|
def delete_all(*key_patterns)
|
34
36
|
log_migration "DELETE ALL #{key_patterns.inspect}" do
|
35
37
|
if key_patterns.length > 1
|
36
|
-
@redis.del
|
38
|
+
@redis.del(*key_patterns)
|
37
39
|
else
|
38
40
|
each_key_batch_matching(key_patterns.first) do |keys, pipeline|
|
39
|
-
pipeline.del
|
41
|
+
pipeline.del(*keys)
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
data/lib/kredis/namespace.rb
CHANGED
data/lib/kredis/railtie.rb
CHANGED
data/lib/kredis/type_casting.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
require "active_model/type"
|
3
|
-
require "kredis/type/
|
5
|
+
require "kredis/type/boolean"
|
4
6
|
require "kredis/type/datetime"
|
7
|
+
require "kredis/type/json"
|
5
8
|
|
6
9
|
module Kredis::TypeCasting
|
7
10
|
class InvalidType < StandardError; end
|
@@ -11,7 +14,7 @@ module Kredis::TypeCasting
|
|
11
14
|
integer: ActiveModel::Type::Integer.new,
|
12
15
|
decimal: ActiveModel::Type::Decimal.new,
|
13
16
|
float: ActiveModel::Type::Float.new,
|
14
|
-
boolean:
|
17
|
+
boolean: Kredis::Type::Boolean.new,
|
15
18
|
datetime: Kredis::Type::DateTime.new,
|
16
19
|
json: Kredis::Type::Json.new
|
17
20
|
}
|
data/lib/kredis/types/counter.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Kredis::Types::Counter < Kredis::Types::Proxying
|
4
|
+
prepend Kredis::DefaultValues
|
5
|
+
|
2
6
|
proxying :multi, :set, :incrby, :decrby, :get, :del, :exists?
|
3
7
|
|
4
8
|
attr_accessor :expires_in
|
5
9
|
|
6
10
|
def increment(by: 1)
|
7
11
|
multi do
|
8
|
-
set 0, ex: expires_in, nx: true
|
12
|
+
set 0, ex: expires_in, nx: true if expires_in
|
9
13
|
incrby by
|
10
14
|
end[-1]
|
11
15
|
end
|
12
16
|
|
13
17
|
def decrement(by: 1)
|
14
18
|
multi do
|
15
|
-
set 0, ex: expires_in, nx: true
|
19
|
+
set 0, ex: expires_in, nx: true if expires_in
|
16
20
|
decrby by
|
17
21
|
end[-1]
|
18
22
|
end
|
@@ -24,4 +28,9 @@ class Kredis::Types::Counter < Kredis::Types::Proxying
|
|
24
28
|
def reset
|
25
29
|
del
|
26
30
|
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def set_default
|
34
|
+
increment by: default
|
35
|
+
end
|
27
36
|
end
|
data/lib/kredis/types/cycle.rb
CHANGED
data/lib/kredis/types/enum.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/object/inclusion"
|
2
4
|
|
3
5
|
class Kredis::Types::Enum < Kredis::Types::Proxying
|
4
|
-
|
6
|
+
prepend Kredis::DefaultValues
|
7
|
+
|
8
|
+
InvalidDefault = Class.new(StandardError)
|
5
9
|
|
6
|
-
|
10
|
+
proxying :set, :get, :del, :exists?, :multi
|
11
|
+
|
12
|
+
attr_accessor :values
|
7
13
|
|
8
14
|
def initialize(...)
|
9
15
|
super
|
@@ -17,11 +23,14 @@ class Kredis::Types::Enum < Kredis::Types::Proxying
|
|
17
23
|
end
|
18
24
|
|
19
25
|
def value
|
20
|
-
get
|
26
|
+
get
|
21
27
|
end
|
22
28
|
|
23
29
|
def reset
|
24
|
-
|
30
|
+
multi do
|
31
|
+
del
|
32
|
+
set_default
|
33
|
+
end
|
25
34
|
end
|
26
35
|
|
27
36
|
private
|
@@ -31,4 +40,12 @@ class Kredis::Types::Enum < Kredis::Types::Proxying
|
|
31
40
|
define_singleton_method("#{defined_value}!") { self.value = defined_value }
|
32
41
|
end
|
33
42
|
end
|
43
|
+
|
44
|
+
def set_default
|
45
|
+
if default.in?(values) || default.nil?
|
46
|
+
set default
|
47
|
+
else
|
48
|
+
raise InvalidDefault, "Default value #{default.inspect} for #{key} is not a valid option (Valid values: #{values.join(", ")})"
|
49
|
+
end
|
50
|
+
end
|
34
51
|
end
|
data/lib/kredis/types/flag.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Kredis::Types::Flag < Kredis::Types::Proxying
|
4
|
+
prepend Kredis::DefaultValues
|
5
|
+
|
2
6
|
proxying :set, :exists?, :del
|
3
7
|
|
4
8
|
attr_accessor :expires_in
|
@@ -14,4 +18,9 @@ class Kredis::Types::Flag < Kredis::Types::Proxying
|
|
14
18
|
def remove
|
15
19
|
del
|
16
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def set_default
|
24
|
+
mark if default
|
25
|
+
end
|
17
26
|
end
|
data/lib/kredis/types/hash.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/hash"
|
2
4
|
|
3
5
|
class Kredis::Types::Hash < Kredis::Types::Proxying
|
6
|
+
prepend Kredis::DefaultValues
|
7
|
+
|
4
8
|
proxying :hget, :hset, :hmget, :hdel, :hgetall, :hkeys, :hvals, :del, :exists?
|
5
9
|
|
6
10
|
attr_accessor :typed
|
@@ -14,7 +18,7 @@ class Kredis::Types::Hash < Kredis::Types::Proxying
|
|
14
18
|
end
|
15
19
|
|
16
20
|
def update(**entries)
|
17
|
-
hset entries.transform_values{ |val| type_to_string(val, typed) } if entries.flatten.any?
|
21
|
+
hset entries.transform_values { |val| type_to_string(val, typed) } if entries.flatten.any?
|
18
22
|
end
|
19
23
|
|
20
24
|
def values_at(*keys)
|
@@ -42,4 +46,9 @@ class Kredis::Types::Hash < Kredis::Types::Proxying
|
|
42
46
|
def values
|
43
47
|
strings_to_types(hvals || [], typed)
|
44
48
|
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def set_default
|
52
|
+
update(**default)
|
53
|
+
end
|
45
54
|
end
|
data/lib/kredis/types/list.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Kredis::Types::List < Kredis::Types::Proxying
|
4
|
+
prepend Kredis::DefaultValues
|
5
|
+
|
2
6
|
proxying :lrange, :lrem, :lpush, :ltrim, :rpush, :exists?, :del
|
3
7
|
|
4
8
|
attr_accessor :typed
|
@@ -28,4 +32,9 @@ class Kredis::Types::List < Kredis::Types::Proxying
|
|
28
32
|
def last(n = nil)
|
29
33
|
n ? lrange(-n, -1) : lrange(-1, -1).first
|
30
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def set_default
|
38
|
+
append default
|
39
|
+
end
|
31
40
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Kredis::Types::OrderedSet < Kredis::Types::Proxying
|
4
|
+
prepend Kredis::DefaultValues
|
5
|
+
|
6
|
+
proxying :multi, :zrange, :zrem, :zadd, :zremrangebyrank, :zcard, :exists?, :del, :zscore
|
7
|
+
|
8
|
+
attr_accessor :typed
|
9
|
+
attr_reader :limit
|
10
|
+
|
11
|
+
def elements
|
12
|
+
strings_to_types(zrange(0, -1) || [], typed)
|
13
|
+
end
|
14
|
+
alias to_a elements
|
15
|
+
|
16
|
+
def remove(*elements)
|
17
|
+
zrem(types_to_strings(elements, typed))
|
18
|
+
end
|
19
|
+
|
20
|
+
def include?(element)
|
21
|
+
!!zscore(type_to_string(element, typed))
|
22
|
+
end
|
23
|
+
|
24
|
+
def prepend(elements)
|
25
|
+
insert(elements, prepending: true)
|
26
|
+
end
|
27
|
+
|
28
|
+
def append(elements)
|
29
|
+
insert(elements)
|
30
|
+
end
|
31
|
+
alias << append
|
32
|
+
|
33
|
+
def limit=(limit)
|
34
|
+
raise "Limit must be greater than 0" if limit && limit <= 0
|
35
|
+
|
36
|
+
@limit = limit
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def insert(elements, prepending: false)
|
41
|
+
elements = Array(elements)
|
42
|
+
return if elements.empty?
|
43
|
+
|
44
|
+
elements_with_scores = types_to_strings(elements, typed).map.with_index do |element, index|
|
45
|
+
incremental_score = index * 0.000001
|
46
|
+
|
47
|
+
score = if prepending
|
48
|
+
-base_score - incremental_score
|
49
|
+
else
|
50
|
+
base_score + incremental_score
|
51
|
+
end
|
52
|
+
|
53
|
+
[ score, element ]
|
54
|
+
end
|
55
|
+
|
56
|
+
multi do
|
57
|
+
zadd(elements_with_scores)
|
58
|
+
trim(from_beginning: prepending)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def base_score
|
63
|
+
process_start_time + process_uptime
|
64
|
+
end
|
65
|
+
|
66
|
+
def process_start_time
|
67
|
+
@process_start_time ||= unproxied_redis.time.join(".").to_f - process_uptime
|
68
|
+
end
|
69
|
+
|
70
|
+
def process_uptime
|
71
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
72
|
+
end
|
73
|
+
|
74
|
+
def trim(from_beginning:)
|
75
|
+
return unless limit
|
76
|
+
|
77
|
+
if from_beginning
|
78
|
+
zremrangebyrank(limit, -1)
|
79
|
+
else
|
80
|
+
zremrangebyrank(0, -(limit + 1))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def set_default
|
85
|
+
append default
|
86
|
+
end
|
87
|
+
end
|
data/lib/kredis/types/proxy.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Kredis::Types::Proxy
|
2
4
|
require_relative "proxy/failsafe"
|
3
5
|
include Failsafe
|
@@ -20,6 +22,16 @@ class Kredis::Types::Proxy
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
25
|
+
def watch(&block)
|
26
|
+
redis.watch(key) do
|
27
|
+
block.call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def unwatch
|
32
|
+
redis.unwatch
|
33
|
+
end
|
34
|
+
|
23
35
|
def method_missing(method, *args, **kwargs)
|
24
36
|
Kredis.instrument :proxy, **log_message(method, *args, **kwargs) do
|
25
37
|
failsafe do
|
@@ -1,13 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/module/delegation"
|
2
4
|
|
3
5
|
class Kredis::Types::Proxying
|
4
6
|
attr_accessor :proxy, :key
|
5
7
|
|
6
8
|
def self.proxying(*commands)
|
7
|
-
delegate
|
9
|
+
delegate(*commands, to: :proxy)
|
8
10
|
end
|
9
11
|
|
10
12
|
def initialize(redis, key, **options)
|
13
|
+
@redis = redis
|
11
14
|
@key = key
|
12
15
|
@proxy = Kredis::Types::Proxy.new(redis, key)
|
13
16
|
options.each { |key, value| send("#{key}=", value) }
|
@@ -17,6 +20,12 @@ class Kredis::Types::Proxying
|
|
17
20
|
proxy.suppress_failsafe_with(returning: returning, &block)
|
18
21
|
end
|
19
22
|
|
23
|
+
def unproxied_redis
|
24
|
+
# Generally, this should not be used. It's only here for the rare case where we need to
|
25
|
+
# call Redis commands that don't reference a key and don't want to be pipelined.
|
26
|
+
@redis
|
27
|
+
end
|
28
|
+
|
20
29
|
private
|
21
30
|
delegate :type_to_string, :string_to_type, :types_to_strings, :strings_to_types, to: :Kredis
|
22
31
|
end
|
data/lib/kredis/types/scalar.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Kredis::Types::Scalar < Kredis::Types::Proxying
|
4
|
+
prepend Kredis::DefaultValues
|
5
|
+
|
2
6
|
proxying :set, :get, :exists?, :del, :expire, :expireat
|
3
7
|
|
4
|
-
attr_accessor :typed, :
|
8
|
+
attr_accessor :typed, :expires_in
|
5
9
|
|
6
10
|
def value=(value)
|
7
11
|
set type_to_string(value, typed), ex: expires_in
|
@@ -36,4 +40,9 @@ class Kredis::Types::Scalar < Kredis::Types::Proxying
|
|
36
40
|
def expire_at(datetime)
|
37
41
|
expireat datetime.to_i
|
38
42
|
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def set_default
|
46
|
+
self.value = default
|
47
|
+
end
|
39
48
|
end
|
data/lib/kredis/types/set.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Kredis::Types::Set < Kredis::Types::Proxying
|
4
|
+
prepend Kredis::DefaultValues
|
5
|
+
|
2
6
|
proxying :smembers, :sadd, :srem, :multi, :del, :sismember, :scard, :spop, :exists?, :srandmember
|
3
7
|
|
4
8
|
attr_accessor :typed
|
@@ -47,4 +51,9 @@ class Kredis::Types::Set < Kredis::Types::Proxying
|
|
47
51
|
strings_to_types(srandmember(count), typed)
|
48
52
|
end
|
49
53
|
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def set_default
|
57
|
+
add default
|
58
|
+
end
|
50
59
|
end
|
data/lib/kredis/types/slots.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# You'd normally call this a set, but Redis already has another data type for that
|
2
4
|
class Kredis::Types::UniqueList < Kredis::Types::List
|
3
5
|
proxying :multi, :ltrim, :exists?
|
@@ -22,7 +24,7 @@ class Kredis::Types::UniqueList < Kredis::Types::List
|
|
22
24
|
multi do
|
23
25
|
remove elements
|
24
26
|
super
|
25
|
-
ltrim
|
27
|
+
ltrim(-limit, -1) if limit
|
26
28
|
end
|
27
29
|
end
|
28
30
|
alias << append
|
data/lib/kredis/types.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kredis::Types
|
2
4
|
autoload :CallbacksProxy, "kredis/types/callbacks_proxy"
|
3
5
|
|
@@ -39,36 +41,40 @@ module Kredis::Types
|
|
39
41
|
end
|
40
42
|
|
41
43
|
|
42
|
-
def counter(key, expires_in: nil, config: :shared, after_change: nil)
|
43
|
-
type_from(Counter, config, key, after_change: after_change, expires_in: expires_in)
|
44
|
+
def counter(key, expires_in: nil, default: nil, config: :shared, after_change: nil)
|
45
|
+
type_from(Counter, config, key, after_change: after_change, default: default, expires_in: expires_in)
|
44
46
|
end
|
45
47
|
|
46
48
|
def cycle(key, values:, expires_in: nil, config: :shared, after_change: nil)
|
47
49
|
type_from(Cycle, config, key, after_change: after_change, values: values, expires_in: expires_in)
|
48
50
|
end
|
49
51
|
|
50
|
-
def flag(key, config: :shared, after_change: nil, expires_in: nil)
|
51
|
-
type_from(Flag, config, key, after_change: after_change, expires_in: expires_in)
|
52
|
+
def flag(key, default: nil, config: :shared, after_change: nil, expires_in: nil)
|
53
|
+
type_from(Flag, config, key, after_change: after_change, default: default, expires_in: expires_in)
|
52
54
|
end
|
53
55
|
|
54
56
|
def enum(key, values:, default:, config: :shared, after_change: nil)
|
55
57
|
type_from(Enum, config, key, after_change: after_change, values: values, default: default)
|
56
58
|
end
|
57
59
|
|
58
|
-
def hash(key, typed: :string, config: :shared, after_change: nil)
|
59
|
-
type_from(Hash, config, key, after_change: after_change, typed: typed)
|
60
|
+
def hash(key, typed: :string, default: nil, config: :shared, after_change: nil)
|
61
|
+
type_from(Hash, config, key, after_change: after_change, default: default, typed: typed)
|
62
|
+
end
|
63
|
+
|
64
|
+
def list(key, default: nil, typed: :string, config: :shared, after_change: nil)
|
65
|
+
type_from(List, config, key, after_change: after_change, default: default, typed: typed)
|
60
66
|
end
|
61
67
|
|
62
|
-
def
|
63
|
-
type_from(
|
68
|
+
def unique_list(key, default: nil, typed: :string, limit: nil, config: :shared, after_change: nil)
|
69
|
+
type_from(UniqueList, config, key, after_change: after_change, default: default, typed: typed, limit: limit)
|
64
70
|
end
|
65
71
|
|
66
|
-
def
|
67
|
-
type_from(
|
72
|
+
def set(key, default: nil, typed: :string, config: :shared, after_change: nil)
|
73
|
+
type_from(Set, config, key, after_change: after_change, default: default, typed: typed)
|
68
74
|
end
|
69
75
|
|
70
|
-
def
|
71
|
-
type_from(
|
76
|
+
def ordered_set(key, default: nil, typed: :string, limit: nil, config: :shared, after_change: nil)
|
77
|
+
type_from(OrderedSet, config, key, after_change: after_change, default: default, typed: typed, limit: limit)
|
72
78
|
end
|
73
79
|
|
74
80
|
def slot(key, config: :shared, after_change: nil)
|
@@ -99,4 +105,5 @@ require "kredis/types/hash"
|
|
99
105
|
require "kredis/types/list"
|
100
106
|
require "kredis/types/unique_list"
|
101
107
|
require "kredis/types/set"
|
108
|
+
require "kredis/types/ordered_set"
|
102
109
|
require "kredis/types/slots"
|
data/lib/kredis/version.rb
CHANGED
data/lib/kredis.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support"
|
2
4
|
require "active_support/core_ext/module/attribute_accessors"
|
3
5
|
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
@@ -8,6 +10,7 @@ require "kredis/connections"
|
|
8
10
|
require "kredis/log_subscriber"
|
9
11
|
require "kredis/namespace"
|
10
12
|
require "kredis/type_casting"
|
13
|
+
require "kredis/default_values"
|
11
14
|
require "kredis/types"
|
12
15
|
require "kredis/attributes"
|
13
16
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kredis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kasper Timm Hansen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-10-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -86,10 +86,12 @@ files:
|
|
86
86
|
- lib/kredis.rb
|
87
87
|
- lib/kredis/attributes.rb
|
88
88
|
- lib/kredis/connections.rb
|
89
|
+
- lib/kredis/default_values.rb
|
89
90
|
- lib/kredis/log_subscriber.rb
|
90
91
|
- lib/kredis/migration.rb
|
91
92
|
- lib/kredis/namespace.rb
|
92
93
|
- lib/kredis/railtie.rb
|
94
|
+
- lib/kredis/type/boolean.rb
|
93
95
|
- lib/kredis/type/datetime.rb
|
94
96
|
- lib/kredis/type/json.rb
|
95
97
|
- lib/kredis/type_casting.rb
|
@@ -101,6 +103,7 @@ files:
|
|
101
103
|
- lib/kredis/types/flag.rb
|
102
104
|
- lib/kredis/types/hash.rb
|
103
105
|
- lib/kredis/types/list.rb
|
106
|
+
- lib/kredis/types/ordered_set.rb
|
104
107
|
- lib/kredis/types/proxy.rb
|
105
108
|
- lib/kredis/types/proxy/failsafe.rb
|
106
109
|
- lib/kredis/types/proxying.rb
|
@@ -129,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
132
|
- !ruby/object:Gem::Version
|
130
133
|
version: '0'
|
131
134
|
requirements: []
|
132
|
-
rubygems_version: 3.4.
|
135
|
+
rubygems_version: 3.4.20
|
133
136
|
signing_key:
|
134
137
|
specification_version: 4
|
135
138
|
summary: Higher-level data structures built on Redis.
|