Last active
January 3, 2022 17:54
-
-
Save deanebarker/c58d76ab357cba88267f20582226bd33 to your computer and use it in GitHub Desktop.
An example of a custom FluidValue to enable fluent(-ish) query specification
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example: | |
// {% assign people = query.sortby['lastname'].direction['desc'].limit[2] %} | |
public class QueryValue : FluidValue | |
{ | |
// This is only needed for testing | |
// In production, the query would be of some external resource | |
private IEnumerable<Person> _items; | |
// This is an anonymous method that handles the index | |
private Action<FluidValue> indexHandler; | |
// These hold the query parameters | |
private string sortBy; | |
private int limit = int.MaxValue; | |
private string direction = "asc"; | |
public QueryValue() | |
{ | |
// This is fake repository for testing | |
_items = new List<Person>() | |
{ | |
new Person() { FirstName = "Annie", LastName = "Barker" }, | |
new Person() { FirstName = "Deane", LastName = "Barker" }, | |
new Person() { FirstName = "James", LastName = "Bond" }, | |
new Person() { FirstName = "Bill", LastName = "Gates" } | |
}; | |
} | |
public override FluidValues Type => FluidValues.Array; | |
public override ValueTask<FluidValue> GetValueAsync(string name, TemplateContext context) | |
{ | |
// This is how we're going to handle the passed-in index, based on what the name is | |
indexHandler = name switch | |
{ | |
"sort-by" => v => { sortBy = v.ToStringValue(); }, | |
"limit" => v => { limit = (int)v.ToNumberValue(); }, | |
"direction" => v => { direction = v.ToStringValue(); }, | |
_ => null | |
}; | |
// Question: how do we enforce the index? Meaning, someone could ... | |
// repo.direction.sortby.limit | |
// ... call a bunch of things and never pass in an index. How could we catch this? | |
// Do anything else you want here | |
return this; | |
} | |
public override ValueTask<FluidValue> GetIndexAsync(FluidValue index, TemplateContext context) | |
{ | |
// Handle the index value, then null it | |
indexHandler?.Invoke(index); | |
indexHandler = null; | |
return this; | |
} | |
public override IEnumerable<FluidValue> Enumerate(TemplateContext context) | |
{ | |
var queryResults = _items.AsQueryable(); | |
// Note: this sucks, but I don't know how to make it more graceful | |
// I assume there's a better way | |
if(sortBy != null) | |
{ | |
if(sortBy == "firstname") | |
{ | |
queryResults = direction == "asc" ? queryResults.OrderBy(p => p.FirstName) : queryResults.OrderByDescending(p => p.FirstName); | |
} | |
if (sortBy == "lastname") | |
{ | |
queryResults = direction == "asc" ? queryResults.OrderBy(p => p.LastName) : queryResults.OrderByDescending(p => p.LastName); | |
} | |
} | |
return queryResults.Take(limit).Select(p => new ObjectValue(p)).ToList(); | |
} | |
public override bool Equals(FluidValue other) => false; | |
public override bool ToBooleanValue() => _items.Any(); | |
public override decimal ToNumberValue() => _items.Count(); | |
public override object ToObjectValue() => null; | |
public override string ToStringValue() => null; | |
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo) {} | |
} | |
public class Person | |
{ | |
public string FirstName { get; set; } | |
public string LastName { get; set;} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment