package com.orientechnologies.orient.core.sql.parser; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.record.impl.ODocument; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * Created by luigidellaquila on 14/11/16. */ public class OMatchPathItemIterator implements Iterator<OIdentifiable> { private final OMatchStatement.MatchContext matchContext; private final OCommandContext ctx; OMatchPathItem item; OIdentifiable nextElement = null; List<Iterator> stack = new LinkedList<Iterator>(); OMatchPathItemIterator(OMatchPathItem item, OMatchStatement.MatchContext matchContext, OCommandContext iCommandContext, final OIdentifiable startingPoint) { this.item = item; this.matchContext = matchContext; this.ctx = iCommandContext; this.stack.add(new Iterator() { boolean executed = false; @Override public boolean hasNext() { return !executed; } @Override public Object next() { if (executed) { throw new IllegalStateException(); } executed = true; return startingPoint; } @Override public void remove() { } }); loadNext(); } protected void loadNext() { while (stack.size() > 0) { if (!stack.get(0).hasNext()) { stack.remove(0); continue; } loadNextInternal(); if (nextElement != null) { return; } } } protected void loadNextInternal() { if (stack == null || stack.size() == 0) { nextElement = null; return; } int depth = stack.size() - 1; Object oldDepth = ctx.getVariable("$depth", depth); ctx.setVariable("$depth", depth); final OWhereClause filter = this.item.filter == null ? null : this.item.filter.getFilter(); final String className = this.item.filter == null ? null : this.item.filter.getClassName(ctx); final OClass clazz = className == null ? null : ODatabaseRecordThreadLocal.INSTANCE.get().getMetadata().getSchema().getClass(className); final OWhereClause whileCondition = this.item.filter == null ? null : this.item.filter.getWhileCondition(); final Integer maxDepth = maxDepth(this.item.filter); final OClass oClass = this.item.filter == null ? null : item.getDatabase().getMetadata().getSchema().getClass(this.item.filter.getClassName(ctx)); boolean notDeep = this.item.filter == null || (whileCondition == null && this.item.filter.getMaxDepth() == null); OIdentifiable startingPoint = (OIdentifiable) stack.get(0).next(); nextElement = null; if (this.item.filter == null || (whileCondition == null && this.item.filter.getMaxDepth() == null)) { //basic case, no traversal, discard level zero if (depth == 1) { Object prevMatch = ctx.getVariable("$currentMatch"); Object prevCurrent = ctx.getVariable("$current"); ctx.setVariable("$currentMatch", startingPoint); ctx.setVariable("$current", startingPoint); if ((filter == null || filter.matchesFilters(startingPoint, ctx)) && (clazz == null || clazz .isSuperClassOf(((ODocument) startingPoint.getRecord()).getSchemaClass()))) { nextElement = startingPoint; } ctx.setVariable("$current", prevCurrent); ctx.setVariable("$currentMatch", prevMatch); } } else { Object prevMatch = ctx.getVariable("$currentMatch"); ctx.setVariable("$currentMatch", startingPoint); if ((filter == null || filter.matchesFilters(startingPoint, ctx)) && (clazz == null || clazz .isSuperClassOf(((ODocument) startingPoint.getRecord()).getSchemaClass()))) { nextElement = startingPoint; } ctx.setVariable("$currentMatch", prevMatch); } if ((notDeep && depth == 0) || ((maxDepth == null || depth < maxDepth) && (whileCondition == null || whileCondition .matchesFilters(startingPoint, ctx)) // && (oClass == null || matchesClass(oClass, startingPoint)) )) { stack.add(0, item.traversePatternEdge(matchContext, startingPoint, ctx).iterator()); } ctx.setVariable("$depth", oldDepth); } @Override public boolean hasNext() { while (stack.size() > 0 && nextElement == null) { loadNext(); } return nextElement != null; } private Integer maxDepth(OMatchFilter filter) { if (filter == null) { return 1; } if (filter.getMaxDepth() != null) { return filter.getMaxDepth(); } if (filter.getWhileCondition() == null) { return 1; } return null; } private boolean matchesClass(OClass oClass, OIdentifiable startingPoint) { if (oClass == null) { return true; } ODocument doc = startingPoint.getRecord(); if (doc == null) { return false; } OClass clazz = doc.getSchemaClass(); if (clazz == null) { return false; } return clazz.isSubClassOf(oClass); } @Override public OIdentifiable next() { if (nextElement == null) { throw new IllegalStateException(); } OIdentifiable result = nextElement; nextElement = null; while (stack.size() > 0 && nextElement == null) { loadNext(); } return result; } @Override public void remove() { } }