/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.internal.query.processor; import com.db4o.foundation.*; import com.db4o.internal.*; import com.db4o.reflect.*; /** * Placeholder for a constraint, only necessary to attach children * to the query graph. * * Added upon a call to Query#descend(), if there is no * other place to hook up a new constraint. * * @exclude */ public class QConPath extends QConClass { public QConPath(){ } QConPath(Transaction a_trans, QCon a_parent, QField a_field) { super(a_trans, a_parent, a_field, null); if(a_field != null){ _classMetadata = a_field.getFieldType(); } } public boolean canLoadByIndex() { return false; } boolean evaluate(InternalCandidate candidate) { if (! candidate.fieldIsAvailable()) { visitOnNull(candidate.getRoot()); } return true; } void evaluateSelf() { // do nothing } boolean isNullConstraint() { return ! hasChildren(); } @Override QConClass shareParentForClass(ReflectClass a_class, BooleanByRef removeExisting) { if (i_parent == null) { return null; } QConClass newConstraint = new QConClass(i_trans, i_parent, getField(), a_class); morph(removeExisting,newConstraint, a_class); return newConstraint; } @Override QCon shareParent(Object a_object, BooleanByRef removeExisting) { if (i_parent == null) { return null; } Object obj = getField().coerce(a_object); if(obj == No4.INSTANCE){ QCon falseConstraint = new QConUnconditional(i_trans, false); morph(removeExisting, falseConstraint, reflectClassForObject(obj)); return falseConstraint; } QConObject newConstraint = new QConObject(i_trans, i_parent, getField(), obj); morph(removeExisting, newConstraint, reflectClassForObject(obj)); return newConstraint; } private ReflectClass reflectClassForObject(Object obj) { return i_trans.reflector().forObject(obj); } // Our QConPath objects are just placeholders to fields, // so the parents are reachable. // If we find a "real" constraint, we throw the QPath // out and replace it with the other constraint. private void morph(BooleanByRef removeExisting, QCon newConstraint, ReflectClass claxx) { boolean mayMorph = true; if (claxx != null) { ClassMetadata yc = i_trans.container().produceClassMetadata(claxx); if (yc != null) { Iterator4 i = iterateChildren(); while (i.moveNext()) { QField qf = ((QCon) i.current()).getField(); if (!yc.hasField(i_trans.container(), qf.name())) { mayMorph = false; break; } } } } if (mayMorph) { Iterator4 j = iterateChildren(); while (j.moveNext()) { newConstraint.addConstraint((QCon) j.current()); } if(hasJoins()){ Iterator4 k = iterateJoins(); while (k.moveNext()) { QConJoin qcj = (QConJoin)k.current(); qcj.exchangeConstraint(this, newConstraint); newConstraint.addJoin(qcj); } } i_parent.exchangeConstraint(this, newConstraint); removeExisting.value = true; } else { i_parent.addConstraint(newConstraint); } } final boolean visitSelfOnNull() { return false; } public String toString(){ return "QConPath " + super.toString(); } @Override public void setProcessedByIndex(QCandidates candidates) { if(childrenCount() <=1){ internalSetProcessedByIndex(null); } } @Override protected boolean canResolveByFieldIndex() { return true; } }