001package gudusoft.gsqlparser.ir.semantic; 002 003import gudusoft.gsqlparser.common.structured.StructuredColumnPath; 004 005/** 006 * One endpoint of a {@link LineageEdge}. Either references an output column 007 * of a {@link StatementGraph} (by index + name) or a column of a base 008 * table (by qualified name + column name). The discriminator is 009 * {@link #getKind()}. 010 * 011 * <p>An optional {@link StructuredColumnPath} carries a typed path under 012 * the root column (e.g. {@code nodes[*].key}) for endpoints produced by 013 * structured-dataflow adapters. Existing factories leave it null. 014 */ 015public final class LineageRef { 016 017 public enum Kind { 018 STATEMENT_OUTPUT, 019 TABLE_COLUMN 020 } 021 022 private final Kind kind; 023 private final int statementIndex; 024 private final String outputName; 025 private final String qualifiedName; 026 private final String columnName; 027 private final StructuredColumnPath structuredPath; 028 029 private LineageRef(Kind kind, int statementIndex, String outputName, 030 String qualifiedName, String columnName, 031 StructuredColumnPath structuredPath) { 032 this.kind = kind; 033 this.statementIndex = statementIndex; 034 this.outputName = outputName; 035 this.qualifiedName = qualifiedName; 036 this.columnName = columnName; 037 this.structuredPath = structuredPath; 038 } 039 040 public static LineageRef statementOutput(int statementIndex, String outputName) { 041 return statementOutput(statementIndex, outputName, null); 042 } 043 044 public static LineageRef statementOutput(int statementIndex, String outputName, 045 StructuredColumnPath structuredPath) { 046 if (statementIndex < 0) { 047 throw new IllegalArgumentException("statementIndex must be >= 0"); 048 } 049 if (outputName == null || outputName.isEmpty()) { 050 throw new IllegalArgumentException("outputName must be non-empty"); 051 } 052 return new LineageRef(Kind.STATEMENT_OUTPUT, statementIndex, outputName, null, null, structuredPath); 053 } 054 055 public static LineageRef tableColumn(String qualifiedName, String columnName) { 056 return tableColumn(qualifiedName, columnName, null); 057 } 058 059 public static LineageRef tableColumn(String qualifiedName, String columnName, 060 StructuredColumnPath structuredPath) { 061 if (qualifiedName == null || qualifiedName.isEmpty()) { 062 throw new IllegalArgumentException("qualifiedName must be non-empty"); 063 } 064 if (columnName == null || columnName.isEmpty()) { 065 throw new IllegalArgumentException("columnName must be non-empty"); 066 } 067 return new LineageRef(Kind.TABLE_COLUMN, -1, null, qualifiedName, columnName, structuredPath); 068 } 069 070 public Kind getKind() { 071 return kind; 072 } 073 074 public int getStatementIndex() { 075 return statementIndex; 076 } 077 078 public String getOutputName() { 079 return outputName; 080 } 081 082 public String getQualifiedName() { 083 return qualifiedName; 084 } 085 086 public String getColumnName() { 087 return columnName; 088 } 089 090 public StructuredColumnPath getStructuredPath() { 091 return structuredPath; 092 } 093}