From: Tomasz P. <tom...@gm...> - 2012-10-30 12:05:54
|
Hi I have recently started implementing filtering part of the fluent API and I would like your opinion on how it should be designed. 1. From high level view I imagine we could go for an IExpressionBuilder as previously discussed. For example there could be a call like graphPattern.Filter(eb => eb.Regex(value, pattern, flags)) There are quite a few built-in methods in SPARQL and many more available in dotNetRDF out-of-the-box so implementing all of those as builder methods will be an effort but there of course will be an opening for passing any pre-built ISparqlExpression: graphPattern.Filter(eb => eb.Expression(new RegexFunction(...))) Also I think we could group some of the functions in extension classes. XPath, Leviathan or ARQ libraries are some likely candidates. 2. The expression builder methods will have to be aware of the expressions' return types so that it should be illegal (ie. compile error) to call any of the below // str function returns literal and not boolean graphPattern.Filter(eb => eb.Str(literal)) // isBlank expects an RDF term and regex returns boolean graphPattern.Filter(eb => eb.IsBlank(eb.Regex(...))); There are two conclusions coming from this. * Filter method should have it's signature similar to: Filter(Func<IExpressionBuilder, IBooleanSparqlExpression> eb) * Each method on the expression builder should return one of the expression types depending on the return type I can't find anything like IBooleanExpression in the library. There is just ISparqlExpression. Do you thnik we could add such (marker?) interfaces to the VDS.RDF.Query.Expressions namespace or just control the expressions' return types in the builder? 3. It should be possible to chain expression calls to manipulate them logically. For example: graphPattern.Filter(eb => eb.Regex(value, pattern).Or(eb.Regex(value, otherPattern))) or graphPattern.Filter(eb => eb.Regex(value, pattern).Or().Regex(value, otherPattern)) or graphPattern.Filter(eb => eb.Or(eb.Regex(value, pattern), eb.Regex(value, otherPattern))) Negation example: graphPattern.Filter(eb => eb.Not(eb.Regex(value, pattern)) or graphPattern.Filter(eb => eb.Not().Regex(value, pattern)) We should decide which of the above is the best design as it will probably influence the internals and flexibility of expression builder. Or actually, meybe we could comnbine the two... 4. Many functions accept literal parameters but there can also be a result of another expression call. For example to match gmail.com email addresses one would call graphPattern.Filter(eb => eb.Regex(eb.Str("email"), "@gmail.com$")) However the problem here is to distinguish between plain string and a variable's name. In the above "email" is a variable and the other string is of course a simple string. One way to have it would be to encapsulate the VariableExpression with its own method so the last call would be rewritten as graphPattern.Filter(eb => eb.Regex(eb.Str(eb.Variable("email")), "@gmail.com$")) Then the I am not convicned though as it could be a little too verbose. Are there any other ideas? 5. Lastly, what are expression factories? Are they of any use in this case? Thanks, Tom |