dataContext.people.where("?$filter=FirstName eq 'Jared'");
He said that this wouldn't save us if we changed the way we queried our service. He was implying that we needed a way to abstract away what we wanted to query through some kind of class. And he was right. My brain got super excited, and thought that this would be a great problem to solve. I remembered studying how C# created Linq. How they use expression trees to abstract the query into a set of expressions. So I knew that I wanted to use expressions trees, but how do I make them?
Linq builds these expressions with lambdas. I personally believe that lambda expressions read really well, and is easy to follow. It also creates a unified way to query List's, Databases and any collection that you need to access. After that point, I knew what I wanted, and I wasn't going to stop until I had it.
So now we query our people collection like this:
dataContext.people.where(function(p){
return p.firstName.equals("Jared");
}).toArray().then(function(array){
console.log(array);
});
So what happens here is that we create a Queryable of Type Person. The Queryable has a where method on it. That where method creates, what we call an ExpressionBuilder, and passes it into the callback as "p". So the "p" in the callback really isn't a person at all, its an ExpressionBuilder that has all the properties of a Person. So through this ExpressionBuilder we build a "where expression". Now from that expression tree built by the Expression Builder we are able to build an OData string to query our service. Isn't that great. :)
Here are some things that you can do.
dataContext.people.where(function(p){
return p.firstName.equals("Jared");
}).orderBy(function(p){
return p.firstName;
}).orderByDesc(function(p){
return p.age;
}).take(5).skip(3).toArray().then(function(array){
///...Do something great!
});
The good news is that I work for a great company, and they believe in open source, and they have allowed me to open source this code. You can find the code here.
I really need to write a longer post about how to write your own Query Provider. If you are interested in how to write a Query Provider look at the ODataProvider.html on github. But for now I'll just show what you can do.
Here I make a Queryable and pass it to the odata object's toString method to make the queryable into a string.
var Person = function(){
this.firstName = null;
this.lastName = null;
this.age = null;
};
var queryable = new BoostJS.Queryable(Person);
queryable = queryable.where(function(p){
return p.firstName.equals("Jared");
});
var odataString = BoostJS.odata.toString(queryable);
console.log(odataString); //--> &$filter=((FirstName eq 'Jared'))
In order to really leverage the power of queryables, we need to treat all collections like they are queryable. So I have created a way to convert an array into a queryable.
var Person = function(){
this.firstName = null;
this.lastName = null;
this.age = null;
};
var jared = new Person();
var justin = new Person();
var array = [jared, justin];
var queryable = array.asQueryable(Person);
Here are most of the ways that you can use it
//...
queryable.where(function(p){
return p.firstName.equals("Jared");
});
//...
queryable.where(function(p){
return p.age.greaterThan(30);
});
//...
queryable.where(function(p){
return p.age.lessThan(30);
});
//...
queryable.where(function(p){
return p.age.greaterThanOrEqualTo(30);
});
//...
queryable.where(function(p){
return p.age.lessThanOrEqualTo(30);
});
//...
queryable.where(function(p){
return p.lastName.substring("are");
});
//...
queryable.where(function(p){
return p.lastName.substringOf("arn");
});
//...
queryable.where(function(p){
return p.firstName.startsWith("Jar");
});
//...
queryable.where(function(p){
return p.firstName.endsWith("red");
});
//...
queryable.where(function(p){
return p.firstName.endsWith("red");
}).skip(1);
//...
queryable.where(function(p){
return p.firstName.endsWith("red");
}).take(5);
//...
queryable.where(function(p){
return p.lastName.substringOf("arn");
}).orderBy(function(p){
return p.age;
}).orderByDesc(function(p){
return p.lastName;
});
//...
// You can also use "and" and "or" operators.
queryable.where(function(p){
return this.and( p.lastName.equals("Barnes"), p.firstName.equals("Jared") );
});
// More Complicated
queryable.where(function(p){
return this.or(this.and( p.lastName.equals("Barnes"), p.firstName.equals("Jared") ), p.age.greaterThan(50));
});
This isn't perfect yet, but I think it has enough to offer right now to benefit lots of companies using .NET's Web API with OData.
I really hope this opens your possibilities as it did ours. Enjoy!
Find Linq for javascript here.