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

tech.ydb.yoj.databind.expression.ScalarExpr Maven / Gradle / Ivy

Go to download

Core data-binding logic used by YOJ (YDB ORM for Java) to convert between Java objects and database rows (or anything representable by a Java Map, really).

The newest version!
package tech.ydb.yoj.databind.expression;

import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.Value;
import tech.ydb.yoj.databind.expression.values.FieldValue;
import tech.ydb.yoj.databind.schema.Schema;

import javax.annotation.Nullable;
import java.util.function.UnaryOperator;

import static java.lang.String.format;
import static lombok.AccessLevel.PRIVATE;

@Value
@AllArgsConstructor(access = PRIVATE)
public class ScalarExpr extends LeafExpression {
    Schema schema;

    boolean generated;

    Operator operator;

    Schema.JavaField field;

    FieldValue value;

    public ScalarExpr(@NonNull Schema schema, boolean generated,
                      @NonNull ModelField field, @NonNull Operator operator, @NonNull FieldValue value) {
        this(schema, generated, operator, field.getJavaField(), field.validateValue(value));
    }

    @Override
    public FilterExpression.Type getType() {
        return Type.SCALAR;
    }

    @Nullable
    public Comparable getActualValue(@NonNull T obj) {
        return FieldValue.getComparable(schema.flatten(obj), field);
    }

    @NonNull
    public Comparable getExpectedValue() {
        return value.getComparable(field);
    }

    @Override
    public  V visit(@NonNull Visitor visitor) {
        return visitor.visitScalarExpr(this);
    }

    @Override
    public FilterExpression negate() {
        Operator negation = operator.negate();
        return negation != null ? new ScalarExpr<>(schema, generated, negation, field, value) : super.negate();
    }

    @Override
    public  ScalarExpr forSchema(@NonNull Schema dstSchema, @NonNull UnaryOperator pathTransformer) {
        Schema.JavaField newField = this.field.forSchema(dstSchema, pathTransformer);
        return new ScalarExpr<>(dstSchema, this.generated, this.operator, newField, this.value);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        ScalarExpr that = (ScalarExpr) o;

        if (!schema.equals(that.schema)) {
            return false;
        }
        if (!operator.name().equals(that.operator.name())) {
            return false;
        }
        if (!field.equals(that.field)) {
            return false;
        }
        return value.equals(that.value);
    }

    @Override
    public int hashCode() {
        int result = schema.hashCode();
        result = 31 * result + operator.name().hashCode();
        result = 31 * result + field.hashCode();
        result = 31 * result + value.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return format("%s %s %s", field.getPath(), operator, value);
    }

    public enum Operator {
        /**
         * Exact match for numbers, case-sensitive match for strings.
         * E.g., {@code zone='ru-central-1'} or {@code size=1024}
         */
        EQ {
            @Override
            public Operator negate() {
                return NEQ;
            }

            @Override
            public String toString() {
                return "==";
            }
        },
        /**
         * Exact negative match for numbers, case-sensitive negative match for strings.
         * E.g., {@code zone!="ru-central-1"} or {@code size!=1024}
         */
        NEQ {
            @Override
            public Operator negate() {
                return EQ;
            }

            @Override
            public String toString() {
                return "!=";
            }
        },
        /**
         * "Less than" match for numbers and strings (strings are compared lexicographically).
         * E.g., {@code size < 100}
         */
        LT {
            @Override
            public Operator negate() {
                return GTE;
            }

            @Override
            public String toString() {
                return "<";
            }
        },
        /**
         * "Less than or equal" match for numbers and strings (strings are compared lexicographically).
         * E.g., {@code size <= 2048}
         */
        LTE {
            @Override
            public Operator negate() {
                return GT;
            }

            @Override
            public String toString() {
                return "<=";
            }
        },
        /**
         * "Greater than" match for numbers and strings (strings are compared lexicographically).
         * E.g., {@code size > 100}
         */
        GT {
            @Override
            public Operator negate() {
                return LTE;
            }

            @Override
            public String toString() {
                return ">";
            }
        },
        /**
         * "Greater than or equal" match for numbers and strings (strings are compared lexicographically).
         * E.g., {@code size >= 4096}
         */
        GTE {
            @Override
            public Operator negate() {
                return LT;
            }

            @Override
            public String toString() {
                return ">=";
            }
        },
        /**
         * "Starts with" is case-sensitive match to check if a string starts with the specified substring.
         * E.g., {@code name startswith "Al"}
         */
        STARTS_WITH {
            @Override
            public Operator negate() {
                return null;
            }

            @Override
            public String toString() {
                return "startswith";
            }
        },
        /**
         * "Ends with" is case-sensitive match to check if a string ends with the specified substring.
         * E.g., {@code name endswith "exey"}
         */
        ENDS_WITH {
            @Override
            public Operator negate() {
                return null;
            }

            @Override
            public String toString() {
                return "endswith";
            }
        },
        /**
         * "Contains" case-sensitive match for a substring in a string
         * E.g., {@code name contains "abc"}
         */
        CONTAINS {
            @Override
            public Operator negate() {
                return NOT_CONTAINS;
            }

            @Override
            public String toString() {
                return "contains";
            }
        },
        /**
         * "Not contains" case-sensitive absence of a substring in a string
         * E.g., {@code name not contains "abc"}
         */
        NOT_CONTAINS {
            @Override
            public Operator negate() {
                return CONTAINS;
            }

            @Override
            public String toString() {
                return "not contains";
            }
        };

        @Nullable
        public abstract Operator negate();
    }
}