How can i manipulate filter in the backend and want the key value pairs of the filter query parameters?
Expression would like below
"?$filter =((Name eq 'John' or Name eq 'Grace Paul') and (Department eq 'Finance and Accounting'))"
As there are 2 filters concatenated & how can i get the values like
Filter 1:
Key: Name
Operator: eq
Value: Name
Operator: or
Filter 2:
Key: Name
Operator: eq
Value: Grace Paul
Operator: and
Filter 3:
Key: Department
Operator: eq
Value: Finance and Accounting
I tried with
I'm using ASP.NET Core 2.1 Web API with OData v4 integration
Is there a way to accomplish the above?
Querying Data Using $filter. You can use filter expressions in OData requests to filter and return only those results that match the expressions specified. You do this by adding the $filter system query option to the end of the OData request.
OData defines parameters that can be used to modify an OData query. The client sends these parameters in the query string of the request URI. For example, to sort the results, a client uses the $orderby parameter: http://localhost/Products?$orderby=Name. The OData specification calls these parameters query options.
The Open Data Protocol (OData) enables the creation of REST-based data services, which allow resources, identified using Uniform Resource Identifiers (URLs) and defined in a data model, to be published and edited by Web clients using simple HTTP messages.
You may want to consider defining your own parser and then walking the AST to get desired values. There are plenty tools to do that (see flex or bison for example). But in .net world Irony might be a viable option: it's available in .net standard 2.0
which I had no issues plugging into a .net core 2.1
console test project.
To start off, you normally need to define a grammar. Luckily, Microsoft have been kind enough to supply us with EBNF reference so all we have to do is to adapt it to Irony. I ended up implementing a subset of the grammar above that seems to cater for your example statement (and a bit above and beyond, feel free to cut it down).
using Irony.Parsing;
namespace irony_playground
{
[Language("OData", "1.0", "OData Filter")]
public class OData: Grammar
{
public OData()
{
// first we define some terms
var identifier = new RegexBasedTerminal("identifier", "[a-zA-Z_][a-zA-Z_0-9]*");
var string_literal = new StringLiteral("string_literal", "'");
var integer_literal = new NumberLiteral("integer_literal", NumberOptions.IntOnly);
var float_literal = new NumberLiteral("float_literal", NumberOptions.AllowSign|NumberOptions.AllowSign)
| new RegexBasedTerminal("float_literal", "(NaN)|-?(INF)");
var boolean_literal = new RegexBasedTerminal("boolean_literal", "(true)|(false)");
var filter_expression = new NonTerminal("filter_expression");
var boolean_expression = new NonTerminal("boolean_expression");
var collection_filter_expression = new NonTerminal("collection_filter_expression");
var logical_expression = new NonTerminal("logical_expression");
var comparison_expression = new NonTerminal("comparison_expression");
var variable = new NonTerminal("variable");
var field_path = new NonTerminal("field_path");
var lambda_expression = new NonTerminal("lambda_expression");
var comparison_operator = new NonTerminal("comparison_operator");
var constant = new NonTerminal("constant");
Root = filter_expression; // this is where our entry point will be.
// and from here on we expand on all terms and their relationships
filter_expression.Rule = boolean_expression;
boolean_expression.Rule = collection_filter_expression
| logical_expression
| comparison_expression
| boolean_literal
| "(" + boolean_expression + ")"
| variable;
variable.Rule = identifier | field_path;
field_path.Rule = MakeStarRule(field_path, ToTerm("/"), identifier);
collection_filter_expression.Rule =
field_path + "/all(" + lambda_expression + ")"
| field_path + "/any(" + lambda_expression + ")"
| field_path + "/any()";
lambda_expression.Rule = identifier + ":" + boolean_expression;
logical_expression.Rule =
boolean_expression + (ToTerm("and", "and") | ToTerm("or", "or")) + boolean_expression
| ToTerm("not", "not") + boolean_expression;
comparison_expression.Rule =
variable + comparison_operator + constant |
constant + comparison_operator + variable;
constant.Rule =
string_literal
| integer_literal
| float_literal
| boolean_literal
| ToTerm("null");
comparison_operator.Rule = ToTerm("gt") | "lt" | "ge" | "le" | "eq" | "ne";
RegisterBracePair("(", ")");
}
}
}
A bit of a hint: Irony comes with Grammar Explorer tool that allows you to load grammar dlls and debug with them, so I'd suggest you put your class in its own project. Then you would have easier time wrapping your head around the concepts:
after you're happy with the grammar, you need to reference it from your project and parse the input string:
class Program
{
static void Main(string[] args)
{
var g = new OData();
var l = new LanguageData(g);
var r = new Parser(l);
var p = r.Parse("((Name eq 'John' or Name eq 'Grace Paul') and (Department eq 'Finance and Accounting'))"); // here's your tree
// this is where you walk it and extract whatever data you desire
}
}
Then, all you have to do is walk the resulting tree and apply your custom logic based on sytax node type. One example how to do that can be found in this SO answer.
Depending on your requirements, you might find this is going to be a total overkill for your purpose, or might actually find that level of control it gives you is exactly right.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With