001package gudusoft.gsqlparser.resolver2.binding;
002
003import gudusoft.gsqlparser.TCustomSqlStatement;
004
005import java.util.ArrayList;
006import java.util.Collections;
007import java.util.List;
008
009/**
010 * Aggregate output of the resolver2 binding post-pass.
011 *
012 * <p>Immutable. {@link #empty()} is the singleton returned when binding flags
013 * are off (the default) — accessors are guaranteed non-null even in this case
014 * (plan §5.6, §12).</p>
015 *
016 * <p>Filter accessors ({@link #getDiagnosticsForStatement(TCustomSqlStatement)},
017 * {@link #getDiagnosticsForCode(BindingDiagnosticCode)},
018 * {@link #getDiagnosticsForClause(BindingClause)}) return immutable, possibly
019 * empty lists. They never throw on unknown inputs (including {@code null}).</p>
020 */
021public final class BindingResult {
022
023    private static final BindingResult EMPTY = new BindingResult(
024        Collections.<BindingDiagnostic>emptyList(),
025        Collections.<BindingReference>emptyList());
026
027    private final List<BindingDiagnostic> diagnostics;
028    private final List<BindingReference> references;
029
030    private BindingResult(List<BindingDiagnostic> diagnostics, List<BindingReference> references) {
031        this.diagnostics = diagnostics;
032        this.references = references;
033    }
034
035    /** Non-null empty singleton; safe to return when binding is disabled. */
036    public static BindingResult empty() {
037        return EMPTY;
038    }
039
040    public static BindingResult of(List<BindingDiagnostic> diagnostics,
041                                   List<BindingReference> references) {
042        if (diagnostics == null) {
043            throw new IllegalArgumentException("BindingResult.diagnostics is required");
044        }
045        if (references == null) {
046            throw new IllegalArgumentException("BindingResult.references is required");
047        }
048        return new BindingResult(
049            Collections.unmodifiableList(new ArrayList<BindingDiagnostic>(diagnostics)),
050            Collections.unmodifiableList(new ArrayList<BindingReference>(references)));
051    }
052
053    public List<BindingDiagnostic> getDiagnostics() {
054        return diagnostics;
055    }
056
057    public List<BindingReference> getReferences() {
058        return references;
059    }
060
061    public boolean hasErrors() {
062        for (BindingDiagnostic d : diagnostics) {
063            if (d.severity() == BindingDiagnosticSeverity.ERROR) {
064                return true;
065            }
066        }
067        return false;
068    }
069
070    public List<BindingDiagnostic> getDiagnosticsForStatement(TCustomSqlStatement stmt) {
071        if (stmt == null || diagnostics.isEmpty()) {
072            return Collections.emptyList();
073        }
074        List<BindingDiagnostic> out = new ArrayList<BindingDiagnostic>();
075        for (BindingDiagnostic d : diagnostics) {
076            if (d.statement().isPresent() && d.statement().get() == stmt) {
077                out.add(d);
078            }
079        }
080        return Collections.unmodifiableList(out);
081    }
082
083    public List<BindingDiagnostic> getDiagnosticsForCode(BindingDiagnosticCode code) {
084        if (code == null || diagnostics.isEmpty()) {
085            return Collections.emptyList();
086        }
087        List<BindingDiagnostic> out = new ArrayList<BindingDiagnostic>();
088        for (BindingDiagnostic d : diagnostics) {
089            if (d.code() == code) {
090                out.add(d);
091            }
092        }
093        return Collections.unmodifiableList(out);
094    }
095
096    public List<BindingDiagnostic> getDiagnosticsForClause(BindingClause clause) {
097        if (clause == null || diagnostics.isEmpty()) {
098            return Collections.emptyList();
099        }
100        List<BindingDiagnostic> out = new ArrayList<BindingDiagnostic>();
101        for (BindingDiagnostic d : diagnostics) {
102            if (d.site().isPresent() && d.site().get().clause() == clause) {
103                out.add(d);
104            }
105        }
106        return Collections.unmodifiableList(out);
107    }
108
109    public List<BindingReference> getUnresolvedReferences() {
110        if (references.isEmpty()) {
111            return Collections.emptyList();
112        }
113        List<BindingReference> out = new ArrayList<BindingReference>();
114        for (BindingReference r : references) {
115            if (!r.bound()) {
116                out.add(r);
117            }
118        }
119        return Collections.unmodifiableList(out);
120    }
121
122    @Override
123    public String toString() {
124        return "BindingResult{diagnostics=" + diagnostics.size()
125            + " references=" + references.size()
126            + " hasErrors=" + hasErrors() + '}';
127    }
128}