Query Expression Extension

Are there any documents or examples of how to extend / add new keywords in query expressions? Is it possible?

For example, I would like to add a lead / lag statement.

+7
source share
2 answers

In addition to the query builder for the Rx Framework listed in @pad, there is also a talk from Wonseok Chae from the F # team about computations that include querying expressions. I'm not sure if the recording was recorded, but there are very detailed slides with a cool example of query syntax for generating .NET IL code.

The source code for the standard F # query constructor is probably the best resource for defining types of operations and compiling them with attributes.

The key attributes you'll probably need are the where clause:

 [<CustomOperation("where",MaintainsVariableSpace=true,AllowIntoPattern=true)>] member Where : : source:QuerySource<'T,'Q> * [<ProjectionParameter>] predicate:('T -> bool) -> QuerySource<'T,'Q> 

The CustomOperation attribute defines the name of the operation. The (rather important) parameter MaintainsVariableSpace lets you say that the operation returns the same values ​​as it did as input. In this case, the variables defined earlier are still available after the operation. For example:

 query { for p in db.Products do let name = p.ProductName where (p.UnitPrice.Value > 100.0M) select name } 

Here the p and name variables are still available after where , because where only filters the input, but does not convert the values ​​to a list.

Finally, ProjectionParameter allows you to say that p.UnitValue > 100.0M should actually be turned into a function that takes a context (available variables) and evaluates this expression. If you do not specify this attribute, then the operation will simply get the value of the argument, as in:

 query { for p in .. do take 10 } 

Here, argument 10 is just a simple expression that cannot use the values ​​in p .

+13
source

Pretty cool feature for language. Just implemented a QuerySource callback.

A simple example, but just a demonstration.

 module QueryExtensions type ExtendedQueryBuilder() = inherit Linq.QueryBuilder() /// Defines an operation 'reverse' that reverses the sequence [<CustomOperation("reverse", MaintainsVariableSpace = true)>] member __.Reverse (source : Linq.QuerySource<'T,System.Collections.IEnumerable>) = let reversed = source.Source |> List.ofSeq |> List.rev new Linq.QuerySource<'T,System.Collections.IEnumerable>(reversed) let query = ExtendedQueryBuilder() 

And now it is used.

 let a = [1 .. 100] let specialReverse = query { for i in a do select i reverse } 
+5
source

All Articles