001package gudusoft.gsqlparser.lineage2.contract;
002
003/**
004 * Contract {@code Endpoint} (lineage2-contract.md ยง4.1).
005 *
006 * <p>Physical endpoints are always emitted fully expanded
007 * ({@code database}/{@code schema}/{@code object} all non-empty, D-15);
008 * endpoints that cannot be fully qualified get a non-RESOLVED
009 * {@link ResolutionStatus} and the surface name observed.
010 *
011 * <p>Location emission is tri-state, mirroring the gold-fixture
012 * conventions: a non-null {@code sourceLocation} is emitted as-is; a null
013 * location with a {@link LocationNullReason} is emitted as
014 * {@code "sourceLocation": null} plus the reason; when both are absent the
015 * keys are omitted entirely.
016 *
017 * <p>Internal API: not part of the public gsqlparser surface.
018 */
019public final class Endpoint {
020
021    private final String database;
022    private final String schema;
023    private final String object;
024    private final String column;
025    private final ObjectKind objectKind;
026    private final ResolutionStatus resolutionStatus;
027    private final ScopeKind scopeKind;
028    private final Integer definedAtStatementIndex;
029    private final SourceLocation sourceLocation;
030    private final LocationNullReason locationNullReason;
031
032    private Endpoint(Builder b) {
033        if (b.object == null) {
034            throw new IllegalArgumentException("object must not be null");
035        }
036        if (b.objectKind == null || b.resolutionStatus == null) {
037            throw new IllegalArgumentException(
038                    "objectKind and resolutionStatus must not be null");
039        }
040        this.database = b.database;
041        this.schema = b.schema;
042        this.object = b.object;
043        this.column = b.column;
044        this.objectKind = b.objectKind;
045        this.resolutionStatus = b.resolutionStatus;
046        this.scopeKind = b.scopeKind;
047        this.definedAtStatementIndex = b.definedAtStatementIndex;
048        this.sourceLocation = b.sourceLocation;
049        this.locationNullReason = b.locationNullReason;
050    }
051
052    public static Builder builder(String object) {
053        return new Builder(object);
054    }
055
056    public String getDatabase() {
057        return database;
058    }
059
060    public String getSchema() {
061        return schema;
062    }
063
064    public String getObject() {
065        return object;
066    }
067
068    public String getColumn() {
069        return column;
070    }
071
072    public ObjectKind getObjectKind() {
073        return objectKind;
074    }
075
076    public ResolutionStatus getResolutionStatus() {
077        return resolutionStatus;
078    }
079
080    /** Nullable โ€” only set for temp/variable/cursor endpoints (D-11). */
081    public ScopeKind getScopeKind() {
082        return scopeKind;
083    }
084
085    /** Nullable โ€” only set for temp/variable/cursor endpoints (D-11). */
086    public Integer getDefinedAtStatementIndex() {
087        return definedAtStatementIndex;
088    }
089
090    /** Nullable. */
091    public SourceLocation getSourceLocation() {
092        return sourceLocation;
093    }
094
095    /** Nullable โ€” set only when {@code sourceLocation} is null. */
096    public LocationNullReason getLocationNullReason() {
097        return locationNullReason;
098    }
099
100    public static final class Builder {
101        private String database;
102        private String schema;
103        private final String object;
104        private String column;
105        private ObjectKind objectKind = ObjectKind.UNKNOWN;
106        private ResolutionStatus resolutionStatus = ResolutionStatus.RESOLVED;
107        private ScopeKind scopeKind;
108        private Integer definedAtStatementIndex;
109        private SourceLocation sourceLocation;
110        private LocationNullReason locationNullReason;
111
112        private Builder(String object) {
113            this.object = object;
114        }
115
116        public Builder database(String database) {
117            this.database = database;
118            return this;
119        }
120
121        public Builder schema(String schema) {
122            this.schema = schema;
123            return this;
124        }
125
126        public Builder column(String column) {
127            this.column = column;
128            return this;
129        }
130
131        public Builder objectKind(ObjectKind objectKind) {
132            this.objectKind = objectKind;
133            return this;
134        }
135
136        public Builder resolutionStatus(ResolutionStatus resolutionStatus) {
137            this.resolutionStatus = resolutionStatus;
138            return this;
139        }
140
141        public Builder scopeKind(ScopeKind scopeKind) {
142            this.scopeKind = scopeKind;
143            return this;
144        }
145
146        public Builder definedAtStatementIndex(Integer definedAtStatementIndex) {
147            this.definedAtStatementIndex = definedAtStatementIndex;
148            return this;
149        }
150
151        public Builder sourceLocation(SourceLocation sourceLocation) {
152            this.sourceLocation = sourceLocation;
153            return this;
154        }
155
156        public Builder locationNullReason(LocationNullReason reason) {
157            this.locationNullReason = reason;
158            return this;
159        }
160
161        public Endpoint build() {
162            return new Endpoint(this);
163        }
164    }
165}