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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -1
- data/lib/ecoportal/api/common/content/array_model.rb +8 -6
- data/lib/ecoportal/api/common/content/collection_model.rb +45 -20
- data/lib/ecoportal/api/common/content/double_model.rb +94 -5
- data/lib/ecoportal/api/common/content/hash_diff_patch.rb +44 -22
- data/lib/ecoportal/api/common/content/model_helpers.rb +36 -0
- data/lib/ecoportal/api/common/content.rb +1 -0
- data/lib/ecoportal/api/v2/page/component/action.rb +17 -8
- data/lib/ecoportal/api/v2/page/component/action_field.rb +37 -2
- data/lib/ecoportal/api/v2/page/component/chart_field/benchmark.rb +30 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/config.rb +23 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/frequency.rb +3 -4
- data/lib/ecoportal/api/v2/page/component/chart_field/heatmap.rb +1 -3
- data/lib/ecoportal/api/v2/page/component/chart_field/indicator.rb +4 -5
- data/lib/ecoportal/api/v2/page/component/chart_field/multiseries.rb +3 -5
- data/lib/ecoportal/api/v2/page/component/chart_field/sankey.rb +1 -3
- data/lib/ecoportal/api/v2/page/component/chart_field/serie.rb +3 -4
- data/lib/ecoportal/api/v2/page/component/chart_field/series_config.rb +5 -7
- data/lib/ecoportal/api/v2/page/component/chart_field.rb +43 -5
- data/lib/ecoportal/api/v2/page/component/chart_fr_field.rb +7 -5
- data/lib/ecoportal/api/v2/page/component/checklist_field.rb +1 -1
- data/lib/ecoportal/api/v2/page/component/checklist_item.rb +7 -5
- data/lib/ecoportal/api/v2/page/component/date_field.rb +71 -4
- data/lib/ecoportal/api/v2/page/component/file.rb +14 -3
- data/lib/ecoportal/api/v2/page/component/files_field.rb +37 -1
- data/lib/ecoportal/api/v2/page/component/gauge_field.rb +2 -2
- data/lib/ecoportal/api/v2/page/component/gauge_stop.rb +5 -5
- data/lib/ecoportal/api/v2/page/component/geo_coordinates.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/geo_field.rb +4 -1
- data/lib/ecoportal/api/v2/page/component/image.rb +2 -1
- data/lib/ecoportal/api/v2/page/component/images_field.rb +57 -1
- data/lib/ecoportal/api/v2/page/component/number_field.rb +1 -0
- data/lib/ecoportal/api/v2/page/component/people_field.rb +115 -5
- data/lib/ecoportal/api/v2/page/component/people_viewable_field.rb +14 -0
- data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +34 -2
- data/lib/ecoportal/api/v2/page/component/reference_field.rb +32 -3
- data/lib/ecoportal/api/v2/page/component/selection_field.rb +65 -7
- data/lib/ecoportal/api/v2/page/component/selection_option.rb +16 -5
- data/lib/ecoportal/api/v2/page/component/signature_field.rb +3 -2
- data/lib/ecoportal/api/v2/page/component/tag_field.rb +31 -1
- data/lib/ecoportal/api/v2/page/component.rb +44 -10
- data/lib/ecoportal/api/v2/page/components.rb +8 -3
- data/lib/ecoportal/api/v2/page/permission_flags.rb +67 -0
- data/lib/ecoportal/api/v2/page/permit.rb +15 -0
- data/lib/ecoportal/api/v2/page/section.rb +70 -9
- data/lib/ecoportal/api/v2/page/sections.rb +64 -6
- data/lib/ecoportal/api/v2/page/stage.rb +12 -4
- data/lib/ecoportal/api/v2/page/stages.rb +7 -7
- data/lib/ecoportal/api/v2/page.rb +19 -2
- data/lib/ecoportal/api/v2/pages/page_stage.rb +9 -3
- data/lib/ecoportal/api/v2/pages.rb +6 -2
- data/lib/ecoportal/api/v2/registers/search_results.rb +13 -0
- data/lib/ecoportal/api/v2/registers.rb +13 -0
- data/lib/ecoportal/api/v2_version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d906a6021cc5fab91f2b2d8f32084d61449eab23b8162ade9e01308bdce3584
|
4
|
+
data.tar.gz: fe195a200860d2696acfc465accb16ee8758f5dfc00d9cbeffed836d654c1f8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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
|
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
|
-
#
|
153
|
-
# @
|
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
|
-
|
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 =
|
247
|
-
|
248
|
-
|
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
|
-
|
229
|
-
|
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
|
-
|
235
|
-
|
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
|