Reputation: 120
I'm creating a OData query language in Scala. It's going pretty well, but there is one error I get which I can't explain.
First let me show you the Query class I created (omitted some code out for brevity):
case class Query(val name: String, val args: Seq[(String, String)] = Seq())
(val parent: Option[Query] = None)
(val options: Seq[QueryOption] = Seq()) {
def /(newChild: Query): Query = new Query(newChild.name, newChild.args)(Some(this))(options)
def $(newOptions: QueryOption*): Query = new Query(name, args)(parent)(options ++ newOptions)
def |(newArgs: (String, String)*): Query = new Query(name, args ++ newArgs)(parent)(options)
}
object Query {
private def emptyQueryWithName(name: String): Query = Query(name, Seq())(None)(Seq())
def /(name: String): Query = emptyQueryWithName(name)
implicit def createQuery(name: String): Query = emptyQueryWithName(name)
}
package object queries {
implicit class QueryOps(name: String) {
def ===(attr: Any): (String, String) = (name, attr.toString)
}
}
I've written some tests for this DSL and they work mostly. For instance this code:
Query / "Pages" / "Component" | ("ItemId" === 123, "PublicationId" === 1) $ ("Title" ==| "Test Title")
Gives me the expected query: /Pages/Component(ItemId=123,PublicationId=1)?$filter=Title eq 'Test Title'
But this one:
Query / "Pages" | ("ItemId" === 123) / "Title" $ jsonFormat $ ("Url" ==| "Bla")
Complains about the '/ "Title"' part. As if the compiler is not aware that the proceeding code results in a Query instance. It can't find the '/' method. To me this seems very strange as the '$' method is found, which has the same scope; the Query class.
I'm probably running into some kind of limitation I can't fathom, but I would like to understand. Thanks for any help!
Upvotes: 0
Views: 75
Reputation: 2353
The fact that parentheses fix the problem usually means an operator precedence problem. Have a look at http://books.google.es/books?id=MFjNhTjeQKkC&pg=PA90&lpg=PA90&dq=scala+operator+precedence+reference&source=bl&ots=FMlkUEDSpq&sig=pf3szEM4GExN_UCsgaxcQNBegPQ&hl=en&sa=X&ei=ZezQU_-SDszY7Ab-pIDQDQ&redir_esc=y#v=onepage&q=scala%20operator%20precedence%20reference&f=false
|
has a lower precedence than /
, and $
has the highest precedence, so your expression is being interpreted as:
(Query / "Pages") | (("ItemId" === 123) / (("Title" $ jsonFormat) $ ("Url" ==| "Bla")))
Also, providing the exact error message is usually useful.
Upvotes: 2