The first part to building a general purpose expression parser is to understand what you will be parsing. That is, we need to define a schema for what an expression looks like. In my case, I knew that I wanted to use slightly XML documents that could be interpreted on the server.
I decided to include tokenized values in the format. This would let me define the XML document once and let it work for a wide variety of instances. That is, the notion of today is different depending on when it is being used. Instead of hard coding a date in the document, I use a token named “TODAY” that will replace with the current date at run time.
The next thing I needed to include was a way to identify fields that would be part of the LINQ Where clause. To make it flexible, I wanted to use the dotted notation for linked entities, such as “MyLinkField.ForeignField”. The XML Schema doesn’t really care about this. The parser class will be the one to understand and handle this.
I also needed the user to use hard coded values. that is, the expression field > 5 needs to know that “5” is a simple literal.
The last thing that I wanted to make sure was possible was nesting expressions inside one another. This would allow the possibility for complex expressions such as (ToDoByStaff.Login = TOKEN(User) AND (SubmitDate >= DATEADD(TODAY, DAYS, –5).
Without further ado, here is the schema that I came up with.
And, here is a quick sample expression file that shows off every part of the schema.
Before I leave you for the day, here are some things to consider:
Why didn’t I specify what the valid functions are? I may want to add new ones to the expression parser. That’s also the reason for the other two choices.
And, why does the root expression need to be logical? This statement doesn’t make sense: SELECT * FROM TABLE1 WHERE 1+5. In my implementation, I don’t accept the “NOT” function. Instead, I construct the expressions around that limitation.
Finally, I didn’t put restrictions on the number of children to an expression so that I could handle any arbitrary function that is acceptable to the Entity Framework. I can also expose custom functions like DATEADD that need to be parsed into correct function calls that the framework accepts (in this example, it gets turned into AddDays because the second expression is the literal DAYS).
Next time, we’ll talk about the actual code that runs.
Tags:
Mission App | RIA Services
Add comment
Cancel reply to comment