package er.extensions.qualifiers;
import com.webobjects.eocontrol.EOKeyValueQualifier;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.eocontrol.EOQualifierVariable;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSKeyValueCodingAdditions;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSSelector;
import com.webobjects.foundation._NSStringUtilities;
import er.extensions.eof.ERXQ;
import er.extensions.foundation.ERXArrayUtilities;
import er.extensions.foundation.ERXProperties;
/**
* ERXKeyValueQualifier is a chainable extension of EOKeyValueQualifier.
*
* @author mschrag
*/
public class ERXKeyValueQualifier extends EOKeyValueQualifier implements IERXChainableQualifier {
/**
* 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;
// Lazy static initialization
private static class PROPERTIES {
static boolean shouldFlattenValueObject = ERXProperties.booleanForKeyWithDefault("er.extensions.ERXKeyValueQualifier.Contains.flatten", true);
}
public ERXKeyValueQualifier(String key, NSSelector selector, Object value) {
super(key, selector, value);
if (key == null) {
throw new IllegalArgumentException("A KeyQualifierQualifier must have a key.");
}
if (selector == null) {
throw new IllegalArgumentException("A KeyQualifierQualifier must have a selector.");
}
}
public ERXAndQualifier and(EOQualifier... qualifiers) {
return ERXChainedQualifierUtils.and(this, qualifiers);
}
public ERXNotQualifier not() {
return ERXQ.not(this);
}
public ERXOrQualifier or(EOQualifier... qualifiers) {
return ERXChainedQualifierUtils.or(this, qualifiers);
}
public void filter(NSMutableArray<?> array) {
ERXQ.filter(array, this);
}
public <T> NSArray<T> filtered(NSArray<T> array) {
return ERXQ.filtered(array, this);
}
public <T> T first(NSArray<T> array) {
return ERXQ.first(array, this);
}
public <T> T one(NSArray<T> array) {
return ERXQ.one(array, this);
}
public <T> T requiredOne(NSArray<T> array) {
return ERXQ.requiredOne(array, this);
}
/**
* Overridden to handle case of in-memory evaluation of QualifierOperatorContains selector and a keyPath that has multiple toMany and/or manyToMany-flattened relationships resulting in arrays of arrays rather than
* an array of discrete objects. In that case the object is evaluated against a flattened array which gives the same result as SQL evaluation.
*
* Since legacy code may depend on workarounds to the incorrect behavior, this patch can be disabled by setting the property <code>er.extensions.ERXKeyValueQualifier.Contains.flatten</code> to <code>false</code>
*/
@Override
public boolean evaluateWithObject(Object object) {
Object objectValue = NSKeyValueCodingAdditions.Utility.valueForKeyPath(object, _key);
if (_value instanceof EOQualifierVariable) {
throw new IllegalStateException("Error evaluating qualifier with key " + _key + ", selector " + _selector + ", value " + _value + " - value must be substitued for variable before evaluating");
}
if (_selector.equals(EOQualifier.QualifierOperatorCaseInsensitiveLike)) {
if (_lowercaseCache == null) {
_lowercaseCache = (_value != NSKeyValueCoding.NullValue) ? (_value.toString()).toLowerCase() : "";
}
return _NSStringUtilities.stringMatchesPattern(((objectValue != null) && (objectValue != NSKeyValueCoding.NullValue)) ? objectValue.toString() : "", _lowercaseCache, true);
}
// Flatten in case we have array of arrays
if (_selector.equals(EOQualifier.QualifierOperatorContains) && PROPERTIES.shouldFlattenValueObject && objectValue != null && objectValue instanceof NSArray) {
objectValue = ERXArrayUtilities.flatten((NSArray<?>) objectValue);
}
return ComparisonSupport.compareValues((objectValue != null) ? objectValue : NSKeyValueCoding.NullValue, _value, _selector);
}
}