001package gudusoft.gsqlparser.ir.semantic; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.List; 006import java.util.Objects; 007 008/** 009 * Result of a {@link SqlSemanticAnalyzer#analyze} call. Carries the 010 * built {@link SemanticProgram}, the JSON-encoded form, and the list 011 * of {@link Diagnostic}s emitted during analysis. 012 * 013 * <p>A successful analysis produces a non-null program and JSON with 014 * an empty (or warning-only) diagnostics list. A failed analysis 015 * produces a {@code null} program / JSON and at least one 016 * {@link Severity#ERROR ERROR}-severity diagnostic. 017 * 018 * <p>This type is immutable and thread-safe. Consumers should 019 * pattern-match on {@link Diagnostic#getCode()} (the 020 * {@link DiagnosticCode} enum is the stable contract) rather than 021 * parsing message text. 022 */ 023public final class AnalysisResult { 024 025 private final String schemaVersion; 026 private final SemanticProgram program; 027 private final String json; 028 private final List<Diagnostic> diagnostics; 029 030 AnalysisResult(String schemaVersion, 031 SemanticProgram program, 032 String json, 033 List<Diagnostic> diagnostics) { 034 this.schemaVersion = Objects.requireNonNull(schemaVersion, "schemaVersion"); 035 this.program = program; 036 this.json = json; 037 this.diagnostics = Collections.unmodifiableList( 038 new ArrayList<>(Objects.requireNonNull(diagnostics, "diagnostics"))); 039 } 040 041 /** 042 * @return {@code true} iff a non-null program was built AND no 043 * {@link Severity#ERROR ERROR}-severity diagnostics are 044 * present. 045 */ 046 public boolean isSuccessful() { 047 if (program == null) { 048 return false; 049 } 050 for (Diagnostic d : diagnostics) { 051 if (d.getSeverity() == Severity.ERROR) { 052 return false; 053 } 054 } 055 return true; 056 } 057 058 /** JSON schema version emitted by the analyzer (currently {@code "1"}). */ 059 public String getSchemaVersion() { 060 return schemaVersion; 061 } 062 063 /** 064 * @return the built program, or {@code null} when analysis 065 * failed. Use {@link #isSuccessful()} as the discriminator. 066 */ 067 public SemanticProgram getProgram() { 068 return program; 069 } 070 071 /** 072 * @return the JSON encoding of {@link #getProgram()}, or 073 * {@code null} when analysis failed. 074 */ 075 public String getJson() { 076 return json; 077 } 078 079 /** Diagnostics emitted during analysis. Never {@code null}; may be empty. */ 080 public List<Diagnostic> getDiagnostics() { 081 return diagnostics; 082 } 083 084 /** 085 * @return the first {@link Severity#ERROR ERROR}-severity 086 * diagnostic, or {@code null} when none were emitted. 087 */ 088 public Diagnostic getFirstError() { 089 for (Diagnostic d : diagnostics) { 090 if (d.getSeverity() == Severity.ERROR) { 091 return d; 092 } 093 } 094 return null; 095 } 096}