001package gudusoft.gsqlparser.catalog.diagnostic;
002
003import gudusoft.gsqlparser.catalog.runtime.CatalogQualifiedName;
004
005import java.util.Objects;
006import java.util.Optional;
007
008/**
009 * One catalog diagnostic record (validator, reader, provider, or runtime).
010 *
011 * <p>Plan §7.3. Diagnostics are immutable value objects; build via {@link #builder()}.</p>
012 *
013 * <p>{@code location} is intentionally left as a free-form {@link String} until P1E
014 * introduces a structured {@code SourceLocation} type — the JSON / DDL readers landing
015 * in P1B and Phase 2.A have no shared shape worth committing to yet.</p>
016 */
017public final class CatalogDiagnostic {
018
019    private final CatalogDiagnosticSeverity severity;
020    private final CatalogDiagnosticCode code;
021    private final String message;
022    private final CatalogQualifiedName name;
023    private final String location;
024    private final String repairHint;
025
026    private CatalogDiagnostic(Builder b) {
027        if (b.severity == null) {
028            throw new IllegalArgumentException("CatalogDiagnostic.severity is required");
029        }
030        if (b.code == null) {
031            throw new IllegalArgumentException("CatalogDiagnostic.code is required");
032        }
033        if (b.message == null || b.message.isEmpty()) {
034            throw new IllegalArgumentException("CatalogDiagnostic.message is required");
035        }
036        this.severity = b.severity;
037        this.code = b.code;
038        this.message = b.message;
039        this.name = b.name;
040        this.location = b.location;
041        this.repairHint = b.repairHint;
042    }
043
044    public static Builder builder() {
045        return new Builder();
046    }
047
048    /**
049     * Convenience: build a diagnostic from severity + code + message only. Most
050     * validator emissions don't have a qualified name or location yet.
051     */
052    public static CatalogDiagnostic of(CatalogDiagnosticSeverity severity,
053                                       CatalogDiagnosticCode code,
054                                       String message) {
055        return builder().severity(severity).code(code).message(message).build();
056    }
057
058    public CatalogDiagnosticSeverity severity() {
059        return severity;
060    }
061
062    public CatalogDiagnosticCode code() {
063        return code;
064    }
065
066    public String message() {
067        return message;
068    }
069
070    public Optional<CatalogQualifiedName> name() {
071        return Optional.ofNullable(name);
072    }
073
074    public Optional<String> location() {
075        return Optional.ofNullable(location);
076    }
077
078    public Optional<String> repairHint() {
079        return Optional.ofNullable(repairHint);
080    }
081
082    @Override
083    public boolean equals(Object o) {
084        if (this == o) return true;
085        if (!(o instanceof CatalogDiagnostic)) return false;
086        CatalogDiagnostic that = (CatalogDiagnostic) o;
087        return severity == that.severity
088            && code == that.code
089            && message.equals(that.message)
090            && Objects.equals(name, that.name)
091            && Objects.equals(location, that.location)
092            && Objects.equals(repairHint, that.repairHint);
093    }
094
095    @Override
096    public int hashCode() {
097        return Objects.hash(severity, code, message, name, location, repairHint);
098    }
099
100    @Override
101    public String toString() {
102        return "CatalogDiagnostic{" + severity + " " + code + ": " + message
103            + (name != null ? " name=" + name : "")
104            + (location != null ? " at=" + location : "")
105            + (repairHint != null ? " hint=" + repairHint : "")
106            + '}';
107    }
108
109    public static final class Builder {
110
111        private CatalogDiagnosticSeverity severity;
112        private CatalogDiagnosticCode code;
113        private String message;
114        private CatalogQualifiedName name;
115        private String location;
116        private String repairHint;
117
118        private Builder() {
119        }
120
121        public Builder severity(CatalogDiagnosticSeverity v) {
122            this.severity = v;
123            return this;
124        }
125
126        public Builder code(CatalogDiagnosticCode v) {
127            this.code = v;
128            return this;
129        }
130
131        public Builder message(String v) {
132            this.message = v;
133            return this;
134        }
135
136        public Builder name(CatalogQualifiedName v) {
137            this.name = v;
138            return this;
139        }
140
141        public Builder location(String v) {
142            this.location = v;
143            return this;
144        }
145
146        public Builder repairHint(String v) {
147            this.repairHint = v;
148            return this;
149        }
150
151        public CatalogDiagnostic build() {
152            return new CatalogDiagnostic(this);
153        }
154    }
155}