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}