ecoportal-api-v2 0.8.7 → 0.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -1
  3. data/lib/ecoportal/api/common/content/array_model.rb +8 -6
  4. data/lib/ecoportal/api/common/content/collection_model.rb +45 -20
  5. data/lib/ecoportal/api/common/content/double_model.rb +94 -5
  6. data/lib/ecoportal/api/common/content/hash_diff_patch.rb +44 -22
  7. data/lib/ecoportal/api/common/content/model_helpers.rb +36 -0
  8. data/lib/ecoportal/api/common/content.rb +1 -0
  9. data/lib/ecoportal/api/v2/page/component/action.rb +17 -8
  10. data/lib/ecoportal/api/v2/page/component/action_field.rb +37 -2
  11. data/lib/ecoportal/api/v2/page/component/chart_field/benchmark.rb +30 -0
  12. data/lib/ecoportal/api/v2/page/component/chart_field/config.rb +23 -0
  13. data/lib/ecoportal/api/v2/page/component/chart_field/frequency.rb +3 -4
  14. data/lib/ecoportal/api/v2/page/component/chart_field/heatmap.rb +1 -3
  15. data/lib/ecoportal/api/v2/page/component/chart_field/indicator.rb +4 -5
  16. data/lib/ecoportal/api/v2/page/component/chart_field/multiseries.rb +3 -5
  17. data/lib/ecoportal/api/v2/page/component/chart_field/sankey.rb +1 -3
  18. data/lib/ecoportal/api/v2/page/component/chart_field/serie.rb +3 -4
  19. data/lib/ecoportal/api/v2/page/component/chart_field/series_config.rb +5 -7
  20. data/lib/ecoportal/api/v2/page/component/chart_field.rb +43 -5
  21. data/lib/ecoportal/api/v2/page/component/chart_fr_field.rb +7 -5
  22. data/lib/ecoportal/api/v2/page/component/checklist_field.rb +1 -1
  23. data/lib/ecoportal/api/v2/page/component/checklist_item.rb +7 -5
  24. data/lib/ecoportal/api/v2/page/component/date_field.rb +71 -4
  25. data/lib/ecoportal/api/v2/page/component/file.rb +14 -3
  26. data/lib/ecoportal/api/v2/page/component/files_field.rb +37 -1
  27. data/lib/ecoportal/api/v2/page/component/gauge_field.rb +2 -2
  28. data/lib/ecoportal/api/v2/page/component/gauge_stop.rb +5 -5
  29. data/lib/ecoportal/api/v2/page/component/geo_coordinates.rb +13 -0
  30. data/lib/ecoportal/api/v2/page/component/geo_field.rb +4 -1
  31. data/lib/ecoportal/api/v2/page/component/image.rb +2 -1
  32. data/lib/ecoportal/api/v2/page/component/images_field.rb +57 -1
  33. data/lib/ecoportal/api/v2/page/component/number_field.rb +1 -0
  34. data/lib/ecoportal/api/v2/page/component/people_field.rb +115 -5
  35. data/lib/ecoportal/api/v2/page/component/people_viewable_field.rb +14 -0
  36. data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +34 -2
  37. data/lib/ecoportal/api/v2/page/component/reference_field.rb +32 -3
  38. data/lib/ecoportal/api/v2/page/component/selection_field.rb +65 -7
  39. data/lib/ecoportal/api/v2/page/component/selection_option.rb +16 -5
  40. data/lib/ecoportal/api/v2/page/component/signature_field.rb +3 -2
  41. data/lib/ecoportal/api/v2/page/component/tag_field.rb +31 -1
  42. data/lib/ecoportal/api/v2/page/component.rb +44 -10
  43. data/lib/ecoportal/api/v2/page/components.rb +8 -3
  44. data/lib/ecoportal/api/v2/page/permission_flags.rb +67 -0
  45. data/lib/ecoportal/api/v2/page/permit.rb +15 -0
  46. data/lib/ecoportal/api/v2/page/section.rb +70 -9
  47. data/lib/ecoportal/api/v2/page/sections.rb +64 -6
  48. data/lib/ecoportal/api/v2/page/stage.rb +12 -4
  49. data/lib/ecoportal/api/v2/page/stages.rb +7 -7
  50. data/lib/ecoportal/api/v2/page.rb +19 -2
  51. data/lib/ecoportal/api/v2/pages/page_stage.rb +9 -3
  52. data/lib/ecoportal/api/v2/pages.rb +6 -2
  53. data/lib/ecoportal/api/v2/registers/search_results.rb +13 -0
  54. data/lib/ecoportal/api/v2/registers.rb +13 -0
  55. data/lib/ecoportal/api/v2_version.rb +1 -1
  56. metadata +10 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a332d0750443bc0d8be5b549032b9f62c493cbff07905dc353f0949248c5120a
4
- data.tar.gz: d89435fd4cebfef7662148f5fc335cc792353666c80e1f5ab07c6dc0a8f73744
3
+ metadata.gz: 3d906a6021cc5fab91f2b2d8f32084d61449eab23b8162ade9e01308bdce3584
4
+ data.tar.gz: fe195a200860d2696acfc465accb16ee8758f5dfc00d9cbeffed836d654c1f8c
5
5
  SHA512:
6
- metadata.gz: 611c6b781a09105bb22a24b85e3b9046513505691bef6256774837fa14a7e1c9ca6061795fe35068b5c5340e82f07d2281682ad2d05b06673495285fabcf1dfb
7
- data.tar.gz: 3b9f347aac2994262df8dd864b564010a37ec01a5d7ed2da4ecdc69bb49fff2ff85d8f858cb1761baa770e352131f9ee444fcacd765888ef7b3a338902b567e6
6
+ metadata.gz: 74b45e1025b675e5675a0d6822fcefee7c464ae0759deb0da1004913793cef32bd2ad14f3656ab5b2177ae80bd5ac79fe9451e74ff9faefac24179f8ba9b621c
7
+ data.tar.gz: 8cab8147deaa80f9d3cd6dd5b31a42d0ba018001ca825e76a9a388999daef2ff686240c546255e6b8ac1785b1b7236ff4c124761b66d7cc414fef3c018480019
data/CHANGELOG.md CHANGED
@@ -1,9 +1,90 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [0.8.7] - 2021-05-xx
4
+ ## [0.8.11] - 2021-08-27
5
5
 
6
6
  ### Added
7
+ - `Ecoportal::API::V2::Page#stages?`
8
+ - `Ecoportal::API::V2::Pages::PageStage#current_stage_id`
9
+ - `Ecoportal::API::V2::Registers#search` added option keyed parameter `:only_first`
10
+ - which will make the method return the first `Ecoportal::API::V2::Registers::SearchResults`
11
+ - This has been **added** with the aim of knowing how many results out of how many entries.
12
+
13
+ ### Changed
14
+ - `Ecoportal::API::V2::Pages::PageStage#update` won't update unless there's something to update.
15
+
16
+ ### Fixed
17
+
18
+
19
+ ## [0.8.10] - 2021-08-22
20
+
21
+ ### Added
22
+ - `Ecoportal::API::Common::Content::CollectionModel#[]` now supports position as well
23
+ - `Ecoportal::API::V2::Page::Component::FilesField#add_file`: support for adding files
24
+ - `Ecoportal::API::V2::Page::Component::PeopleField#viewable_fields`: support for managing `viewable_fields`
25
+
26
+ ### Changed
27
+
28
+ ### Fixed
29
+ - `Ecoportal::API::V2::Page::Component::FilesField`: was not requiring `File`
30
+ - `Ecoportal::API::V2::Page::Component::NumberField#value`: it was missing :/
31
+ - `Ecoportal::API::Common::Content::HashDiffPatch` did not support nested objects in Arrays, where the nested object wouldn't have a `patch_ver`. This **fix** allows for it
32
+ - `Ecoportal::API::Common::Content::DoubleModel.passforced` to define `methods` that should always be present. This allows to define `patch_ver` as a forced `key` in models that have it
33
+ - The enforcement (`self.class.enforce!`) happens on `initialize`
34
+ - `passenforced` subjacent model `forced_model_keys` is inheritable
35
+ - `Ecoportal::API::Common::Content::CollectionModel`:
36
+ - Method `upsert!` was not working fine the parameters `pos`, `before` and `after`
37
+ - Method `delete!` did not support position
38
+
39
+ ## [0.8.9] - 2021-08-16
40
+
41
+ ### Added
42
+ - `Ecoportal::API::Common::Content::ModelHelpers`
43
+ - Starting with `#same_string?`, this lib aims to offer a full set of helper comparers.
44
+ - `Ecoportal::API::V2::Page::Components#get_by_id`
45
+ - In future changes, method `[]` might be overriding the method of the parent class `CollectionModel`.
46
+ - `Ecoportal::API::V2::Page::PermissionFlags` to offer support to `can_permission`, `subscribed`, etc.
47
+ - `Ecoportal::API::V2::Page::Section#add_component` super handy helper to add fields to sections.
48
+ - `Ecoportal::API::V2::Page::Component::PeopleField#delete` to remove people using their ids.
49
+ - `Ecoportal::API::V2::Page::Component::GeoField` **added** suport for `#coordinates`
50
+ - With embedded object `Ecoportal::API::V2::Page::Component::GeoCoordinates`
51
+ - `#configure` method, to all the `Component` types (but `ChartField` s)
52
+ - This method allows to quickly set field properties.
53
+ - `Ecoportal::API::V2::Page::Sections#between`, aiming to obtain sections between two other ones
54
+
55
+
56
+ ### Changed
57
+ - `Ecoportal::API::V2::Page::Section` real support for `split` sections (right vs left)
58
+ - This is actually a **FIX**
59
+ - `Ecoportal::API::V2::Page::Component::DateField#create_event`
60
+ - Now it switches to _allow future dates_
61
+ - `Ecoportal::API::V2::Page::Component::SelectionField#add_option`, the `name` parameter is now optional
62
+ - This change aims to make it consistent with the back-end.
63
+ - To its actual `Boolean` type some properties
64
+ - All `Component` types
65
+
66
+ ### Fixed
67
+ - `Ecoportal::API::Common::Content::HashDiffPatch` did not support `Hash` values without `id` or `patch_ver`
68
+ - This fix should allow them to flow to the update
69
+ - `Ecoportal::API::V2::Page::Component::ChartField` did not have `doc` for `mode` based configuration
70
+ - `Ecoportal::API::Common::Content::ArrayModel#insert_one`
71
+ - When `pos`, `before` & `after` were `nil` it was failing to attach the element.
72
+ - `Ecoportal::API::V2::Page::Sections#add` was not adding in the correct order
73
+ - `Ecoportal::API::V2::Page::Section.new_doc` was unnecessarily giving `9999` as default weight
74
+
75
+ ## [0.8.8] - 2021-08-03
76
+
77
+ ### Added
78
+ - `Ecoportal::API::V2::Page::Component::ChartField::Benchmark`
79
+ - Support to convert selection options between numeric and text type.
80
+ - Add `Permit` object to `Page` and `Stage`
81
+
82
+ ### Changed
83
+ - Removed `Stages.ordered_stages`: detected bug with Enumerable iteration
84
+
85
+
86
+ ## [0.8.7] - 2021-05-25
87
+
7
88
  ### Changed
8
89
  - Upgrade `ecoportal-api` gem
9
90
 
@@ -3,7 +3,8 @@ module Ecoportal
3
3
  module Common
4
4
  module Content
5
5
  # Class to handle a plain Array embedded in a Hashed model.
6
- # @note its purpose is to handle an Array of basic objects (i.e. `Date`, `String`, `Number`)
6
+ # @note
7
+ # - Its purpose is to handle an Array of basic objects (i.e. `Date`, `String`, `Number`)
7
8
  class ArrayModel < Content::DoubleModel
8
9
  class TypeMismatchedComparison < Exception
9
10
  def initialize (this: nil, that: msg = "Trying to compare objects with different behavior.")
@@ -222,15 +223,16 @@ module Ecoportal
222
223
  def insert_one(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
223
224
  i = index(value)
224
225
  return i if (i && uniq?)
225
-
226
226
  pos = case
227
227
  when used_param?(pos)
228
- pos
228
+ pos || length
229
229
  when used_param?(before)
230
- index(before)
230
+ before ? index(before) : length
231
231
  when used_param?(after)
232
- if i = index(after)
233
- i + 1
232
+ if after
233
+ if i = index(after) then i + 1 end
234
+ else
235
+ length
234
236
  end
235
237
  else
236
238
  length
@@ -2,6 +2,9 @@ module Ecoportal
2
2
  module API
3
3
  module Common
4
4
  module Content
5
+ # CollectionModel aims to deal with Arrays of actual objects.
6
+ # @note to be able to refer to the correct element of the Collection,
7
+ # it is required that those elements have a unique `key` that allows to identify them
5
8
  class CollectionModel < Content::DoubleModel
6
9
 
7
10
  class << self
@@ -140,17 +143,21 @@ module Ecoportal
140
143
  end
141
144
 
142
145
  # Get an element usign the `key`.
146
+ # @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
147
+ # @return [Object] the `items_class` element object
143
148
  def [](value)
144
149
  items_by_key[get_key(value)]
145
150
  end
146
151
 
152
+ # @return [Array<Object>] the `items_class` element object
147
153
  def values_at(*keys)
148
154
  keys.map {|key| self[key]}
149
155
  end
150
156
 
151
157
  # Tries to find the element `value`, if it exists, it updates it
152
- # Otherwise it pushes it to the end
153
- # @return the element
158
+ # Otherwise it pushes it to the end
159
+ # @value [Hash, Ecoportal::API::Common::Content::DoubleModel] the eleement to be added
160
+ # @return [Object] the `items_class` element object
154
161
  def upsert!(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
155
162
  unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
156
163
  raise "'Content::DoubleModel' or 'Hash' doc required"
@@ -160,15 +167,20 @@ module Ecoportal
160
167
  if item = self[value]
161
168
  item.replace_doc(item_doc)
162
169
  else
163
- _doc_upsert(item_doc, pos: pos, before: before, after: after)
170
+ pos_idx = _doc_upsert(item_doc, pos: pos, before: before, after: after)
164
171
  end
165
172
  (item || self[item_doc]).tap do |item|
166
173
  yield(item) if block_given?
167
174
  end
168
175
  end
169
176
 
177
+ # Deletes `value` from this `CollectionModel` instance
178
+ # @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
179
+ # - When used as `String`, the `key` value (i.e. `id` value) is expected
180
+ # - When used as `Hash`, it should be the `doc` of the target element
181
+ # - When used as `DoubleModel`, it should be the specific object to be deleted
170
182
  def delete!(value)
171
- unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
183
+ unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel) || value.is_a?(String)
172
184
  raise "'Content::DoubleModel' or 'Hash' doc required"
173
185
  end
174
186
  if item = self[value]
@@ -186,7 +198,7 @@ module Ecoportal
186
198
  variables_remove!
187
199
  end
188
200
 
189
- # Gets the `key` of the object
201
+ # Gets the `key` of the object `value`
190
202
  def get_key(value)
191
203
  case value
192
204
  when Content::DoubleModel
@@ -195,6 +207,8 @@ module Ecoportal
195
207
  value[items_key]
196
208
  when String
197
209
  value
210
+ when Numeric
211
+ get_key(self.to_a[value])
198
212
  end
199
213
  end
200
214
 
@@ -235,27 +249,22 @@ module Ecoportal
235
249
  super
236
250
  end
237
251
 
252
+ # Deletes `value` from `doc` (here referred as `_doc_items`)
253
+ # @return [Object] the element deleted from `doc`
238
254
  def _doc_delete(value)
239
255
  if current_pos = _doc_key(value)
240
- _doc_items.delete_at(current_pos)
241
- on_change
256
+ _doc_items.delete_at(current_pos).tap do |deleted|
257
+ on_change
258
+ end
242
259
  end
243
260
  end
244
261
 
245
262
  def _doc_upsert(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
246
- current_pos = _doc_key(value)
247
- pos = case
248
- when used_param?(pos)
249
- pos
250
- when used_param?(before)
251
- _doc_key(before)
252
- when used_param?(after)
253
- #puts "to add after #{after.id}"
254
- if i = _doc_key(after)
255
- i + 1
256
- end
257
- end
263
+ current_pos = if elem = self[value]
264
+ _doc_key(elem)
265
+ end
258
266
 
267
+ pos = scope_position(pos: pos, before: before, after: after)
259
268
  pos ||= current_pos
260
269
 
261
270
  if current_pos && pos
@@ -264,7 +273,6 @@ module Ecoportal
264
273
  end
265
274
 
266
275
  pos = (pos && pos < _doc_items.length)? pos : _doc_items.length
267
-
268
276
  pos.tap do |i|
269
277
  _doc_items.insert(pos, value)
270
278
  on_change
@@ -272,6 +280,23 @@ module Ecoportal
272
280
 
273
281
  end
274
282
 
283
+ def scope_position(pos: NOT_USED, before: NOT_USED, after: NOT_USED)
284
+ case
285
+ when used_param?(pos)
286
+ if elem = self[pos]
287
+ _doc_key(elem) - 1
288
+ end
289
+ when used_param?(before)
290
+ if elem = self[before]
291
+ _doc_key(elem) - 1
292
+ end
293
+ when used_param?(after)
294
+ if elem = self[after]
295
+ _doc_key(elem)
296
+ end
297
+ end
298
+ end
299
+
275
300
  end
276
301
  end
277
302
  end
@@ -10,6 +10,7 @@ module Ecoportal
10
10
  class DoubleModel < Common::BaseModel
11
11
  NOT_USED = Common::Content::ClassHelpers::NOT_USED
12
12
  extend Common::Content::ClassHelpers
13
+ include Common::Content::ModelHelpers
13
14
 
14
15
  class UnlinkedModel < Exception
15
16
  def initialize (msg = "Something went wrong when linking the document.", from: nil, key: nil)
@@ -36,6 +37,8 @@ module Ecoportal
36
37
 
37
38
  # Same as `attr_reader` but links to a subjacent `Hash` model property
38
39
  # @note it does **not** create an _instance variable_
40
+ # @param methods [Array<Symbol>] the method that exposes the value
41
+ # as well as its `key` in the underlying `Hash` model.
39
42
  def pass_reader(*methods)
40
43
  methods.each do |method|
41
44
  method = method.to_s.freeze
@@ -51,6 +54,8 @@ module Ecoportal
51
54
 
52
55
  # Same as `attr_writer` but links to a subjacent `Hash` model property
53
56
  # @note it does **not** create an _instance variable_
57
+ # @param methods [Array<Symbol>] the method that exposes the value
58
+ # as well as its `key` in the underlying `Hash` model.
54
59
  def pass_writer(*methods)
55
60
  methods.each do |method|
56
61
  method = method.to_s.freeze
@@ -69,6 +74,8 @@ module Ecoportal
69
74
  # no chance you can avoid invinite loop for `get_key` without setting an
70
75
  # instance variable key at the moment of the object creation, when the
71
76
  # `doc` is firstly received
77
+ # @param method [Symbol] the method that exposes the value
78
+ # as well as its `key` in the underlying `Hash` model.
72
79
  def passkey(method)
73
80
  method = method.to_s.freeze
74
81
  var = instance_variable_name(method)
@@ -90,7 +97,33 @@ module Ecoportal
90
97
  self
91
98
  end
92
99
 
100
+ # These are methods that should always be present in patch update
101
+ # @note
102
+ # - `DoubleModel` can be used with objects that do not use `patch_ver`
103
+ # - This ensures that does that do, will get the correct patch update model
104
+ # @param method [Symbol] the method that exposes the value
105
+ # as well as its `key` in the underlying `Hash` model.
106
+ # @param default [Value] the default value that
107
+ # this `key` will be written in the model when it doesn't exixt
108
+ def passforced(method, default: , read_only: false)
109
+ model_forced_keys[method.to_s.freeze] = default
110
+ passthrough(method, read_only: read_only)
111
+ end
112
+
113
+ # Ensures `doc` has the `model_forced_keys`. If it doesn't, it adds those missing
114
+ # with the defined `default` values
115
+ def enforce!(doc)
116
+ return unless doc && doc.is_a?(Hash)
117
+ return if model_forced_keys.empty?
118
+ model_forced_keys.each do |key, default|
119
+ doc[key] = default unless doc.key?(key)
120
+ end
121
+ doc
122
+ end
123
+
93
124
  # Same as `attr_accessor` but links to a subjacent `Hash` model property
125
+ # @param methods [Array<Symbol>] the method that exposes the value
126
+ # as well as its `key` in the underlying `Hash` model.
94
127
  # @param read_only [Boolean] should it only define the reader?
95
128
  def passthrough(*methods, read_only: false)
96
129
  pass_reader *methods
@@ -100,6 +133,8 @@ module Ecoportal
100
133
 
101
134
  # To link as a `Time` date to a subjacent `Hash` model property
102
135
  # @see Ecoportal::API::Common::Content::DoubleModel#passthrough
136
+ # @param methods [Array<Symbol>] the method that exposes the value
137
+ # as well as its `key` in the underlying `Hash` model.
103
138
  # @param read_only [Boolean] should it only define the reader?
104
139
  def passdate(*methods, read_only: false)
105
140
  pass_reader(*methods) {|value| to_time(value)}
@@ -109,7 +144,21 @@ module Ecoportal
109
144
  self
110
145
  end
111
146
 
147
+ # To link as a `Boolean` to a subjacent `Hash` model property
148
+ # @param methods [Array<Symbol>] the method that exposes the value
149
+ # as well as its `key` in the underlying `Hash` model.
150
+ # @param read_only [Boolean] should it only define the reader?
151
+ def passboolean(*methods, read_only: false)
152
+ pass_reader(*methods) {|value| value}
153
+ unless read_only
154
+ pass_writer(*methods) {|value| !!value}
155
+ end
156
+ self
157
+ end
158
+
112
159
  # To link as plain `Array` to a subjacent `Hash` model property
160
+ # @param methods [Array<Symbol>] the method that exposes the value
161
+ # as well as its `key` in the underlying `Hash` model.
113
162
  # @param order_matters [Boolean] does the order matter
114
163
  # @param uniq [Boolean] should it contain unique elements
115
164
  def passarray(*methods, order_matters: true, uniq: true)
@@ -131,6 +180,10 @@ module Ecoportal
131
180
  end
132
181
 
133
182
  # Helper to embed one nested object under one property
183
+ # @param method [Symbol] the method that exposes the embeded object
184
+ # @param key [Symbol] the `key` that embeds it to the underlying `Hash` model
185
+ # @nullable [Boolean] to specify if this object can be `nil`
186
+ # @param klass [Class, String] the class of the embedded object
134
187
  def embeds_one(method, key: method, nullable: false, klass:)
135
188
  embed(method, key: key, nullable: nullable, multiple: false, klass: klass)
136
189
  end
@@ -138,7 +191,11 @@ module Ecoportal
138
191
  # @note
139
192
  # - if you have a dedicated `Enumerable` class to manage `many`, you should use `:enum_class`
140
193
  # - otherwise, just indicate the child class in `:klass` and it will auto generate the class
141
- # @param
194
+ # @param method [Symbol] the method that exposes the embeded object
195
+ # @param key [Symbol] the `key` that embeds it to the underlying `Hash` model
196
+ # @param order_matters [Boolean] to state if the order will matter
197
+ # @param klass [Class, String] the class of the individual elements it embeds
198
+ # @param enum_class [Class, String] the class of the collection that will hold the individual elements
142
199
  def embeds_many(method, key: method, order_matters: false, order_key: nil, klass: nil, enum_class: nil)
143
200
  if enum_class
144
201
  eclass = enum_class
@@ -175,8 +232,15 @@ module Ecoportal
175
232
  end
176
233
  end
177
234
 
235
+ # The list of keys that will be forced in the model
236
+ def model_forced_keys
237
+ @forced_model_keys ||= {}
238
+ end
239
+
178
240
  end
179
241
 
242
+ inheritable_class_vars :forced_model_keys
243
+
180
244
  attr_reader :_parent, :_key
181
245
 
182
246
  def initialize(doc = {}, parent: self, key: nil)
@@ -184,6 +248,8 @@ module Ecoportal
184
248
  @_parent = parent || self
185
249
  @_key = key || self
186
250
 
251
+ self.class.enforce!(doc)
252
+
187
253
  if _parent == self
188
254
  @doc = doc
189
255
  @original_doc = JSON.parse(@doc.to_json)
@@ -200,11 +266,13 @@ module Ecoportal
200
266
  _parent.root
201
267
  end
202
268
 
269
+ # @return [String] the `value` of the `key` method (i.e. `id` value)
203
270
  def key
204
271
  raise "No key_method defined for #{self.class}" unless key_method?
205
272
  self.method(key_method).call
206
273
  end
207
274
 
275
+ # @param [String] the `value` of the `key` method (i.e. `id` value)
208
276
  def key=(value)
209
277
  raise "No key_method defined for #{self.class}" unless key_method?
210
278
  method = "#{key_method}="
@@ -223,16 +291,25 @@ module Ecoportal
223
291
  end
224
292
  end
225
293
 
294
+ # @return [nil, Hash] the underlying `Hash` model as is (carrying current changes)
226
295
  def doc
227
296
  raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
228
- return @doc if is_root?
229
- _parent.doc.dig(*[_doc_key(_key)].flatten)
297
+ if is_root?
298
+ @doc
299
+ else
300
+ _parent.doc.dig(*[_doc_key(_key)].flatten)
301
+ end
230
302
  end
231
303
 
304
+ # The `original_doc` holds the model as is now on server-side.
305
+ # @return [nil, Hash] the underlying `Hash` model as after last `consolidate!` changes
232
306
  def original_doc
233
307
  raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
234
- return @original_doc if is_root?
235
- _parent.original_doc.dig(*[_doc_key(_key)].flatten)
308
+ if is_root?
309
+ @original_doc
310
+ else
311
+ _parent.original_doc.dig(*[_doc_key(_key)].flatten)
312
+ end
236
313
  end
237
314
 
238
315
  def as_json
@@ -243,19 +320,31 @@ module Ecoportal
243
320
  doc.to_json(*args)
244
321
  end
245
322
 
323
+ # @return [nil, Hash] the patch `Hash` model including only the changes between
324
+ # `original_doc` and `doc`
246
325
  def as_update
247
326
  new_doc = as_json
248
327
  Common::Content::HashDiffPatch.patch_diff(new_doc, original_doc)
249
328
  end
250
329
 
330
+ # @return [Boolean] stating if there are changes
251
331
  def dirty?
252
332
  as_update != {}
253
333
  end
254
334
 
335
+ # It makes `original_doc` to be like `doc`
336
+ # @note
337
+ # - after executing it, there will be no pending changes
338
+ # - you should technically run this command, after a successful update request to the server
255
339
  def consolidate!
256
340
  replace_original_doc(JSON.parse(doc.to_json))
257
341
  end
258
342
 
343
+ # It makes `doc` to be like `original`
344
+ # @note
345
+ # - after executing it, changes in `doc` will be lost
346
+ # - you should technically run this command only if you want to remove certain changes
347
+ # @key [Symbol] the specific part of the model you want to `reset`
259
348
  def reset!(key = nil)
260
349
  if key
261
350
  keys = [key].flatten.compact