Skip to content

Default values for entries #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
133a0e0
Add default proxy value
tleish Jun 10, 2022
4eff947
Add default list values
tleish Jun 10, 2022
903f2a9
Add default to unique_list
tleish Jun 10, 2022
a668f78
Add default to flag
tleish Jun 10, 2022
35dc9bf
Add default to string
tleish Jun 10, 2022
e6bcbbd
Add default to integer
tleish Jun 10, 2022
ba0092c
Add default to decimal
tleish Jun 10, 2022
52b308b
Add default to datetime
tleish Jun 10, 2022
de0e5b1
Add default to float
tleish Jun 10, 2022
77499ed
Add default proc to enum
tleish Jun 10, 2022
46fa83a
rename default_value method to default
tleish Jun 10, 2022
abdf95a
Add default proc to set
tleish Jun 10, 2022
4933f6c
Add additional unit tests
tleish Jun 10, 2022
321d33c
Add default proc to json and counter
tleish Jun 10, 2022
411d04a
Add default proc to hash and boolean
tleish Jun 11, 2022
ed3cbd8
Add before_method_hook
tleish Jun 11, 2022
1030836
Fix for ruby 3
tleish Jun 11, 2022
1bb9288
refactor Kredis::Types::BeforeMethodsHook#before_methods
tleish Jun 20, 2022
10ceac9
code review updates
tleish Jun 20, 2022
1bff6bf
merge main
tleish Jun 29, 2022
7e85720
fix code review feedback
tleish Jul 15, 2022
180f57c
Match indentation
dhh Jul 15, 2022
bf2ba58
create custom callnx method and refactor
tleish Jul 20, 2022
d0146ee
add additional default options to set
tleish Jul 20, 2022
90d9208
move primary #set_default method to Kredis::Types::Proxying
tleish Jul 20, 2022
5c4664b
updated enum multi block to use standar [-1] pattern instead of .last
tleish Jul 20, 2022
ddf555f
refactor init_default_in_multi to not use multi if default not defined
tleish Jul 20, 2022
ef2eacb
refactor multi in Kredis::Types::Proxying
tleish Jul 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 37 additions & 28 deletions lib/kredis/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,56 @@ module Kredis::Attributes
extend ActiveSupport::Concern

class_methods do
def kredis_proxy(name, key: nil, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change
def kredis_proxy(name, key: nil, default: nil, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change
end

def kredis_string(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_string(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

def kredis_integer(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_integer(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

def kredis_decimal(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_decimal(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

def kredis_datetime(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_datetime(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

def kredis_flag(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_flag(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in

define_method("#{name}?") do
send(name).marked?
end
end

def kredis_float(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_float(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

def kredis_enum(name, key: nil, values:, default:, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, values: values, default: default, config: config, after_change: after_change
end

def kredis_json(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_json(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

def kredis_list(name, key: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
def kredis_list(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
end

def kredis_unique_list(name, limit: nil, key: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, limit: limit, typed: typed, config: config, after_change: after_change
def kredis_unique_list(name, limit: nil, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, default: default, limit: limit, typed: typed, config: config, after_change: after_change
end

def kredis_set(name, key: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
def kredis_set(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
end

def kredis_slot(name, key: nil, config: :shared, after_change: nil)
Expand All @@ -62,16 +62,16 @@ def kredis_slots(name, available:, key: nil, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, available: available, config: config, after_change: after_change
end

def kredis_counter(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_counter(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

def kredis_hash(name, key: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
def kredis_hash(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
end

def kredis_boolean(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
def kredis_boolean(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
end

private
Expand All @@ -84,6 +84,7 @@ def kredis_connection_with(method, name, key, **options)
if instance_variable_defined?(ivar_symbol)
instance_variable_get(ivar_symbol)
else
options.merge!(default: kredis_default_evaluated(options[:default])) if options[:default]
new_type = Kredis.send(type, kredis_key_evaluated(key) || kredis_key_for_attribute(name), **options)
instance_variable_set ivar_symbol,
after_change ? enrich_after_change_with_record_access(new_type, after_change) : new_type
Expand Down Expand Up @@ -115,4 +116,12 @@ def enrich_after_change_with_record_access(type, original_after_change)
when Symbol then Kredis::Types::CallbacksProxy.new(type, ->(_) { send(original_after_change) })
end
end

def kredis_default_evaluated(default)
case default
when Proc then Proc.new { default.call(self) }
when Symbol then send(default)
else default
end
end
end
6 changes: 5 additions & 1 deletion lib/kredis/type/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ def type
end

def cast_value(value)
JSON.load(value)
if value.is_a? Hash
value.stringify_keys
else
JSON.load(value)
end
end

def serialize(value)
Expand Down
28 changes: 14 additions & 14 deletions lib/kredis/types.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Kredis::Types
autoload :CallbacksProxy, "kredis/types/callbacks_proxy"

def proxy(key, config: :shared, after_change: nil)
type_from(Proxy, config, key, after_change: after_change)
def proxy(key, default: nil, config: :shared, after_change: nil)
type_from(Proxy, config, key, after_change: after_change, default: default)
end


Expand Down Expand Up @@ -39,36 +39,36 @@ def json(key, default: nil, config: :shared, after_change: nil, expires_in: nil)
end


def counter(key, expires_in: nil, config: :shared, after_change: nil)
type_from(Counter, config, key, after_change: after_change, expires_in: expires_in)
def counter(key, expires_in: nil, default: nil, config: :shared, after_change: nil)
type_from(Counter, config, key, after_change: after_change, default: default, expires_in: expires_in)
end

def cycle(key, values:, expires_in: nil, config: :shared, after_change: nil)
type_from(Cycle, config, key, after_change: after_change, values: values, expires_in: expires_in)
end

def flag(key, config: :shared, after_change: nil, expires_in: nil)
type_from(Flag, config, key, after_change: after_change, expires_in: expires_in)
def flag(key, default: nil, config: :shared, after_change: nil, expires_in: nil)
type_from(Flag, config, key, after_change: after_change, default: default, expires_in: expires_in)
end

def enum(key, values:, default:, config: :shared, after_change: nil)
type_from(Enum, config, key, after_change: after_change, values: values, default: default)
end

def hash(key, typed: :string, config: :shared, after_change: nil)
type_from(Hash, config, key, after_change: after_change, typed: typed)
def hash(key, typed: :string, default: nil, config: :shared, after_change: nil)
type_from(Hash, config, key, after_change: after_change, default: default, typed: typed)
end

def list(key, typed: :string, config: :shared, after_change: nil)
type_from(List, config, key, after_change: after_change, typed: typed)
def list(key, default: nil, typed: :string, config: :shared, after_change: nil)
type_from(List, config, key, after_change: after_change, default: default, typed: typed)
end

def unique_list(key, typed: :string, limit: nil, config: :shared, after_change: nil)
type_from(UniqueList, config, key, after_change: after_change, typed: typed, limit: limit)
def unique_list(key, default: nil, typed: :string, limit: nil, config: :shared, after_change: nil)
type_from(UniqueList, config, key, after_change: after_change, default: default, typed: typed, limit: limit)
end

def set(key, typed: :string, config: :shared, after_change: nil)
type_from(Set, config, key, after_change: after_change, typed: typed)
def set(key, default: nil, typed: :string, config: :shared, after_change: nil)
type_from(Set, config, key, after_change: after_change, default: default, typed: typed)
end

def slot(key, config: :shared, after_change: nil)
Expand Down
21 changes: 12 additions & 9 deletions lib/kredis/types/counter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,27 @@ class Kredis::Types::Counter < Kredis::Types::Proxying
attr_accessor :expires_in

def increment(by: 1)
multi do
set 0, ex: expires_in, nx: true
incrby by
end[-1]
init_default_in_multi { incrby by }
end

def decrement(by: 1)
multi do
set 0, ex: expires_in, nx: true
decrby by
end[-1]
init_default_in_multi { decrby by }
end

def value
get.to_i
(get || default).to_i
end

def reset
del
end

private
def set_default(value)
set value.to_i, ex: expires_in, nx: true
end

def default
super.to_i
end
end
4 changes: 2 additions & 2 deletions lib/kredis/types/enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
class Kredis::Types::Enum < Kredis::Types::Proxying
proxying :set, :get, :del, :exists?

attr_accessor :values, :default
attr_accessor :values

def initialize(...)
super
Expand All @@ -17,7 +17,7 @@ def value=(value)
end

def value
get || default
get || default.presence_in(values)
end

def reset
Expand Down
30 changes: 22 additions & 8 deletions lib/kredis/types/hash.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
require "active_support/core_ext/hash"

class Kredis::Types::Hash < Kredis::Types::Proxying
proxying :hget, :hset, :hmget, :hdel, :hgetall, :hkeys, :hvals, :del, :exists?
ZERO_FIELDS_ADDED = 0

proxying :hset, :hdel, :hgetall, :del, :exists?, :multi, :callnx
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed some of these proxying methods because they were no longer used in the class. Do they need to be kept because of the public api others may have tied into?


attr_accessor :typed

def [](key)
string_to_type(hget(key), typed)
string_to_type(entries[key], typed)
end

def []=(key, value)
update key => value
end


def update(**entries)
hset entries.transform_values{ |val| type_to_string(val, typed) } if entries.flatten.any?
return ZERO_FIELDS_ADDED if entries.flatten.blank?

init_default_in_multi do
hset entries.transform_values{ |val| type_to_string(val, typed) }
end
end

def values_at(*keys)
strings_to_types(hmget(keys) || [], typed)
strings_to_types(entries.values_at(*keys) || [], typed)
end

def delete(*keys)
hdel keys if keys.flatten.any?
return ZERO_FIELDS_ADDED if keys.flatten.blank?

init_default_in_multi { hdel keys }
end

def remove
Expand All @@ -31,15 +40,20 @@ def remove
alias clear remove

def entries
(hgetall || {}).transform_values { |val| string_to_type(val, typed) }.with_indifferent_access
(hgetall.presence || default || {}).transform_values { |val| string_to_type(val, typed) }.with_indifferent_access
end
alias to_h entries

def keys
hkeys || []
entries.keys || []
end

def values
strings_to_types(hvals || [], typed)
strings_to_types(entries.values || [], typed)
end

private
def set_default(entries)
callnx(:hset, entries.transform_values{ |val| type_to_string(val, typed) })
end
end
28 changes: 23 additions & 5 deletions lib/kredis/types/list.rb
Original file line number Diff line number Diff line change
@@ -1,27 +1,45 @@
class Kredis::Types::List < Kredis::Types::Proxying
proxying :lrange, :lrem, :lpush, :rpush, :exists?, :del
proxying :lrange, :lrem, :lpush, :rpush, :exists?, :del, :callnx

attr_accessor :typed

def elements
strings_to_types(lrange(0, -1) || [], typed)
values = init_default_in_multi { lrange(0, -1) }
strings_to_types(values || [], typed)
end
alias to_a elements

def remove(*elements)
types_to_strings(elements, typed).each { |element| lrem 0, element }
return [] if elements.flatten.blank?

init_default_in_multi do
types_to_strings(elements, typed).each { |element| lrem 0, element }
end
end

def prepend(*elements)
lpush types_to_strings(elements, typed) if elements.flatten.any?
return self.elements.count if elements.flatten.blank?

init_default_in_multi do
lpush types_to_strings(elements, typed)
end
end

def append(*elements)
rpush types_to_strings(elements, typed) if elements.flatten.any?
return self.elements.count if elements.flatten.blank?

init_default_in_multi do
rpush types_to_strings(elements, typed)
end
end
alias << append

def clear
del
end

private
def set_default(elements)
callnx(:rpush, types_to_strings(Array(elements), typed))
end
end
17 changes: 17 additions & 0 deletions lib/kredis/types/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ def initialize(redis, key, **options)
end

def multi(*args, **kwargs, &block)
return block.call if self.pipeline # return and execute block for nested multi pipeline

redis.multi(*args, **kwargs) do |pipeline|
self.pipeline = pipeline
block.call
Expand All @@ -28,6 +30,21 @@ def method_missing(method, *args, **kwargs)
end
end

CALLNX = <<~LUA
if redis.call("exists", KEYS[1]) == 0 then
redis.call("%{method}", KEYS[1], unpack(ARGV))
end
LUA
def callnx(method, values)
safe_method_name = method.to_s.gsub(/[^a-z_]/, '_')
cmd = format(CALLNX, method: safe_method_name)
Kredis.instrument :proxy, **log_message(:callnx, *([safe_method_name] + Array(values))) do
failsafe do
redis.eval cmd, Array(key), Array(values).flatten
end
end
end

private
def redis
pipeline || @redis
Expand Down
Loading