-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't use Table<TModel>.Where(Expression<Func<TModel, bool>> predicate)
with more than 2 or'ed conditions in the predicate expression
#84
Comments
Table<TModel>.Where(Expression<Func<TModel, bool>> predicate)
with more than 2 or'ed conditions in the predicate expression
Ah, yes indeed! This is an easily re-duplicated issue. Thanks for the clear bug report! As an easy (albeit verbose fix) you can use the var response = await client.From<Contact>().Or([
new QueryFilter("first_name", Operator.Contains, filter),
new QueryFilter("middle_name", Operator.Contains, filter),
new QueryFilter("last_name", Operator.Contains, filter),
]).Get(); Otherwise, I'm going to externally process a bit, as it's not immediately clear how to go about addressing this issue and it's helpful for me to ramble a bit to organize my thoughts. The postgrest library declares its own LINQ expression parsers, as it translates a LINQ expression into a query string so that the Postgrest server knows what to do with it. The benefit being (as may be obvious) the LINQ queries are actually translated into server-side filters. Which is a pretty nice deal. However, it means that translating to a string can be a bit complicated. The way that Microsoft handles this in C# is using Essentially, the expression is broken down into nodes. So, for an expression like this (EX1): var query = await client.Table<User>().Where(u => u.Contains("David") || u.Contains("John")).Get() The expression is broken into a tree (that is, left and right nodes) as it is parsed. EX1
Unfortunately, this becomes complicated when an additional node is added to the expression. As the Left and Right sides become confused. The initial So, for an expression like this (EX2): var query = await client.Table<User>().Where(u => u.Contains("David") || u.Contains("John") || u.Contains("Adam")).Get() EX2
At the moment, I'm unsure how to bridge the gap between steps 2 and 3 and recognize the whole expression as a series of |
Thanks @acupofjose for the fast response! I tried the fix and it works well. I was hoping not to have to use the actual field names (e.g., I'll continue on with the Thanks again! |
@hunsra for the record, with var filters = new List<IPostgrestQueryFilter> {
new QueryFilter<Contact, string>(x => x.FirstName, Operator.Contains, filter),
new QueryFilter<Contact, string>(x => x.MiddleName, Operator.Contains, filter),
new QueryFilter<Contact, string>(x => x.LastName, Operator.Contains, filter),
}
var response = await client.From<Contact>().Or(filters).Get(); Unfortunately, the generic signature is a little verbose. But it's de-coupled from the |
@acupofjose, Thanks. This is excellent! |
This doesn't work, the Operator.Contains need list as criterion (gave errors when used to query array data type), from QueryFilter constructor "List or Dictionary must be used supplied as criteria with filters that accept an array of arguments." var filters = new List<IPostgrestQueryFilter> {
new QueryFilter<Contact, List<string>>(x => x.FirstName, Operator.Contains, filter),
new QueryFilter<Contact, List<string>>(x => x.MiddleName, Operator.Contains, filter),
new QueryFilter<Contact, List<string>>(x => x.LastName, Operator.Contains, filter),
}
var response = await client.From<Contact>().Or(filters).Get(); should work. took me a few hours get my mix of and and or filters working.. List<IPostgrestQueryFilter> andFilter = new List<IPostgrestQueryFilter>()
{
new QueryFilter<SupaGameTable, DateTime>(x => x.CreatedAt, Operator.LessThan, DateTime.Now),
new QueryFilter<SupaGameTable, DateTime>(x => x.CreatedAt, Operator.GreaterThanOrEqual, DateTime.Now.AddSeconds(-Preferences.findTableWaitTime)),
new QueryFilter<SupaGameTable, List<string>>(x => x.Players, Operator.Contains, new List<string>() { "-" }),
new QueryFilter<SupaGameTable, int>(x => x.MinJoinPoints, Operator.LessThan, player.UserGold)
}; with ModeledResponse<SupaGameTable> tables = await _Supabase.Postgrest.Table<SupaGameTable>()
.And(andFilter)
.Not(x => x.Players, Operator.Contains, new List<string>() { player.UserId })
.Order(x => x.MinJoinPoints, Ordering.Descending)
.Get(); works as expected. |
Bug report
Describe the bug
An exception occurs in
Table<TModel> Where(Expression<Func<TModel, bool>> predicate)
if the predicate includes more than 2 or'ed conditions.To Reproduce
Given the following model (and corresponding table in a Supabase project):
Use of the following code:
Results in the following PostgrestException exception:
If the code is modified to use fewer or'ed conditions, such as in:
The filter succeeds and behaves as expected.
It appears from the exception message that the underlying Postgrest code is improperly formatting the logic tree:
((or.(first_name.like.*Ran*,middle_name.like.*Ran*),last_name.like.*Ran*))
Perhaps it should have been:
((or.(first_name.like.*Ran*,middle_name.like.*Ran*,last_name.like.*Ran*)))
Expected behavior
The query should successfully select records whose first_name, middle_name, or last_name fields contain the specified filter string.
System information
Additional context
This is happening in a .NET MAUI application targeting iOS, Android, Windows, and mac Catalyst.
The text was updated successfully, but these errors were encountered: