module Eco module API class Session class Config class TagTree < BaseConfig class MissingTagtree < StandardError end attr_key :file, :structure_id # The location node classifications of the organization # @return [Eco::API::Organization::NodeClassifications] def node_classifications(active: true) return [] unless (graphql = graphql_api) node_types = graphql.locationStructure.nodeClassifications(active: active) Eco::API::Organization::NodeClassifications.new(node_types) end # @note it retrieves the tree this way: # 1. If there's a file tagtree.json file, it uses it # 2. If no file, retrieves `structure_id` (config) # @param include_archived [Boolean] whether or not it should include archived nodes. # @param [recache] used for re-caching # @return [Eco::API::Organization::TagTree] def scope_tree( include_archived: true, recache: false, raise_on_missing: true # rubocop:disable Lint/UnusedMethodArgument ) return @tagtree if instance_variable_defined?(:@tagtree) && !recache kargs = { includeArchivedNodes: include_archived } if (tree_file = file) if (tree = file_manager.load_json(tree_file)) && !tree.empty? @tagtree = Eco::API::Organization::TagTree.new(tree) end elsif structure_id kargs.merge(id: structure_id) end @tagtree ||= live_tree(**kargs).tap do |tr| # rubocop:disable Naming/MemoizedInstanceVariableName next if tr && !tr.empty? msg = "Could not find a local or live locations structure." raise MissingTagtree, msg end end # Among all the locations structures it selects the one with more location nodes # If `id` is provided, it only retrieves this locations structure. # @param [recache] used for re-caching def live_tree( # rubocop:disable Metrics/AbcSize id: nil, include_archived: false, **kargs, &block ) existing_cache = !@live_tree.nil? first_load = !existing_cache switching_target = existing_cache && id && @live_tree.id != id kargs = { includeArchivedNodes: include_archived }.merge(kargs) if id args = { id: id }.merge(kargs) @live_tree = live_tree_get(**args, &block) else trees = live_trees(**kargs, &block) if trees.count > 1 @live_tree = trees.reject(&:empty?).max do |a, b| a.count <=> b.count end else @live_tree = trees.first end end.tap do |tree| if tree msg = "LIVE LOCATIONS Structure (#{tree.id}): '#{tree.name}' (#{tree.count} nodes)" if first_load log(:info) { "Using #{msg}" } elsif switching_target log(:info) { "Switched to #{msg}" } else # refresh_cache log(:debug) { "Reloading #{msg}" } end else log(:info) { "Could not retrive live tree (#{id})" } end end end # Gets a single locations structure # @note it does not memoize # @param include_archived [Boolean] whether or not to include archived **nodes** # @return [Eco::API::Organization::TagTree, NilClass] def live_tree_get(id: nil, include_archived: false, **kargs, &block) return nil unless (graphql = graphql_api) kargs = { id: id, includeArchivedNodes: include_archived }.merge(kargs) start = Time.now tree = graphql.currentOrganization.locationStructure(**kargs, &block) return nil unless tree end_time = Time.now secs = (end_time - start).round(3) Eco::API::Organization::TagTree.new(tree.treeify, id: tree.id, name: tree.name).tap do |eco_tree| cnt = eco_tree.count per_sec = (cnt.to_f / secs).round(2) log(:info) { "Loaded #{cnt} location nodes in #{secs} seconds (#{per_sec} nodes/sec)" } end end # Retrieves all the location structures of the organisation # @param include_archived [Boolean] whether or not to include archived **nodes** # @return [Array] def live_trees(include_archived: false, **kargs, &block) [].tap do |eco_trees| next unless (graphql = graphql_api) kargs = { includeArchivedNodes: include_archived }.merge(kargs) start = Time.now trees = graphql.currentOrganization.locationStructures(**kargs, &block) next unless trees end_time = Time.now secs = (end_time - start).round(3) cnt = 0 trees.each do |tree| eco_tree = Eco::API::Organization::TagTree.new(tree.treeify, id: tree.id, name: tree.name) cnt += eco_tree.count eco_trees.push(eco_tree) end per_sec = (cnt.to_f / secs).round(2) log(:info) { "Loaded #{cnt} location nodes in #{secs} seconds (#{per_sec} nodes/sec)" } end end private def graphql_api return nil unless apis.active_api.version_available?(:graphql) apis.api(version: :graphql) end end end end end end