Class: Dynomite::Item::Typecaster

Inherits:
Object
  • Object
show all
Defined in:
lib/dynomite/item/typecaster.rb

Constant Summary collapse

FALSEY =

IE: field :price, type: :integer For most cases, we rely on aws-sdk-dynamodb to do the typecasting by inference.

The method also helps keep track of where we cast_to_type It’s only a few spots this provides an easy to search for it. See: rubyonjets.com/docs/database/dynamodb/model/typecasting/

[false, 'false', 'FALSE', 0, '0', 'f', 'F', 'off', 'OFF']
REGEXP =
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/

Instance Method Summary collapse

Constructor Details

#initialize(model) ⇒ Typecaster

Returns a new instance of Typecaster.



6
7
8
# File 'lib/dynomite/item/typecaster.rb', line 6

def initialize(model)
  @model = model
end

Instance Method Details

#cast_to_attribute_type(attribute_name, attribute_value) ⇒ Object

string to float if attribute_type is N number to string if attribute_type is S



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/dynomite/item/typecaster.rb', line 68

def cast_to_attribute_type(attribute_name, attribute_value)
  definition = @model.attribute_definitions.find { |d| d[:attribute_name] == attribute_name.to_s }
  if definition
    case definition[:attribute_type]
    when "N"  # Number
      attribute_value.to_f
    when "S"  # String
      attribute_value.to_s
    when "BOOL" # Boolean
      attribute_value == true
    else
      attribute_value # passthrough
    end
  else
    attribute_value # passthrough
  end
end

#cast_to_time(value, on: :read) ⇒ Object

datetime to string



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/dynomite/item/typecaster.rb', line 50

def cast_to_time(value, on: :read)
  if on == :read
    if value.is_a?(String)
      Time.parse(value) # 2023-08-26T14:35:37Z
    elsif value.respond_to?(:to_datetime) # time-like object already Time or DateTime
      value
    end
  else # write or raw (for querying)
    if value.respond_to?(:to_datetime) && !value.is_a?(String)
      value.utc.strftime('%Y-%m-%dT%TZ') # Timestamp format iso8601 from AWS docs: http://amzn.to/2z98Bdc
    else
      value # passthrough string
    end
  end
end

#cast_to_type(type, value, on: :read) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/dynomite/item/typecaster.rb', line 34

def cast_to_type(type, value, on: :read)
  case type
  when :integer
    value.to_i
  when :boolean
    !FALSEY.include?(value)
  when :time
    cast_to_time(value, on: on)
  when :string
    value.to_s # force to string
  else # :infer
    value # passthrough and let aws-sdk-dynamodb handle it
  end
end

#dump(data, depth = 0) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/dynomite/item/typecaster.rb', line 10

def dump(data, depth=0)
  case data
  when Array
    data.map! { |v| dump(v, depth+1) }
  when Hash
    data.each_with_object({}) do |(k,v), dumped|
      if depth == 0
        v = cast_to_attribute_type(k, v) # cast to attribute type if defined
      end
      dumped[k] = dump(v, depth+1)
      dumped
    end
  else
    data # pass through
  end
end

#load(data) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/dynomite/item/typecaster.rb', line 86

def load(data)
  case data
  when Array
    data.map! { |v| load(v) }
  when Hash
    data.each_with_object({}) do |(k,v), loaded|
      loaded[k] = load(v)
      loaded
    end
  else
    load_item(data)
  end
end

#load_item(obj) ⇒ Object



101
102
103
104
# File 'lib/dynomite/item/typecaster.rb', line 101

def load_item(obj)
  return obj unless obj.is_a?(String)
  obj.match(REGEXP) ? Time.parse(obj) : obj
end