001package gudusoft.gsqlparser.ir.semantic;
002
003/**
004 * Per-output window frame clause (slice 22). When a {@link WindowSpec} carries
005 * a non-null frame, the SQL projection had a {@code ROWS}/{@code RANGE}/{@code
006 * GROUPS BETWEEN ...} clause inside its {@code OVER (...)}.
007 *
008 * <p><b>Frame is presentation metadata only.</b> The dlineage XML harvests no
009 * frame information: {@code DataFlowAnalyzer.generateDataFlow()} walks only
010 * {@code PARTITION BY} / {@code OVER ORDER BY} expressions for windowed calls
011 * (DataFlowAnalyzer.java:20558-20575). Frame information therefore does NOT
012 * appear in the canonical model. Adding canonical edges only on the IR side
013 * would manufacture divergence-by-design (same reasoning as slice-13
014 * PARTITION BY refs, slice-21 outer ORDER BY refs).
015 *
016 * <p>{@code end} is null for the unary form ({@code ROWS UNBOUNDED PRECEDING})
017 * which standard SQL treats as {@code BETWEEN UNBOUNDED PRECEDING AND CURRENT
018 * ROW}; the IR preserves the surface shape rather than expanding it.
019 *
020 * <p>The {@code EXCLUDE} clause is rejected at build time: Netezza's parser
021 * populates {@code TWindowFrameBoundary.getExclusionClause()} on the END
022 * boundary; lifting requires deciding whether EXCLUDE contributes to
023 * row-influence semantics.
024 */
025public final class WindowFrame {
026
027    public enum Unit {
028        ROWS,
029        RANGE,
030        GROUPS
031    }
032
033    private final Unit unit;
034    private final FrameBound start;
035    private final FrameBound end;
036
037    public WindowFrame(Unit unit, FrameBound start, FrameBound end) {
038        if (unit == null) {
039            throw new IllegalArgumentException("unit must not be null");
040        }
041        if (start == null) {
042            throw new IllegalArgumentException("start must not be null");
043        }
044        this.unit = unit;
045        this.start = start;
046        this.end = end;
047    }
048
049    public Unit getUnit() {
050        return unit;
051    }
052
053    public FrameBound getStart() {
054        return start;
055    }
056
057    public FrameBound getEnd() {
058        return end;
059    }
060}