Filtering
To quickly add filtering capabilities to your collection fields use the UseFilter() field extension.
schema.ReplaceField("people",
ctx => ctx.People,
"Return a list of people. Optional filtered")
.UseFilter();
If you are using the SchemaBuilder.FromObject you can use the UseFilterAttribute on your collection properties.
public class DemoContext : DbContext
{
[UseFilter]
public DbSet<Movie> Movies { get; set; }
[UseFilter]
public DbSet<Person> People { get; set; }
[UseFilter]
public DbSet<Actor> Actors { get; set; }
}
This field extension can only be used on a field that has a Resolve expression that is assignable to IEnumerable - I.e. collections. The extension adds an argument called filter: String.
Note: When using with the paging or sort extensions ensure you call UseFilter before both others. If you are using the attribute, then ensure the Filter attribute comes before the other attributes.
The filter argument takes a string that will be compiled to an expression and inserted into a Where() call. The expression is compiled against your schema and the context is the type of elements in the collection.
For example, given ctx => ctx.People returns a IEnumerable<Person> and Person is defined as:
public class Person
{
public uint Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Dob { get; set; }
public List<Actor> ActorIn { get; set; }
public List<Writer> WriterOf { get; set; }
public List<Movie> DirectorOf { get; set; }
public DateTime? Died { get; set; }
public bool IsDeleted { get; set; }
}
We can write some filter expressions like so:
{
people(filter: "id == 12 || id == 10") {
firstName
}
}
{
deletedPeople: people(filter: "isDeleted == true") {
firstName
}
}
{
people(filter: "dob > \"2010-08-11T00:00:00\" && isDeleted == false") {
firstName
}
}
The expression language supports the following constants:
- Booleans -
true&false - Integers - e.g.
2,-8 - Floats - e.g.
0.2,-8.3 null- Strings -
"within double quotes"; when representing a date, use an ISO 8601 format such as"2022-07-31T20:00:00"
The expression language supports the following operators:
-- Subtraction+- Addition*- Multiply/- Divide%- Mod^- Power==- Equals!=- Not Equals<=- Less than or equal to>=- Greater than or equal to<- Less than>- Greater thanoror||- Orandor&&- And
The expression language supports the following methods, these are called against fields within the filter context:
List.any(filter)- Returntrueif any of the items in the list match the filter. The filter withinanyis on the context of the list item type. Otherwisefalse
{
# In C# - people.Where(p => p.ActorIn.Any(a => a.Name == "Star Wars"))
people(filter: "actorIn.any(name == \"Star Wars\")") { ... }
}
List.count(filter?)- Return the count of a list. Optionally counting items that match a filter
{
# No filter - all people that acted in 3 movies
people(filter: "actorIn.count() == 3") { ... }
# Count only those that match the filter - all people that acted in any movie starting with "Star"
people(filter: "actorIn.count(name.startsWith(\"Star\")) > 0") { ... }
}
List.first(filter?)/List.firstOrDefault(filter?)- Return the first item from a list. Optionally by a filterList.last(filter?)/List.lastOrDefault(filter?)- Return the last item from a list. Optionally by a filterList.take(int)- Return the firstxitemsList.skip(int)- Return the items afterxList.orderBy(field)- Order the list by a given fieldList.orderByDesc(field)- Order the list in reverse by a given fieldList.where(filter), orList.filter(filter)- Filter the liststring.contains(string)- Returntrueif the specified string occurs in this string instance
{
people(filter: "firstName.contains(\"o\")") { ... }
}
string.startsWith(string)- Returntrueif the beginning of this string instance matches the specified string
{
people(filter: "firstName.startsWith(\"b\")") { ... }
}
string.endsWith(string)- Returntrueif the end of this string instance matches the specified string
{
people(filter: "firstName.endsWith(\"b\")") { ... }
}
string.toLower()- Return the string converted to lowercase
{
people(filter: "firstName.toLower() == \"bob\"") { ... }
}
string.toUpper()- Return the string converted to uppercase
{
people(filter: "firstName.toUpper() == \"BOB\"") { ... }
}
<scalar>.isAny([])- Returntrueif the scalar value (string,int, etc.) equals any of the values provided in the array argument of the method call.
{
people(filter: "firstName.isAny([\"Bob\", \"Bobby\"])") { ... }
}
The expression language supports ternary and conditional:
__ ? __ : __if __ then __ else __