001package gudusoft.gsqlparser.lineage2.contract;
002
003/**
004 * Contract {@code Edge} (lineage2-contract.md §4) — the atomic lineage
005 * assertion: <em>source endpoint influences target endpoint in manner
006 * {@code role}</em>.
007 *
008 * <p>{@code source} is nullable exclusively for {@code role: DERIVED}
009 * (constant-only / synthesized targets); the identity layer treats a null
010 * source as empty strings for all source components per rev-3
011 * normalization. {@code rowLevel} is derived: {@code true} iff
012 * {@code axis == ROW}.
013 *
014 * <p>Internal API: not part of the public gsqlparser surface.
015 */
016public final class ContractEdge {
017
018    private final Endpoint source;
019    private final Endpoint target;
020    private final LineageRole role;
021    private final LineageAxis axis;
022    private final EvaluationModel evaluationModel;
023    private final CaseBranch caseBranch;
024    private final boolean dynamic;
025    private final double confidence;
026    private final int statementIndex;
027    private final Transformation transformation;
028    private final EdgeIdentity identity;
029
030    private ContractEdge(Builder b) {
031        if (b.target == null) {
032            throw new IllegalArgumentException("target must not be null");
033        }
034        if (b.role == null || b.axis == null || b.evaluationModel == null) {
035            throw new IllegalArgumentException(
036                    "role, axis, and evaluationModel must not be null");
037        }
038        if (b.source == null && b.role != LineageRole.DERIVED) {
039            throw new IllegalArgumentException(
040                    "source is nullable exclusively for role DERIVED; got " + b.role);
041        }
042        if (b.identity == null) {
043            throw new IllegalArgumentException("identity must not be null");
044        }
045        this.source = b.source;
046        this.target = b.target;
047        this.role = b.role;
048        this.axis = b.axis;
049        this.evaluationModel = b.evaluationModel;
050        this.caseBranch = b.caseBranch;
051        this.dynamic = b.dynamic;
052        this.confidence = b.confidence;
053        this.statementIndex = b.statementIndex;
054        this.transformation = b.transformation;
055        this.identity = b.identity;
056    }
057
058    public static Builder builder() {
059        return new Builder();
060    }
061
062    /** Nullable exclusively for {@code role: DERIVED}. */
063    public Endpoint getSource() {
064        return source;
065    }
066
067    public Endpoint getTarget() {
068        return target;
069    }
070
071    public LineageRole getRole() {
072        return role;
073    }
074
075    public LineageAxis getAxis() {
076        return axis;
077    }
078
079    public EvaluationModel getEvaluationModel() {
080        return evaluationModel;
081    }
082
083    /** Contract invariant: {@code rowLevel} is true iff axis is ROW. */
084    public boolean isRowLevel() {
085        return axis == LineageAxis.ROW;
086    }
087
088    /** Nullable. */
089    public CaseBranch getCaseBranch() {
090        return caseBranch;
091    }
092
093    public boolean isDynamic() {
094        return dynamic;
095    }
096
097    public double getConfidence() {
098        return confidence;
099    }
100
101    public int getStatementIndex() {
102        return statementIndex;
103    }
104
105    /** Nullable — omitted on pure-copy DIRECT edges. */
106    public Transformation getTransformation() {
107        return transformation;
108    }
109
110    public EdgeIdentity getIdentity() {
111        return identity;
112    }
113
114    public static final class Builder {
115        private Endpoint source;
116        private Endpoint target;
117        private LineageRole role;
118        private LineageAxis axis;
119        private EvaluationModel evaluationModel = EvaluationModel.EXACT;
120        private CaseBranch caseBranch;
121        private boolean dynamic;
122        private double confidence = 1.0;
123        private int statementIndex = 1;
124        private Transformation transformation;
125        private EdgeIdentity identity;
126
127        private Builder() {}
128
129        public Builder source(Endpoint source) {
130            this.source = source;
131            return this;
132        }
133
134        public Builder target(Endpoint target) {
135            this.target = target;
136            return this;
137        }
138
139        public Builder role(LineageRole role) {
140            this.role = role;
141            return this;
142        }
143
144        public Builder axis(LineageAxis axis) {
145            this.axis = axis;
146            return this;
147        }
148
149        public Builder evaluationModel(EvaluationModel evaluationModel) {
150            this.evaluationModel = evaluationModel;
151            return this;
152        }
153
154        public Builder caseBranch(CaseBranch caseBranch) {
155            this.caseBranch = caseBranch;
156            return this;
157        }
158
159        public Builder dynamic(boolean dynamic) {
160            this.dynamic = dynamic;
161            return this;
162        }
163
164        public Builder confidence(double confidence) {
165            this.confidence = confidence;
166            return this;
167        }
168
169        public Builder statementIndex(int statementIndex) {
170            this.statementIndex = statementIndex;
171            return this;
172        }
173
174        public Builder transformation(Transformation transformation) {
175            this.transformation = transformation;
176            return this;
177        }
178
179        public Builder identity(EdgeIdentity identity) {
180            this.identity = identity;
181            return this;
182        }
183
184        public ContractEdge build() {
185            return new ContractEdge(this);
186        }
187    }
188}