Class: Ecoportal::API::Common::BaseModel

Inherits:
Object
  • Object
show all
Extended by:
BaseClass
Defined in:
lib/ecoportal/api/common/base_model.rb

Defined Under Namespace

Classes: UnlinkedModel

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BaseClass

class_resolver, redef_without_warning, resolve_class

Constructor Details

#initialize(doc = {}, parent: self, key: nil) ⇒ BaseModel

Returns a new instance of BaseModel.



62
63
64
65
66
67
68
69
70
71
# File 'lib/ecoportal/api/common/base_model.rb', line 62

def initialize(doc = {}, parent: self, key: nil)
  @_parent = parent
  @_key    = key

  return unless !_parent || !_key

  @doc          = JSON.parse(doc.to_json)
  @original_doc = JSON.parse(@doc.to_json)
  @initial_doc  = JSON.parse(@doc.to_json)
end

Instance Attribute Details

#_keyObject (readonly)

Returns the value of attribute _key.



60
61
62
# File 'lib/ecoportal/api/common/base_model.rb', line 60

def _key
  @_key
end

#_parentObject (readonly)

Returns the value of attribute _parent.



60
61
62
# File 'lib/ecoportal/api/common/base_model.rb', line 60

def _parent
  @_parent
end

Class Method Details

.embeds_one(method, klass:, key: method, nullable: false) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ecoportal/api/common/base_model.rb', line 31

def embeds_one(method, klass:, key: method, nullable: false)
  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 do |obj|
      instance_variable_set(var, obj)
    end
  end
end

.passthrough(*methods, to: :doc) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/ecoportal/api/common/base_model.rb', line 17

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

Instance Method Details

#as_jsonObject



114
115
116
# File 'lib/ecoportal/api/common/base_model.rb', line 114

def as_json
  doc
end

#as_update(ref = :last, ignore: []) ⇒ Object



122
123
124
125
126
# File 'lib/ecoportal/api/common/base_model.rb', line 122

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!Object

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



136
137
138
139
140
141
142
143
144
145
146
# File 'lib/ecoportal/api/common/base_model.rb', line 136

def consolidate!
  err = UnlinkedModel.new(from: "#{self.class}##{__method__}", key: _key)
  raise err 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?Boolean

Returns:

  • (Boolean)


128
129
130
131
132
133
# File 'lib/ecoportal/api/common/base_model.rb', line 128

def dirty?
  return false unless (json = as_update)
  return false unless json.is_a?(Hash)

  !json.empty?
end

#docObject

Raises:



73
74
75
76
77
78
# File 'lib/ecoportal/api/common/base_model.rb', line 73

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_docObject

Raises:



87
88
89
90
91
92
# File 'lib/ecoportal/api/common/base_model.rb', line 87

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_docObject

Raises:



80
81
82
83
84
85
# File 'lib/ecoportal/api/common/base_model.rb', line 80

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


181
182
183
184
# File 'lib/ecoportal/api/common/base_model.rb', line 181

def print_pretty
  puts JSON.pretty_generate(as_json)
  self
end

#replace_doc!(new_doc) ⇒ Hash

It replaces doc by new_doc

Returns:

  • (Hash)

    doc before change

Raises:



96
97
98
99
100
101
102
# File 'lib/ecoportal/api/common/base_model.rb', line 96

def replace_doc!(new_doc)
  raise UnlinkedModel.new(from: "#{self.class}#replace_doc", key: _key) unless linked?

  @doc.tap do
    @doc = new_doc
  end
end

#replace_original_doc!(new_doc) ⇒ Hash

It replaces original_doc by new_doc

Returns:

  • (Hash)

    original_doc before change

Raises:



106
107
108
109
110
111
112
# File 'lib/ecoportal/api/common/base_model.rb', line 106

def replace_original_doc!(new_doc)
  raise UnlinkedModel.new(from: "#{self.class}#replace_original_doc", key: _key) unless linked?

  @original_doc.tap do
    @original_doc = new_doc
  end
end

#reset!(key = nil) ⇒ Object

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

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

Parameters:

  • key (String, Array<String>, nil) (defaults to: nil)

    if given, it only resets the specified property

Raises:

  • (ArgumentError)


154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ecoportal/api/common/base_model.rb', line 154

def reset!(key = nil) # rubocop:disable Metrics/AbcSize>
  msg = "'key' should be a String. Given #{key}"
  raise ArgumentError, msg unless !key || key.is_a?(String)

  err = UnlinkedModel.new(from: "#{self.class}##{__method__}", key: _key)
  raise err unless linked?

  if key
    if respond_to?(key) && (child = 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
      send(key) if !new_doc && 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) ⇒ Object



118
119
120
# File 'lib/ecoportal/api/common/base_model.rb', line 118

def to_json(*args)
  doc.to_json(*args)
end