class Ecoportal::API::Common::BaseModel

Attributes

_key[R]
_parent[R]

Public Class Methods

embeds_one(method, key: method, nullable: false, klass:) click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 28
def embeds_one(method, key: method, nullable: false, klass:)
  method = method.to_s.freeze
  var    = "@#{method}".freeze
  key    = key.to_s.freeze
  define_method(method) do
    if instance_variable_defined?(var)
      value = instance_variable_get(var)
      return value unless nullable
      return value if (value && doc[key]) || (!value && !doc[key])
      remove_instance_variable(var)
    end
    doc[key] ||= {} unless nullable
    return instance_variable_set(var, nil) unless doc[key]

    self.class.resolve_class(klass).new(
      doc[key], parent: self, key: key
    ).tap {|obj| instance_variable_set(var, obj)}
  end
end
new(doc = {}, parent: self, key: nil) click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 52
def initialize(doc = {}, parent: self, key: nil)
  @_parent = parent
  @_key    = key
  if !_parent || !_key
    @doc          = doc
    @original_doc = JSON.parse(@doc.to_json)
    @initial_doc  = JSON.parse(@doc.to_json)
  end
end
passthrough(*methods, to: :doc) click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 16
def passthrough(*methods, to: :doc)
  methods.each do |method|
    method = method.to_s
    define_method method do
      send(to)[method]
    end
    define_method "#{method}=" do |value|
      send(to)[method] = value
    end
  end
end

Public Instance Methods

as_json() click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 80
def as_json
  doc
end
as_update(ref = :last, ignore: []) click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 88
def as_update(ref = :last, ignore: [])
  new_doc = as_json
  ref_doc = ref == :total ? initial_doc : original_doc
  Common::HashDiff.diff(new_doc, ref_doc, ignore: ignore)
end
consolidate!() click to toggle source

It consolidates all the changes carried by `doc` by setting it as `original_doc`.

# File lib/ecoportal/api/common/base_model.rb, line 99
def consolidate!
  raise UnlinkedModel.new(from: "#{self.class}#consolidate!", key: _key)  unless linked?
  new_doc = JSON.parse(doc.to_json)
  if is_root?
    @original_doc = new_doc
  else
    dig_set(_parent.original_doc, [_key].flatten, new_doc)
  end
end
dirty?() click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 94
def dirty?
  as_update != {}
end
doc() click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 62
def doc
  raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key)  unless linked?
  return @doc if is_root?
  _parent.doc.dig(*[_key].flatten)
end
initial_doc() click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 74
def initial_doc
  raise UnlinkedModel.new(from: "#{self.class}#initial_doc", key: _key)  unless linked?
  return @initial_doc if is_root?
  _parent.initial_doc.dig(*[_key].flatten)
end
original_doc() click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 68
def original_doc
  raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key)  unless linked?
  return @original_doc if is_root?
  _parent.original_doc.dig(*[_key].flatten)
end
print_pretty() click to toggle source
reset!(key = nil) click to toggle source

It removes all the changes carried by `doc` by restoring `original_doc` into `doc`. @note

1. When there are nullable properties, it may be required to apply `reset!` from the parent
 i.e. `parent.reset!("child")` # when parent.child is `nil`
2. In such a case, only immediate childs are allowed to be reset

@param key [String, Array<String>, nil] if given, it only resets the specified property

# File lib/ecoportal/api/common/base_model.rb, line 115
def reset!(key = nil)
  raise "'key' should be a String. Given #{key}" unless !key || key.is_a?(String)
  raise UnlinkedModel.new(from: "#{self.class}#reset!", key: _key)  unless linked?

  if key
    if self.respond_to?(key) && child = self.send(key) && child.is_a?(Ecoportal::API::Common::BaseModel)
      child.reset!
    else
      new_doc = original_doc && original_doc[key]
      dig_set(doc, [key], new_doc && JSON.parse(new_doc.to_json))
      # regenerate object if new_doc is null
      self.send(key) if !new_doc && self.respond_to?(key)
    end
  else
    new_doc = JSON.parse(original_doc.to_json)
    if is_root?
      @doc = new_doc
    else
      dig_set(_parent.doc, [_key].flatten, new_doc)
    end
  end
end
to_json(*args) click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 84
def to_json(*args)
  doc.to_json(*args)
end

Protected Instance Methods

is_root?() click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 145
def is_root?
  _parent == self && !!defined?(@doc)
end
linked?() click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 149
def linked?
  is_root? || !!_parent.doc.dig(*[_key].flatten)
end

Private Instance Methods

dig_set(obj, keys, value) click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 155
def dig_set(obj, keys, value)
  if keys.length == 1
    obj[keys.first] = value
  else
    dig_set(obj[keys.first], keys.slice(1..-1), value)
  end
end
set_uniq_array_keep_order(key, value) click to toggle source
# File lib/ecoportal/api/common/base_model.rb, line 163
def set_uniq_array_keep_order(key, value)
  unless value.is_a?(Array)
    raise "#{key}= needs to be passed an Array, got #{value.class}"
  end
  ini_vals = (original_doc && original_doc[key]) || []

  value    = value.uniq
  # preserve original order to avoid false updates
  doc[key] = ((ini_vals & value) + (value - ini_vals)).compact
end