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

org.deephacks.graphene.Criteria Maven / Gradle / Ivy

There is a newer version: 0.2.2
Show newest version
/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.deephacks.graphene;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.sleepycat.je.LockMode;
import org.deephacks.graphene.internal.EntityClassWrapper;
import org.deephacks.graphene.internal.RowKey;
import org.deephacks.graphene.internal.UniqueIds;
import org.deephacks.graphene.internal.ValueSerialization.ValueReader;

import java.io.Serializable;
import java.util.Date;

/**
 * A criteria is used as a rule that evaluates to true or false on a
 * specific type of value.
 */
@SuppressWarnings("rawtypes")
public class Criteria implements Predicate {

    private static final EntityRepository repository = new EntityRepository();

    private static final UniqueIds ids = new UniqueIds();
    private final String fieldName;
    private Predicate p;

    private Criteria(String name, Predicate p) {
        this.fieldName = name;
        this.p = p;
    }

    public static Builder field(String name) {
        return new Builder(name);
    }

    @SuppressWarnings("unchecked")
    public Criteria and(Predicate predicate) {
        if (!Criteria.class.isInstance(predicate)) {
            predicate = new PredicateProxy(fieldName, predicate);
        }
        p = Predicates.and(p, predicate);
        return this;
    }

    @SuppressWarnings("unchecked")
    public Criteria or(Predicate predicate) {
        if (!Criteria.class.isInstance(predicate)) {
            predicate = new PredicateProxy(fieldName, predicate);
        }
        p = Predicates.or(p, predicate);
        return this;
    }

    public static class Builder {
        String fieldName;

        private Builder(String name) {
            this.fieldName = name;
        }

        public Criteria is(Predicate p) {
            return new Criteria(fieldName, new PredicateProxy(fieldName, p));
        }

        @SuppressWarnings("unchecked")
        public Criteria not(Predicate p) {
            return new Criteria(fieldName, new PredicateProxy(fieldName, Predicates.not(p)));
        }
    }

    /**
     * If a date is before.
     *
     * @param value
     * @return A date criteria
     */
    public static Predicate before(final Date value) {
        return new Predicate() {

            @Override
            public boolean apply(Date field) {
                if (field == null) {
                    return false;
                }
                return field.before(value);
            }

        };
    }

    /**
     * If a date is before or equals.
     *
     * @param value
     * @return A date criteria
     */
    public static Predicate beforeOrEquals(final Date value) {
        return new Predicate() {

            @Override
            public boolean apply(Date field) {
                if (field == null) {
                    return false;
                }
                return field.before(value) || field.equals(value);
            }

        };
    }

    /**
     * If a date is after.
     *
     * @param value
     * @return A date criteria
     */
    public static Predicate after(final Date value) {
        return new Predicate() {

            @Override
            public boolean apply(Date field) {
                if (field == null) {
                    return false;
                }
                return field.after(value);
            }

        };
    }

    /**
     * If a date is after or equals.
     *
     * @param value
     * @return A date criteria
     */
    public static Predicate afterOrEquals(final Date value) {
        return new Predicate() {

            @Override
            public boolean apply(Date field) {
                if (field == null) {
                    return false;
                }
                return field.after(value) || field.equals(value);
            }

        };
    }

    /**
     * If a a date is between two other dates.
     *
     * @param start
     * @param end
     * @return A date criteria
     */
    public static Predicate between(final Date start, final Date end) {
        return new Predicate() {

            @Override
            public boolean apply(Date field) {
                if (field == null) {
                    return false;
                }
                boolean startMatch = field.after(start) || field.equals(start);
                boolean endMatch = field.before(end) || field.equals(end);
                return startMatch && endMatch;
            }

        };
    }

    /**
     * If a number is larger.
     *
     * @param value
     * @return A number criteria
     */
    public static Predicate largerThan(final Number value) {
        return new Predicate() {

            @Override
            public boolean apply(Number field) {
                if (field == null) {
                    return false;
                }
                return field.doubleValue() > value.doubleValue();
            }

        };
    }

    /**
     * If a number is larger or equals.
     *
     * @param value
     * @return A number criteria
     */
    public static Predicate largerOrEquals(final Number value) {
        return new Predicate() {

            @Override
            public boolean apply(Number field) {
                if (field == null) {
                    return false;
                }
                return field.doubleValue() >= value.doubleValue();
            }

        };
    }

    /**
     * If a number is less than.
     *
     * @param value
     * @return A number criteria
     */
    public static Predicate lessThan(final Number value) {
        return new Predicate() {

            @Override
            public boolean apply(Number field) {
                if (field == null) {
                    return false;
                }
                return field.doubleValue() < value.doubleValue();
            }

        };
    }

    /**
     * If a number is less or equal.
     *
     * @param value
     * @return A number criteria
     */
    public static Predicate lessOrEquals(final Number value) {
        return new Predicate() {

            @Override
            public boolean apply(Number field) {
                if (field == null) {
                    return false;
                }
                return field.doubleValue() < value.doubleValue();
            }

        };
    }

    /**
     * Evaluate if a Serializable if equal another Serializable.
     *
     * @param value
     * @return A Serializable criteria
     */
    public static Predicate equal(final Object value) {
        return new Predicate() {

            @Override
            public boolean apply(Serializable field) {
                if (field == null) {
                    return value == null;
                }
                return field.equals(value);
            }

        };
    }

    /**
     * Evaluate if a string contains another string.
     *
     * @param value
     * @return A string criteria
     */
    public static Predicate contains(final String value) {
        return new Predicate() {

            @Override
            public boolean apply(String field) {
                if (field == null) {
                    return false;
                }
                return field.contains(value);
            }

        };
    }

    /**
     * Evaluate if a string contains another string, case insensitive
     *
     * @param value
     * @return A string criteria
     */
    public static Predicate containsNoCase(final String value) {
        return new Predicate() {

            @Override
            public boolean apply(String field) {
                if (field == null) {
                    return false;
                }
                return field.toLowerCase().contains(value.toLowerCase());
            }

        };
    }

    /**
     * Evaluate if a string starts with another string.
     *
     * @param value
     * @return A string criteria
     */
    public static Predicate startsWith(final String value) {
        return new Predicate() {

            @Override
            public boolean apply(String field) {
                if (field == null) {
                    return false;
                }
                return field.startsWith(value);
            }

        };
    }

    /**
     * Evaluate if a string ends with another string.
     *
     * @param value
     * @return A string criteria
     */
    public static Predicate endsWith(final String value) {
        return new Predicate() {

            @Override
            public boolean apply(String field) {
                if (field == null) {
                    return false;
                }
                return field.endsWith(value);
            }

        };
    }

    /**
     * Evaluate a regular expression.
     *
     * @param pattern
     * @return A string criteria
     */
    public static Predicate regexp(final String pattern) {
        return new Predicate() {

            @Override
            public boolean apply(String field) {
                if (field == null) {
                    return false;
                }
                return field.matches(pattern);
            }

        };
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean apply(Object input) {
        return p.apply(input);
    }

    private static class PredicateProxy implements Predicate {
        private final Predicate target;
        private final String fieldName;

        public PredicateProxy(String fieldName, Predicate target) {
            this.target = target;
            this.fieldName = fieldName;
        }

        @SuppressWarnings("unchecked")
        @Override
        public boolean apply(Object object) {
            String[] fields = fieldName.split("\\.");
            byte[][] entity =  (byte[][]) object;
            if (fields.length == 1) {
                return evaluateField(entity[1], fieldName);
            } else if (fields.length > 1) {
                RowKey key = new RowKey(entity[0]);
                EntityClassWrapper cls = EntityClassWrapper.get(key.getCls());
                if (cls.isEmbedded(fields[0])) {
                    return evaluateEmdeddedFields(entity[1], fields);
                } else if (cls.isReference(fields[0])) {
                    return evaluateReferenceFields(entity[1], fields, cls);
                } else {
                    throw new IllegalStateException("Cannot handle field " + fieldName);
                }
            } else {
                throw new IllegalArgumentException("Cannot handle field " + fieldName);
            }
        }

        public boolean evaluateField(byte[] data, String fieldName) {
            Object value = getValue(data, fieldName);
            return target.apply(value);
        }

        public boolean evaluateEmdeddedFields(byte[] data, String[] fields) {
            if (fields.length > 2) {
                throw new UnsupportedOperationException("Can only handle one deep embedded object ATM " + fields.length);
            }
            ValueReader reader = new ValueReader(data);
            int[][] header = reader.getHeader();
            int id = ids.getSchemaId(fields[0]);
            Object value = reader.getValue(id, header);

            reader = new ValueReader((byte[])value);
            header = reader.getHeader();
            id = ids.getSchemaId(fields[1]);
            value = reader.getValue(id, header);
            return target.apply(value);
        }

        public boolean evaluateReferenceFields(byte[] data, String[] fields, EntityClassWrapper cls) {
            if (fields.length > 2) {
                throw new UnsupportedOperationException("Can only handle one deep reference object ATM " + fields.length);
            }
            ValueReader reader = new ValueReader(data);
            int[][] header = reader.getHeader();
            int id = ids.getSchemaId(fields[0]);
            Object instanceId = reader.getValue(id, header);
            Class refCls = cls.getReferences().get(fields[0]).getType();
            EntityClassWrapper entityRefCls = EntityClassWrapper.get(refCls);
            RowKey key = new RowKey(refCls, instanceId);
            Optional  kv = repository.getKv(key, LockMode.DEFAULT);
            if (!kv.isPresent()) {
                return false;
            }
            if (entityRefCls.getId().getField().getName().equals(fields[1])) {
                String instance = new RowKey(kv.get()[0]).getInstance();
                return target.apply(instance);
            } else {
                return evaluateField(kv.get()[1], fields[1]);
            }
        }

        public Object getValue(byte[] data, String fieldName) {
            ValueReader reader = new ValueReader(data);
            int[][] header = reader.getHeader();
            return reader.getValue(ids.getSchemaId(fieldName), header);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy