eco-helpers 2.5.4 → 2.5.6
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 +34 -1
- data/eco-helpers.gemspec +1 -1
- data/lib/eco/api/common/people/person_entry.rb +0 -1
- data/lib/eco/api/organization/tag_tree.rb +36 -7
- data/lib/eco/api/session/config/tagtree.rb +57 -17
- data/lib/eco/api/session/config.rb +9 -7
- data/lib/eco/api/session.rb +1 -1
- data/lib/eco/api/usecases/default_cases/reinvite_trans_case.rb +2 -2
- data/lib/eco/api/usecases/graphql/helpers/location/base.rb +8 -2
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_map.rb +66 -0
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_set.rb +95 -0
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap.rb +88 -0
- data/lib/eco/api/usecases/graphql/helpers/location.rb +1 -0
- data/lib/eco/api/usecases/graphql/samples/location/command/results.rb +11 -7
- data/lib/eco/data/locations/node_level/cleaner.rb +7 -4
- data/lib/eco/data/locations/node_level/parsing.rb +11 -3
- data/lib/eco/data/locations/node_level.rb +11 -1
- data/lib/eco/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed268fb73bb35106da813f51a7b9469d0ee0fe167cee520ac44f98fed22c622b
|
4
|
+
data.tar.gz: c6b6e0f72037f2a1dac9313293317a78a4d25c52568c7577f88efdafb37d7994
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21d9f1703574866e548daa22f1e196b237a8415fb750fe53bb6c4cd63e5fa90002a9e2d5f90e5f3aaca769f639e6d9c02f40b0e7a7a123a15965af41bff91828
|
7
|
+
data.tar.gz: a02e32a2945f0e4e7a5780e340e8ef400e434d00f2cf44d9969d8573bf84e94c5d35c4c0319e205e351837dc016eb9e389759db3d2291ceab493943af597170b
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,45 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
-
## [2.5.
|
4
|
+
## [2.5.7] - 2023-08-xx
|
5
5
|
|
6
6
|
### Added
|
7
7
|
### Changed
|
8
8
|
### Fixed
|
9
9
|
|
10
|
+
## [2.5.6] - 2023-08-14
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
- `Eco::API::Session::Config::Tagtree#live_tree` remove memmoize tree: it now always trigger a query to the back-end
|
14
|
+
- Better messaging to know what's going on.
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
- `Eco::API::Session#live_tree` was not forwarding target structure id `id`
|
18
|
+
- `Eco::Data::Locations::NodeLevel#override_lower_levels`
|
19
|
+
- By **default** should only override empty upper levels
|
20
|
+
- `Eco::Data::Locations::NodeLevel::Cleaner`
|
21
|
+
- `#tidy_nodes` when **gap** (merged parent) identified, `level` is still correct
|
22
|
+
- `Eco::Data::Locations::NodeLevel`
|
23
|
+
- `#nodes_from_csv` correctly identify parent with big gaps
|
24
|
+
- This fix ensures a correct normalization
|
25
|
+
- `Eco::API::UseCases::GraphQL::Samples::Location::Command::Result`
|
26
|
+
- **Batch remap tags** _built_ requires full path to keep from-filter specificity
|
27
|
+
- This change also wraps into a new class the remap tags table.
|
28
|
+
|
29
|
+
## [2.5.5] - 2023-08-03
|
30
|
+
|
31
|
+
### Added
|
32
|
+
- `Eco::API::Organization::TagTree` - **added/improved methods**
|
33
|
+
- `#as_json` new parameter `max_depth:` to be able to cut the tree
|
34
|
+
- `#active_tree` new method to exclude archived nodes.
|
35
|
+
- `#truncate` new method to obtain a tree cut to `max_depth:`
|
36
|
+
- `Eco::API::Session::Config::Tagtree`: **exposed** `include_archived:` (a.k.a. `inludeArchivedNodes`).
|
37
|
+
- This change states that `session.tagtree` does not retrieve archived nodes by default, while `session.live_tree` does retrieve archived nodes.
|
38
|
+
- This change required an update on the `ecoportal-api-graphql` **gem**
|
39
|
+
|
40
|
+
### Fixed
|
41
|
+
- `Eco::API::Organization::TagTree#path` - dups the result (rather than exposing the internal path array)
|
42
|
+
|
10
43
|
## [2.5.4] - 2023-07-27
|
11
44
|
|
12
45
|
### Added
|
data/eco-helpers.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
|
33
33
|
spec.add_dependency 'ecoportal-api', '>= 0.9.4', '< 0.10'
|
34
34
|
spec.add_dependency 'ecoportal-api-v2', '>= 1.1.3', '< 1.2'
|
35
|
-
spec.add_dependency 'ecoportal-api-graphql', '>= 0.3.
|
35
|
+
spec.add_dependency 'ecoportal-api-graphql', '>= 0.3.10', '< 0.4'
|
36
36
|
spec.add_dependency 'aws-sdk-s3', '>= 1.83.0', '< 2'
|
37
37
|
spec.add_dependency 'aws-sdk-ses', '>= 1.36.0', '< 2'
|
38
38
|
spec.add_dependency 'dotenv', '>= 2.7.6', '< 3'
|
@@ -76,9 +76,23 @@ module Eco
|
|
76
76
|
@archived
|
77
77
|
end
|
78
78
|
|
79
|
+
def active?
|
80
|
+
!archived?
|
81
|
+
end
|
82
|
+
|
79
83
|
# @return [Eco::API::Organization::TagTree]
|
80
84
|
def dup
|
81
|
-
self.class.new(as_json)
|
85
|
+
self.class.new(as_json, name: name, id: id)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return [Eco::API::Organization::TagTree] with **non** `archived` nodes only
|
89
|
+
def active_tree
|
90
|
+
self.class.new(as_json(include_archived: false), name: name, id: id)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [Eco::API::Organization::TagTree] with nodes up to `max_depth`
|
94
|
+
def truncate(max_depth: total_depth)
|
95
|
+
self.class.new(as_json(max_depth: max_depth), name: name, id: id)
|
82
96
|
end
|
83
97
|
|
84
98
|
# Iterate through all the nodes of this tree
|
@@ -161,11 +175,26 @@ module Eco
|
|
161
175
|
# Returns a tree of Hashes form nested via `nodes` (or just a list of hash nodes)
|
162
176
|
# @yield [node_json, node] block for custom output json model
|
163
177
|
# @yiledreturn [Hash] the custom json model.
|
164
|
-
# @include_children [Boolean] whether it should return a tree hash or just a list of hash nodes.
|
178
|
+
# @param include_children [Boolean] whether it should return a tree hash or just a list of hash nodes.
|
179
|
+
# @param include_archived [Boolean] whether it should include archived nodes.
|
180
|
+
# @param max_depth [Boolean] up to what level `depth` nodes should be included.
|
165
181
|
# @return [Array[Hash]] where `Hash` is a `node` (i.e. `{"tag" => TAG, "nodes": Array[Hash]}`)
|
166
|
-
def as_json(include_children: true, &block)
|
167
|
-
|
168
|
-
|
182
|
+
def as_json(include_children: true, include_archived: true, max_depth: total_depth, &block)
|
183
|
+
max_depth ||= total_depth
|
184
|
+
return nil if max_depth < depth
|
185
|
+
return [] if top? && !include_children
|
186
|
+
return nil if archived? && !include_archived
|
187
|
+
|
188
|
+
if include_children
|
189
|
+
child_nodes = nodes
|
190
|
+
child_nodes = child_nodes.select(&:active?) unless include_archived
|
191
|
+
kargs = {
|
192
|
+
include_children: include_children,
|
193
|
+
include_archived: include_archived,
|
194
|
+
max_depth: max_depth
|
195
|
+
}
|
196
|
+
children_json = child_nodes.map {|nd| nd.as_json(**kargs, &block)}.compact
|
197
|
+
end
|
169
198
|
|
170
199
|
if top?
|
171
200
|
children_json
|
@@ -287,8 +316,8 @@ module Eco
|
|
287
316
|
# @param key [String] tag to find the path to.
|
288
317
|
# @return [Array<String>]
|
289
318
|
def path(key = nil)
|
290
|
-
return @path if !key
|
291
|
-
@hash_paths[key.upcase]
|
319
|
+
return @path.dup if !key
|
320
|
+
@hash_paths[key.upcase].dup
|
292
321
|
end
|
293
322
|
|
294
323
|
# Helper to assign tags to a person account.
|
@@ -3,18 +3,31 @@ module Eco
|
|
3
3
|
class Session
|
4
4
|
class Config
|
5
5
|
class TagTree < BaseConfig
|
6
|
+
class MissingTagtree < StandardError
|
7
|
+
end
|
8
|
+
|
6
9
|
attr_key :file
|
7
10
|
|
8
|
-
|
11
|
+
# @param include_archived [Boolean] whether or not it should include archived nodes.
|
12
|
+
# @return [Eco::API::Organization::TagTree]
|
13
|
+
def scope_tree(enviro: nil, include_archived: true, raise_on_missing: true)
|
9
14
|
return @tagtree if instance_variable_defined?(:@tagtree) && @tagtree.enviro == enviro
|
15
|
+
|
10
16
|
if tree_file = self.file
|
11
17
|
if (tree = file_manager.load_json(tree_file)) && !tree.empty?
|
12
18
|
@tagtree = Eco::API::Organization::TagTree.new(tree, enviro: enviro)
|
13
19
|
end
|
14
20
|
end
|
15
|
-
|
21
|
+
|
22
|
+
kargs = {
|
23
|
+
enviro: enviro,
|
24
|
+
includeArchivedNodes: include_archived
|
25
|
+
}
|
26
|
+
|
27
|
+
@tagtree ||= live_tree(**kargs).tap do |tree|
|
16
28
|
unless tree && !tree.empty?
|
17
|
-
|
29
|
+
msg = "Could not find a local or live locations structure."
|
30
|
+
raise MissingTagtree, msg
|
18
31
|
end
|
19
32
|
end
|
20
33
|
end
|
@@ -22,14 +35,25 @@ module Eco
|
|
22
35
|
# Among all the locations structures it selects the one with more location nodes
|
23
36
|
# If `id` is provided, it only retrieves this locations structure.
|
24
37
|
def live_tree(id: nil, enviro: nil, include_archived: false, **kargs, &block)
|
25
|
-
|
38
|
+
existing_cache = !!@live_tree
|
39
|
+
first_load = !existing_cache
|
40
|
+
|
41
|
+
target_change = existing_cache && id && @live_tree.id != id
|
42
|
+
enviro_change = existing_cache && enviro && @live_tree.enviro != enviro
|
43
|
+
|
44
|
+
switching_target = existing_cache && (target_change || enviro_change)
|
45
|
+
refresh_cache = existing_cache && !switching_target
|
46
|
+
|
47
|
+
kargs = {
|
48
|
+
enviro: enviro,
|
49
|
+
includeArchivedNodes: include_archived
|
50
|
+
}.merge(kargs)
|
51
|
+
|
26
52
|
if id
|
27
|
-
args = {id: id
|
53
|
+
args = { id: id }.merge(kargs)
|
28
54
|
@live_tree = live_tree_get(**args, &block)
|
29
55
|
else
|
30
|
-
|
31
|
-
# => In `live_tree` the paramter refers to nodes
|
32
|
-
trees = live_trees(enviro: enviro, &block)
|
56
|
+
trees = live_trees(**kargs, &block)
|
33
57
|
@live_tree = trees.reject do |tree|
|
34
58
|
tree.empty?
|
35
59
|
end.max do |a,b|
|
@@ -37,34 +61,50 @@ module Eco
|
|
37
61
|
end
|
38
62
|
end.tap do |tree|
|
39
63
|
if tree
|
40
|
-
msg = "
|
41
|
-
|
64
|
+
msg = "LIVE LOCATIONS Structure (#{tree.id}): '#{tree.name}' (#{tree.count} nodes)"
|
65
|
+
if first_load
|
66
|
+
session_logger.info("Using #{msg}")
|
67
|
+
elsif switching_target
|
68
|
+
session_logger.info("Switched to #{msg}")
|
69
|
+
else # refresh_cache
|
70
|
+
session_logger.debug("Reloading #{msg}")
|
71
|
+
end
|
72
|
+
else
|
73
|
+
session_logger.info "Could not retrive live tree (#{id})"
|
42
74
|
end
|
43
75
|
end
|
44
76
|
end
|
45
77
|
|
46
78
|
# Gets a single locations structure
|
47
79
|
# @note it does not memoize
|
80
|
+
# @param include_archived [Boolean] whether or not to include archived **nodes**
|
81
|
+
# @return [Eco::API::Organization::TagTree, NilClass]
|
48
82
|
def live_tree_get(id: nil, enviro: nil, include_archived: false, **kargs, &block)
|
49
83
|
return nil unless apis.active_api.version_available?(:graphql)
|
50
84
|
return nil unless graphql = apis.api(version: :graphql)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
85
|
+
|
86
|
+
kargs = {
|
87
|
+
id: id,
|
88
|
+
includeArchivedNodes: include_archived
|
89
|
+
}.merge(kargs)
|
90
|
+
|
91
|
+
return nil unless tree = graphql.currentOrganization.locationStructure(**kargs, &block)
|
92
|
+
|
55
93
|
args = { enviro: enviro, id: tree.id, name: tree.name }
|
56
94
|
Eco::API::Organization::TagTree.new(tree.treeify, **args)
|
57
95
|
end
|
58
96
|
|
59
97
|
# Retrieves all the location structures of the organisation
|
98
|
+
# @param include_archived [Boolean] whether or not to include archived **nodes**
|
99
|
+
# @return [Array<Eco::API::Organization::TagTree>]
|
60
100
|
def live_trees(enviro: nil, include_archived: false, **kargs, &block)
|
61
101
|
[].tap do |eco_trees|
|
62
102
|
next unless apis.active_api.version_available?(:graphql)
|
63
103
|
next unless graphql = apis.api(version: :graphql)
|
104
|
+
|
64
105
|
kargs = {
|
65
|
-
|
66
|
-
|
67
|
-
}.merge(kargs).slice(:includeArchived, :includeUnpublished)
|
106
|
+
includeArchivedNodes: include_archived
|
107
|
+
}.merge(kargs)
|
68
108
|
|
69
109
|
next unless trees = graphql.currentOrganization.locationStructures(**kargs, &block)
|
70
110
|
trees.each do |tree|
|
@@ -235,20 +235,22 @@ module Eco
|
|
235
235
|
end
|
236
236
|
|
237
237
|
# It uses the `tagtree.json` file and in its absence, if `graphql` enabled, the largest `life_tagtree`
|
238
|
+
# @note it does NOT include archived nodes by default.
|
239
|
+
# - This is for legacy (most usecases don't)
|
240
|
+
# @param include_archived [Boolean] whether or not it should include archived nodes.
|
238
241
|
# @return [Eco::API::Organization::TagTree]
|
239
|
-
def tagtree(enviro: nil)
|
240
|
-
|
242
|
+
def tagtree(enviro: nil, include_archived: false, raise_on_missing: true)
|
243
|
+
kargs = {
|
244
|
+
enviro: enviro, include_archived: include_archived, raise_on_missing: raise_on_missing
|
245
|
+
}
|
246
|
+
@tagtree ||= tagtree_config.scope_tree(**kargs)
|
241
247
|
end
|
242
248
|
|
243
249
|
# It obtains the first of the live tagtree in the org
|
244
250
|
# @note it requires graphql connection configuration parameters
|
245
251
|
# @return [Eco::API::Organization::TagTree]
|
246
252
|
def live_tree(id: nil, enviro: nil, **kargs, &block)
|
247
|
-
|
248
|
-
tagtree_config.live_tree_get(id: id, enviro: enviro, **kargs, &block)
|
249
|
-
else
|
250
|
-
tagtree_config.live_tree(enviro: enviro, **kargs, &block)
|
251
|
-
end
|
253
|
+
tagtree_config.live_tree(id: id, enviro: enviro, **kargs, &block)
|
252
254
|
end
|
253
255
|
|
254
256
|
# @return [Eco::API::Organization::PolicyGroups]
|
data/lib/eco/api/session.rb
CHANGED
@@ -46,7 +46,7 @@ module Eco
|
|
46
46
|
|
47
47
|
# @see Eco::API::Session::Config#live_tree
|
48
48
|
def live_tree(id: nil, include_archived: false, **kargs, &block)
|
49
|
-
config.live_tree(id:
|
49
|
+
config.live_tree(id: id, include_archived: include_archived, enviro: enviro, **kargs, &block)
|
50
50
|
end
|
51
51
|
|
52
52
|
# @see Eco::API::Session::Config#schemas
|
@@ -12,9 +12,9 @@ class Eco::API::UseCases::DefaultCases::ReinviteTransCase < Eco::API::Common::Lo
|
|
12
12
|
invite = session.new_job("main", "invite", :update, usecase, :account)
|
13
13
|
users.each do |person|
|
14
14
|
if force_invite?
|
15
|
-
person.account.send_invites = true
|
16
|
-
else
|
17
15
|
person.account.force_send_invites = true
|
16
|
+
else
|
17
|
+
person.account.send_invites = true
|
18
18
|
end
|
19
19
|
invite.add(person)
|
20
20
|
end
|
@@ -68,7 +68,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
68
68
|
msg << "nor options(:source, :structure_id). "
|
69
69
|
msg << "Infering active locations structure."
|
70
70
|
log(:warn) { msg }
|
71
|
-
if self.current_tree =
|
71
|
+
if self.current_tree = session_live_tree
|
72
72
|
@target_structure_id = current_tree.id
|
73
73
|
end
|
74
74
|
end
|
@@ -81,7 +81,13 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
81
81
|
tree_init = current_tree
|
82
82
|
target_id = target_structure_id
|
83
83
|
return current_tree if current_tree != tree_init
|
84
|
-
self.current_tree =
|
84
|
+
self.current_tree = session_live_tree(id: target_id)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Unique access point to retrieve the live tree
|
88
|
+
# @note ensures archived nodes are retrieved.
|
89
|
+
def session_live_tree(id: nil)
|
90
|
+
session.live_tree(id: id, include_archived: true)
|
85
91
|
end
|
86
92
|
end
|
87
93
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Eco::API::UseCases::GraphQL::Helpers::Location
|
2
|
+
class TagsRemap
|
3
|
+
class TagsMap
|
4
|
+
attr_reader :from, :to
|
5
|
+
|
6
|
+
def initialize(from, to)
|
7
|
+
@from = TagsSet.new(from)
|
8
|
+
@to = TagsSet.new(to)
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_csv_row
|
12
|
+
[from.to_s, to.to_s]
|
13
|
+
end
|
14
|
+
|
15
|
+
# @note to create a stable sort we assume `self` is a sorted element
|
16
|
+
def <=>(other)
|
17
|
+
return -1 if maps? && !other.maps?
|
18
|
+
return 1 if !maps? && other.maps?
|
19
|
+
return -1 if rename? && other.move?
|
20
|
+
return 1 if move? && other.rename?
|
21
|
+
return -1 if rename? && other.rename?
|
22
|
+
# both are being moved (specific/long mappings first)
|
23
|
+
return 1 if from.subset_of?(other.from)
|
24
|
+
return -1 if from.superset_of?(other.from)
|
25
|
+
return -1 if (from & other.from).empty?
|
26
|
+
return -1 if from.length >= other.from.length
|
27
|
+
return 1 if from.length < other.from.length
|
28
|
+
-1
|
29
|
+
end
|
30
|
+
|
31
|
+
# @note to create a stable sort we assume `self` is a sorted element
|
32
|
+
def goes_before?(other)
|
33
|
+
(self <=> other) == -1
|
34
|
+
end
|
35
|
+
|
36
|
+
# @note to create a stable sort we assume `self` is a sorted element
|
37
|
+
def goes_after?(other)
|
38
|
+
(self <=> other) == 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def both?(&block)
|
42
|
+
[from, to].all?(&block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def any?(&block)
|
46
|
+
[from, to].any?(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def maps?
|
50
|
+
return false if any?(&:empty?)
|
51
|
+
return false if from == to
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
def rename?
|
56
|
+
return false unless maps?
|
57
|
+
both? {|set| set.length == 1}
|
58
|
+
end
|
59
|
+
|
60
|
+
def move?
|
61
|
+
return false unless maps?
|
62
|
+
!rename?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Eco::API::UseCases::GraphQL::Helpers::Location
|
2
|
+
class TagsRemap
|
3
|
+
class TagsSet
|
4
|
+
class << self
|
5
|
+
def attr_compare(*attrs)
|
6
|
+
attrs.each do |attr|
|
7
|
+
meth = "#{attr}".to_sym
|
8
|
+
define_method meth do |value|
|
9
|
+
set.send(meth, to_set(value))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
def attr_operate(*attrs)
|
14
|
+
attrs.each do |attr|
|
15
|
+
meth = "#{attr}".to_sym
|
16
|
+
define_method meth do |value|
|
17
|
+
self.class.new(set.send(meth, to_set(value)))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
COMPARE_METHODS = %i[< <= == > >=].freeze
|
24
|
+
OPERATE_METHIDS = %i[& + - ^].freeze
|
25
|
+
|
26
|
+
attr_compare *COMPARE_METHODS
|
27
|
+
attr_operate *OPERATE_METHIDS
|
28
|
+
|
29
|
+
attr_reader :tags, :set
|
30
|
+
|
31
|
+
def initialize(tags)
|
32
|
+
@ini_tags = value_to_a(tags)
|
33
|
+
@set = to_set(tags)
|
34
|
+
end
|
35
|
+
|
36
|
+
def length
|
37
|
+
set.length
|
38
|
+
end
|
39
|
+
|
40
|
+
def tags
|
41
|
+
ini_tags.compact.map(&:upcase)
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_a
|
45
|
+
tags
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
tags.join('|')
|
50
|
+
end
|
51
|
+
|
52
|
+
def empty?
|
53
|
+
set.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def include?(value)
|
57
|
+
value = value.to_s.strip
|
58
|
+
return false if value.empty?
|
59
|
+
set.include?(value)
|
60
|
+
end
|
61
|
+
|
62
|
+
def include_any?(value)
|
63
|
+
value.to_a.any? {|tag| self.include?(tag)}
|
64
|
+
end
|
65
|
+
|
66
|
+
def subset_of?(value)
|
67
|
+
set.subset?(to_set(value))
|
68
|
+
end
|
69
|
+
|
70
|
+
def superset_of?(value)
|
71
|
+
set.superset?(to_set(value))
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def ini_tags
|
77
|
+
@ini_tags
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def value_to_a(value)
|
83
|
+
return value.ini_tags.dup if value.is_a?(self.class)
|
84
|
+
return value.dup if value.is_a?(Array)
|
85
|
+
return value.to_a if value.is_a?(Set)
|
86
|
+
raise ArgumentError, "Expecting #{self.class}, Set or Array. Given: #{value.class}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_set(value)
|
90
|
+
values = value_to_a(value)
|
91
|
+
Set.new.merge(values.compact.map(&:upcase))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Eco::API::UseCases::GraphQL::Helpers::Location
|
2
|
+
class TagsRemap
|
3
|
+
def self.correct_pair?(pair)
|
4
|
+
correct_pair = pair.is_a?(Array)
|
5
|
+
correct_pair && pair.length == 2
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :src_maps
|
9
|
+
attr_reader :from, :to
|
10
|
+
|
11
|
+
def each(&block)
|
12
|
+
return to_enum(:each) unless block
|
13
|
+
src_maps.each(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_csv(filename)
|
17
|
+
CSV.open(filename, "w") do |fd|
|
18
|
+
fd << ["src_tags", "dst_tags"]
|
19
|
+
each do |tags_map|
|
20
|
+
fd << tags_map.to_csv_row
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"".tap do |str|
|
27
|
+
each.map do |tags_map|
|
28
|
+
from, to = tags_map.to_csv_row
|
29
|
+
str << " • from: #{from}\n"
|
30
|
+
str << " • to: #{to}\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Sorts the maps in the correct order
|
36
|
+
# @note it assumes that:
|
37
|
+
# 1. renames go before moving nodes
|
38
|
+
# 2. moving nodes does not include a rename
|
39
|
+
# 3. moving nodes includes all the path on both, source and destination tags
|
40
|
+
# @note DISABLED: the order should be that in what the operations happened!
|
41
|
+
# An important thing is that all the path is always included in the mappings.
|
42
|
+
# * The only way that this would work is to apply upper (previous) tags_maps
|
43
|
+
# to subsequent ones. But the order should still be kept!
|
44
|
+
# def sorted_maps
|
45
|
+
# [].tap do |sorted|
|
46
|
+
# src_maps.each do |curr_map|
|
47
|
+
# pos = nil
|
48
|
+
# sorted.each_with_index.reverse_each do |prev_map, idx|
|
49
|
+
# pos = idx + 1 if prev_map.goes_before?(curr_map)
|
50
|
+
# break if pos
|
51
|
+
# end
|
52
|
+
# sorted.insert(pos || 0, curr_map)
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
|
57
|
+
def empty?
|
58
|
+
src_maps.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
def <<(pair)
|
62
|
+
raise ArgumentError, "Expecting pair of Array in Array. Given: #{pair}" unless self.class.correct_pair?(pair)
|
63
|
+
add(*pair)
|
64
|
+
end
|
65
|
+
|
66
|
+
def add(from, to)
|
67
|
+
raise ArgumentError, "Expecting Array. Given: #{from.class}" unless from.is_a?(Array)
|
68
|
+
raise ArgumentError, "Expecting Array. Given: #{to.class}" unless to.is_a?(Array)
|
69
|
+
new_src TagsMap.new(from, to)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
attr_reader :src_maps
|
75
|
+
attr_reader :from_key, :to_key
|
76
|
+
|
77
|
+
def new_src(tags_map)
|
78
|
+
src_maps << tags_map
|
79
|
+
end
|
80
|
+
|
81
|
+
def src_maps
|
82
|
+
@src_maps ||= []
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
require_relative 'tags_remap/tags_map'
|
88
|
+
require_relative 'tags_remap/tags_set'
|
@@ -18,6 +18,10 @@ class Eco::API::UseCases::GraphQL::Samples::Location
|
|
18
18
|
Eco::API::UseCases::GraphQL::Helpers::Location::Command::Results
|
19
19
|
end
|
20
20
|
|
21
|
+
def tags_remap_class
|
22
|
+
Eco::API::UseCases::GraphQL::Helpers::Location::TagsRemap
|
23
|
+
end
|
24
|
+
|
21
25
|
# Capture results
|
22
26
|
def results
|
23
27
|
@results ||= {}
|
@@ -26,7 +30,7 @@ class Eco::API::UseCases::GraphQL::Samples::Location
|
|
26
30
|
# The maps of tags to be used in batch remap tags
|
27
31
|
# @return [Array<Array>] source/destination pairs of `Array<String>`
|
28
32
|
def tags_remap_table
|
29
|
-
@tags_remap_table ||=
|
33
|
+
@tags_remap_table ||= tags_remap_class.new
|
30
34
|
end
|
31
35
|
|
32
36
|
# Errors tracking/logging.
|
@@ -87,17 +91,17 @@ class Eco::API::UseCases::GraphQL::Samples::Location
|
|
87
91
|
node_id, parent_id = result.command_input_data.values_at(:nodeId, :parentId)
|
88
92
|
prev_node = previous_tree.node(node_id)
|
89
93
|
curr_node = current_tree.node(node_id)
|
90
|
-
|
91
|
-
|
94
|
+
prev_path = prev_node.path.reverse
|
95
|
+
new_path = curr_node.path.reverse
|
92
96
|
|
93
97
|
curr_parent = curr_node.parent.top? ? nil : curr_node.parent
|
94
98
|
unless curr_parent&.id == parent_id
|
95
|
-
msg = "Node '#{node_id}' was moved
|
99
|
+
msg = "Node '#{node_id}' was moved under '#{parent_id}', "
|
96
100
|
msg << "but in current structure has parent '#{curr_parent&.id}'"
|
97
101
|
log(:warn) { msg }
|
98
102
|
end
|
99
103
|
|
100
|
-
tags_remap_table << [
|
104
|
+
tags_remap_table << [prev_path, new_path]
|
101
105
|
end
|
102
106
|
end
|
103
107
|
end
|
@@ -108,8 +112,8 @@ class Eco::API::UseCases::GraphQL::Samples::Location
|
|
108
112
|
timestamp_file(filename).tap do |file|
|
109
113
|
CSV.open(file, 'w') do |csv|
|
110
114
|
csv << ["source_tags", "destination_tags"]
|
111
|
-
tags_remap_table.each do |
|
112
|
-
csv <<
|
115
|
+
tags_remap_table.each do |tags_remap|
|
116
|
+
csv << tags_remap.to_csv_row
|
113
117
|
end
|
114
118
|
end
|
115
119
|
log(:info) { "Generated file '#{file}'" }
|
@@ -28,10 +28,11 @@ class Eco::Data::Locations::NodeLevel
|
|
28
28
|
msg << "\n Adding missing upper level(s): " + missing_nodes.map(&:raw_tag).pretty_inspect
|
29
29
|
log(:info) { msg }
|
30
30
|
|
31
|
-
|
32
|
-
#
|
33
|
-
|
34
|
-
|
31
|
+
# The very top missing node (first in list) should be checked against prev_level
|
32
|
+
# alongside any descendants in missing_nodes (when gap 2+)
|
33
|
+
tidied_nodes = tidy_nodes(missing_nodes, prev_level: prev_level, main: false)
|
34
|
+
out.push(*tidied_nodes)
|
35
|
+
#level = prev_level + 1 # <= we are actually on level and filled in the gaps
|
35
36
|
end
|
36
37
|
out << node
|
37
38
|
done_ids << node_id
|
@@ -44,6 +45,8 @@ class Eco::Data::Locations::NodeLevel
|
|
44
45
|
end
|
45
46
|
|
46
47
|
# Sets the `parentId` property.
|
48
|
+
# Although with normalized nodes parents are self-contained
|
49
|
+
# we use this method
|
47
50
|
def fill_in_parents(nodes)
|
48
51
|
nodes.tap do |nodes|
|
49
52
|
prev_nodes = empty_level_tracker_hash(11)
|
@@ -31,7 +31,13 @@ class Eco::Data::Locations::NodeLevel
|
|
31
31
|
prev_level = nil
|
32
32
|
prev_node = nil
|
33
33
|
prev_nodes = empty_level_tracker_hash(11)
|
34
|
-
|
34
|
+
prev_node_get = proc do |raw_level|
|
35
|
+
prev = nil
|
36
|
+
(1..raw_level).to_a.reverse.each do |lev|
|
37
|
+
prev ||= prev_nodes[lev]
|
38
|
+
end
|
39
|
+
prev
|
40
|
+
end
|
35
41
|
# Convert to Eco::CSV::Table for a fresh start
|
36
42
|
csv = Eco::CSV.parse(csv.to_csv).nil_blank_cells.add_index_column(:row_num)
|
37
43
|
|
@@ -42,10 +48,12 @@ class Eco::Data::Locations::NodeLevel
|
|
42
48
|
|
43
49
|
# If node is nested in prev_node or is a sibling thereof
|
44
50
|
if prev_node.raw_level <= node.raw_level
|
45
|
-
# Make sure
|
51
|
+
# Make sure upper level tags are there (including parent)
|
52
|
+
# This normalizes input to all upper level tags always filled in
|
53
|
+
# which allows to node#actual_level to work
|
46
54
|
node.set_high_levels(prev_node)
|
47
55
|
else
|
48
|
-
if parent_node =
|
56
|
+
if parent_node = prev_node_get[node.raw_level - 1]
|
49
57
|
node.set_high_levels(parent_node)
|
50
58
|
elsif node.raw_level == 1
|
51
59
|
# It is expected not to have parent (as it's top level tag)
|
@@ -47,6 +47,13 @@ module Eco::Data::Locations
|
|
47
47
|
tags_array.index(raw_tag) + 1
|
48
48
|
end
|
49
49
|
|
50
|
+
def raw_prev_empty_level
|
51
|
+
tags_array[0..raw_level-1].each_with_index.reverse_each do |value, idx|
|
52
|
+
return idx + 1 unless value
|
53
|
+
end
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
50
57
|
def tag_idx
|
51
58
|
tags_array.index(raw_tag)
|
52
59
|
end
|
@@ -106,6 +113,7 @@ module Eco::Data::Locations
|
|
106
113
|
true
|
107
114
|
end
|
108
115
|
|
116
|
+
# Cleanses deepest tags
|
109
117
|
def override_upper_levels(src_tags_array, from_level: self.raw_level + 1)
|
110
118
|
target_lev = Array(from_level..tag_attrs_count)
|
111
119
|
target_tags = src_tags_array[level_to_idx(from_level)..level_to_idx(tag_attrs_count)]
|
@@ -115,7 +123,9 @@ module Eco::Data::Locations
|
|
115
123
|
self
|
116
124
|
end
|
117
125
|
|
118
|
-
|
126
|
+
# Ensures parent is among the upper level tags
|
127
|
+
def override_lower_levels(src_tags_array, to_level: self.raw_prev_empty_level)
|
128
|
+
return self unless to_level
|
119
129
|
target_lev = Array(1..to_level)
|
120
130
|
target_tags = src_tags_array[level_to_idx(1)..level_to_idx(to_level)]
|
121
131
|
target_lev.zip(target_tags).each do |(n, tag)|
|
data/lib/eco/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eco-helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oscar Segura
|
@@ -156,7 +156,7 @@ dependencies:
|
|
156
156
|
requirements:
|
157
157
|
- - ">="
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: 0.3.
|
159
|
+
version: 0.3.10
|
160
160
|
- - "<"
|
161
161
|
- !ruby/object:Gem::Version
|
162
162
|
version: '0.4'
|
@@ -166,7 +166,7 @@ dependencies:
|
|
166
166
|
requirements:
|
167
167
|
- - ">="
|
168
168
|
- !ruby/object:Gem::Version
|
169
|
-
version: 0.3.
|
169
|
+
version: 0.3.10
|
170
170
|
- - "<"
|
171
171
|
- !ruby/object:Gem::Version
|
172
172
|
version: '0.4'
|
@@ -598,6 +598,9 @@ files:
|
|
598
598
|
- lib/eco/api/usecases/graphql/helpers/location/command.rb
|
599
599
|
- lib/eco/api/usecases/graphql/helpers/location/command/result.rb
|
600
600
|
- lib/eco/api/usecases/graphql/helpers/location/command/results.rb
|
601
|
+
- lib/eco/api/usecases/graphql/helpers/location/tags_remap.rb
|
602
|
+
- lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_map.rb
|
603
|
+
- lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_set.rb
|
601
604
|
- lib/eco/api/usecases/graphql/samples.rb
|
602
605
|
- lib/eco/api/usecases/graphql/samples/location.rb
|
603
606
|
- lib/eco/api/usecases/graphql/samples/location/command.rb
|