kredis 1.5.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72d301175c0d6bac257d10d925bddcaaa4d9fda78f0aa75264fc3b6c5a8af677
4
- data.tar.gz: aa7dd573678ca4f8bb18478cf6b606fe2afc3833e6c9b9bb9b693e361f7706ee
3
+ metadata.gz: f90d8ba8eadeb9cc6dbd2ca4bbb8532629281595e5a1feccd42487b98f248e67
4
+ data.tar.gz: 3d5e2768e7647d27bb004bc7167f9b35b97702bdcc3e3f6f76032abd3b85bb5d
5
5
  SHA512:
6
- metadata.gz: e12490fc43dd3e73dcc39dfe3af5ab0f44405eae7a071b08edb14b1cba08c4b96bdb968af61072b2329e0f5e449c8c281252f4e32f423656d77bcc5ebf0e95e0
7
- data.tar.gz: f047ac1e52365a7b25e10b2d2187df699abe34ced746f4d34b8e47511c019019eee3e9e6f69a5e46d58286a5ad5e38899d0db8517015d809b278ea46526f81b4
6
+ metadata.gz: 590e5baac4b4a2c85c4867f6ee55d4598c3b21e9c9b22961556626f59e8b17524cc4e4e9040f9109d30671ba4b615b074edcad5723df459f75a10dd1da956a23
7
+ data.tar.gz: 8ad76868f04ac0c0828485f2e03ce93fc8514eb32e2661028adcbc6ff9866f6016d26530b6af30f8df15009723e01797fc913084bb6bcb219f36558db7ed2768
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([ 1, 2, 3 ]) # => RPUSH myintegerlist "1" "2" "3"
54
- integer_list << 4 # => RPUSH myintegerlist "4"
55
- [ 1, 2, 3, 4 ] == integer_list.elements # => LRANGE myintegerlist 0 -1
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"
@@ -163,15 +163,7 @@ sleep 0.6.seconds
163
163
  false == flag.marked? #=> EXISTS myflag
164
164
  ```
165
165
 
166
- And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`:
167
-
168
- ```ruby
169
- one_string = Kredis.string "mystring"
170
- two_string = Kredis.string "mystring", config: :secondary
171
-
172
- one_string.value = "just on shared"
173
- two_string.value != one_string.value
174
- ```
166
+ ### Models
175
167
 
176
168
  You can use all these structures in models:
177
169
 
@@ -197,6 +189,29 @@ person.morning.value = "blue" # => SET people:5:morning
197
189
  true == person.morning.blue? # => GET people:5:morning
198
190
  ```
199
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
+
200
215
  You can also define `after_change` callbacks that trigger on mutations:
201
216
 
202
217
  ```ruby
@@ -209,6 +224,18 @@ class Person < ApplicationRecord
209
224
  end
210
225
  ```
211
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
+
212
239
  ## Installation
213
240
 
214
241
  1. Run `./bin/bundle add kredis`
@@ -218,6 +245,8 @@ Additional configurations can be added under `config/redis/*.yml` and referenced
218
245
 
219
246
  Kredis passes the configuration to `Redis.new` to establish the connection. See the [Redis documentation](https://github.com/redis/redis-rb) for other configuration options.
220
247
 
248
+ If you don't have `config/redis/shared.yml` (or use another named configuration), Kredis will default to look in env for `REDIS_URL`, then fallback to a default URL of `redis://127.0.0.1:6379/0`.
249
+
221
250
  ### Redis support
222
251
 
223
252
  Kredis works with Redis server 4.0+, with the [Redis Ruby](https://github.com/redis/redis-rb) client version 4.2+.
@@ -228,14 +257,14 @@ If you need to connect to Redis with SSL, the recommended approach is to set you
228
257
 
229
258
  ```ruby
230
259
  Kredis::Connections.connections[:shared] = Redis.new(
231
- url: ENV['REDIS_URL'],
260
+ url: ENV["REDIS_URL"],
232
261
  ssl_params: {
233
262
  cert_store: OpenSSL::X509::Store.new.tap { |store|
234
- store.add_file(Rails.root.join('config', 'ca_cert.pem').to_s)
263
+ store.add_file(Rails.root.join("config", "ca_cert.pem").to_s)
235
264
  },
236
265
 
237
266
  cert: OpenSSL::X509::Certificate.new(File.read(
238
- Rails.root.join('config', 'client.crt')
267
+ Rails.root.join("config", "client.crt")
239
268
  )),
240
269
 
241
270
  key: OpenSSL::PKey::RSA.new(
@@ -259,6 +288,29 @@ config.kredis.connector = ->(config) { SomeRedisProxy.new(config) }
259
288
 
260
289
  By default Kredis will use `Redis.new(config)`.
261
290
 
291
+ ## Development
292
+
293
+ A development console is available by running `bin/console`.
294
+
295
+ From there, you can experiment with Kredis. e.g.
296
+
297
+ ```erb
298
+ >> str = Kredis.string "mystring"
299
+ Kredis (0.1ms) Connected to shared
300
+ =>
301
+ #<Kredis::Types::Scalar:0x0000000134c7d938
302
+ ...
303
+ >> str.value = "hello, world"
304
+ Kredis Proxy (2.4ms) SET mystring ["hello, world"]
305
+ => "hello, world"
306
+ >> str.value
307
+ ```
308
+
309
+ Run tests with `bin/test`.
310
+
311
+ [`debug`](https://github.com/ruby/debug) can be used in the development console and in the test suite by inserting a
312
+ breakpoint, e.g. `debugger`.
313
+
262
314
  ## License
263
315
 
264
316
  Kredis is released under the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  yaml_path = Rails.root.join("config/redis/shared.yml")
2
4
  unless yaml_path.exist?
3
5
  say "Adding `config/redis/shared.yml`"
@@ -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 kredis_list(name, key: nil, typed: :string, config: :shared, after_change: nil)
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 kredis_unique_list(name, limit: nil, key: nil, typed: :string, config: :shared, after_change: nil)
50
- kredis_connection_with __method__, name, key, limit: limit, typed: typed, config: config, after_change: after_change
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 kredis_set(name, key: nil, typed: :string, config: :shared, after_change: nil)
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.gsub("/", ":")}:#{extract_kredis_id}:#{name}"
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
@@ -1,14 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "redis"
2
4
 
3
5
  module Kredis::Connections
6
+ DEFAULT_REDIS_URL = "redis://127.0.0.1:6379/0"
7
+ DEFAULT_REDIS_TIMEOUT = 1
8
+
4
9
  mattr_accessor :connections, default: Hash.new
5
10
  mattr_accessor :configurator
6
11
  mattr_accessor :connector, default: ->(config) { Redis.new(config) }
7
12
 
8
13
  def configured_for(name)
9
- connections[name] ||= begin
10
- Kredis.instrument :meta, message: "Connected to #{name}" do
14
+ connections[name] ||= Kredis.instrument :meta, message: "Connected to #{name}" do
15
+ if configurator.root.join("config/redis/#{name}.yml").exist?
11
16
  connector.call configurator.config_for("redis/#{name}")
17
+ elsif name == :shared
18
+ Redis.new url: ENV.fetch("REDIS_URL", DEFAULT_REDIS_URL), timeout: DEFAULT_REDIS_TIMEOUT
19
+ else
20
+ raise "No configuration found for #{name}"
12
21
  end
13
22
  end
14
23
  end
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/log_subscriber"
2
4
 
3
5
  class Kredis::LogSubscriber < ActiveSupport::LogSubscriber
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kredis::Namespace
2
4
  def namespace=(namespace)
3
5
  Thread.current[:kredis_namespace] = namespace
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Railtie < ::Rails::Railtie
2
4
  config.kredis = ActiveSupport::OrderedOptions.new
3
5
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kredis
4
+ module Type
5
+ class Boolean < ActiveModel::Type::Boolean
6
+ def serialize(value)
7
+ super ? 1 : 0
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "json"
2
4
  require "active_model/type"
3
- require "kredis/type/json"
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: ActiveModel::Type::Boolean.new,
17
+ boolean: Kredis::Type::Boolean.new,
15
18
  datetime: Kredis::Type::DateTime.new,
16
19
  json: Kredis::Type::Json.new
17
20
  }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::CallbacksProxy
2
4
  attr_reader :type
3
5
  delegate :to_s, to: :type
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Cycle < Kredis::Types::Counter
2
4
  attr_accessor :values
3
5
 
@@ -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
- proxying :set, :get, :del, :exists?
6
+ prepend Kredis::DefaultValues
7
+
8
+ InvalidDefault = Class.new(StandardError)
5
9
 
6
- attr_accessor :values, :default
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 || default
26
+ get
21
27
  end
22
28
 
23
29
  def reset
24
- del
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
@@ -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
@@ -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
@@ -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
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::OrderedSet < Kredis::Types::Proxying
2
- proxying :multi, :zrange, :zrem, :zadd, :zremrangebyrank, :zcard, :exists?, :del
4
+ prepend Kredis::DefaultValues
5
+
6
+ proxying :multi, :zrange, :zrem, :zadd, :zremrangebyrank, :zcard, :exists?, :del, :zscore
3
7
 
4
8
  attr_accessor :typed
5
9
  attr_reader :limit
@@ -13,6 +17,10 @@ class Kredis::Types::OrderedSet < Kredis::Types::Proxying
13
17
  zrem(types_to_strings(elements, typed))
14
18
  end
15
19
 
20
+ def include?(element)
21
+ !!zscore(type_to_string(element, typed))
22
+ end
23
+
16
24
  def prepend(elements)
17
25
  insert(elements, prepending: true)
18
26
  end
@@ -42,7 +50,7 @@ class Kredis::Types::OrderedSet < Kredis::Types::Proxying
42
50
  base_score + incremental_score
43
51
  end
44
52
 
45
- [ score , element ]
53
+ [ score, element ]
46
54
  end
47
55
 
48
56
  multi do
@@ -72,4 +80,8 @@ class Kredis::Types::OrderedSet < Kredis::Types::Proxying
72
80
  zremrangebyrank(0, -(limit + 1))
73
81
  end
74
82
  end
83
+
84
+ def set_default
85
+ append default
86
+ end
75
87
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kredis::Types::Proxy::Failsafe
2
4
  def initialize(*)
3
5
  super
@@ -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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/delegation"
2
4
 
3
5
  class Kredis::Types::Proxying
@@ -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, :default, :expires_in
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
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Slots < Kredis::Types::Proxying
2
4
  class NotAvailable < StandardError; end
3
5
 
@@ -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?
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,40 +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)
60
62
  end
61
63
 
62
- def list(key, typed: :string, config: :shared, after_change: nil)
63
- type_from(List, config, key, after_change: after_change, typed: typed)
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)
64
66
  end
65
67
 
66
- def unique_list(key, typed: :string, limit: nil, config: :shared, after_change: nil)
67
- type_from(UniqueList, config, key, after_change: after_change, typed: typed, limit: limit)
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)
68
70
  end
69
71
 
70
- def set(key, typed: :string, config: :shared, after_change: nil)
71
- type_from(Set, config, key, after_change: after_change, typed: typed)
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)
72
74
  end
73
75
 
74
- def ordered_set(key, typed: :string, limit: nil, config: :shared, after_change: nil)
75
- type_from(OrderedSet, config, key, after_change: after_change, typed: typed, limit: limit)
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)
76
78
  end
77
79
 
78
80
  def slot(key, config: :shared, after_change: nil)
@@ -1,3 +1,3 @@
1
1
  module Kredis
2
- VERSION = "1.5.0"
2
+ VERSION = "1.6.1"
3
3
  end
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
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :kredis do
2
4
  desc "Install kredis"
3
5
  task :install do
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.5.0
4
+ version: 1.6.1
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-06-26 00:00:00.000000000 Z
12
+ date: 2023-12-29 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
@@ -130,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
132
  - !ruby/object:Gem::Version
131
133
  version: '0'
132
134
  requirements: []
133
- rubygems_version: 3.4.10
135
+ rubygems_version: 3.4.14
134
136
  signing_key:
135
137
  specification_version: 4
136
138
  summary: Higher-level data structures built on Redis.