001package gudusoft.gsqlparser.ir.semantic.diff; 002 003/** 004 * Pure-function return type for both projectors. {@link #getReason()} is 005 * non-null when the projector cannot produce a meaningful canonical model. 006 * The reporter translates a non-null reason into a single query-wide 007 * {@link DivergenceClass#UNSUPPORTED_BY_DLINEAGE} or 008 * {@link DivergenceClass#UNSUPPORTED_BY_IR} divergence. 009 * 010 * <p>Keeping this as data (not a thrown exception) means the comparison 011 * harness can produce a stable JSON for every corpus SQL even when one 012 * side is unsupported. 013 */ 014public final class ProjectorResult { 015 016 public enum UnsupportedReason { 017 /** No relationships in the dlineage XML, or builder produced no statements. */ 018 NO_RELATIONSHIPS, 019 /** Dlineage XML had zero or two-plus terminal select_list resultsets. */ 020 MULTIPLE_TERMINAL_SELECTS, 021 /** Dlineage XML failed to parse. */ 022 MALFORMED_XML 023 } 024 025 private final CanonicalLineageModel model; 026 private final UnsupportedReason reason; 027 private final String detail; 028 029 public ProjectorResult(CanonicalLineageModel model, UnsupportedReason reason, String detail) { 030 if (model == null) { 031 throw new IllegalArgumentException("model must not be null"); 032 } 033 this.model = model; 034 this.reason = reason; 035 this.detail = detail; 036 } 037 038 public static ProjectorResult ok(CanonicalLineageModel model) { 039 return new ProjectorResult(model, null, null); 040 } 041 042 public static ProjectorResult unsupported(UnsupportedReason reason, String detail) { 043 if (reason == null) { 044 throw new IllegalArgumentException("reason must not be null for unsupported result"); 045 } 046 return new ProjectorResult(CanonicalLineageModel.empty(), reason, detail); 047 } 048 049 public CanonicalLineageModel getModel() { 050 return model; 051 } 052 053 public UnsupportedReason getReason() { 054 return reason; 055 } 056 057 public String getDetail() { 058 return detail; 059 } 060 061 public boolean isSupported() { 062 return reason == null; 063 } 064}