kredis 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of kredis might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +86 -3
- data/lib/kredis.rb +6 -6
- data/lib/kredis/attributes.rb +45 -55
- data/lib/kredis/connections.rb +5 -1
- data/lib/kredis/migration.rb +47 -0
- data/lib/kredis/railtie.rb +4 -4
- data/lib/kredis/type_casting.rb +48 -0
- data/lib/kredis/types.rb +57 -16
- data/lib/kredis/types/counter.rb +5 -6
- data/lib/kredis/types/enum.rb +31 -0
- data/lib/kredis/types/flag.rb +5 -3
- data/lib/kredis/types/list.rb +14 -8
- data/lib/kredis/types/proxy.rb +16 -4
- data/lib/kredis/types/proxying.rb +18 -0
- data/lib/kredis/types/scalar.rb +25 -0
- data/lib/kredis/types/set.rb +42 -0
- data/lib/kredis/types/slots.rb +41 -0
- data/lib/kredis/types/unique_list.rb +8 -8
- data/lib/kredis/version.rb +1 -1
- metadata +9 -6
- data/lib/kredis/logger.rb +0 -5
- data/lib/kredis/types/integer.rb +0 -9
- data/lib/kredis/types/mutex.rb +0 -25
- data/lib/kredis/types/string.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9aa90994f3d30a19d52df3fbc284d43d2637e940de06f221ecffc2853eeda459
|
4
|
+
data.tar.gz: 713137c0ec2c28bfb80df9c94b3e61c4b8f5906c9d68631fd5e26e4ac8ef0771
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afcbb020c7e7c412090a7798c433882adf7d54e293728eff3a7d39b655d41531a3bae5f307ea10faa72a39e6ed1cb1f7db1f3f6535351299d26f65fd20e728fb
|
7
|
+
data.tar.gz: 7de324aa868056600c28d82911ef654c7d9f58c5d85823ab1271a7518c76f9dbb31a2be23082cb9ab2bf210401eac0ceca698412a38f01779af310bcf5893624
|
data/README.md
CHANGED
@@ -1,11 +1,94 @@
|
|
1
1
|
# Kredis
|
2
2
|
|
3
|
-
Keyed Redis encapsulates higher-level data structures around a single key, so you can interact with them as coherent objects rather than isolated procedural commands.
|
3
|
+
Kredis (Keyed Redis) encapsulates higher-level types and data structures around a single key, so you can interact with them as coherent objects rather than isolated procedural commands. These higher-level structures can be configured as attributes within Active Models and Active Records using a declarative DSL.
|
4
4
|
|
5
|
+
Kredis is configured using env-aware yaml files, using `Rails.application.config_for`, so you can locate the data structures on separate redis instances, if you've reached a scale where a single shared instance is no longer sufficient.
|
5
6
|
|
6
|
-
|
7
|
+
Kredis provides namespacing support for keys such that you can safely run parallel testing against the data structures without different tests trampling each others data.
|
8
|
+
|
9
|
+
|
10
|
+
## Examples
|
11
|
+
|
12
|
+
Kredis provides typed scalars for strings, integers, decimals, floats, booleans, datetimes, and json hashes:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
string = Kredis.string "mystring"
|
16
|
+
string.value = "hello world!" # => SET mystring "hello world"
|
17
|
+
"hello world!" == string.value # => GET mystring
|
18
|
+
|
19
|
+
integer = Kredis.string "myinteger"
|
20
|
+
integer.value = 5 # => SET myinteger "5"
|
21
|
+
5 == string.value # => GET myinteger
|
22
|
+
|
23
|
+
json = Kredis.json "myjson"
|
24
|
+
integer.value = { "one" => 1, "two" => "2" } # => SET myjson "{\"one\":1,\"two\":\"2\"}"
|
25
|
+
{ "one" => 1, "two" => "2" } == string.value # => GET myjson
|
26
|
+
```
|
27
|
+
|
28
|
+
There are data structures for counters, enums, flags, lists, uniqe lists, sets, and slots:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
list = Kredis.list "mylist", typed: :integer
|
32
|
+
list.append([ 1, 2, 3 ]) # => LPUSH mylist "1" "2" "3"
|
33
|
+
list << 4 # => LPUSH mylist "4"
|
34
|
+
[ 1, 2, 3, 4 ] == list.elements # LRANGE 0 -1
|
35
|
+
|
36
|
+
set = Kredis.set "myset", typed: :datetime
|
37
|
+
set.add(DateTime.tomorrow, DateTime.yesterday) # => SADD myset "2021-02-03 00:00:00 +0100" "2021-02-01 00:00:00 +0100"
|
38
|
+
set << DateTime.tomorrow # => SADD myset "2021-02-03 00:00:00 +0100"
|
39
|
+
2 == set.size # => SCARD myset
|
40
|
+
[ DateTime.tomorrow, DateTime.yesterday ] == set.elements # => SMEMBERS myset
|
41
|
+
|
42
|
+
counter = Kredis.counter "mycounter", expires_in: 15.minutes
|
43
|
+
counter.increment by: 2 # => SETEX "mycounter" 900 0 + INCR "mycounter" 2
|
44
|
+
2 == counter.value # => GET "mycounter"
|
45
|
+
travel 16.minutes
|
46
|
+
0 == counter.value # => GET "mycounter"
|
47
|
+
```
|
48
|
+
|
49
|
+
You can use all these structures in models:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
class Person < ApplicationRecord
|
53
|
+
kredis_list :names
|
54
|
+
kredis_list :names_with_custom_key, key: ->(p) { "person:#{p.id}:names_customized" }
|
55
|
+
kredis_unique_list :skills, limit: 2
|
56
|
+
kredis_enum :morning, values: %w[ bright blue black ], default: "bright"
|
57
|
+
end
|
58
|
+
|
59
|
+
person = Person.find(5)
|
60
|
+
person.names.append "David", "Heinemeier", "Hansson" # => SADD person:5:names "David" "Heinemeier" "Hansson"
|
61
|
+
true == person.morning.bright?
|
62
|
+
person.morning.value = "blue"
|
63
|
+
true == person.morning.blue?
|
64
|
+
```
|
65
|
+
|
66
|
+
|
67
|
+
## Installation
|
68
|
+
|
69
|
+
1. Add the `kredis` gem to your Gemfile: `gem 'kredis'`
|
70
|
+
2. Run `./bin/bundle install`
|
71
|
+
3. Add a default configuration under `config/redis/shared.yml`
|
72
|
+
|
73
|
+
A default configuration can look like this for `config/redis/shared.yml`:
|
74
|
+
|
75
|
+
```yaml
|
76
|
+
production: &production
|
77
|
+
host: <%= ENV.fetch("REDIS_SHARED_HOST", "127.0.0.1") %>
|
78
|
+
port: <%= ENV.fetch("REDIS_SHARED_PORT", "6379") %>
|
79
|
+
timeout: 1
|
80
|
+
|
81
|
+
development: &development
|
82
|
+
host: <%= ENV.fetch("REDIS_SHARED_HOST", "127.0.0.1") %>
|
83
|
+
port: <%= ENV.fetch("REDIS_SHARED_PORT", "6379") %>
|
84
|
+
timeout: 1
|
85
|
+
|
86
|
+
test:
|
87
|
+
<<: *development
|
88
|
+
```
|
89
|
+
|
90
|
+
Additional configurations can be added under `config/redis/*.yml` and referenced when a type is created.
|
7
91
|
|
8
|
-
...
|
9
92
|
|
10
93
|
## License
|
11
94
|
|
data/lib/kredis.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
require "kredis/railtie"
|
2
|
+
require "kredis/version"
|
2
3
|
|
3
4
|
require "kredis/connections"
|
5
|
+
require "kredis/namespace"
|
4
6
|
require "kredis/types"
|
5
7
|
require "kredis/attributes"
|
6
|
-
require "kredis/
|
7
|
-
require "kredis/logger"
|
8
|
+
require "kredis/type_casting"
|
8
9
|
|
9
10
|
module Kredis
|
10
|
-
include Connections
|
11
|
-
include Namespace
|
12
|
-
include Types
|
13
|
-
include Logger
|
11
|
+
include Connections, Namespace, Types, TypeCasting
|
14
12
|
|
15
13
|
extend self
|
16
14
|
|
15
|
+
mattr_accessor :logger
|
16
|
+
|
17
17
|
def redis(config: :shared)
|
18
18
|
configured_for(config)
|
19
19
|
end
|
data/lib/kredis/attributes.rb
CHANGED
@@ -3,80 +3,70 @@ module Kredis::Attributes
|
|
3
3
|
|
4
4
|
class_methods do
|
5
5
|
def kredis_proxy(name, key: nil, config: :shared)
|
6
|
-
|
6
|
+
kredis_connection_with __method__, name, key, config: config
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
instance_variable_get(ivar_symbol)
|
11
|
-
else
|
12
|
-
instance_variable_set(ivar_symbol, Kredis.proxy(kredis_key_evaluated(key) || kredis_key_for_attribute(name), config: config))
|
13
|
-
end
|
14
|
-
end
|
9
|
+
def kredis_string(name, key: nil, config: :shared)
|
10
|
+
kredis_connection_with __method__, name, key, config: config
|
15
11
|
end
|
16
12
|
|
17
|
-
def
|
18
|
-
|
13
|
+
def kredis_integer(name, key: nil, config: :shared)
|
14
|
+
kredis_connection_with __method__, name, key, config: config
|
15
|
+
end
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
instance_variable_get(ivar_symbol)
|
23
|
-
else
|
24
|
-
instance_variable_set(ivar_symbol, Kredis.list(kredis_key_evaluated(key) || kredis_key_for_attribute(name), config: config))
|
25
|
-
end
|
26
|
-
end
|
17
|
+
def kredis_datetime(name, key: nil, config: :shared)
|
18
|
+
kredis_connection_with __method__, name, key, config: config
|
27
19
|
end
|
28
20
|
|
29
|
-
def
|
30
|
-
|
21
|
+
def kredis_flag(name, key: nil, config: :shared)
|
22
|
+
kredis_connection_with __method__, name, key, config: config
|
31
23
|
|
32
|
-
define_method(name) do
|
33
|
-
|
34
|
-
instance_variable_get(ivar_symbol)
|
35
|
-
else
|
36
|
-
instance_variable_set(ivar_symbol, Kredis.unique_list(kredis_key_evaluated(key) || kredis_key_for_attribute(name), limit: limit, config: config))
|
37
|
-
end
|
24
|
+
define_method("#{name}?") do
|
25
|
+
send(name).marked?
|
38
26
|
end
|
39
27
|
end
|
40
28
|
|
41
|
-
def
|
42
|
-
|
29
|
+
def kredis_enum(name, key: nil, values:, default:, config: :shared)
|
30
|
+
kredis_connection_with __method__, name, key, values: values, default: default, config: config
|
31
|
+
end
|
43
32
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
instance_variable_set(ivar_symbol, Kredis.flag(kredis_key_evaluated(key) || kredis_key_for_attribute(name), config: config))
|
49
|
-
end
|
50
|
-
end
|
33
|
+
def kredis_json(name, key: nil, config: :shared)
|
34
|
+
kredis_connection_with __method__, name, key, config: config
|
35
|
+
end
|
51
36
|
|
52
|
-
|
53
|
-
|
54
|
-
end
|
37
|
+
def kredis_list(name, key: nil, typed: :string, config: :shared)
|
38
|
+
kredis_connection_with __method__, name, key, typed: typed, config: config
|
55
39
|
end
|
56
40
|
|
57
|
-
def
|
58
|
-
|
41
|
+
def kredis_unique_list(name, limit: nil, key: nil, typed: :string, config: :shared)
|
42
|
+
kredis_connection_with __method__, name, key, limit: limit, typed: typed, config: config
|
43
|
+
end
|
59
44
|
|
60
|
-
|
61
|
-
|
62
|
-
instance_variable_get(ivar_symbol)
|
63
|
-
else
|
64
|
-
instance_variable_set(ivar_symbol, Kredis.string(kredis_key_evaluated(key) || kredis_key_for_attribute(name), config: config))
|
65
|
-
end
|
66
|
-
end
|
45
|
+
def kredis_set(name, key: nil, typed: :string, config: :shared)
|
46
|
+
kredis_connection_with __method__, name, key, typed: typed, config: config
|
67
47
|
end
|
68
48
|
|
69
|
-
def
|
70
|
-
|
49
|
+
def kredis_slot(name, key: nil, config: :shared)
|
50
|
+
kredis_connection_with __method__, name, key, config: config
|
51
|
+
end
|
71
52
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
53
|
+
def kredis_slots(name, available:, key: nil, config: :shared)
|
54
|
+
kredis_connection_with __method__, name, key, available: available, config: config
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def kredis_connection_with(method, name, key, **options)
|
59
|
+
ivar_symbol = :"@#{name}_#{method}"
|
60
|
+
type = method.to_s.sub("kredis_", "")
|
61
|
+
|
62
|
+
define_method(name) do
|
63
|
+
if instance_variable_defined?(ivar_symbol)
|
64
|
+
instance_variable_get(ivar_symbol)
|
65
|
+
else
|
66
|
+
instance_variable_set(ivar_symbol, Kredis.send(type, kredis_key_evaluated(key) || kredis_key_for_attribute(name), **options))
|
67
|
+
end
|
77
68
|
end
|
78
69
|
end
|
79
|
-
end
|
80
70
|
end
|
81
71
|
|
82
72
|
private
|
@@ -87,7 +77,7 @@ module Kredis::Attributes
|
|
87
77
|
end
|
88
78
|
end
|
89
79
|
|
90
|
-
def kredis_key_for_attribute(name
|
80
|
+
def kredis_key_for_attribute(name)
|
91
81
|
"#{self.class.name.tableize.gsub("/", ":")}:#{id}:#{name}"
|
92
82
|
end
|
93
83
|
end
|
data/lib/kredis/connections.rb
CHANGED
@@ -5,10 +5,14 @@ module Kredis::Connections
|
|
5
5
|
mattr_accessor :configurator
|
6
6
|
|
7
7
|
def configured_for(name)
|
8
|
-
connections[name] ||=
|
8
|
+
connections[name] ||= begin
|
9
|
+
logger&.info "[Kredis] Connected to #{name}"
|
10
|
+
Redis.new configurator.config_for("redis/#{name}")
|
11
|
+
end
|
9
12
|
end
|
10
13
|
|
11
14
|
def clear_all
|
15
|
+
logger&.info "[Kredis] Connections all cleared"
|
12
16
|
connections.each_value(&:flushdb)
|
13
17
|
end
|
14
18
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
2
|
+
|
3
|
+
class Kredis::Migration
|
4
|
+
singleton_class.delegate :migrate_all, :migrate, to: :new
|
5
|
+
|
6
|
+
def initialize(config = :shared)
|
7
|
+
@redis = Kredis.configured_for config
|
8
|
+
@copy_sha = @redis.script "load", "redis.call('SETNX', KEYS[2], redis.call('GET', KEYS[1])); return 1;"
|
9
|
+
end
|
10
|
+
|
11
|
+
def migrate_all(key_pattern)
|
12
|
+
find_keys_in_batches_matching(key_pattern) do |keys|
|
13
|
+
@redis.multi do
|
14
|
+
keys.each do |key|
|
15
|
+
ids = key.scan(/\d+/).map(&:to_i)
|
16
|
+
migrate from: key, to: yield(key, *ids)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def migrate(from:, to:)
|
23
|
+
to = Kredis.namespaced_key(to)
|
24
|
+
|
25
|
+
if from != to
|
26
|
+
log_migration "Migrating key #{from} to #{to}"
|
27
|
+
@redis.evalsha @copy_sha, keys: [ from, to ]
|
28
|
+
else
|
29
|
+
log_migration "Skipping unaltered migration key #{from}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
SCAN_BATCH_SIZE = 1_000
|
35
|
+
|
36
|
+
def find_keys_in_batches_matching(key_pattern, &block)
|
37
|
+
cursor = "0"
|
38
|
+
begin
|
39
|
+
cursor, keys = @redis.scan(cursor, match: key_pattern, count: SCAN_BATCH_SIZE)
|
40
|
+
yield keys
|
41
|
+
end until cursor == "0"
|
42
|
+
end
|
43
|
+
|
44
|
+
def log_migration(message)
|
45
|
+
Kredis.logger&.debug "[Kredis Migration] #{message}"
|
46
|
+
end
|
47
|
+
end
|
data/lib/kredis/railtie.rb
CHANGED
@@ -3,7 +3,6 @@ require "rails/railtie"
|
|
3
3
|
module Kredis
|
4
4
|
class Railtie < ::Rails::Railtie
|
5
5
|
config.kredis = ActiveSupport::OrderedOptions.new
|
6
|
-
config.eager_load_namespaces << Kredis
|
7
6
|
|
8
7
|
initializer "kredis.testing" do
|
9
8
|
ActiveSupport.on_load(:active_support_test_case) do
|
@@ -13,7 +12,7 @@ module Kredis
|
|
13
12
|
end
|
14
13
|
|
15
14
|
initializer "kredis.logger" do
|
16
|
-
Kredis.logger = Rails.logger
|
15
|
+
Kredis.logger = config.kredis.logger || Rails.logger
|
17
16
|
end
|
18
17
|
|
19
18
|
initializer "kredis.configurator" do
|
@@ -21,12 +20,13 @@ module Kredis
|
|
21
20
|
end
|
22
21
|
|
23
22
|
initializer "kredis.attributes" do
|
23
|
+
# TODO: Add run_load_hooks to ActiveModel::Model so this runs.
|
24
24
|
ActiveSupport.on_load(:active_model) do
|
25
|
-
|
25
|
+
include Kredis::Attributes
|
26
26
|
end
|
27
27
|
|
28
28
|
ActiveSupport.on_load(:active_record) do
|
29
|
-
|
29
|
+
include Kredis::Attributes
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Kredis::TypeCasting
|
2
|
+
class InvalidType < StandardError; end
|
3
|
+
|
4
|
+
VALID_TYPES = %i[ string integer decimal float boolean datetime json ]
|
5
|
+
|
6
|
+
def type_to_string(value)
|
7
|
+
case value
|
8
|
+
when nil
|
9
|
+
""
|
10
|
+
when Integer
|
11
|
+
value.to_s
|
12
|
+
when BigDecimal
|
13
|
+
value.to_d
|
14
|
+
when Float
|
15
|
+
value.to_s
|
16
|
+
when TrueClass, FalseClass
|
17
|
+
value ? "t" : "f"
|
18
|
+
when Time, DateTime, ActiveSupport::TimeWithZone
|
19
|
+
value.to_f
|
20
|
+
when Hash
|
21
|
+
JSON.dump(value)
|
22
|
+
else
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def string_to_type(value, type)
|
28
|
+
raise InvalidType if type && !type.in?(VALID_TYPES)
|
29
|
+
|
30
|
+
case type
|
31
|
+
when nil, :string then value
|
32
|
+
when :integer then value.to_i
|
33
|
+
when :decimal then value.to_d
|
34
|
+
when :float then value.to_f
|
35
|
+
when :boolean then value == "t" ? true : false
|
36
|
+
when :datetime then Time.at(value.to_i)
|
37
|
+
when :json then JSON.load(value)
|
38
|
+
end if value.present?
|
39
|
+
end
|
40
|
+
|
41
|
+
def types_to_strings(values)
|
42
|
+
Array(values).flatten.map { |value| type_to_string(value) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def strings_to_types(values, type)
|
46
|
+
Array(values).flatten.map { |value| string_to_type(value, type) }
|
47
|
+
end
|
48
|
+
end
|
data/lib/kredis/types.rb
CHANGED
@@ -1,16 +1,42 @@
|
|
1
1
|
module Kredis::Types
|
2
2
|
def proxy(key, config: :shared)
|
3
|
-
|
3
|
+
Proxy.new configured_for(config), namespaced_key(key)
|
4
4
|
end
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
|
7
|
+
def scalar(key, typed: :string, default: nil, config: :shared)
|
8
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: typed, default: default
|
9
|
+
end
|
10
|
+
|
11
|
+
def string(key, default: nil, config: :shared)
|
12
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: :string, default: default
|
13
|
+
end
|
14
|
+
|
15
|
+
def integer(key, default: nil, config: :shared)
|
16
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: :integer, default: default
|
17
|
+
end
|
18
|
+
|
19
|
+
def decimal(key, default: nil, config: :shared)
|
20
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: :decimal, default: default
|
21
|
+
end
|
22
|
+
|
23
|
+
def float(key, default: nil, config: :shared)
|
24
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: :float, default: default
|
25
|
+
end
|
26
|
+
|
27
|
+
def boolean(key, default: nil, config: :shared)
|
28
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: :boolean, default: default
|
29
|
+
end
|
30
|
+
|
31
|
+
def datetime(key, default: nil, config: :shared)
|
32
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: :datetime, default: default
|
8
33
|
end
|
9
34
|
|
10
|
-
def
|
11
|
-
|
35
|
+
def json(key, default: nil, config: :shared)
|
36
|
+
Scalar.new configured_for(config), namespaced_key(key), typed: :json, default: default
|
12
37
|
end
|
13
38
|
|
39
|
+
|
14
40
|
def counter(key, expires_in: nil, config: :shared)
|
15
41
|
Counter.new configured_for(config), namespaced_key(key), expires_in: expires_in
|
16
42
|
end
|
@@ -19,24 +45,39 @@ module Kredis::Types
|
|
19
45
|
Flag.new configured_for(config), namespaced_key(key)
|
20
46
|
end
|
21
47
|
|
22
|
-
def
|
23
|
-
|
48
|
+
def enum(key, values:, default:, config: :shared)
|
49
|
+
Enum.new configured_for(config), namespaced_key(key), values: values, default: default
|
50
|
+
end
|
51
|
+
|
52
|
+
def list(key, typed: :string, config: :shared)
|
53
|
+
List.new configured_for(config), namespaced_key(key), typed: typed
|
54
|
+
end
|
55
|
+
|
56
|
+
def unique_list(key, typed: :string, limit: nil, config: :shared)
|
57
|
+
UniqueList.new configured_for(config), namespaced_key(key), typed: typed, limit: limit
|
58
|
+
end
|
59
|
+
|
60
|
+
def set(key, typed: :string, config: :shared)
|
61
|
+
Set.new configured_for(config), namespaced_key(key), typed: typed
|
24
62
|
end
|
25
63
|
|
26
|
-
def
|
27
|
-
|
64
|
+
def slot(key, config: :shared)
|
65
|
+
Slots.new configured_for(config), namespaced_key(key), available: 1
|
28
66
|
end
|
29
67
|
|
30
|
-
def
|
31
|
-
|
68
|
+
def slots(key, available:, config: :shared)
|
69
|
+
Slots.new configured_for(config), namespaced_key(key), available: available
|
32
70
|
end
|
33
71
|
end
|
34
72
|
|
35
73
|
require "kredis/types/proxy"
|
36
|
-
require "kredis/types/
|
37
|
-
|
74
|
+
require "kredis/types/proxying"
|
75
|
+
|
76
|
+
require "kredis/types/scalar"
|
38
77
|
require "kredis/types/counter"
|
39
78
|
require "kredis/types/flag"
|
40
|
-
require "kredis/types/
|
41
|
-
require "kredis/types/
|
42
|
-
require "kredis/types/
|
79
|
+
require "kredis/types/enum"
|
80
|
+
require "kredis/types/list"
|
81
|
+
require "kredis/types/unique_list"
|
82
|
+
require "kredis/types/set"
|
83
|
+
require "kredis/types/slots"
|
data/lib/kredis/types/counter.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
class Kredis::Types::Counter < Kredis::Types::
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
1
|
+
class Kredis::Types::Counter < Kredis::Types::Proxying
|
2
|
+
proxying :multi, :set, :incrby, :get
|
3
|
+
|
4
|
+
attr_accessor :expires_in
|
6
5
|
|
7
6
|
def increment(by: 1)
|
8
7
|
multi do
|
9
|
-
set 0, ex:
|
8
|
+
set 0, ex: expires_in, nx: true
|
10
9
|
incrby by
|
11
10
|
end
|
12
11
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Kredis::Types::Enum < Kredis::Types::Proxying
|
2
|
+
proxying :set, :get, :del
|
3
|
+
|
4
|
+
attr_accessor :values, :default
|
5
|
+
|
6
|
+
def initialize(...)
|
7
|
+
super
|
8
|
+
define_predicates_for_values
|
9
|
+
end
|
10
|
+
|
11
|
+
def value=(value)
|
12
|
+
if validated_choice = value.presence_in(values)
|
13
|
+
set validated_choice
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def value
|
18
|
+
get || default
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset
|
22
|
+
del
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def define_predicates_for_values
|
27
|
+
values.each do |defined_value|
|
28
|
+
define_singleton_method("#{defined_value}?") { value == defined_value }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/kredis/types/flag.rb
CHANGED
data/lib/kredis/types/list.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
|
-
class Kredis::Types::List < Kredis::Types::
|
1
|
+
class Kredis::Types::List < Kredis::Types::Proxying
|
2
|
+
proxying :lrange, :lrem, :lpush, :rpush
|
3
|
+
|
4
|
+
attr_accessor :typed
|
5
|
+
|
2
6
|
def elements
|
3
|
-
lrange(0, -1) || []
|
7
|
+
strings_to_types(lrange(0, -1) || [], typed)
|
4
8
|
end
|
9
|
+
alias to_a elements
|
5
10
|
|
6
|
-
def remove(elements)
|
7
|
-
|
11
|
+
def remove(*elements)
|
12
|
+
types_to_strings(elements).each { |element| lrem 0, element }
|
8
13
|
end
|
9
14
|
|
10
|
-
def prepend(elements)
|
11
|
-
lpush elements if
|
15
|
+
def prepend(*elements)
|
16
|
+
lpush types_to_strings(elements) if elements.flatten.any?
|
12
17
|
end
|
13
18
|
|
14
|
-
def append(elements)
|
15
|
-
rpush elements if
|
19
|
+
def append(*elements)
|
20
|
+
rpush types_to_strings(elements) if elements.flatten.any?
|
16
21
|
end
|
22
|
+
alias << append
|
17
23
|
end
|
data/lib/kredis/types/proxy.rb
CHANGED
@@ -1,14 +1,26 @@
|
|
1
1
|
class Kredis::Types::Proxy
|
2
|
-
|
2
|
+
attr_accessor :redis, :key
|
3
|
+
|
4
|
+
def initialize(redis, key, **options)
|
3
5
|
@redis, @key = redis, key
|
6
|
+
options.each { |key, value| send("#{key}=", value) }
|
4
7
|
end
|
5
8
|
|
6
9
|
def multi(...)
|
7
|
-
|
10
|
+
redis.multi(...)
|
8
11
|
end
|
9
12
|
|
10
13
|
def method_missing(method, *args, **kwargs)
|
11
|
-
Kredis.logger&.debug
|
12
|
-
|
14
|
+
Kredis.logger&.debug log_message(method, *args, **kwargs)
|
15
|
+
redis.public_send method, key, *args, **kwargs
|
13
16
|
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def log_message(method, *args, **kwargs)
|
20
|
+
args = args.flatten.compact_blank.presence
|
21
|
+
kwargs = kwargs.compact_blank.presence
|
22
|
+
type_name = self.class.name.split("::").last
|
23
|
+
|
24
|
+
"[Kredis #{type_name}] #{method.upcase} #{key} #{args&.inspect} #{kwargs&.inspect}".chomp
|
25
|
+
end
|
14
26
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
2
|
+
|
3
|
+
class Kredis::Types::Proxying
|
4
|
+
attr_accessor :proxy, :redis, :key
|
5
|
+
|
6
|
+
def self.proxying(*commands)
|
7
|
+
delegate *commands, to: :proxy
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(redis, key, **options)
|
11
|
+
@redis, @key = redis, key
|
12
|
+
@proxy = Kredis::Types::Proxy.new(redis, key)
|
13
|
+
options.each { |key, value| send("#{key}=", value) }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
delegate :type_to_string, :string_to_type, :types_to_strings, :strings_to_types, to: :Kredis
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Kredis::Types::Scalar < Kredis::Types::Proxying
|
2
|
+
proxying :set, :get, :exists?, :del
|
3
|
+
|
4
|
+
attr_accessor :typed, :default
|
5
|
+
|
6
|
+
def value=(value)
|
7
|
+
set type_to_string(value)
|
8
|
+
end
|
9
|
+
|
10
|
+
def value
|
11
|
+
string_to_type(get, typed) || default
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
get || default&.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def assigned?
|
19
|
+
exists?
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear
|
23
|
+
del
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Kredis::Types::Set < Kredis::Types::Proxying
|
2
|
+
proxying :smembers, :sadd, :srem, :multi, :del, :sismember, :scard, :spop
|
3
|
+
|
4
|
+
attr_accessor :typed
|
5
|
+
|
6
|
+
def members
|
7
|
+
strings_to_types(smembers || [], typed).sort
|
8
|
+
end
|
9
|
+
alias to_a members
|
10
|
+
|
11
|
+
def add(*members)
|
12
|
+
sadd types_to_strings(members) if members.flatten.any?
|
13
|
+
end
|
14
|
+
alias << add
|
15
|
+
|
16
|
+
def remove(*members)
|
17
|
+
srem types_to_strings(members) if members.flatten.any?
|
18
|
+
end
|
19
|
+
|
20
|
+
def replace(*members)
|
21
|
+
multi do
|
22
|
+
del
|
23
|
+
add members
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def include?(member)
|
28
|
+
sismember type_to_string(member)
|
29
|
+
end
|
30
|
+
|
31
|
+
def size
|
32
|
+
scard
|
33
|
+
end
|
34
|
+
|
35
|
+
def take
|
36
|
+
spop
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear
|
40
|
+
del
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Kredis::Types::Slots < Kredis::Types::Proxying
|
2
|
+
class NotAvailable < StandardError; end
|
3
|
+
|
4
|
+
proxying :incr, :decr, :get, :del
|
5
|
+
|
6
|
+
attr_accessor :available
|
7
|
+
|
8
|
+
def reserve
|
9
|
+
if block_given?
|
10
|
+
begin
|
11
|
+
if reserve
|
12
|
+
yield
|
13
|
+
true
|
14
|
+
else
|
15
|
+
false
|
16
|
+
end
|
17
|
+
ensure
|
18
|
+
release
|
19
|
+
end
|
20
|
+
else
|
21
|
+
if incr <= available
|
22
|
+
true
|
23
|
+
else
|
24
|
+
release
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def release
|
31
|
+
decr
|
32
|
+
end
|
33
|
+
|
34
|
+
def available?
|
35
|
+
get.to_i < available
|
36
|
+
end
|
37
|
+
|
38
|
+
def reset
|
39
|
+
del
|
40
|
+
end
|
41
|
+
end
|
@@ -1,23 +1,23 @@
|
|
1
1
|
# You'd normally call this a set, but Redis already has another data type for that
|
2
2
|
class Kredis::Types::UniqueList < Kredis::Types::List
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
3
|
+
proxying :multi, :ltrim
|
4
|
+
|
5
|
+
attr_accessor :typed, :limit
|
7
6
|
|
8
7
|
def prepend(elements)
|
9
8
|
multi do
|
10
9
|
remove elements
|
11
10
|
super
|
12
|
-
ltrim 0, (
|
13
|
-
end if Array(elements).any?
|
11
|
+
ltrim 0, (limit - 1) if limit
|
12
|
+
end if Array(elements).flatten.any?
|
14
13
|
end
|
15
14
|
|
16
15
|
def append(elements)
|
17
16
|
multi do
|
18
17
|
remove elements
|
19
18
|
super
|
20
|
-
ltrim (
|
21
|
-
end if Array(elements).any?
|
19
|
+
ltrim (limit - 1), -1 if limit
|
20
|
+
end if Array(elements).flatten.any?
|
22
21
|
end
|
22
|
+
alias << append
|
23
23
|
end
|
data/lib/kredis/version.rb
CHANGED
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: 0.
|
4
|
+
version: 0.2.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: 2021-
|
12
|
+
date: 2021-02-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -50,17 +50,20 @@ files:
|
|
50
50
|
- lib/kredis.rb
|
51
51
|
- lib/kredis/attributes.rb
|
52
52
|
- lib/kredis/connections.rb
|
53
|
-
- lib/kredis/
|
53
|
+
- lib/kredis/migration.rb
|
54
54
|
- lib/kredis/namespace.rb
|
55
55
|
- lib/kredis/railtie.rb
|
56
|
+
- lib/kredis/type_casting.rb
|
56
57
|
- lib/kredis/types.rb
|
57
58
|
- lib/kredis/types/counter.rb
|
59
|
+
- lib/kredis/types/enum.rb
|
58
60
|
- lib/kredis/types/flag.rb
|
59
|
-
- lib/kredis/types/integer.rb
|
60
61
|
- lib/kredis/types/list.rb
|
61
|
-
- lib/kredis/types/mutex.rb
|
62
62
|
- lib/kredis/types/proxy.rb
|
63
|
-
- lib/kredis/types/
|
63
|
+
- lib/kredis/types/proxying.rb
|
64
|
+
- lib/kredis/types/scalar.rb
|
65
|
+
- lib/kredis/types/set.rb
|
66
|
+
- lib/kredis/types/slots.rb
|
64
67
|
- lib/kredis/types/unique_list.rb
|
65
68
|
- lib/kredis/version.rb
|
66
69
|
homepage: https://github.com/rails/kredis
|
data/lib/kredis/logger.rb
DELETED
data/lib/kredis/types/integer.rb
DELETED
data/lib/kredis/types/mutex.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
class Kredis::Types::Mutex < Kredis::Types::Proxy
|
2
|
-
def initialize(redis, key, expires_in: nil)
|
3
|
-
@expires_in = expires_in
|
4
|
-
super redis, key
|
5
|
-
end
|
6
|
-
|
7
|
-
def lock
|
8
|
-
set 1, ex: @expires_in
|
9
|
-
end
|
10
|
-
|
11
|
-
def unlock
|
12
|
-
del
|
13
|
-
end
|
14
|
-
|
15
|
-
def locked?
|
16
|
-
get
|
17
|
-
end
|
18
|
-
|
19
|
-
def synchronize
|
20
|
-
lock
|
21
|
-
yield
|
22
|
-
ensure
|
23
|
-
unlock
|
24
|
-
end
|
25
|
-
end
|
data/lib/kredis/types/string.rb
DELETED