eco-helpers 2.6.3 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +95 -0
- data/CHANGELOG.md +135 -2
- data/Rakefile +13 -7
- data/eco-helpers.gemspec +3 -3
- data/lib/eco/api/common/loaders/base.rb +2 -2
- data/lib/eco/api/common/loaders/case_base.rb +1 -1
- data/lib/eco/api/common/loaders/config/workflow/mailer.rb +5 -5
- data/lib/eco/api/common/loaders/error_handler.rb +8 -5
- data/lib/eco/api/common/loaders/parser.rb +44 -22
- data/lib/eco/api/common/loaders/policy.rb +6 -4
- data/lib/eco/api/common/loaders/use_case.rb +13 -7
- data/lib/eco/api/common/people/base_parser.rb +0 -2
- data/lib/eco/api/common/people/default_parsers/boolean_parser.rb +0 -1
- data/lib/eco/api/common/people/default_parsers/csv_parser.rb +1 -1
- data/lib/eco/api/common/people/default_parsers/date_parser.rb +64 -12
- data/lib/eco/api/common/people/default_parsers/freemium_parser.rb +0 -1
- data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +13 -5
- data/lib/eco/api/common/people/default_parsers/multi_parser.rb +0 -1
- data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +18 -5
- data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +8 -8
- data/lib/eco/api/common/people/default_parsers/select_parser.rb +50 -26
- data/lib/eco/api/common/people/default_parsers/send_invites_parser.rb +6 -6
- data/lib/eco/api/common/people/default_parsers/xls_parser.rb +9 -12
- data/lib/eco/api/common/people/default_parsers.rb +1 -12
- data/lib/eco/api/common/people/entries.rb +13 -13
- data/lib/eco/api/common/people/entry_factory.rb +76 -45
- data/lib/eco/api/common/people/person_attribute_parser.rb +8 -12
- data/lib/eco/api/common/people/person_entry.rb +86 -75
- data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +60 -44
- data/lib/eco/api/common/people/person_factory.rb +30 -22
- data/lib/eco/api/common/people/person_modifier.rb +11 -13
- data/lib/eco/api/common/people/person_parser.rb +101 -39
- data/lib/eco/api/common/people/supervisor_helpers.rb +25 -26
- data/lib/eco/api/common/session/base_session.rb +9 -9
- data/lib/eco/api/common/session/environment.rb +7 -5
- data/lib/eco/api/common/session/sftp.rb +59 -32
- data/lib/eco/api/common/version_patches/ecoportal_api/external_person.rb +10 -6
- data/lib/eco/api/common/version_patches/exception.rb +11 -13
- data/lib/eco/api/error.rb +32 -20
- data/lib/eco/api/microcases/set_supervisor.rb +0 -3
- data/lib/eco/api/organization/node_classifications.rb +82 -0
- data/lib/eco/api/organization/policy_groups.rb +4 -6
- data/lib/eco/api/organization/tag_tree.rb +169 -93
- data/lib/eco/api/organization.rb +1 -0
- data/lib/eco/api/session/batch/job.rb +1 -1
- data/lib/eco/api/session/config/tagtree.rb +41 -23
- data/lib/eco/api/session/config/workflow.rb +113 -88
- data/lib/eco/api/session/config.rb +6 -0
- data/lib/eco/api/session.rb +51 -29
- data/lib/eco/api/usecases/base_io.rb +28 -25
- data/lib/eco/api/usecases/default/locations/cli/tagtree_extract_cli.rb +7 -2
- data/lib/eco/api/usecases/default/locations/cli/tagtree_upload_cli.rb +21 -0
- data/lib/eco/api/usecases/default/locations/csv_to_tree_case.rb +3 -3
- data/lib/eco/api/usecases/default/locations/tagtree_extract_case.rb +54 -23
- data/lib/eco/api/usecases/default/locations/tagtree_upload_case.rb +87 -0
- data/lib/eco/api/usecases/default/locations.rb +1 -0
- data/lib/eco/api/usecases/default/people/analyse_people_case.rb +60 -56
- data/lib/eco/api/usecases/default/people/change_email_case.rb +8 -9
- data/lib/eco/api/usecases/default/people/clean_unknown_tags_case.rb +13 -11
- data/lib/eco/api/usecases/default/people/clear_abilities_case.rb +2 -2
- data/lib/eco/api/usecases/default/people/org_data_convert_case.rb +25 -27
- data/lib/eco/api/usecases/default/people/refresh_case.rb +2 -2
- data/lib/eco/api/usecases/default/people/reinvite_trans_case.rb +1 -1
- data/lib/eco/api/usecases/default/people/reinvite_trans_cli.rb +0 -1
- data/lib/eco/api/usecases/default/people/restore_db_case.rb +39 -34
- data/lib/eco/api/usecases/default/people/set_default_tag_case.rb +19 -15
- data/lib/eco/api/usecases/default/people/supers_cyclic_identify_case.rb +16 -12
- data/lib/eco/api/usecases/default_cases/hris_case.rb +17 -15
- data/lib/eco/api/usecases/default_cases/samples/sftp_case.rb +30 -16
- data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +0 -2
- data/lib/eco/api/usecases/graphql/base.rb +5 -3
- data/lib/eco/api/usecases/graphql/helpers/base/case_env.rb +4 -1
- data/lib/eco/api/usecases/graphql/helpers/base/graphql_env.rb +14 -0
- data/lib/eco/api/usecases/graphql/helpers/base.rb +5 -4
- data/lib/eco/api/usecases/graphql/helpers/location/base/classifications_parser.rb +60 -0
- data/lib/eco/api/usecases/graphql/helpers/location/base/tree_tracking.rb +72 -0
- data/lib/eco/api/usecases/graphql/helpers/location/base.rb +25 -59
- data/lib/eco/api/usecases/graphql/helpers/location/command/diff/as_update.rb +59 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diff/compare.rb +49 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diff.rb +11 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/commandable.rb +46 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable/for_archive.rb +23 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable/for_unarchive.rb +65 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable.rb +49 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/sortable/relation_safe_sort.rb +119 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/sortable.rb +59 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages.rb +82 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs.rb +20 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/optimizations.rb +84 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/result.rb +4 -4
- data/lib/eco/api/usecases/graphql/helpers/location/command/results.rb +24 -12
- data/lib/eco/api/usecases/graphql/helpers/location/command.rb +21 -24
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_map.rb +1 -1
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_set.rb +10 -11
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap.rb +8 -9
- data/lib/eco/api/usecases/graphql/samples/location/command/dsl.rb +41 -12
- data/lib/eco/api/usecases/graphql/samples/location/command/results.rb +11 -80
- data/lib/eco/api/usecases/graphql/samples/location/command/service/tree_update.rb +89 -0
- data/lib/eco/api/usecases/graphql/samples/location/command/service.rb +6 -0
- data/lib/eco/api/usecases/graphql/samples/location/command/track_changed_ids.rb +89 -0
- data/lib/eco/api/usecases/graphql/samples/location/command.rb +3 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/base.rb +9 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/heading.rb +18 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/inputable.rb +53 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing/classifications.rb +34 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing/helpers.rb +28 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing.rb +46 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible.rb +38 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff.rb +105 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/discarded.rb +16 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/input.rb +15 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/node_attr_maps.rb +22 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/parser.rb +45 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter.rb +36 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/output.rb +56 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list.rb +41 -0
- data/lib/eco/api/usecases/graphql/samples/location/service.rb +8 -0
- data/lib/eco/api/usecases/graphql/samples/location.rb +1 -0
- data/lib/eco/api/usecases/graphql/utils/sftp.rb +96 -36
- data/lib/eco/api/usecases/ooze_cases/export_register_case.rb +8 -6
- data/lib/eco/api/usecases/ooze_samples/helpers/creatable.rb +4 -3
- data/lib/eco/api/usecases/ooze_samples/helpers/exportable_ooze.rb +39 -25
- data/lib/eco/api/usecases/ooze_samples/helpers/exportable_register.rb +13 -15
- data/lib/eco/api/usecases/ooze_samples/helpers/filters.rb +50 -21
- data/lib/eco/api/usecases/ooze_samples/helpers/ooze_handlers.rb +21 -11
- data/lib/eco/api/usecases/ooze_samples/helpers/rescuable.rb +2 -0
- data/lib/eco/api/usecases/ooze_samples/helpers/shortcuts.rb +49 -43
- data/lib/eco/api/usecases/ooze_samples/ooze_base_case.rb +17 -19
- data/lib/eco/api/usecases/ooze_samples/register_export_case.rb +48 -43
- data/lib/eco/api/usecases/ooze_samples/register_update_case.rb +34 -34
- data/lib/eco/api/usecases/ooze_samples/target_oozes_update_case.rb +8 -10
- data/lib/eco/api/usecases.rb +0 -1
- data/lib/eco/cli/config/use_cases.rb +31 -29
- data/lib/eco/cli_default/input_filters.rb +0 -5
- data/lib/eco/cli_default/people_filters.rb +4 -4
- data/lib/eco/cli_default/workflow.rb +13 -14
- data/lib/eco/csv/table.rb +34 -25
- data/lib/eco/data/hashes/array_diff.rb +24 -35
- data/lib/eco/data/hashes/diff_result/meta.rb +131 -0
- data/lib/eco/data/hashes/diff_result.rb +65 -57
- data/lib/eco/data/hashes/sanke_camel_indifferent_access.rb +278 -0
- data/lib/eco/data/hashes.rb +1 -1
- data/lib/eco/data/locations/convert.rb +1 -1
- data/lib/eco/data/locations/node_base/csv_convert.rb +19 -9
- data/lib/eco/data/locations/node_base/parsing.rb +4 -2
- data/lib/eco/data/locations/node_base/treeify.rb +149 -132
- data/lib/eco/data/locations/node_base.rb +15 -4
- data/lib/eco/data/locations/node_diff/accessors.rb +13 -5
- data/lib/eco/data/locations/node_diff/nodes_diff/clustered_treeify.rb +101 -0
- data/lib/eco/data/locations/node_diff/nodes_diff/diffs_tree.rb +99 -0
- data/lib/eco/data/locations/node_diff/{selectors.rb → nodes_diff/selectors.rb} +1 -1
- data/lib/eco/data/locations/node_diff/nodes_diff.rb +50 -35
- data/lib/eco/data/locations/node_diff.rb +45 -17
- data/lib/eco/data/locations/node_level/parsing.rb +15 -21
- data/lib/eco/data/locations/node_level.rb +66 -22
- data/lib/eco/data/locations/node_plain/parsing.rb +1 -1
- data/lib/eco/data/locations/node_plain.rb +60 -7
- data/lib/eco/data/strings/camel_case.rb +35 -0
- data/lib/eco/data/strings/snake_case.rb +18 -0
- data/lib/eco/data/strings.rb +8 -0
- data/lib/eco/data.rb +1 -0
- data/lib/eco/language/methods/call_detector.rb +11 -0
- data/lib/eco/language/methods/dsl_able.rb +7 -1
- data/lib/eco/language/methods.rb +2 -1
- data/lib/eco/language/models/collection.rb +23 -25
- data/lib/eco/language/models/parser_serializer.rb +24 -5
- data/lib/eco/version.rb +1 -1
- data/lib/eco-helpers.rb +0 -1
- metadata +54 -9
- data/lib/eco/data/hashes/diff_meta.rb +0 -52
@@ -0,0 +1,82 @@
|
|
1
|
+
# @note The order in which updates should happen:
|
2
|
+
# (1) UNARCHIVE (top-bottom) should go FIRST, to ensure consistency througout all the stages sequence
|
3
|
+
# * Currently: CANNOT UPDATE (or move) ARCHIVED NODES
|
4
|
+
# * It can unarchive children with same archivedToken
|
5
|
+
# * Changing order to happen after MOVE does NOT prevent this to happen.
|
6
|
+
# * And archived children nodes cannot be moved somewhere else anyway either.
|
7
|
+
# * Within UNARCHIVE, the preferable order would be ALL nodes from leafs to root
|
8
|
+
# * to the purpose of preventing `already unarchived node` errors
|
9
|
+
# * because, from top to bottom, the `unarchivedToken` could have already unarchived children.
|
10
|
+
# * This still does not prevent the unintended consequence of automatic unarchive of children.
|
11
|
+
# * HOWEVER, the error _you can't unarchive a child of an archived node_ suggest that
|
12
|
+
# within UNARCHIVE, the order MUST BE from top-to-bottom, and MOREOVER
|
13
|
+
# * Among nodes with the same `archiveToken` only the topest one should be unarchived (the others follow),
|
14
|
+
# which prevents the errors `already unarchived node` and `can't unarchive child of archived node`
|
15
|
+
# * Children with same `archiveToken` that are not to be unarchived, should be rearchived
|
16
|
+
# * IMPORTANT: this could require to track all the way up to the first archived ancestor,
|
17
|
+
# path from leave-to archive-root, and then for unarchive from top to bottom only those
|
18
|
+
# with different archiveToken.
|
19
|
+
# (1.b) IMPORTANT: automatically unarchived nodes (archivedToken) that should remain archived
|
20
|
+
# should be RE-ARCHIVEd as part of the update (in the ARCHIVE stage)
|
21
|
+
# (2) UPDATE ID (--) needs to happen before
|
22
|
+
# * This allows other commands to refer to nodes and their parents with current ids.
|
23
|
+
# * If INSERT happened before UPDATE ID, they would need to refer to the previous value of `parentId`,
|
24
|
+
# but inserts don't have previous source in NodeDiff (they are new) and only a working-around (i.e. general lookup)
|
25
|
+
# would allow to obtain this value (not really neat)
|
26
|
+
# * Technically, the internal ORDER does NOT MATTER, but if something has to fail, let's make it fail
|
27
|
+
# big: so let's do top-to-bottom.
|
28
|
+
# (2.b) UPDATE NAME can happen anywhere, so let's keep tree consistent and do it as soon as possible.
|
29
|
+
# (3) INSERT (top-bottom) has priority over MOVE, as there may be existing nodes being moved to or inserted to.
|
30
|
+
# * And should happen AFTER the UNARCHIVE, because we could be inserting to an unarchived node
|
31
|
+
# and that would make our inserted node an archived one as well.
|
32
|
+
# * The internal ORDER MATTERS and it's from top to bottom (root to leaves) to prevent unknown parentId error.
|
33
|
+
# (4) MOVE (--) should happen before ARCHIVE and after UNARCHIVE
|
34
|
+
# * This prevents active nodes to be archived from their previous parent node, now being archived.
|
35
|
+
# * It also prevents the error of moving to an archived node, or not being able to move an archived node.
|
36
|
+
# * If it happened before UNARCHIVE, we would be either move ARCHIVED nodes to be unarchived,
|
37
|
+
# or moving other nodes to them before they are unarchived
|
38
|
+
# * Technically, for MOVE, the internal ORDER does NOT MATTER. It would matter for new/inserted nodes,
|
39
|
+
# but we do not move inserted nodes (we add them directly to the parent).
|
40
|
+
# * However, to build the remap tags table, it does matter: from bottom to top. Children should be
|
41
|
+
# retagged first because retagging first parents changes the path of their children retags.
|
42
|
+
# (5) ARCHIVE (bottom-top) should happen always LAST, after nodes have been MOVED.
|
43
|
+
# • The order of archiving should probably be:
|
44
|
+
# (a) although firstly thought go from leafs to root to prevent the `archiveToken`
|
45
|
+
# it should go from top-to-bottom, so precisely the `archiveToken` is generated and history well sorted.
|
46
|
+
# (b) to preventing `already archived node` errors, we should only include the parent
|
47
|
+
# (6) RE-ARCHIVE (bottom-top) see (1.b) all those that were automatically unarchived but should remain archived.
|
48
|
+
# • The neat solution is to recalculate changes with the live_tree and the final desired result,
|
49
|
+
# but perhaps only target those to be re-archived?
|
50
|
+
class Eco::API::UseCases::GraphQL::Helpers::Location::Command::Diffs
|
51
|
+
module Stages
|
52
|
+
STAGES = %i[unarchive id_name insert move archive].freeze
|
53
|
+
|
54
|
+
def stages
|
55
|
+
STAGES
|
56
|
+
end
|
57
|
+
|
58
|
+
def stage_idx(stage)
|
59
|
+
stages.index(stage)
|
60
|
+
end
|
61
|
+
|
62
|
+
def id_update_stage_idx
|
63
|
+
@id_update_stage_idx ||= stage_idx(:id) || stage_idx(:id_name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def move_stage_idx
|
67
|
+
@move_stage_idx ||= stage_idx(:move)
|
68
|
+
end
|
69
|
+
|
70
|
+
def after_id_update?(stage)
|
71
|
+
(idx = stage_idx(stage)) && idx > id_update_stage_idx
|
72
|
+
end
|
73
|
+
|
74
|
+
def during_or_after_move?(stage)
|
75
|
+
(idx = stage_idx(stage)) && idx >= move_stage_idx
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
require_relative 'stages/sortable'
|
81
|
+
require_relative 'stages/diff_sortable'
|
82
|
+
require_relative 'stages/commandable'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# The order in which updates should happen:
|
2
|
+
# @note several challenges were found during the design of this class:
|
3
|
+
# This translated into dividing the command sequence into different `STAGES`.
|
4
|
+
module Eco::API::UseCases::GraphQL::Helpers::Location
|
5
|
+
class Command::Diffs < Eco::Data::Locations::NodeDiff::NodesDiff
|
6
|
+
class_resolver :diff_result_class, Command::Diff
|
7
|
+
|
8
|
+
require_relative 'diffs/stages'
|
9
|
+
|
10
|
+
include Stages::Commandable
|
11
|
+
|
12
|
+
def commands
|
13
|
+
self.class.stages.each_with_object([]) do |stage, out|
|
14
|
+
comms = stage_commands(stage)
|
15
|
+
out.concat(comms)
|
16
|
+
yield(comms, stage) if block_given?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Eco::API::UseCases::GraphQL::Helpers::Location
|
2
|
+
module Command::Optimizations
|
3
|
+
DEFAULT_COMMANDS_PER_PAGE = 45
|
4
|
+
DEFAULT_FORCE_CONTINUE = false
|
5
|
+
|
6
|
+
# Available options are:
|
7
|
+
# - :per_request -> on each request
|
8
|
+
# - :per_batch -> at the end of each batch / stage (on last page)
|
9
|
+
# - :once -> only when the script starts to run
|
10
|
+
def default_tree_tracking_mode
|
11
|
+
:per_request
|
12
|
+
end
|
13
|
+
|
14
|
+
# Helper to identify the commands payload block
|
15
|
+
# @note
|
16
|
+
# 1. Gives flexibility on at what time the structure should be retrieved
|
17
|
+
# 2. This increases performacne, as we don't retrieve the full tree on
|
18
|
+
# each request unless necessary/specified
|
19
|
+
# 3. `nil` falls the block back to the `ecoportal-api-graphql` gem, which
|
20
|
+
# has a default block that retrieves the structure
|
21
|
+
# @return [Proc, NilClass] the payload block
|
22
|
+
def scope_commands_block(idx, total, track_tree_mode: default_tree_tracking_mode)
|
23
|
+
case track_tree_mode
|
24
|
+
when :per_request
|
25
|
+
nil
|
26
|
+
when :once
|
27
|
+
commands_payload_without_structure_block
|
28
|
+
when :per_batch
|
29
|
+
return nil if idx == total
|
30
|
+
commands_payload_without_structure_block
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Prevents each request from timing out
|
35
|
+
def commands_per_page
|
36
|
+
if self.class.const_defined?(:COMMANDS_PER_PAGE)
|
37
|
+
self.class::COMMANDS_PER_PAGE
|
38
|
+
else
|
39
|
+
DEFAULT_COMMANDS_PER_PAGE
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Whether to stop or continue on command fail
|
44
|
+
def force_continue?
|
45
|
+
if self.class.const_defined?(:FORCE_CONTINUE)
|
46
|
+
self.class::FORCE_CONTINUE
|
47
|
+
else
|
48
|
+
DEFAULT_FORCE_CONTINUE
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Commands payload without querying Structure
|
53
|
+
# @note this servces the purpose of optimizing/speeding up the requests.
|
54
|
+
def commands_payload_without_structure_block
|
55
|
+
proc {
|
56
|
+
clientMutationId
|
57
|
+
error { # rubocop:disable Style/BlockDelimiters
|
58
|
+
message
|
59
|
+
conflictingIds
|
60
|
+
validationErrors { # rubocop:disable Style/BlockDelimiters
|
61
|
+
error
|
62
|
+
message
|
63
|
+
}
|
64
|
+
}
|
65
|
+
results { # rubocop:disable Style/BlockDelimiters
|
66
|
+
command { # rubocop:disable Style/BlockDelimiters
|
67
|
+
id
|
68
|
+
state
|
69
|
+
__typename
|
70
|
+
}
|
71
|
+
ok
|
72
|
+
error { # rubocop:disable Style/BlockDelimiters
|
73
|
+
conflictingIds
|
74
|
+
message
|
75
|
+
validationErrors { # rubocop:disable Style/BlockDelimiters
|
76
|
+
error
|
77
|
+
message
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -42,11 +42,11 @@ module Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
|
42
42
|
def error_msg
|
43
43
|
return nil unless error?
|
44
44
|
msg = ''
|
45
|
-
msg << "(#{command} '#{node_id}') #{error.message}\n"
|
45
|
+
msg << "(#{command} '#{node_id}') #{error.message}\n"
|
46
46
|
return msg if error.validationErrors.empty?
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
|
48
|
+
msg << " • "
|
49
|
+
msg << error.validationErrors.map(&:message).join("\n • ")
|
50
50
|
msg
|
51
51
|
end
|
52
52
|
|
@@ -8,12 +8,10 @@ module Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def stats
|
11
|
-
msg
|
12
|
-
|
13
|
-
msg << " •
|
14
|
-
|
15
|
-
msg << " • Applied: #{errored.count} #{last_okay}\n" if some_applied?
|
16
|
-
msg << " • Pending: #{pending.count}\n" if some_pending?
|
11
|
+
msg = ''
|
12
|
+
msg << " • Errored: #{errored.count} #{first_err_str}\n" if errored?
|
13
|
+
msg << " • Applied: #{errored.count} #{last_okay_str}\n" if some_applied?
|
14
|
+
msg << " • Pending: #{pending.count}\n" if some_pending?
|
17
15
|
msg
|
18
16
|
end
|
19
17
|
|
@@ -38,7 +36,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
|
38
36
|
end
|
39
37
|
|
40
38
|
def success?
|
41
|
-
!error? && results.all?
|
39
|
+
!error? && results.all?(&:success?)
|
42
40
|
end
|
43
41
|
|
44
42
|
def results
|
@@ -64,7 +62,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
|
64
62
|
end
|
65
63
|
|
66
64
|
def errored
|
67
|
-
@errored ||= results.select
|
65
|
+
@errored ||= results.select(&:error?)
|
68
66
|
end
|
69
67
|
|
70
68
|
def errored?
|
@@ -80,15 +78,15 @@ module Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
|
80
78
|
end
|
81
79
|
|
82
80
|
def applied
|
83
|
-
@applied ||= results.select
|
81
|
+
@applied ||= results.select(&:applied?)
|
84
82
|
end
|
85
83
|
|
86
84
|
def applied?
|
87
|
-
results.all?
|
85
|
+
results.all?(&:applied?)
|
88
86
|
end
|
89
87
|
|
90
88
|
def some_applied?
|
91
|
-
applied.count
|
89
|
+
applied.count.positive?
|
92
90
|
end
|
93
91
|
|
94
92
|
def last_applied
|
@@ -100,7 +98,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
|
100
98
|
end
|
101
99
|
|
102
100
|
def pending
|
103
|
-
@pending ||= results.select
|
101
|
+
@pending ||= results.select(&:pending?)
|
104
102
|
end
|
105
103
|
|
106
104
|
def some_pending?
|
@@ -122,5 +120,19 @@ module Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
|
122
120
|
def response_results
|
123
121
|
response&.results || []
|
124
122
|
end
|
123
|
+
|
124
|
+
# First error is relevant only if request was NOT forced to continue.
|
125
|
+
def first_err_str
|
126
|
+
return '' if force?
|
127
|
+
pre_str = 'stopped on node'
|
128
|
+
pre_str = 'first error' unless force?
|
129
|
+
"(#{pre_str}: '#{first_errored&.node_id}' - idx: #{first_errored_idx})"
|
130
|
+
end
|
131
|
+
|
132
|
+
# Last successfully applied is relevant only if request was NOT forced to continue.
|
133
|
+
def last_okay_str
|
134
|
+
return '' if force?
|
135
|
+
"(last node done: '#{last_applied&.node_id}' - idx: #{last_applied_idx})"
|
136
|
+
end
|
125
137
|
end
|
126
138
|
end
|
@@ -3,25 +3,12 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
3
3
|
include Eco::Language::AuxiliarLogger
|
4
4
|
include Eco::API::UseCases::GraphQL::Helpers::Location::Base
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
require_relative 'command/optimizations'
|
7
|
+
include Eco::API::UseCases::GraphQL::Helpers::Location::Command::Optimizations
|
8
8
|
|
9
|
-
#
|
10
|
-
def
|
11
|
-
|
12
|
-
self.class::COMMANDS_PER_PAGE
|
13
|
-
else
|
14
|
-
DEFAULT_COMMANDS_PER_PAGE
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Whether to stop or continue on command fail
|
19
|
-
def force_continue?
|
20
|
-
if self.class.const_defined?(:FORCE_CONTINUE)
|
21
|
-
self.class::FORCE_CONTINUE
|
22
|
-
else
|
23
|
-
DEFAULT_FORCE_CONTINUE
|
24
|
-
end
|
9
|
+
# Actual GraphQL request
|
10
|
+
def apply_commands(input, &block)
|
11
|
+
graphql.locationStructure.applyCommands(input: input, &block)
|
25
12
|
end
|
26
13
|
|
27
14
|
# With given the commands, it generates the input of the endpoint mutation.
|
@@ -29,14 +16,20 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
29
16
|
def input(commands, force_continue: force_continue?)
|
30
17
|
{
|
31
18
|
clientMutationId: "",
|
32
|
-
id:
|
33
|
-
force:
|
34
|
-
commands:
|
19
|
+
id: target_structure_id,
|
20
|
+
force: force_continue,
|
21
|
+
commands: commands
|
35
22
|
}
|
36
23
|
end
|
37
24
|
|
25
|
+
# @param track_tree_mode [Symbol] when should updates happen
|
38
26
|
# @return see #with_sliced_input
|
39
|
-
def sliced_batches(
|
27
|
+
def sliced_batches(
|
28
|
+
batch_input,
|
29
|
+
size: commands_per_page,
|
30
|
+
desc: :input,
|
31
|
+
track_tree_mode: default_tree_tracking_mode
|
32
|
+
)
|
40
33
|
dry_run_msg = simulate? ? '(dry-run) ' : ''
|
41
34
|
|
42
35
|
if batch_input[:commands].empty?
|
@@ -60,7 +53,8 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
60
53
|
if simulate?
|
61
54
|
log(:info) { sliced_input.pretty_inspect } if page < 3
|
62
55
|
else
|
63
|
-
|
56
|
+
curr_block = scope_commands_block(page, pages, track_tree_mode: track_tree_mode)
|
57
|
+
response = apply_commands(sliced_input, &curr_block)
|
64
58
|
backup(response, type: "tree_update_#{desc}_response_#{page}_of_#{pages}")
|
65
59
|
end
|
66
60
|
|
@@ -75,7 +69,8 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
75
69
|
comms = input_data[:commands]
|
76
70
|
total = comms.count
|
77
71
|
pages = (total.to_f / size).ceil.to_i
|
78
|
-
page = 1
|
72
|
+
page = 1
|
73
|
+
out = []
|
79
74
|
comms.each_slice(size) do |comms_slice|
|
80
75
|
sliced_input = input_data.slice(:clientMutationId, :id).merge(commands: comms_slice)
|
81
76
|
yield(sliced_input, page, pages, comms_slice.count, total).tap do |response|
|
@@ -90,3 +85,5 @@ end
|
|
90
85
|
|
91
86
|
require_relative 'command/result'
|
92
87
|
require_relative 'command/results'
|
88
|
+
require_relative 'command/diff'
|
89
|
+
require_relative 'command/diffs'
|
@@ -13,7 +13,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# @note to create a stable sort we assume `self` is a sorted element
|
16
|
-
def <=>(other)
|
16
|
+
def <=>(other) # rubocop:disable Metrics/AbcSize
|
17
17
|
return -1 if maps? && !other.maps?
|
18
18
|
return 1 if !maps? && other.maps?
|
19
19
|
return -1 if rename? && other.move?
|
@@ -4,15 +4,16 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
4
4
|
class << self
|
5
5
|
def attr_compare(*attrs)
|
6
6
|
attrs.each do |attr|
|
7
|
-
meth = "#{attr}".to_sym
|
7
|
+
meth = "#{attr}".to_sym # rubocop:disable Style/RedundantInterpolation
|
8
8
|
define_method meth do |value|
|
9
9
|
set.send(meth, to_set(value))
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
+
|
13
14
|
def attr_operate(*attrs)
|
14
15
|
attrs.each do |attr|
|
15
|
-
meth = "#{attr}".to_sym
|
16
|
+
meth = "#{attr}".to_sym # rubocop:disable Style/RedundantInterpolation
|
16
17
|
define_method meth do |value|
|
17
18
|
self.class.new(set.send(meth, to_set(value)))
|
18
19
|
end
|
@@ -21,12 +22,12 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
21
22
|
end
|
22
23
|
|
23
24
|
COMPARE_METHODS = %i[< <= == > >=].freeze
|
24
|
-
|
25
|
+
OPERATE_METHODS = %i[& + - ^].freeze
|
25
26
|
|
26
|
-
attr_compare
|
27
|
-
attr_operate
|
27
|
+
attr_compare(*COMPARE_METHODS)
|
28
|
+
attr_operate(*OPERATE_METHODS)
|
28
29
|
|
29
|
-
attr_reader :
|
30
|
+
attr_reader :set
|
30
31
|
|
31
32
|
def initialize(tags)
|
32
33
|
@ini_tags = value_to_a(tags)
|
@@ -48,7 +49,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
48
49
|
def to_s
|
49
50
|
tags.join('|')
|
50
51
|
end
|
51
|
-
|
52
|
+
|
52
53
|
def empty?
|
53
54
|
set.empty?
|
54
55
|
end
|
@@ -60,7 +61,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
60
61
|
end
|
61
62
|
|
62
63
|
def include_any?(value)
|
63
|
-
value.to_a.any? {|tag|
|
64
|
+
value.to_a.any? {|tag| include?(tag)}
|
64
65
|
end
|
65
66
|
|
66
67
|
def subset_of?(value)
|
@@ -73,9 +74,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
73
74
|
|
74
75
|
protected
|
75
76
|
|
76
|
-
|
77
|
-
@ini_tags
|
78
|
-
end
|
77
|
+
attr_reader :ini_tags
|
79
78
|
|
80
79
|
private
|
81
80
|
|
@@ -5,9 +5,14 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
5
5
|
correct_pair && pair.length == 2
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
include Enumerable
|
9
|
+
|
9
10
|
attr_reader :from, :to
|
10
11
|
|
12
|
+
def src_maps
|
13
|
+
@src_maps ||= []
|
14
|
+
end
|
15
|
+
|
11
16
|
def each(&block)
|
12
17
|
return to_enum(:each) unless block
|
13
18
|
src_maps.each(&block)
|
@@ -15,7 +20,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
15
20
|
|
16
21
|
def to_csv(filename)
|
17
22
|
CSV.open(filename, "w") do |fd|
|
18
|
-
fd << [
|
23
|
+
fd << %w[src_tags dst_tags]
|
19
24
|
each do |tags_map|
|
20
25
|
fd << tags_map.to_csv_row
|
21
26
|
end
|
@@ -26,8 +31,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
26
31
|
"".tap do |str|
|
27
32
|
each.map do |tags_map|
|
28
33
|
from, to = tags_map.to_csv_row
|
29
|
-
str << " • from
|
30
|
-
str << " • to: #{to}\n"
|
34
|
+
str << " • '#{from}' => '#{to}'\n"
|
31
35
|
end
|
32
36
|
end
|
33
37
|
end
|
@@ -71,16 +75,11 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
71
75
|
|
72
76
|
private
|
73
77
|
|
74
|
-
attr_reader :src_maps
|
75
78
|
attr_reader :from_key, :to_key
|
76
79
|
|
77
80
|
def new_src(tags_map)
|
78
81
|
src_maps << tags_map
|
79
82
|
end
|
80
|
-
|
81
|
-
def src_maps
|
82
|
-
@src_maps ||= []
|
83
|
-
end
|
84
83
|
end
|
85
84
|
end
|
86
85
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class Eco::API::UseCases::GraphQL::Samples::Location
|
2
2
|
module Command::DSL
|
3
3
|
include Eco::API::UseCases::GraphQL::Helpers::Location::Command
|
4
|
+
include Eco::API::UseCases::GraphQL::Samples::Location::Command::TrackChangedIds
|
4
5
|
include Eco::API::UseCases::GraphQL::Samples::Location::Command::Results
|
5
6
|
|
6
7
|
# @example of implementation:
|
@@ -15,40 +16,68 @@ class Eco::API::UseCases::GraphQL::Samples::Location
|
|
15
16
|
# end
|
16
17
|
# end
|
17
18
|
# end
|
18
|
-
def inputs(*
|
19
|
+
def inputs(*_args, force_continue: force_continue?, **_kargs, &_block) # rubocop:disable Lint/UnusedMethodArgument
|
19
20
|
msg = "You should implement this method in your child class.\n"
|
20
21
|
msg << "Which should yield the input Hash and the stage or descriptor."
|
21
22
|
raise Eco::API::UseCases::GraphQL::Base::NotImplementedMethod, msg
|
22
23
|
end
|
23
24
|
|
24
25
|
# Main processor
|
25
|
-
def process
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
def process # rubocop:disable Metrics/AbcSize
|
27
|
+
self.error = false
|
28
|
+
self.exception = nil
|
29
|
+
|
30
|
+
super if defined?(super)
|
30
31
|
|
31
|
-
|
32
|
-
# this triggers a backup of the tagtree
|
32
|
+
# this may trigger a backup of the tagtree
|
33
33
|
self.current_tree ||= live_tree
|
34
34
|
|
35
35
|
inputs(force_continue: force_continue?) do |input, stage|
|
36
36
|
results[stage] ||= []
|
37
|
-
|
37
|
+
|
38
|
+
track_mode = batch_tree_track_mode(stage)
|
39
|
+
|
40
|
+
# yields the result of each batch
|
41
|
+
sliced_batches(input, desc: stage, track_tree_mode: track_mode) do |sliced_input, response, page, pages, done, total| # rubocop:disable Metrics/ParameterLists, Layout/LineLength
|
38
42
|
track_current_tree(response&.structure)
|
39
|
-
|
43
|
+
|
40
44
|
results[stage] << (page_results = request_results_class.new(sliced_input, response))
|
41
|
-
update_tags_remap_table(page_results, stage)
|
42
|
-
|
45
|
+
update_tags_remap_table(page_results, stage, current_tree)
|
46
|
+
|
47
|
+
self.error = page_errors?(page_results, page, pages, done, total, stage: stage)
|
48
|
+
break if error
|
43
49
|
end
|
44
50
|
|
45
51
|
break if error
|
46
52
|
end
|
53
|
+
rescue SystemStackError
|
54
|
+
puts $! # rubocop:disable Style/SpecialGlobalVars
|
55
|
+
puts caller[0..100]
|
56
|
+
raise
|
47
57
|
rescue StandardError => e
|
48
58
|
log(:error) { self.exception ||= e.patch_full_message }
|
49
59
|
raise
|
50
60
|
ensure
|
51
61
|
rescued { self.tags_remap_csv_file = generate_tags_remap_csv }
|
62
|
+
rescued { close_handling_tags_remap_csv }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Default tree tacking behaviour
|
67
|
+
# @note
|
68
|
+
# 1. This aims to optimize the time run
|
69
|
+
# 2. Based on update stage, there are differentiated tracking needs
|
70
|
+
# @return [Symbol] the tracking mode
|
71
|
+
def batch_tree_track_mode(stage)
|
72
|
+
case stage
|
73
|
+
when :unarchive, :archive
|
74
|
+
:once
|
75
|
+
when :id, :id_name
|
76
|
+
:per_request
|
77
|
+
when :insert, :move
|
78
|
+
:per_batch
|
79
|
+
else
|
80
|
+
default_tree_tracking_mode
|
52
81
|
end
|
53
82
|
end
|
54
83
|
end
|