001package gudusoft.gsqlparser.lineage.v2.fold;
002
003/**
004 * The label of a fold walk ({@code algorithms/fold-v1.md}, Section 5.1): {@code VALUE}, or {@code ROW} with a
005 * role. Labels compose with {@link #compose}; {@code VALUE} is the identity.
006 *
007 * @since 4.2.17
008 */
009public final class FoldLabel {
010
011    /** The label of a walk of {@code VALUE} micro-edges only. */
012    public static final FoldLabel VALUE = new FoldLabel("VALUE", null);
013
014    private static final String PROPAGATION = "ROW_PROPAGATION";
015
016    private final String kind;
017    private final String role;
018
019    private FoldLabel(String kind, String role) {
020        this.kind = kind;
021        this.role = role;
022    }
023
024    /** The label of one micro-edge or Fact: {@code VALUE} for kind {@code VALUE}, otherwise {@code ROW(role)}. */
025    public static FoldLabel of(Object kind, Object role) {
026        return "VALUE".equals(kind) ? VALUE : row(role instanceof String ? (String) role : null);
027    }
028
029    /** {@code ROW(role)}; a null role stands for a role that is absent. */
030    public static FoldLabel row(String role) {
031        return new FoldLabel("ROW", role);
032    }
033
034    /** {@code VALUE} or {@code ROW}. */
035    public String getKind() {
036        return kind;
037    }
038
039    /** The role of a {@code ROW} label; null for {@code VALUE}. */
040    public String getRole() {
041        return role;
042    }
043
044    public boolean isValue() {
045        return this == VALUE;
046    }
047
048    /** {@code this ยท next}: Section 5.1 of fold-v1. */
049    public FoldLabel compose(FoldLabel next) {
050        if (isValue()) {
051            return next;
052        }
053        if (!PROPAGATION.equals(role)) {
054            return this;
055        }
056        return next.isValue() ? this : next;
057    }
058
059    /**
060     * The text the reference runner sorts labels by (Python {@code repr} of its label tuple): {@code ('ROW',
061     * 'FILTER')}, {@code ('ROW', None)}, {@code ('VALUE',)}.
062     */
063    String sortText() {
064        if (isValue()) {
065            return "('VALUE',)";
066        }
067        return role == null ? "('ROW', None)" : "('ROW', '" + role + "')";
068    }
069
070    @Override
071    public boolean equals(Object other) {
072        if (!(other instanceof FoldLabel)) {
073            return false;
074        }
075        FoldLabel label = (FoldLabel) other;
076        return kind.equals(label.kind) && (role == null ? label.role == null : role.equals(label.role));
077    }
078
079    @Override
080    public int hashCode() {
081        return kind.hashCode() * 31 + (role == null ? 0 : role.hashCode());
082    }
083
084    @Override
085    public String toString() {
086        return isValue() ? "VALUE" : "ROW " + role;
087    }
088}