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

jetbrains.exodus.query.QueryEngine Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/**
 * Copyright 2010 - 2019 JetBrains s.r.o.
 *
 * 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 jetbrains.exodus.query;


import jetbrains.exodus.entitystore.Entity;
import jetbrains.exodus.entitystore.EntityIterable;
import jetbrains.exodus.entitystore.PersistentEntityStoreImpl;
import jetbrains.exodus.entitystore.StoreTransaction;
import jetbrains.exodus.entitystore.iterate.EntityIterableBase;
import jetbrains.exodus.entitystore.iterate.SingleEntityIterable;
import jetbrains.exodus.query.metadata.AssociationEndMetaData;
import jetbrains.exodus.query.metadata.EntityMetaData;
import jetbrains.exodus.query.metadata.ModelMetaData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Iterator;

@SuppressWarnings("UnusedParameters")
public class QueryEngine {

    private final ModelMetaData mmd;
    private final PersistentEntityStoreImpl persistentStore;
    private final UniqueKeyIndicesEngine ukiEngine;
    private SortEngine sortEngine;

    public QueryEngine(final ModelMetaData mmd, final PersistentEntityStoreImpl persistentStore) {
        this.mmd = mmd;
        this.persistentStore = persistentStore;
        ukiEngine = new MetaDataAwareUniqueKeyIndicesEngine(persistentStore, mmd);
    }

    protected Iterable inMemorySelectDistinct(Iterable it, final String linkName) {
        throw new UnsupportedOperationException("NOT IMPLEMENTED YET");
    }

    protected Iterable inMemorySelectManyDistinct(Iterable it, final String linkName) {
        throw new UnsupportedOperationException("NOT IMPLEMENTED YET");
    }

    protected Iterable inMemoryIntersect(Iterable left, Iterable right) {
        throw new UnsupportedOperationException("NOT IMPLEMENTED YET");
    }

    protected Iterable inMemoryUnion(Iterable left, Iterable right) {
        throw new UnsupportedOperationException("NOT IMPLEMENTED YET");
    }

    protected Iterable inMemoryConcat(Iterable left, Iterable right) {
        throw new UnsupportedOperationException("NOT IMPLEMENTED YET");
    }

    protected Iterable inMemoryExclude(Iterable left, Iterable right) {
        throw new UnsupportedOperationException("NOT IMPLEMENTED YET");
    }

    public ModelMetaData getModelMetaData() {
        return mmd;
    }

    public PersistentEntityStoreImpl getPersistentStore() {
        return persistentStore;
    }

    public UniqueKeyIndicesEngine getUniqueKeyIndicesEngine() {
        return ukiEngine;
    }

    public SortEngine getSortEngine() {
        return sortEngine;
    }

    public void setSortEngine(SortEngine sortEngine) {
        this.sortEngine = sortEngine;
    }

    protected void assertOperational() {
    }

    protected boolean isWrapped(@Nullable Iterable it) {
        return true;
    }

    @NotNull
    protected EntityIterable wrap(@NotNull EntityIterable it) {
        return it;
    }

    @Nullable
    protected Iterable wrap(@NotNull Entity entity) {
        return new SingleEntityIterable(persistentStore.getAndCheckCurrentTransaction(), entity.getId());
    }

    public boolean isPersistentIterable(Iterable it) {
        return it instanceof EntityIterableBase;
    }

    public TreeKeepingEntityIterable queryGetAll(String entityType) {
        return query(null, entityType, NodeFactory.all());
    }

    public TreeKeepingEntityIterable query(@NotNull String entityType, @NotNull final NodeBase tree) {
        return query(null, entityType, tree);
    }

    public TreeKeepingEntityIterable query(@Nullable final Iterable instance, @NotNull String entityType, @NotNull final NodeBase tree) {
        return new TreeKeepingEntityIterable(instance, entityType, tree, this);
    }

    public Iterable intersect(Iterable left, Iterable right) {
        if (left == right) {
            return left;
        }
        if (isEmptyIterable(left) || isEmptyIterable(right)) {
            return EntityIterableBase.EMPTY;
        }
        if (left instanceof TreeKeepingEntityIterable) {
            final TreeKeepingEntityIterable l = (TreeKeepingEntityIterable) left;
            final String leftType = l.getEntityType();
            if (right instanceof TreeKeepingEntityIterable) {
                final TreeKeepingEntityIterable r = (TreeKeepingEntityIterable) right;
                if (l.getInstance() == r.getInstance()) {
                    final String rightType = r.getEntityType();
                    if (Utils.isTypeOf(leftType, rightType, mmd)) {
                        return new TreeKeepingEntityIterable(r.getInstance(), leftType, new And(l.getTree(), r.getTree()), l.annotatedTree, r.annotatedTree, this);
                    } else if (Utils.isTypeOf(rightType, leftType, mmd)) {
                        return new TreeKeepingEntityIterable(r.getInstance(), rightType, new And(l.getTree(), r.getTree()), l.annotatedTree, r.annotatedTree, this);
                    }
                }
            }
        }
        String staticType = null;
        if (left instanceof StaticTypedEntityIterable) {
            final StaticTypedEntityIterable l = (StaticTypedEntityIterable) left;
            final String leftType = l.getEntityType();
            if (right instanceof StaticTypedEntityIterable) {
                final StaticTypedEntityIterable r = (StaticTypedEntityIterable) right;
                final String rightType = r.getEntityType();
                if (Utils.isTypeOf(rightType, leftType, mmd)) {
                    staticType = rightType;
                } else if (Utils.isTypeOf(leftType, rightType, mmd)) {
                    staticType = leftType;
                }
                if (leftType.equals(rightType)) {
                    if (isGetAllTree(l)) {
                        return new ExcludeNullStaticTypedEntityIterable(rightType, r, this);
                    }
                    if (isGetAllTree(r)) {
                        return new ExcludeNullStaticTypedEntityIterable(leftType, l, this);
                    }
                }
            }
        }
        right = instantiateAndAdjust(right);
        left = instantiateAndAdjust(left);
        final Iterable result = intersectNonTrees(left, right);
        return staticType != null ? new StaticTypedIterableDecorator(staticType, result, this) : result;
    }

    public Iterable union(Iterable left, Iterable right) {
        if (left == right) {
            return left;
        }
        if (isEmptyIterable(left)) {
            return right;
        }
        if (isEmptyIterable(right)) {
            return left;
        }
        if (left instanceof TreeKeepingEntityIterable) {
            final TreeKeepingEntityIterable l = (TreeKeepingEntityIterable) left;
            String leftType = l.getEntityType();
            if (right instanceof TreeKeepingEntityIterable) {
                final TreeKeepingEntityIterable r = (TreeKeepingEntityIterable) right;
                if (l.getInstance() == r.getInstance() && leftType.equals(r.getEntityType())) {
                    return new TreeKeepingEntityIterable(r.getInstance(), leftType, new Or(l.getTree(), r.getTree()), l.annotatedTree, r.annotatedTree, this);
                }
            }
        }
        String staticType = null;
        if (left instanceof StaticTypedEntityIterable) {
            final StaticTypedEntityIterable l = (StaticTypedEntityIterable) left;
            final String leftType = l.getEntityType();
            if (right instanceof StaticTypedEntityIterable) {
                final StaticTypedEntityIterable r = (StaticTypedEntityIterable) right;
                final String rightType = r.getEntityType();
                if (leftType.equals(rightType)) {
                    staticType = rightType;
                    if (isGetAllTree(l)) {
                        return new AddNullStaticTypedEntityIterable(staticType, l, r, this);
                    }
                    if (isGetAllTree(r)) {
                        return new AddNullStaticTypedEntityIterable(staticType, r, l, this);
                    }
                }
            }
        }
        right = instantiateAndAdjust(right);
        left = instantiateAndAdjust(left);
        final Iterable result = unionNonTrees(left, right);
        return staticType != null ? new StaticTypedIterableDecorator(staticType, result, this) : result;
    }

    public Iterable concat(Iterable left, Iterable right) {
        if (isEmptyIterable(left)) {
            return right;
        }
        if (isEmptyIterable(right)) {
            return left;
        }
        if (left instanceof TreeKeepingEntityIterable) {
            final TreeKeepingEntityIterable l = (TreeKeepingEntityIterable) left;
            String leftType = l.getEntityType();
            if (right instanceof TreeKeepingEntityIterable) {
                final TreeKeepingEntityIterable r = (TreeKeepingEntityIterable) right;
                if (l.getInstance() == r.getInstance() && leftType.equals(r.getEntityType())) {
                    return new TreeKeepingEntityIterable(r.getInstance(), leftType, new Concat(l.getTree(), r.getTree()),
                        l.annotatedTree, r.annotatedTree, this);
                }
            }
        }
        final String staticType = retrieveStaticType(left, right);
        right = instantiateAndAdjust(right);
        left = instantiateAndAdjust(left);
        final Iterable result = concatNonTrees(left, right);
        return staticType != null ? new StaticTypedIterableDecorator(staticType, result, this) : result;
    }

    public Iterable exclude(Iterable left, Iterable right) {
        if (isEmptyIterable(left) || left == right) {
            return EntityIterableBase.EMPTY;
        }
        if (isEmptyIterable(right)) {
            return left;
        }
        if (left instanceof TreeKeepingEntityIterable) {
            final TreeKeepingEntityIterable l = (TreeKeepingEntityIterable) left;
            String leftType = l.getEntityType();
            if (right instanceof TreeKeepingEntityIterable) {
                final TreeKeepingEntityIterable r = (TreeKeepingEntityIterable) right;
                if (l.getInstance() == r.getInstance() && leftType.equals(r.getEntityType())) {
                    return new TreeKeepingEntityIterable(r.getInstance(), leftType, new Minus(l.getTree(), r.getTree()), l.annotatedTree, r.annotatedTree, this);
                }
            }
        }
        final String staticType = retrieveStaticType(left, right);
        right = instantiateAndAdjust(right);
        left = instantiateAndAdjust(left);
        final Iterable result = excludeNonTrees(left, right);
        return staticType != null ? new StaticTypedIterableDecorator(staticType, result, this) : result;
    }

    public Iterable selectDistinct(Iterable it, final String linkName) {
        if (it == null) {
            return EntityIterableBase.EMPTY;
        }
        if (mmd != null) {
            if (it instanceof StaticTypedEntityIterable) {
                final StaticTypedEntityIterable ktei = (StaticTypedEntityIterable) it;
                it = toEntityIterable(it);
                if (isPersistentIterable(it)) {
                    final String entityType = ktei.getEntityType();
                    final EntityMetaData emd = mmd.getEntityMetaData(entityType);
                    if (emd != null) {
                        final AssociationEndMetaData aemd = emd.getAssociationEndMetaData(linkName);
                        if (aemd != null) {
                            final String resultType = aemd.getOppositeEntityMetaData().getType();
                            return new StaticTypedIterableDecorator(resultType,
                                selectDistinctImpl((EntityIterableBase) it, linkName), this);
                        }
                    }
                }
            } else if (isPersistentIterable(it)) {
                return selectDistinctImpl((EntityIterableBase) it, linkName);
            }
        }
        return inMemorySelectDistinct(it, linkName);
    }

    public Iterable selectManyDistinct(Iterable it, final String linkName) {
        if (it == null) {
            return EntityIterableBase.EMPTY;
        }
        if (mmd != null) {
            if (it instanceof StaticTypedEntityIterable) {
                final StaticTypedEntityIterable tree = (StaticTypedEntityIterable) it;
                it = toEntityIterable(it);
                if (isPersistentIterable(it)) {
                    final String entityType = tree.getEntityType();
                    final EntityMetaData emd = mmd.getEntityMetaData(entityType);
                    if (emd != null) {
                        final AssociationEndMetaData aemd = emd.getAssociationEndMetaData(linkName);
                        if (aemd != null) {
                            final String resultType = aemd.getOppositeEntityMetaData().getType();
                            return new StaticTypedIterableDecorator(resultType,
                                selectManyDistinctImpl((EntityIterableBase) it, linkName), this);
                        }
                    }
                }
            } else if (isPersistentIterable(it)) {
                return selectManyDistinctImpl((EntityIterableBase) it, linkName);
            }
        }
        return inMemorySelectManyDistinct(it, linkName);
    }

    public Iterable toEntityIterable(Iterable it) {
        if (it instanceof StaticTypedEntityIterable) {
            it = ((StaticTypedEntityIterable) it).instantiate();
        }
        return adjustEntityIterable(it);
    }

    public Iterable intersectNonTrees(Iterable left, Iterable right) {
        if (isPersistentIterable(left) && isPersistentIterable(right)) {
            return wrap(((EntityIterableBase) left).getSource().intersect(((EntityIterableBase) right).getSource()));
        }
        return inMemoryIntersect(left, right);
    }

    public Iterable unionNonTrees(Iterable left, Iterable right) {
        if (isPersistentIterable(left) && isPersistentIterable(right)) {
            return wrap(((EntityIterableBase) left).getSource().union(((EntityIterableBase) right).getSource()));
        }
        return inMemoryUnion(left, right);
    }

    public Iterable concatNonTrees(Iterable left, Iterable right) {
        if (isPersistentIterable(left) && isPersistentIterable(right)) {
            return wrap(((EntityIterableBase) left).getSource().concat(((EntityIterableBase) right).getSource()));
        }
        return inMemoryConcat(left, right);
    }

    public Iterable excludeNonTrees(Iterable left, Iterable right) {
        if (isPersistentIterable(left) && isPersistentIterable(right)) {
            return wrap(((EntityIterableBase) left).getSource().minus(((EntityIterableBase) right).getSource()));
        }
        // subtract
        return inMemoryExclude(left, right);
    }

    private Iterable instantiateAndAdjust(Iterable it) {
        return adjustEntityIterable(StaticTypedEntityIterable.instantiate(it));
    }

    private Iterable selectDistinctImpl(final EntityIterableBase it, String linkName) {
        assertOperational();
        return wrap(it.getSource().selectDistinct(linkName));
    }

    private Iterable selectManyDistinctImpl(final EntityIterableBase it, String linkName) {
        assertOperational();
        return wrap(it.getSource().selectManyDistinct(linkName));
    }

    public Iterable adjustEntityIterable(Iterable it) {
        if (it == EntityIterableBase.EMPTY) {
            return it;
        }
        // try to convert collection to entity iterable.
        if (it instanceof Collection) {
            final Collection collection = (Collection) it;
            final Iterator itr = collection.iterator();
            if (itr.hasNext()) {
                final Entity e = itr.next();
                if (!itr.hasNext()) {
                    final Iterable wrapped = wrap(e);
                    if (wrapped != null) {
                        it = wrapped;
                    }
                }
            } else {
                return EntityIterableBase.EMPTY;
            }
        }
        // wrap with transient iterable
        return isPersistentIterable(it) && !isWrapped(it) ? wrap(((EntityIterableBase) it).getSource()) : it;
    }

    public Iterable unionAdjusted(final Iterable left, final Iterable right) {
        return unionNonTrees(adjustEntityIterable(left), adjustEntityIterable(right));
    }

    public Iterable intersectAdjusted(final Iterable left, final Iterable right) {
        return intersectNonTrees(adjustEntityIterable(left), adjustEntityIterable(right));
    }

    public Iterable concatAdjusted(final Iterable left, final Iterable right) {
        return concatNonTrees(adjustEntityIterable(left), adjustEntityIterable(right));
    }

    public Iterable excludeAdjusted(final Iterable left, final Iterable right) {
        return excludeNonTrees(adjustEntityIterable(left), adjustEntityIterable(right));
    }

    public EntityIterable instantiateGetAll(@NotNull final String entityType) {
        return instantiateGetAll(getPersistentStore().getAndCheckCurrentTransaction(), entityType);
    }

    public EntityIterable instantiateGetAll(@NotNull final StoreTransaction txn, @NotNull final String entityType) {
        return txn.getAll(entityType);
    }

    public static boolean isEmptyIterable(Iterable it) {
        return it == null || it == EntityIterableBase.EMPTY || (it instanceof StaticTypedIterableDecorator && ((StaticTypedIterableDecorator) it).getDecorated() == EntityIterableBase.EMPTY);
    }

    public static boolean isGetAllTree(final StaticTypedEntityIterable tree) {
        return tree instanceof TreeKeepingEntityIterable && ((TreeKeepingEntityIterable) tree).getTree() instanceof GetAll;
    }

    private static String retrieveStaticType(Iterable left, Iterable right) {
        if (left instanceof StaticTypedEntityIterable) {
            final String leftType = ((StaticTypedEntityIterable) left).getEntityType();
            if (right instanceof StaticTypedEntityIterable) {
                final String rightType = ((StaticTypedEntityIterable) right).getEntityType();
                if (leftType.equals(rightType)) {
                    return rightType;
                }
            }
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy