001package gudusoft.gsqlparser.lineage2.contract;
002
003import java.util.ArrayList;
004import java.util.Collections;
005import java.util.List;
006
007/**
008 * Contract {@code TransformGraph} (lineage2-contract.md ยง7) โ€”
009 * statement-local computation graph, TRANSFORM-GRAPH-V1 with coordinates.
010 * The engine emits local node ids only; node/step GUID materialization
011 * stays a repository concern per rev 3.
012 *
013 * <p>Internal API: not part of the public gsqlparser surface.
014 */
015public final class TransformGraph {
016
017    /** Node kinds of TRANSFORM-GRAPH-V1. */
018    public enum NodeKind {
019        PHYSICAL_COLUMN, CTE_COLUMN, DERIVED_COLUMN, TEMP_COLUMN, EXPRESSION,
020        CONSTANT, PARAMETER, UNKNOWN
021    }
022
023    /** Step operation types of TRANSFORM-GRAPH-V1. */
024    public enum OperationType {
025        ASSIGN, CAST, FUNCTION, ARITHMETIC, CONCAT, CASE, AGGREGATE, JOIN,
026        FILTER, LOOKUP, WINDOW, UNION, EXPRESSION, UNKNOWN
027    }
028
029    public static final class Node {
030        private final String localNodeId;
031        private final NodeKind nodeKind;
032        private final String label;
033        private final SourceLocation sourceLocation;
034        private final LocationNullReason locationNullReason;
035
036        public Node(String localNodeId, NodeKind nodeKind, String label,
037                    SourceLocation sourceLocation,
038                    LocationNullReason locationNullReason) {
039            if (localNodeId == null || nodeKind == null) {
040                throw new IllegalArgumentException(
041                        "localNodeId and nodeKind must not be null");
042            }
043            this.localNodeId = localNodeId;
044            this.nodeKind = nodeKind;
045            this.label = label;
046            this.sourceLocation = sourceLocation;
047            this.locationNullReason = locationNullReason;
048        }
049
050        public String getLocalNodeId() {
051            return localNodeId;
052        }
053
054        public NodeKind getNodeKind() {
055            return nodeKind;
056        }
057
058        /** Nullable. */
059        public String getLabel() {
060            return label;
061        }
062
063        /** Nullable. */
064        public SourceLocation getSourceLocation() {
065            return sourceLocation;
066        }
067
068        /** Nullable โ€” set only when {@code sourceLocation} is null. */
069        public LocationNullReason getLocationNullReason() {
070            return locationNullReason;
071        }
072    }
073
074    public static final class Step {
075        private final int stepIndex;
076        private final OperationType operationType;
077        private final List<String> inputNodeIds;
078        private final String outputNodeId;
079        private final String expressionHash;
080        private final SourceLocation sourceLocation;
081        private final LocationNullReason locationNullReason;
082
083        public Step(int stepIndex, OperationType operationType,
084                    List<String> inputNodeIds, String outputNodeId,
085                    String expressionHash, SourceLocation sourceLocation,
086                    LocationNullReason locationNullReason) {
087            if (operationType == null || inputNodeIds == null
088                    || outputNodeId == null) {
089                throw new IllegalArgumentException("operationType, inputNodeIds, "
090                        + "and outputNodeId must not be null");
091            }
092            this.stepIndex = stepIndex;
093            this.operationType = operationType;
094            this.inputNodeIds = Collections.unmodifiableList(
095                    new ArrayList<>(inputNodeIds));
096            this.outputNodeId = outputNodeId;
097            this.expressionHash = expressionHash;
098            this.sourceLocation = sourceLocation;
099            this.locationNullReason = locationNullReason;
100        }
101
102        public int getStepIndex() {
103            return stepIndex;
104        }
105
106        public OperationType getOperationType() {
107            return operationType;
108        }
109
110        public List<String> getInputNodeIds() {
111            return inputNodeIds;
112        }
113
114        public String getOutputNodeId() {
115            return outputNodeId;
116        }
117
118        /** Nullable. */
119        public String getExpressionHash() {
120            return expressionHash;
121        }
122
123        /** Nullable. */
124        public SourceLocation getSourceLocation() {
125            return sourceLocation;
126        }
127
128        /** Nullable โ€” set only when {@code sourceLocation} is null. */
129        public LocationNullReason getLocationNullReason() {
130            return locationNullReason;
131        }
132    }
133
134    private final int statementIndex;
135    private final String occurrenceGuidRef;
136    private final List<Node> nodes;
137    private final List<Step> steps;
138
139    public TransformGraph(int statementIndex, String occurrenceGuidRef,
140                          List<Node> nodes, List<Step> steps) {
141        this.statementIndex = statementIndex;
142        this.occurrenceGuidRef = occurrenceGuidRef;
143        this.nodes = (nodes == null) ? Collections.<Node>emptyList()
144                : Collections.unmodifiableList(new ArrayList<>(nodes));
145        this.steps = (steps == null) ? Collections.<Step>emptyList()
146                : Collections.unmodifiableList(new ArrayList<>(steps));
147    }
148
149    public int getStatementIndex() {
150        return statementIndex;
151    }
152
153    /** Nullable. */
154    public String getOccurrenceGuidRef() {
155        return occurrenceGuidRef;
156    }
157
158    public List<Node> getNodes() {
159        return nodes;
160    }
161
162    public List<Step> getSteps() {
163        return steps;
164    }
165}