/*
* Copyright (C) NetStruxr, Inc. All rights reserved.
*
* This software is published under the terms of the NetStruxr
* Public Software License version 0.5, a copy of which has been
* included with this distribution in the LICENSE.NPL file. */
package er.extensions.eof.qualifiers;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EOEntityClassDescription;
import com.webobjects.eoaccess.EOQualifierSQLGeneration;
import com.webobjects.eoaccess.EOSQLExpression;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.eocontrol.EOKeyValueQualifier;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import er.extensions.eof.ERXEOAccessUtilities;
/**
* The primary key list qualifier is used to generate
* a qualifier that can be used to filter a result set
* for a given set of primary keys. Note that this uses
* the IN expression and as such may not work with some
* databases.
* <p>
* Given a list of EOs, this generates a query looking like
*
* ... t0.ID in (< the list of primary Keys for EOs in the list >) ..
*
* this is useful for pre-fetching type uses.
*/
public class ERXPrimaryKeyListQualifier extends ERXInQualifier {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
public static final String IsContainedInArraySelectorName = "isContainedInArray";
static {
EOQualifierSQLGeneration.Support.setSupportForClass(new ERXPrimaryKeyListQualifier.Support(), ERXPrimaryKeyListQualifier.class);
}
/**
* Support class that listens for EOKeyValueQualifiers that have an <code>isContainedInArray</code>-selector and replaces these
* with the ERXInQualifier. This means that when you set <code>isContainedInArray</code> as a display group
* queryOperator and an NSArray of EOs as the value, then this qualifier is magically replaced by
* one that selects objects with an IN qualifier.
* @author ak
*/
public static class Support extends EOQualifierSQLGeneration._KeyValueQualifierSupport {
@Override
public String sqlStringForSQLExpression(EOQualifier eoqualifier, EOSQLExpression e) {
return super.sqlStringForSQLExpression(eoqualifier, e);
}
@Override
public EOQualifier schemaBasedQualifierWithRootEntity(EOQualifier eoqualifier, EOEntity eoentity) {
EOQualifier result = null;
EOKeyValueQualifier qualifier = (EOKeyValueQualifier)eoqualifier;
String key = qualifier.key();
if(key.indexOf('.') < 0) {
// ak: this code is only for binding values in display groups and
// to support the twolevelrelationship and the ERD2WQuery*Relationship, it probably should go away...
Object value = qualifier.value();
if(!(value instanceof NSArray)) {
value = new NSArray(value);
}
NSArray objects = ((NSArray)value);
if(objects.lastObject() instanceof EOEnterpriseObject) {
objects = ERXEOAccessUtilities.primaryKeysForObjects(objects);
value = objects;
}
}
EOQualifierSQLGeneration.Support support = EOQualifierSQLGeneration.Support.supportForClass(ERXInQualifier.class);
result = support.schemaBasedQualifierWithRootEntity(qualifier, eoentity);
return result;
}
@Override
public EOQualifier qualifierMigratedFromEntityRelationshipPath(EOQualifier eoqualifier, EOEntity eoentity, String s) {
return super.qualifierMigratedFromEntityRelationshipPath(eoqualifier, eoentity, s);
}
}
/**
* Constructs a primary key list qualifer for a given
* set of enterprise objects. For now only use this
* qualifier if the primary key attribute of your
* enterprise object is named 'id'.
* @param eos array of enterprise objects
*/
public ERXPrimaryKeyListQualifier(NSArray eos) {
this(primaryKeyNameForObjects(eos), eos);
}
// Only used during cloning
private ERXPrimaryKeyListQualifier(String key, NSArray eos, boolean ignoreMe) {
super(key,eos);
}
/**
* Constructs a primary key list qualifer for a given
* set of enterprise objects and the primary key
* attribute name.
* @param key primary key attribute name
* @param eos array of enterprise objects
*/
public ERXPrimaryKeyListQualifier(String key, NSArray eos) {
super(key, ERXEOAccessUtilities.primaryKeysForObjects(eos));
}
/**
* Constructs a primary key list qualifer for a given
* set of enterprise objects, the primary key
* attribute name and a foreign key. This type of
* qualifier can be useful for prefetching a to-one
* relationship off of many enterprise objects.
* @param key primary key attribute name
* @param foreignKey attribute name.
* @param eos array of enterprise objects
*/
public ERXPrimaryKeyListQualifier(String key, String foreignKey, NSArray eos) {
this(key, ERXEOAccessUtilities.snapshotsForObjectsFromRelationshipNamed(eos, foreignKey));
}
/*
* Implementation of the Cloneable interface.
* @return cloned primary key list qualifier.
*/
@Override
public Object clone() {
return new ERXPrimaryKeyListQualifier(key(), (NSArray)value(), true);
}
/**
* Calculates the primary key attribute name for an
* array of enterprise objects. This method assumes
* that all the entities of the objects have the same
* primary key attribute name.
* @param eos array of enterprise objects
* @return primary key name for the enterprise objects
* in the array.
*/
protected static String primaryKeyNameForObjects(NSArray eos) {
validateObjects(eos);
EOEnterpriseObject eo = (EOEnterpriseObject)eos.lastObject();
EOEntity entity = ((EOEntityClassDescription)eo.classDescription()).entity();
if (entity.primaryKeyAttributeNames().count() != 1)
throw new IllegalStateException("Attempting to construct a qualifier for an entity with a compound primary key: " + entity);
return entity.primaryKeyAttributeNames().lastObject();
}
/**
* Simple validation routine used to ensure that
* the objects being passed in are enterprise
* objects and have more than one in the array.
* @param eos array of objects to check
* @return the array of objects if they pass the
* check.
*/
protected static NSArray validateObjects(NSArray eos) {
if (eos == null || eos.count() == 0 || !(eos.lastObject() instanceof EOEnterpriseObject))
throw new IllegalStateException("Attempting to construct a qualifier for a bad array: " + eos);
return eos;
}
}