Re: wildcard search - how to escape asterisk?
Re: wildcard search - how to escape asterisk?
- Subject: Re: wildcard search - how to escape asterisk?
- From: Aaron Rosenzweig via Webobjects-dev <email@hidden>
- Date: Fri, 13 Oct 2023 15:49:01 -0400
Thank you Jesse and Michael,
I’ll share the solution we came up with :-)
We have a “user search” tool were we can dynamically fill out and query for
users in the system with various checks such as obvious things like first and
last name but also by their roles, whether they are expired or not, and also
their email address.
We wanted a new checkbox to look for “non-standard” email addresses. Weird
characters, or at least ones we think are suspicious like % and * (percent and
asterisk). Things we don’t like shouldn’t be let in but there is also very old
data and a desire to clean it up.
If we want a qualifier to search for asterisk, we might naively attempt using
Wonder ERXKeys like so:
===
EOQualifier qualifier = User.PERSON.dot(Person.EMAIL).contains("*")
The “contains” method guts are the following:
===
public static ERXKeyValueQualifier contains(String key, String value) {
value = "*" + value + "*";
return ERXQ.likeInsensitive(key, value);
}
So we are effectively doing a case-insensitive-like on triple-asterisk which
yields all records. The asterisk in WO is like percent for regular SQL, it gets
translated so * becomes % when it hits the DB.
As far as I know, there is no way to escape an asterisk. Can’t be done! But
hope is not lost, when you meet a brick wall, walk around it.
I dug the raw SQL qualifier out of the basement. NeXT/Apple provides it, it is
deprecated, but useful when you are in a pickle.
You would do something like this:
===
EOEntity userEntity = EOUtilities.entityNamed(editingContext(),
User.ENTITY_NAME);
EOQualifier qualifier = new EOSQLQualifier(userEntity,
User.PERSON.dot(Person.EMAIL).key() + " like '%%*%%'", null)
WARNING: you might think there should be a single percent (%) but that would
lead to errors because that is a qualifierFormat string and you typically
provide variables for replacement with %@ or if you want to be clear you would
do %s for a string, %d for an int, and %f for a float/double. Then where I
passed in “null” you would instead pass in an array of values to use for
replacement. You have to escape the percent and to do that you double it as %%
In context the code could be crafted like so:
===
EOEntity userEntity = EOUtilities.entityNamed(editingContext(),
User.ENTITY_NAME);
EOQualifier otherThanStandardCharactersQualifier = ERXQ.or(
User.PERSON.dot(Person.EMAIL).contains("#"),
User.PERSON.dot(Person.EMAIL).contains("$"),
User.PERSON.dot(Person.EMAIL).contains("%"),
… other similar checks
new EOSQLQualifier(userEntity, User.PERSON.dot(Person.EMAIL).key() + "
like '%%*%%'", null),
new EOSQLQualifier(userEntity, User.PERSON.dot(Person.EMAIL).key() + "
like '%%?%%'", null)
);
… do a fetch using EOF.
What gets generated by EOF into SQL looks something like:
===
SELECT *
FROM
user t0
INNER JOIN person T1 ON t0.person_id = T1.id
WHERE
UPPER(T1.email) LIKE UPPER('%#%' :: varchar(255)) ESCAPE '|'
OR
UPPER(T1.email) LIKE UPPER('%$%' :: varchar(255)) ESCAPE '|'
OR
UPPER(T1.email) LIKE UPPER('%|%%' :: varchar(255)) ESCAPE '|'
OR
T1.email like '%*%'
OR
T1.email like '%?%'
;
Note #1: look at how regular qualifiers always produce something that is
escaped with a pipe symbol "|" even when they have nothing to escape.
Note #2: when doing a contains("%") it does escape it using a pipe in the
generated output and makes sense.
Note #3: The last two lines are from our raw SQL qualifier but it was cool that
it figured out how to follow the key path and use the join appropriately then
only using T1.email where its needed. Pretty smart. I was surprised it was able
to do that.
Note #4: We could use the raw SQL qualifier to do things that EOF has no way of
supporting like regular expressions.
But now we’d have two problems:
https://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/
How to do regex in Postgres:
https://www.sqlshack.com/working-with-regular-expressions-in-postgresql/
https://www.postgresql.org/docs/current/functions-matching.html
Note #5: I also added the question mark because there is an undocumented
feature of EOF that would otherwise treat it like a wildcard courtesy of “he
who will not be named” (a NeXT engineer).
Cheers,
— Aaron
> On Oct 12, 2023, at 12:52 PM, Michael Kondratov <email@hidden>
> wrote:
>
> I think you can pass it as a variable to a fetch specification.
>
>
> Sent from my iPhone
>
>> On Oct 12, 2023, at 10:45, Aaron Rosenzweig via Webobjects-dev
>> <email@hidden> wrote:
>>
>> Hi all,
>>
>> We can do a case insensitive like with EOF for *blue* on a text field (to
>> find “blue” at the beginning, middle, or end of a field)
>>
>> But what if we want to find an asterisk anywhere in a text field? How do we
>> do a case insensitive like looking for an asterisk anywhere in the text? Is
>> this possible with WO or do we need to resort to a raw SQL qualifier?
>>
>> Thanks in advance,
>> — Aaron
>>
>> _______________________________________________
>> Do not post admin requests to the list. They will be ignored.
>> Webobjects-dev mailing list (email@hidden)
>> Help/Unsubscribe/Update your Subscription:
>>
>> This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden