All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.babyfish.jimmer.sql.ast.impl.CaseBuilder Maven / Gradle / Ivy

There is a newer version: 0.9.19
Show newest version
package org.babyfish.jimmer.sql.ast.impl;

import org.babyfish.jimmer.sql.ast.*;
import org.babyfish.jimmer.sql.ast.impl.render.AbstractSqlBuilder;
import org.babyfish.jimmer.sql.ast.tuple.Tuple2;
import org.babyfish.jimmer.sql.runtime.SqlBuilder;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class CaseBuilder {

    private Class type;

    private List>> whens = new ArrayList<>();

    CaseBuilder(Class type) {
        this.type = type;
    }

    public CaseBuilder when(Predicate cond, T then) {
        return when(cond, Literals.any(then));
    }

    public CaseBuilder when(Predicate cond, Expression then) {
        whens.add(new Tuple2<>(cond, then));
        return this;
    }

    public Expression otherwise(T otherwise) {
        return otherwise(Literals.any(otherwise));
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    public Expression otherwise(Expression otherwise) {
        List>> whens = new ArrayList<>(this.whens);
        if (String.class.isAssignableFrom(type)) {
            return (Expression) new StrExpr(
                    (List>>)(List)whens,
                    (Expression)otherwise
            );
        }
        if (type.isPrimitive() || Number.class.isAssignableFrom(type)) {
            return (Expression) new NumExpr(
                    type,
                    whens,
                    otherwise
            );
        }
        if (Comparable.class.isAssignableFrom(type)) {
            return (Expression) new CmpExpr(
                    type,
                    whens,
                    otherwise
            );
        }
        return new AnyExpr<>(type, whens, otherwise);
    }
    
    public static class Str extends CaseBuilder {

        Str() {
            super(String.class);
        }

        @Override
        public Str when(Predicate cond, String then) {
            return (Str) super.when(cond, then);
        }

        @Override
        public Str when(Predicate cond, Expression then) {
            return (Str) super.when(cond, then);
        }

        @Override
        public StringExpression otherwise(String otherwise) {
            return (StringExpression) super.otherwise(otherwise);
        }

        @Override
        public StringExpression otherwise(Expression otherwise) {
            return (StringExpression) super.otherwise(otherwise);
        }
    }
    
    public static class Num> extends CaseBuilder {

        Num(Class type) {
            super(type);
        }

        @Override
        public Num when(Predicate cond, N then) {
            return (Num)super.when(cond, then);
        }

        @Override
        public Num when(Predicate cond, Expression then) {
            return (Num)super.when(cond, then);
        }

        @Override
        public NumericExpression otherwise(N otherwise) {
            return (NumericExpression) super.otherwise(otherwise);
        }

        @Override
        public NumericExpression otherwise(Expression otherwise) {
            return (NumericExpression) super.otherwise(otherwise);
        }
    }
    
    public static class Cmp> extends CaseBuilder {

        Cmp(Class type) {
            super(type);
        }

        @Override
        public Cmp when(Predicate cond, T then) {
            return (Cmp) super.when(cond, then);
        }

        @Override
        public Cmp when(Predicate cond, Expression then) {
            return (Cmp) super.when(cond, then);
        }

        @Override
        public ComparableExpression otherwise(T otherwise) {
            return (ComparableExpression) super.otherwise(otherwise);
        }

        @Override
        public ComparableExpression otherwise(Expression otherwise) {
            return (ComparableExpression) super.otherwise(otherwise);
        }
    }

    private static class AnyExpr extends AbstractExpression {

        private final Class type;

        private List>> whens;

        private Expression otherwise;

        AnyExpr(
                Class type,
                List>> whens,
                Expression otherwise
        ) {
            this.type = type;
            this.whens = whens;
            this.otherwise = otherwise;
        }


        @Override
        public Class getType() {
            return type;
        }

        @Override
        public int precedence() {
            return 0;
        }

        @Override
        public void accept(@NotNull AstVisitor visitor) {
            for (Tuple2> when : whens) {
                ((Ast) when.get_1()).accept(visitor);
                ((Ast) when.get_2()).accept(visitor);
            }
            ((Ast) otherwise).accept(visitor);
        }

        @Override
        public void renderTo(@NotNull AbstractSqlBuilder builder) {
            usingLowestPrecedence(() -> {
                builder.sql("case");
                for (Tuple2> when : whens) {
                    builder.sql(" when ");
                    renderChild((Ast) when.get_1(), builder);
                    builder.sql(" then ");
                    renderChild((Ast) when.get_2(), builder);
                }
                builder.sql(" else ");
                renderChild((Ast) otherwise, builder);
                builder.sql(" end");
            });
        }

        @Override
        protected boolean determineHasVirtualPredicate() {
            return whens.stream().anyMatch(it -> hasVirtualPredicate(it.get_1()) || hasVirtualPredicate(it.get_2())) ||
                    hasVirtualPredicate(otherwise);
        }

        @Override
        protected Ast onResolveVirtualPredicate(AstContext ctx) {
            this.whens = whens.stream().map(
                    it -> new Tuple2<>(
                            ctx.resolveVirtualPredicate(it.get_1()),
                            ctx.resolveVirtualPredicate(it.get_2())
                    )
            ).collect(Collectors.toList());
            this.otherwise = ctx.resolveVirtualPredicate(otherwise);
            return this;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            AnyExpr anyExpr = (AnyExpr) o;
            return type.equals(anyExpr.type) && whens.equals(anyExpr.whens) && otherwise.equals(anyExpr.otherwise);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, whens, otherwise);
        }
    }
    
    private static class StrExpr extends AnyExpr implements StringExpressionImplementor {
        
        StrExpr(
                List>> whens, 
                Expression otherwise
        ) {
            super(String.class, whens, otherwise);
        }
    }
    
    private static class NumExpr> extends AnyExpr implements NumericExpressionImplementor {

        NumExpr(
                Class type,
                List>> whens, 
                Expression otherwise
        ) {
            super(type, whens, otherwise);
        }
    }
    
    private static class CmpExpr> extends AnyExpr implements ComparableExpressionImplementor {
        
        CmpExpr(
                Class type, 
                List>> whens,
                Expression otherwise
        ) {
            super(type, whens, otherwise);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy