001package gudusoft.gsqlparser.resolver2.binding;
002
003import java.util.Objects;
004
005/**
006 * One name reference observed by the binding pass.
007 *
008 * <p>Immutable; build via {@link #builder()}. {@link #bound()} indicates
009 * whether resolver2 successfully resolved the reference. References are
010 * surfaced only when the consumer opts in via
011 * {@code TSQLResolverConfig.setBindingIncludeSuccessfulReferences(true)};
012 * unresolved references are also surfaced via {@link BindingResult#getUnresolvedReferences()}.</p>
013 *
014 * <p>{@code objectNameText} carries the textual reference (e.g. {@code "o.id1"})
015 * — the public binding API does NOT expose internal resolver2 nodes
016 * ({@code ResolutionResult}, {@code IScope}, namespaces) per plan §15 R5/R6.</p>
017 */
018public final class BindingReference {
019
020    private final BindingReferenceKind kind;
021    private final String objectNameText;
022    private final BindingReferenceSite site;
023    private final boolean bound;
024
025    private BindingReference(Builder b) {
026        if (b.kind == null) {
027            throw new IllegalArgumentException("BindingReference.kind is required");
028        }
029        if (b.objectNameText == null || b.objectNameText.isEmpty()) {
030            throw new IllegalArgumentException("BindingReference.objectNameText is required");
031        }
032        if (b.site == null) {
033            throw new IllegalArgumentException("BindingReference.site is required");
034        }
035        this.kind = b.kind;
036        this.objectNameText = b.objectNameText;
037        this.site = b.site;
038        this.bound = b.bound;
039    }
040
041    public static Builder builder() {
042        return new Builder();
043    }
044
045    public BindingReferenceKind kind() {
046        return kind;
047    }
048
049    public String objectNameText() {
050        return objectNameText;
051    }
052
053    public BindingReferenceSite site() {
054        return site;
055    }
056
057    public boolean bound() {
058        return bound;
059    }
060
061    @Override
062    public boolean equals(Object o) {
063        if (this == o) return true;
064        if (!(o instanceof BindingReference)) return false;
065        BindingReference that = (BindingReference) o;
066        return bound == that.bound
067            && kind == that.kind
068            && objectNameText.equals(that.objectNameText)
069            && site.equals(that.site);
070    }
071
072    @Override
073    public int hashCode() {
074        return Objects.hash(kind, objectNameText, site, bound);
075    }
076
077    @Override
078    public String toString() {
079        return "BindingReference{" + kind + " " + objectNameText
080            + (bound ? " (bound)" : " (unbound)")
081            + " " + site + '}';
082    }
083
084    public static final class Builder {
085
086        private BindingReferenceKind kind;
087        private String objectNameText;
088        private BindingReferenceSite site;
089        private boolean bound;
090
091        private Builder() {
092        }
093
094        public Builder kind(BindingReferenceKind v) {
095            this.kind = v;
096            return this;
097        }
098
099        public Builder objectNameText(String v) {
100            this.objectNameText = v;
101            return this;
102        }
103
104        public Builder site(BindingReferenceSite v) {
105            this.site = v;
106            return this;
107        }
108
109        public Builder bound(boolean v) {
110            this.bound = v;
111            return this;
112        }
113
114        public BindingReference build() {
115            return new BindingReference(this);
116        }
117    }
118}