class JoinPair {

    private final JoinType joinType;

    private final RelationName left;
    private final RelationName right;

    @Nullable
    private final Symbol condition;

    public static JoinPair of(RelationName left, RelationName right, JoinType joinType, Symbol condition) {
        assert condition != null || joinType == JoinType.CROSS : "condition must be present unless it's a cross-join";
        return new JoinPair(left, right, joinType, condition);
    }

    private JoinPair(RelationName left, RelationName right, JoinType joinType, @Nullable Symbol condition) {
        this.left = left;
        this.right = right;
        this.joinType = joinType;
        this.condition = condition;
    }

    public RelationName left() {
        return left;
    }

    public RelationName right() {
        return right;
    }

    public JoinType joinType() {
        return joinType;
    }

    @Nullable
    public Symbol condition() {
        return condition;
    }

    @Override
    public String toString() {
        return "Join{" + joinType + " " + left + " ⇔ " + right + '}';
    }

    @Override
    public boolean equals(Object o) {<FILL_FUNCTION_BODY>}

    @Override
    public int hashCode() {
        return Objects.hash(joinType, left, right, condition);
    }
}

        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        JoinPair joinPair = (JoinPair) o;
        return joinType == joinPair.joinType &&
               Objects.equals(left, joinPair.left) &&
               Objects.equals(right, joinPair.right) &&
               Objects.equals(condition, joinPair.condition);
    
<no_super_class>