class Lutaml::Qea::Validation::PackageValidator
Validates package structure and hierarchy
def packages
def packages @packages ||= context[:db_packages] || [] end
def parent_exists?(parent_id)
def parent_exists?(parent_id) return true if parent_id.nil? || parent_id.zero? packages.any? { |p| p.package_id == parent_id } end
def validate
def validate validate_parent_references validate_duplicate_names validate_circular_hierarchy end
def validate_circular_hierarchy # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
def validate_circular_hierarchy # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity packages.each do |package| next if package.root? path = [package.package_id] current_id = package.parent_id while current_id && !current_id.zero? if path.include?(current_id) package_path = resolve_package_path(package.package_id) result.add_error( category: :circular_reference, entity_type: :package, entity_id: package.package_id.to_s, entity_name: package.name, field: "parent_id", message: "Circular package hierarchy detected: " \ "#{path.join(' -> ')} -> #{current_id}", location: package_path, ) break end path << current_id parent = packages.find { |p| p.package_id == current_id } break unless parent current_id = parent.parent_id end end end
def validate_duplicate_names # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
def validate_duplicate_names # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity packages_by_parent = packages.group_by(&:parent_id) packages_by_parent.each do |parent_id, sibling_packages| names = sibling_packages.map(&:name) duplicates = names.select { |name| names.count(name) > 1 }.uniq duplicates.each do |dup_name| dup_packages = sibling_packages.select { |p| p.name == dup_name } dup_packages.each do |package| package_path = resolve_package_path(package.package_id) parent_path = if parent_id resolve_package_path(parent_id) else "Root" end result.add_warning( category: :duplicate, entity_type: :package, entity_id: package.package_id.to_s, entity_name: package.name, field: "name", message: "Duplicate package name '#{dup_name}' " \ "in parent #{parent_path}", location: package_path, ) end end end end
def validate_parent_references # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
def validate_parent_references # rubocop:disable Metrics/AbcSize,Metrics/MethodLength packages.each do |package| next if package.root? unless parent_exists?(package.parent_id) package_path = resolve_package_path(package.package_id) result.add_error( category: :missing_reference, entity_type: :package, entity_id: package.package_id.to_s, entity_name: package.name, field: "parent_id", reference: package.parent_id.to_s, message: "Parent package #{package.parent_id} does not exist", location: package_path, ) end end end