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}