Class: ActiveRecordGraphExtractor::DependencyResolver
- Inherits:
-
Object
- Object
- ActiveRecordGraphExtractor::DependencyResolver
- Defined in:
- lib/activerecord_graph_extractor/dependency_resolver.rb
Instance Attribute Summary collapse
-
#dependency_graph ⇒ Object
readonly
Returns the value of attribute dependency_graph.
-
#resolved_order ⇒ Object
readonly
Returns the value of attribute resolved_order.
Instance Method Summary collapse
- #build_creation_order(records_by_model, dependency_graph) ⇒ Object
- #detect_circular_dependencies(dependency_graph) ⇒ Object
- #group_by_dependency_level ⇒ Object
-
#initialize(dependency_graph) ⇒ DependencyResolver
constructor
A new instance of DependencyResolver.
- #resolve(dependency_graph) ⇒ Object
- #resolve_creation_order ⇒ Object
- #resolve_deletion_order ⇒ Object
- #validate_dependencies(records_data) ⇒ Object
Constructor Details
#initialize(dependency_graph) ⇒ DependencyResolver
Returns a new instance of DependencyResolver.
7 8 9 10 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 7 def initialize(dependency_graph) @dependency_graph = dependency_graph @resolved_order = [] end |
Instance Attribute Details
#dependency_graph ⇒ Object (readonly)
Returns the value of attribute dependency_graph.
5 6 7 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 5 def dependency_graph @dependency_graph end |
#resolved_order ⇒ Object (readonly)
Returns the value of attribute resolved_order.
5 6 7 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 5 def resolved_order @resolved_order end |
Instance Method Details
#build_creation_order(records_by_model, dependency_graph) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 117 def build_creation_order(records_by_model, dependency_graph) grouped_records = group_records_by_dependencies(records_by_model) ordered_models = resolve(dependency_graph) # Create ordered list of [model_name, records] pairs ordered_records = [] ordered_models.each do |model_class| model_name = model_class.name if grouped_records.key?(model_name) ordered_records << [model_name, grouped_records[model_name]] end end # Add any remaining models not in dependency graph grouped_records.each do |model_name, records| unless ordered_records.any? { |entry| entry[0] == model_name } ordered_records << [model_name, records] end end ordered_records end |
#detect_circular_dependencies(dependency_graph) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 99 def detect_circular_dependencies(dependency_graph) # Handle different formats if dependency_graph.values.first.is_a?(Hash) return detect_complex_circular_dependencies(dependency_graph) end # Original boolean detection visited = Set.new rec_stack = Set.new dependency_graph.each_key do |node| next if visited.include?(node) return true if has_cycle?(node, dependency_graph, visited, rec_stack) end false end |
#group_by_dependency_level ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 53 def group_by_dependency_level creation_order = resolve_creation_order levels = {} current_level = 0 creation_order.each do |model_name| dependencies = dependency_graph[model_name] || [] if dependencies.empty? # No dependencies - can be created first levels[current_level] ||= [] levels[current_level] << model_name else # Find the maximum level of dependencies max_dependency_level = dependencies.map do |dep| find_model_level(dep, levels) end.max || 0 model_level = max_dependency_level + 1 levels[model_level] ||= [] levels[model_level] << model_name end end levels end |
#resolve(dependency_graph) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 80 def resolve(dependency_graph) # Handle different input formats based on test expectations if dependency_graph.values.first.is_a?(Hash) # New format: { 'TestOrder' => { 'test_user' => { 'model_class' => 'TestUser' } } } return resolve_complex_graph(dependency_graph) end # Original format: { TestOrder => [TestUser] } return [] if dependency_graph.empty? # Check for circular dependencies if detect_circular_dependencies(dependency_graph) raise CircularDependencyError, "Circular dependency detected in model relationships" end # Perform topological sort topological_sort(dependency_graph) end |
#resolve_creation_order ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 12 def resolve_creation_order # Create a copy to avoid modifying the original graph = dependency_graph.dup visited = Set.new temp_visited = Set.new graph.keys.each do |model| next if visited.include?(model) visit_model(model, graph, visited, temp_visited) end # Reverse to get creation order (dependencies first) @resolved_order.reverse end |
#resolve_deletion_order ⇒ Object
28 29 30 31 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 28 def resolve_deletion_order # For deletion, we want the reverse of creation order resolve_creation_order.reverse end |
#validate_dependencies(records_data) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/activerecord_graph_extractor/dependency_resolver.rb', line 33 def validate_dependencies(records_data) missing_dependencies = {} records_data.each do |model_name, records| next unless dependency_graph[model_name] dependency_graph[model_name].each do |dependency| unless records_data.key?(dependency) missing_dependencies[model_name] ||= [] missing_dependencies[model_name] << dependency end end end return missing_dependencies if missing_dependencies.any? # Validate foreign key references validate_foreign_key_references(records_data) end |