Class: Amount::ActiveRecord::AttributeDefinition

Inherits:
Object
  • Object
show all
Defined in:
lib/amount/active_record/attribute_definition.rb

Overview

Describes one ‘has_amount` attribute and its backing columns.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, symbol: nil) ⇒ AttributeDefinition

Returns a new instance of AttributeDefinition.



9
10
11
12
13
# File 'lib/amount/active_record/attribute_definition.rb', line 9

def initialize(name, symbol: nil)
  @name = name.to_sym
  @symbol = symbol&.to_sym
  @type = Type.new(symbol: @symbol)
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



7
8
9
# File 'lib/amount/active_record/attribute_definition.rb', line 7

def name
  @name
end

#symbolObject (readonly)

Returns the value of attribute symbol.



7
8
9
# File 'lib/amount/active_record/attribute_definition.rb', line 7

def symbol
  @symbol
end

#typeObject (readonly)

Returns the value of attribute type.



7
8
9
# File 'lib/amount/active_record/attribute_definition.rb', line 7

def type
  @type
end

Instance Method Details

#atomic_columnObject



19
20
21
# File 'lib/amount/active_record/attribute_definition.rb', line 19

def atomic_column
  "#{name}_atomic"
end

#before_last_save(record) ⇒ Object



118
119
120
# File 'lib/amount/active_record/attribute_definition.rb', line 118

def before_last_save(record)
  saved_change(record)&.first
end

#between_relation(model, lower, upper) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/amount/active_record/attribute_definition.rb', line 74

def between_relation(model, lower, upper)
  lower_amount = type.cast(lower)
  upper_amount = type.cast(upper)
  ensure_same_query_symbol!(lower_amount, upper_amount)

  relation_for_symbol(model, lower_amount)
    .where("#{atomic_column} >= ? AND #{atomic_column} <= ?", lower_amount.atomic, upper_amount.atomic)
end

#build_from_values(values) ⇒ Object



49
50
51
# File 'lib/amount/active_record/attribute_definition.rb', line 49

def build_from_values(values)
  type.deserialize(values[atomic_column], fixed_symbol? ? symbol : values[symbol_column])
end

#change(record) ⇒ Object



91
92
93
94
95
# File 'lib/amount/active_record/attribute_definition.rb', line 91

def change(record)
  return unless changed?(record)

  [value_in_database(record), read(record)]
end

#changed?(record) ⇒ Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/amount/active_record/attribute_definition.rb', line 87

def changed?(record)
  component_columns.any? { |column| record.will_save_change_to_attribute?(column) }
end

#component_columnsObject



27
28
29
30
31
# File 'lib/amount/active_record/attribute_definition.rb', line 27

def component_columns
  columns = [atomic_column]
  columns << symbol_column unless fixed_symbol?
  columns
end

#currency_relation(model, symbol) ⇒ Object



83
84
85
# File 'lib/amount/active_record/attribute_definition.rb', line 83

def currency_relation(model, symbol)
  model.where(symbol_column => symbol.to_s)
end

#fixed_symbol?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/amount/active_record/attribute_definition.rb', line 15

def fixed_symbol?
  !@symbol.nil?
end

#greater_than_or_equal_relation(model, value) ⇒ Object



62
63
64
# File 'lib/amount/active_record/attribute_definition.rb', line 62

def greater_than_or_equal_relation(model, value)
  query_relation_with_operator(model, value, :>=)
end

#greater_than_relation(model, value) ⇒ Object



58
59
60
# File 'lib/amount/active_record/attribute_definition.rb', line 58

def greater_than_relation(model, value)
  query_relation_with_operator(model, value, :>)
end

#less_than_or_equal_relation(model, value) ⇒ Object



70
71
72
# File 'lib/amount/active_record/attribute_definition.rb', line 70

def less_than_or_equal_relation(model, value)
  query_relation_with_operator(model, value, :<=)
end

#less_than_relation(model, value) ⇒ Object



66
67
68
# File 'lib/amount/active_record/attribute_definition.rb', line 66

def less_than_relation(model, value)
  query_relation_with_operator(model, value, :<)
end

#query_relation(model, value) ⇒ Object



53
54
55
56
# File 'lib/amount/active_record/attribute_definition.rb', line 53

def query_relation(model, value)
  amount = type.cast(value)
  relation_for_symbol(model, amount).where(atomic_column => amount.atomic)
end

#read(record) ⇒ Object



33
34
35
# File 'lib/amount/active_record/attribute_definition.rb', line 33

def read(record)
  type.deserialize(record.read_attribute(atomic_column), resolved_symbol(record))
end

#saved_change(record) ⇒ Object



109
110
111
112
113
114
115
116
# File 'lib/amount/active_record/attribute_definition.rb', line 109

def saved_change(record)
  return unless saved_change?(record)

  [
    build_from_values(previous_values(record, before: true)),
    build_from_values(previous_values(record, before: false))
  ]
end

#saved_change?(record) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/amount/active_record/attribute_definition.rb', line 105

def saved_change?(record)
  component_columns.any? { |column| record.saved_change_to_attribute?(column) }
end

#symbol_columnObject



23
24
25
# File 'lib/amount/active_record/attribute_definition.rb', line 23

def symbol_column
  "#{name}_symbol"
end

#validate(record) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/amount/active_record/attribute_definition.rb', line 122

def validate(record)
  add_assignment_error(record)

  atomic = record.read_attribute(atomic_column)
  return if atomic.nil? && fixed_symbol?

  if fixed_symbol?
    validate_deserialization(record, atomic, symbol)
    return
  end

  symbol_value = record.read_attribute(symbol_column)
  if atomic.nil? != symbol_value.nil?
    record.errors.add(name, "must set both atomic and symbol or neither")
    return
  end

  return if atomic.nil? && symbol_value.nil?

  validate_deserialization(record, atomic, symbol_value)
end

#value_in_database(record) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/amount/active_record/attribute_definition.rb', line 97

def value_in_database(record)
  values = component_columns.to_h do |column|
    [column, record.attribute_in_database(column)]
  end

  build_from_values(values)
end

#write(record, value) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/amount/active_record/attribute_definition.rb', line 37

def write(record, value)
  if value.nil?
    record.write_attribute(atomic_column, nil)
    record.write_attribute(symbol_column, nil) unless fixed_symbol?
    return nil
  end

  record.write_attribute(atomic_column, value.atomic.to_s)
  record.write_attribute(symbol_column, value.symbol.to_s) unless fixed_symbol?
  value
end