lib/eventbrite_sdk/resource/field.rb
module EventbriteSDK
class Resource
class Field
SIBLING_KEYMAP = { 'timezone' => 'utc', 'utc' => 'timezone' }.freeze
SIBLING_REGEX = /\A(.+)\.(utc|timezone)\z/
attr_reader :key, :value, :initial_value
def initialize(key, value, prefix: nil, schema: NullSchemaDefinition.new)
@key = (prefix && "#{prefix}.#{key}") || key
@schema = schema
@value = value
@datetime = false
end
def changes(attrs, changes)
%i[basic_changes rich_changes].reduce(changes) do |diff, method|
send(method, attrs, diff)
end
end
def keys
key.split('.')
end
def writeable?
schema.writeable?(key)
end
def apply(attrs, existing_changes)
if writeable?
changes(attrs, existing_changes).tap { bury(attrs) }
else
{}
end
end
def bury(hash = {})
nested_keys = keys
# Hand rolling #bury, hopefully we get it in the next release of Ruby.
# UPDATE: we won't https://bugs.ruby-lang.org/issues/11747
nested_keys.each_cons(2).reduce(hash) do |prev_attrs, (nkey, _)|
prev_attrs[nkey] ||= {}
end[nested_keys.last] = value
hash
end
private
attr_reader :datetime, :schema
def basic_changes(attrs, changes)
@initial_value = attrs.dig(*keys)
comp_value = schema.dirty_comparable(self)
changes.merge(
(comp_value != value && { key => [initial_value, value] }) || {}
)
end
def rich_changes(attrs, changes)
if key =~ SIBLING_REGEX && changes[key] && !changes[sister_field]
@datetime = true
changes.merge(sister_field => sister_change(attrs))
else
changes
end
end
def sister
if key =~ SIBLING_REGEX
key_prefix = Regexp.last_match(1)
sister_field = SIBLING_KEYMAP[Regexp.last_match(2)]
[key_prefix, sister_field]
end
end
def sister_field
sister.join('.')
end
# Since we use dirty checking to determine what the payload is
# you can run into a case where a "rich media" field needs other attrs
# Namely timezone, so if a rich date changed, add the tz with it.
def sister_change(attrs)
Array.new(2) { attrs.dig(*sister) }
end
end
end
end