001package gudusoft.gsqlparser.dlineage.dynamicsql; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.LinkedHashMap; 006import java.util.LinkedHashSet; 007import java.util.List; 008import java.util.Map; 009import java.util.Set; 010 011/** 012 * Public observation result of {@link ProceduralLineageAnalyzer}. 013 * 014 * <p>This result deliberately does not masquerade as a mutated legacy 015 * {@code dataflow}. Composed edges are observations only in every mode. 016 * {@link #getAppliedAdditions()} remains empty until call validity, type 017 * compatibility, actual mutability, and execution context are exhaustively 018 * proven. Every observation carries {@link ShadowSummaryApplier.EdgeOrigin}, 019 * {@link ShadowSummaryApplier.ApplicationGate#OBSERVATION_ONLY}, and a stable 020 * application-deferral reason. 021 */ 022public final class ProceduralLineageResult { 023 024 private final ProceduralLineageOptions.Mode mode; 025 private final Set<ShadowSummaryApplier.ComposedEdge> observedAdditions; 026 private final Set<ShadowSummaryApplier.ComposedEdge> appliedAdditions; 027 private final List<String> diagnostics; 028 private final Map<RoutineIdentity, RoutineSummary> summaries; 029 private final Map<RoutineIdentity, Integer> fixedPointIterations; 030 031 ProceduralLineageResult(ProceduralLineageOptions.Mode mode, 032 ShadowSummaryApplier.ShadowResult result) { 033 this.mode = mode; 034 this.observedAdditions = Collections.unmodifiableSet( 035 new LinkedHashSet<ShadowSummaryApplier.ComposedEdge>( 036 result.getAdditions())); 037 this.appliedAdditions = 038 Collections.<ShadowSummaryApplier.ComposedEdge>emptySet(); 039 this.diagnostics = Collections.unmodifiableList( 040 new ArrayList<String>(result.getDiagnostics())); 041 this.summaries = Collections.unmodifiableMap( 042 new LinkedHashMap<RoutineIdentity, RoutineSummary>( 043 result.getSummaries())); 044 this.fixedPointIterations = Collections.unmodifiableMap( 045 new LinkedHashMap<RoutineIdentity, Integer>( 046 result.getFixedPointIterations())); 047 } 048 049 public ProceduralLineageOptions.Mode getMode() { return mode; } 050 051 /** Isolated summary-composed edges; non-empty in SHADOW and ENHANCED. */ 052 public Set<ShadowSummaryApplier.ComposedEdge> getObservedAdditions() { 053 return observedAdditions; 054 } 055 056 /** 057 * Reserved future additive projection. Empty in LEGACY, SHADOW, and 058 * ENHANCED while call-validity proof is incomplete. Consumers must not 059 * merge {@link #getObservedAdditions()} into an authoritative model. 060 */ 061 public Set<ShadowSummaryApplier.ComposedEdge> getAppliedAdditions() { 062 return appliedAdditions; 063 } 064 065 public List<String> getDiagnostics() { return diagnostics; } 066 public Map<RoutineIdentity, RoutineSummary> getSummaries() { return summaries; } 067 public Map<RoutineIdentity, Integer> getFixedPointIterations() { 068 return fixedPointIterations; 069 } 070 071 /** Reserved future view; currently always empty. */ 072 public Set<ShadowSummaryApplier.ComposedEdge> getReplacementEligible() { 073 return byGate(ShadowSummaryApplier.ApplicationGate.REPLACEMENT_ELIGIBLE); 074 } 075 076 public Set<ShadowSummaryApplier.ComposedEdge> getObservationOnly() { 077 return byGate(ShadowSummaryApplier.ApplicationGate.OBSERVATION_ONLY); 078 } 079 080 /** 081 * @deprecated composed edges are not authorized to augment lineage. 082 * This compatibility view is deliberately always empty. 083 */ 084 @Deprecated 085 public Set<ShadowSummaryApplier.ComposedEdge> getAugmentOnly() { 086 return Collections.emptySet(); 087 } 088 089 private Set<ShadowSummaryApplier.ComposedEdge> byGate( 090 ShadowSummaryApplier.ApplicationGate gate) { 091 Set<ShadowSummaryApplier.ComposedEdge> result = 092 new LinkedHashSet<ShadowSummaryApplier.ComposedEdge>(); 093 for (ShadowSummaryApplier.ComposedEdge edge : observedAdditions) { 094 if (edge.getApplicationGate() == gate) { 095 result.add(edge); 096 } 097 } 098 return Collections.unmodifiableSet(result); 099 } 100}