module Ecoportal module API module Common class BaseModel class UnlinkedModel < Exception def initialize (msg = "Something went wrong when linking the document.") super(msg) end end extend BaseClass class << self 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 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 return instance_variable_get(var) if instance_variable_defined?(var) 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 end attr_reader :_parent, :_key def initialize(doc = {}, parent: self, key: nil) @_parent = parent @_key = key if !_parent || !_key @doc = doc @original_doc = JSON.parse(@doc.to_json) end end def doc raise UnlinkedModel.new unless linked? return _parent.doc[_key] unless _parent == self @doc end def original_doc raise UnlinkedModel.new unless linked? return _parent.original_doc[_key] unless _parent == self @original_doc end def as_json doc end def to_json(*args) doc.to_json(*args) end def as_update new_doc = as_json Common::HashDiff.diff(new_doc, original_doc) end def dirty? as_update != {} end def consolidate! raise UnlinkedModel.new unless linked? case when @original_doc @original_doc = JSON.parse(@doc.to_json) else _parent.original_doc[_key] = JSON.parse(doc.to_json) end end def reset! raise UnlinkedModel.new unless linked? case when @doc @doc = JSON.parse(@original_doc.to_json) else _parent.doc[_key] = JSON.parse(original_doc.to_json) end end def print puts JSON.pretty_generate(as_json) self end protected def linked? is_root = _parent == self && defined?(@doc) is_root || _parent.doc[_key] end end end end end