ecoportal-api-v2 0.8.8 → 0.8.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +85 -3
- 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/doc_helpers.rb +2 -2
- 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 +9 -7
- 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 +39 -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 +59 -3
- data/lib/ecoportal/api/v2/page/component/selection_option.rb +6 -4
- 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 +2 -1
- 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 +11 -7
- data/lib/ecoportal/api/v2/page/stages.rb +2 -2
- data/lib/ecoportal/api/v2/page.rb +18 -2
- data/lib/ecoportal/api/v2/pages/page_stage.rb +13 -1
- data/lib/ecoportal/api/v2/pages.rb +3 -0
- data/lib/ecoportal/api/v2/registers/search_results.rb +13 -0
- data/lib/ecoportal/api/v2/registers.rb +15 -2
- data/lib/ecoportal/api/v2_version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 692fe87a2a9dd089ee091bae7133915ac5c9ae4b0643be6086b57206569a1044
|
4
|
+
data.tar.gz: 4d9866b6e5727b176caaff881cb44a3cd13ca08418884e69283f8c64c0e80272
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b812fc350ccdfd173d8ca7b02b05bd0676eda8dac97e2a981cd6c87e1e62c7170744a352ef962144ffb24b3bf9eb43011156c78c09f22a00db154431fd2be5ca
|
7
|
+
data.tar.gz: 00c551099e991a339125e5a985f98aa918b8f9844e03b7b6ba79c6cc2fc5d9ffa4303eaee51c2acc6205932472cdf5324692a73d875e647ba0bcd685f676c60c
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +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.12] - 2021-08-xx
|
5
|
+
|
6
|
+
### Added
|
7
|
+
- `Ecoportal::API::V2::Pages::PageStage#current_stage`
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
- `Ecoportal::API::Common::Content::DocHelpers#get_body` typo and wrong parameters on call.
|
13
|
+
- `Ecoportal::API::V2::Pages#update` should always return `Result` object.
|
14
|
+
- `Ecoportal::API::V2::Registers#search` was not using `cursor_id` to iterate.
|
15
|
+
|
16
|
+
## [0.8.11] - 2021-08-27
|
17
|
+
|
18
|
+
### Added
|
19
|
+
- `Ecoportal::API::V2::Page#stages?`
|
20
|
+
- `Ecoportal::API::V2::Pages::PageStage#current_stage_id`
|
21
|
+
- `Ecoportal::API::V2::Registers#search` added option keyed parameter `:only_first`
|
22
|
+
- which will make the method return the first `Ecoportal::API::V2::Registers::SearchResults`
|
23
|
+
- This has been **added** with the aim of knowing how many results out of how many entries.
|
24
|
+
|
25
|
+
### Changed
|
26
|
+
- `Ecoportal::API::V2::Pages::PageStage#update` won't update unless there's something to update.
|
27
|
+
|
28
|
+
### Fixed
|
29
|
+
|
30
|
+
|
31
|
+
## [0.8.10] - 2021-08-22
|
32
|
+
|
33
|
+
### Added
|
34
|
+
- `Ecoportal::API::Common::Content::CollectionModel#[]` now supports position as well
|
35
|
+
- `Ecoportal::API::V2::Page::Component::FilesField#add_file`: support for adding files
|
36
|
+
- `Ecoportal::API::V2::Page::Component::PeopleField#viewable_fields`: support for managing `viewable_fields`
|
37
|
+
|
38
|
+
### Changed
|
39
|
+
|
40
|
+
### Fixed
|
41
|
+
- `Ecoportal::API::V2::Page::Component::FilesField`: was not requiring `File`
|
42
|
+
- `Ecoportal::API::V2::Page::Component::NumberField#value`: it was missing :/
|
43
|
+
- `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
|
44
|
+
- `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
|
45
|
+
- The enforcement (`self.class.enforce!`) happens on `initialize`
|
46
|
+
- `passenforced` subjacent model `forced_model_keys` is inheritable
|
47
|
+
- `Ecoportal::API::Common::Content::CollectionModel`:
|
48
|
+
- Method `upsert!` was not working fine the parameters `pos`, `before` and `after`
|
49
|
+
- Method `delete!` did not support position
|
50
|
+
|
51
|
+
## [0.8.9] - 2021-08-16
|
52
|
+
|
53
|
+
### Added
|
54
|
+
- `Ecoportal::API::Common::Content::ModelHelpers`
|
55
|
+
- Starting with `#same_string?`, this lib aims to offer a full set of helper comparers.
|
56
|
+
- `Ecoportal::API::V2::Page::Components#get_by_id`
|
57
|
+
- In future changes, method `[]` might be overriding the method of the parent class `CollectionModel`.
|
58
|
+
- `Ecoportal::API::V2::Page::PermissionFlags` to offer support to `can_permission`, `subscribed`, etc.
|
59
|
+
- `Ecoportal::API::V2::Page::Section#add_component` super handy helper to add fields to sections.
|
60
|
+
- `Ecoportal::API::V2::Page::Component::PeopleField#delete` to remove people using their ids.
|
61
|
+
- `Ecoportal::API::V2::Page::Component::GeoField` **added** suport for `#coordinates`
|
62
|
+
- With embedded object `Ecoportal::API::V2::Page::Component::GeoCoordinates`
|
63
|
+
- `#configure` method, to all the `Component` types (but `ChartField` s)
|
64
|
+
- This method allows to quickly set field properties.
|
65
|
+
- `Ecoportal::API::V2::Page::Sections#between`, aiming to obtain sections between two other ones
|
66
|
+
|
67
|
+
|
68
|
+
### Changed
|
69
|
+
- `Ecoportal::API::V2::Page::Section` real support for `split` sections (right vs left)
|
70
|
+
- This is actually a **FIX**
|
71
|
+
- `Ecoportal::API::V2::Page::Component::DateField#create_event`
|
72
|
+
- Now it switches to _allow future dates_
|
73
|
+
- `Ecoportal::API::V2::Page::Component::SelectionField#add_option`, the `name` parameter is now optional
|
74
|
+
- This change aims to make it consistent with the back-end.
|
75
|
+
- To its actual `Boolean` type some properties
|
76
|
+
- All `Component` types
|
77
|
+
|
78
|
+
### Fixed
|
79
|
+
- `Ecoportal::API::Common::Content::HashDiffPatch` did not support `Hash` values without `id` or `patch_ver`
|
80
|
+
- This fix should allow them to flow to the update
|
81
|
+
- `Ecoportal::API::V2::Page::Component::ChartField` did not have `doc` for `mode` based configuration
|
82
|
+
- `Ecoportal::API::Common::Content::ArrayModel#insert_one`
|
83
|
+
- When `pos`, `before` & `after` were `nil` it was failing to attach the element.
|
84
|
+
- `Ecoportal::API::V2::Page::Sections#add` was not adding in the correct order
|
85
|
+
- `Ecoportal::API::V2::Page::Section.new_doc` was unnecessarily giving `9999` as default weight
|
86
|
+
|
87
|
+
## [0.8.8] - 2021-08-03
|
5
88
|
|
6
89
|
### Added
|
7
90
|
- `Ecoportal::API::V2::Page::Component::ChartField::Benchmark`
|
@@ -10,8 +93,7 @@ All notable changes to this project will be documented in this file.
|
|
10
93
|
|
11
94
|
### Changed
|
12
95
|
- Removed `Stages.ordered_stages`: detected bug with Enumerable iteration
|
13
|
-
|
14
|
-
### Fixed
|
96
|
+
|
15
97
|
|
16
98
|
## [0.8.7] - 2021-05-25
|
17
99
|
|
@@ -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
|
@@ -13,9 +13,9 @@ module Ecoportal
|
|
13
13
|
when doc.respond_to?(:as_update)
|
14
14
|
doc.as_update
|
15
15
|
when doc.respond_to?(:as_json)
|
16
|
-
Common::Content::
|
16
|
+
Common::Content::HashDiffPatch.patch_diff(doc.as_json, nil)
|
17
17
|
when doc.is_a?(Hash)
|
18
|
-
Common::Content::
|
18
|
+
Common::Content::HashDiffPatch.patch_diff(doc, nil)
|
19
19
|
else
|
20
20
|
raise "Could not get body for doc: #{doc}"
|
21
21
|
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
|