class PIM::Services::ItemService::ItemHierarchy
Public Class Methods
PIM::Utils::EnhancedStruct::new
# File services.rb, line 2799 def initialize *args super # Ensure root_primary_key is set and is a string raise "'root_primary_key' must not be empty" if PIM::Utils.is_empty?(self.root_primary_key) self.root_primary_key = self.root_primary_key.to_s # Ensure name is set and is a string raise "'name' must not be empty" if PIM::Utils.is_empty?(self.name) self.name = self.name.to_s # Create an internal deep copy of 'hierarchy', # so it is not available outside of this class @_hierarchy = to_internal_hierarchy(self.hierarchy) # Overwrite methods to hide internal hierarchy class << self define_method(:hierarchy) { return @_hierarchy.map { |k,v| [k.to_s, v.to_a] }.to_h } define_method(:'hierarchy=') { |hierarchy| @hierarchy = to_internal_hierarchy(hierarchy) } end end
Public Instance Methods
Adds the specified items as ‘child’ items of the specified ‘parent’. Returns a copy(!) of the Set of all children attached to the parent.
# File services.rb, line 3031 def add_children parent, *children, validate: true children = PIM::Utils.stringified_non_empty_set(children) parent = parent.to_s validate_parents(parent) if validate existing_children = @_hierarchy[parent] if existing_children.nil? # Create a new set validate_children(parent, children) if validate @_hierarchy[parent] = existing_children = Set.new(children) else # Only retain children which do not yet exist, to minimize validation children -= existing_children validate_children(parent, children) if validate # Add children to existing children existing_children.merge(children) end return existing_children.to_a end
# File services.rb, line 2835 def as_json # Convert values back to "camelized" hash, # but leave out the non writable fields PIM::Utils.unsymbolized_camelized_hash({ root_primary_key: self.root_primary_key, name: self.name, checksum: self.checksum, hierarchy: hierarchy }) end
Returns a copy(!) of the Set of all children attached to the parent. Returns nil if no children are linked.
# File services.rb, line 2985 def get_children parent parent = parent.to_s children = @_hierarchy[parent] return nil if children.nil? or children.empty? return children.to_a end
Returns a Set of all descendant items of the specified parent. Set will include the parent itself, if ‘include_self’ is set to true. Returns nil if parent does not exist in hierarchy.
# File services.rb, line 2998 def get_descendants parent, include_self: false parent = parent.to_s return nil if not @_hierarchy.include?(parent) descendants = Set.new descendants << parent if include_self _add_descendants @_hierarchy, @_hierarchy[parent], descendants: descendants return descendants end
Removes the specified items as ‘child’ items from the specified ‘parent’. Returns either a copy(!) of the Set of all children still attached to the parent, or nil, if the parent no longer has any children attached.
# File services.rb, line 3086 def remove_children parent, *children, validate: true children = PIM::Utils.stringified_non_empty_set(children) parent = parent.to_s existing_children = @_hierarchy[parent] return nil if existing_children.nil? # Only retain children which actually exist, and ensure removed children are still valid parents children &= existing_children validate_parents(parent, children) if validate # Remove the whole parent if all children are to be removed if children == existing_children @_hierarchy.delete(parent) return nil end # Remove children existing_children.subtract(children) return existing_children.to_a end
Removes all child items from the specified ‘parent’ item. Returns a copy(!) of the Set of all children previously attached to the parent, or nil, if parent had no children attached before.
# File services.rb, line 3114 def remove_parent parent, validate: true parent = parent.to_s existing_children = @_hierarchy[parent] return nil if existing_children.nil? # Ensure removed children are still valid parents validate_parents(parent, existing_children) if validate # Remove the whole parent @_hierarchy.delete(parent) return existing_children.to_a end
Sets the specified items as ‘child’ items of the specified ‘parent’. Returns a copy(!) of the Set of all children attached to the parent. Returns nil if an empty list of children was specified.
# File services.rb, line 3063 def set_children parent, *children, validate: true children = PIM::Utils.stringified_non_empty_set(children) # If no children are specified, remove the parent if children.empty? remove_parent(parent, validate: validate) return nil end parent = parent.to_s validate_parents(parent) if validate validate_children(parent, children) if validate @_hierarchy[parent] = existing_children = Set.new(children) return existing_children.to_a end
Ensure that ‘children’ under ‘parent’ are valid children, i.e. they and their descendants do not form a cycle.
If ‘children’ is not specified, only ensure that children to ‘parent’ are valid, i.e. they and their descendants do not form a cycle.
If neither ‘parent’ nor ‘children’ are specified, validate all children of the hierarchy.
If ‘raise_on_error’ is true, raises an exception if not valid, otherwise returns a list of invalid paths
# File services.rb, line 2924 def validate_children parent = nil, children = nil, hierarchy: @_hierarchy, root: self.root_primary_key, raise_on_error: true if parent.nil? # Start at root and check children of 'root' parent_path = [root] check_children = hierarchy[root] elsif children.nil? # Start at parent and check children of it parent_path = [parent] check_children = PIM::Utils.flattened_compacted_array(hierarchy[parent]) else # Start at parent and only check specified children parent_path = [parent] check_children = PIM::Utils.flattened_compacted_array(children) end return true if check_children.empty? cycle_paths = Set.new _check_cycle(hierarchy, parent_path, check_children, cycle_paths: cycle_paths, raise_on_error: raise_on_error) return cycle_paths.empty? ? true : cycle_paths.to_a end
Validates the complete hierarchy and raises an exception if not valid.
# File services.rb, line 2850 def validate_hierarchy hierarchy: @_hierarchy, root: self.root_primary_key # Validate parent to exist as child validate_parents hierarchy: hierarchy, root: root # Validate child items to be cycle-free validate_children hierarchy: hierarchy, root: root return true end
Ensure that ‘children’ under ‘parent’ are valid parents, i.e. they must be children to at least one other parent than ‘parent’.
If ‘children’ is not specified, only ensure that ‘parent’ is a valid parent, i.e. it is included in the hierarchy keys.
If neither ‘parent’ nor ‘children’ are specified, validate all parents of the hierarchy.
If ‘raise_on_error’ is true, raises an exception if not valid, otherwise returns a list of invalid parents
# File services.rb, line 2871 def validate_parents parent = nil, children = nil, hierarchy: @_hierarchy, root: self.root_primary_key, raise_on_error: true if parent.nil? # Check all keys check_parents = hierarchy.keys elsif children.nil? # Only check specified parent check_parents = PIM::Utils.flattened_compacted_array(parent) else # Only check children which are included in keys check_parents = hierarchy.keys & PIM::Utils.flattened_compacted_array(children) end return true if check_parents.empty? invalid_parents = Set.new # Ensure, each parent is a child to at least one other parent check_parents.each do |check_parent| # OK, if parent is root next if check_parent == root # OK, if parent exists in any of the hierarchy's value, but not for the ignored parent next if hierarchy.any? { |k, v| (parent.nil? or parent != k) and v.include?(check_parent) } raise "Parent '#{check_parent}' is not linked by any other parent in the hierarchy" if raise_on_error invalid_parents << check_parent end return invalid_parents.empty? ? true : invalid_parents.to_a end