Hi Tom,
As it turns out I did something very similar to this yesterday to create a soundex qualifier. In my case, I used the Wonder qualifiers as a guide on how to do it as, like you, I didn't find much in the way of documentation by Apple.
The first thing you'll want to do is subclass ERXKeyValueQualifier (Wonder) or EOKeyValueQualifier (non-Wonder) as you'll want to see if this key contains that string.
You'll want to override the 'evaluatesWithObject' method, which essentially returns true if a certain object qualifies against this qualifier. Since you'll want the key's value on the object, use something like this:
public boolean evaluateWithObject(Object object) {
Object result = NSKeyValueCodingAdditions.Utility.valueForKeyPath(object, key());
if (result == null)
return false;
return value().toString().contains(result.toString());
}
checking for null values where appropriate, of course.
You can test this out now in unit tests / elsewhere in the application that uses in-memory filtering and it'll do exactly as you'd expect. The problem is when you try to use your qualifier in a fetch specification - when it actually hits the database - you'll get nothing back because EOF isn't sure how to express your query in SQL, so you have to tell it how.
So, you'll want to create a subclass of EOQualifierSQLGeneration._KeyValueQualifierSupport and override this method:
public String sqlStringForSQLExpression(EOQualifier rawQualifier, EOSQLExpression sqlExpression)
rawQualifier is your contains qualifier, so feel free to cast it to that if you need it (you'll need the key() and value() methods!) and sqlExpression contains some goodies that you'll need a bit later.
What you want this method to return is a qualifying string in SQL - that is, if your SELECT statement looks like this:
select FIRST_NAME, LAST_NAME from PERSON where PERSON_ID = 1 and AGE >= 19
you're looking to return the PERSON_ID = 1 or AGE >= 19 bits. At this point, EOF has already been awesome and figured out what the table/field name bit of this is - it'll look like t0.PERSON_ID or t1.LOCATION_ID or something, so you can get this like this:
NSArray<?> attributePath = ERXEOAccessUtilities.attributePathForKeyPath(e.entity(), yourQualifier.key());
EOAttribute attribute = (EOAttribute) attributePath.lastObject();
String sqlName;
if (attributePath.count() > 1)
sqlName = e.sqlStringForAttributePath(attributePath);
else
sqlName = e.sqlStringForAttribute(attribute);
I stole this from Wonder, and I'm not sure if there's a shorter way to do it, but now you have sqlName and, by using yourQualifier.value(), you should be able to make your qualifying string without too much difficulty. I'm not sure how to do this *without* ERXEOAccessUtilities. Be careful at this level, though, because you could be vulnerable to SQL injection.
The final little bit you want to do is tell EOF to use your special SQL generator when using this qualifier. At the top of your qualifier, add this lovely little bit of code:
static {
EOQualifierSQLGeneration.Support.setSupportForClass(new YourQualifierSQLGenerationSupport(), YourQualifier.class);
}
Hope this helps.
Bill