Skip to content
4 changes: 4 additions & 0 deletions lib/kredis/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def kredis_flag(name, key: nil, config: :shared, after_change: nil)
end
end

def kredis_float(name, key: nil, config: :shared, after_change: nil)
kredis_connection_with __method__, name, key, config: config, after_change: after_change
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
Expand Down
15 changes: 15 additions & 0 deletions lib/kredis/type/datetime.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Kredis
module Type
class DateTime < ActiveModel::Type::DateTime
def serialize(value)
super&.iso8601(9)
end

def cast_value(value)
super&.to_datetime
end
end
end
end
19 changes: 19 additions & 0 deletions lib/kredis/type/json.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module Kredis
module Type
class Json < ActiveModel::Type::Value
def type
:json
end

def cast_value(value)
JSON.load(value)
end

def serialize(value)
JSON.dump(value)
end
end
end
end
56 changes: 22 additions & 34 deletions lib/kredis/type_casting.rb
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
require "json"
require "active_model/type"
require "kredis/type/json"
require "kredis/type/datetime"

module Kredis::TypeCasting
class InvalidType < StandardError; end

VALID_TYPES = %i[ string integer decimal float boolean datetime json ]

def type_to_string(value)
case value
when nil
""
when Integer
value.to_s
when BigDecimal
value.to_d
when Float
value.to_s
when TrueClass, FalseClass
value ? "t" : "f"
when Time, DateTime, ActiveSupport::TimeWithZone
value.iso8601(9)
when Hash
JSON.dump(value)
else
value
end
TYPES = {
string: ActiveModel::Type::String.new,
integer: ActiveModel::Type::Integer.new,
decimal: ActiveModel::Type::Decimal.new,
float: ActiveModel::Type::Float.new,
boolean: ActiveModel::Type::Boolean.new,
datetime: Kredis::Type::DateTime.new,
json: Kredis::Type::Json.new
}

def type_to_string(value, type)
raise InvalidType if type && !TYPES.key?(type)

TYPES[type || :string].serialize(value)
end

def string_to_type(value, type)
raise InvalidType if type && !VALID_TYPES.include?(type)

case type
when nil, :string then value
when :integer then value.to_i
when :decimal then value.to_d
when :float then value.to_f
when :boolean then value == "t" ? true : false
when :datetime then Time.iso8601(value)
when :json then JSON.load(value)
end if value.present?
raise InvalidType if type && !TYPES.key?(type)

TYPES[type || :string].cast(value)
end

def types_to_strings(values)
Array(values).flatten.map { |value| type_to_string(value) }
def types_to_strings(values, type)
Array(values).flatten.map { |value| type_to_string(value, type) }
end

def strings_to_types(values, type)
Expand Down
2 changes: 2 additions & 0 deletions lib/kredis/types/enum.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "active_support/core_ext/object/inclusion"

class Kredis::Types::Enum < Kredis::Types::Proxying
proxying :set, :get, :del

Expand Down
7 changes: 3 additions & 4 deletions lib/kredis/types/hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,20 @@ def []=(key, value)
update key => value
end


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

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

def delete(*keys)
hdel types_to_strings(keys) if keys.flatten.any?
hdel keys if keys.flatten.any?
end

def remove
del
del
end

def entries
Expand Down
6 changes: 3 additions & 3 deletions lib/kredis/types/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ def elements
alias to_a elements

def remove(*elements)
types_to_strings(elements).each { |element| lrem 0, element }
types_to_strings(elements, typed).each { |element| lrem 0, element }
end

def prepend(*elements)
lpush types_to_strings(elements) if elements.flatten.any?
lpush types_to_strings(elements, typed) if elements.flatten.any?
end

def append(*elements)
rpush types_to_strings(elements) if elements.flatten.any?
rpush types_to_strings(elements, typed) if elements.flatten.any?
end
alias << append
end
4 changes: 2 additions & 2 deletions lib/kredis/types/scalar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ class Kredis::Types::Scalar < Kredis::Types::Proxying
attr_accessor :typed, :default, :expires_in

def value=(value)
set type_to_string(value), ex: expires_in
set type_to_string(value, typed), ex: expires_in
end

def value
value_after_casting = string_to_type(get, typed)

if value_after_casting.nil?
default
else
Expand Down
6 changes: 3 additions & 3 deletions lib/kredis/types/set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ def members
alias to_a members

def add(*members)
sadd types_to_strings(members) if members.flatten.any?
sadd types_to_strings(members, typed) if members.flatten.any?
end
alias << add

def remove(*members)
srem types_to_strings(members) if members.flatten.any?
srem types_to_strings(members, typed) if members.flatten.any?
end

def replace(*members)
Expand All @@ -25,7 +25,7 @@ def replace(*members)
end

def include?(member)
sismember type_to_string(member)
sismember type_to_string(member, typed)
end

def size
Expand Down
9 changes: 8 additions & 1 deletion test/attributes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Person
kredis_integer :age
kredis_decimal :salary
kredis_datetime :last_seen_at
kredis_float :height
kredis_enum :morning, values: %w[ bright blue black ], default: "bright"
kredis_slot :attention
kredis_slots :meetings, available: 3
Expand Down Expand Up @@ -103,7 +104,13 @@ class AttributesTest < ActiveSupport::TestCase
test "decimal" do
@person.salary.value = 10000.07
assert_equal 10000.07, @person.salary.value
assert_equal "10000.07", @person.salary.to_s
assert_equal "0.1000007e5", @person.salary.to_s
end

test "float" do
@person.height.value = 1.85
assert_equal 1.85, @person.height.value
assert_equal "1.85", @person.height.to_s
end

test "datetime" do
Expand Down
8 changes: 7 additions & 1 deletion test/types/scalar_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class ScalarTest < ActiveSupport::TestCase
assert_nil datetime.value
end

test "datetime casting Dates" do
datetime = Kredis.datetime "myscalar"
datetime.value = Date.current
assert_equal Date.current.to_datetime, datetime.value
end

test "json" do
json = Kredis.json "myscalar"
json.value = { "one" => 1, "string" => "hello" }
Expand All @@ -58,7 +64,7 @@ class ScalarTest < ActiveSupport::TestCase

test "invalid type" do
nothere = Kredis.scalar "myscalar", typed: :nothere
nothere.value = true
assert_raises(Kredis::TypeCasting::InvalidType) { nothere.value = true }

assert_raises(Kredis::TypeCasting::InvalidType) { nothere.value }
end
Expand Down
4 changes: 4 additions & 0 deletions test/types/unique_list_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,9 @@ class UniqueListTest < ActiveSupport::TestCase

@list.remove(2)
assert_equal [ 1 ], @list.elements

@list.append [ "1-a", 2 ]

assert_equal [ 1, 2 ], @list.elements
end
end