开发者

Groovy 1.8 :: LINQ Applied

UPDATE 8/31/2011

Guillaume Laforge has nearly done it:

http://gaelyk.appspot.com/tutorial/app-engine-shortcuts#query

Looks like he's doing an AST transform to pull off the:

alias as Entity

bit. Cool stuff, Groovy 1.8 + AST transform = LINQ-esque queries on the JVM. GL's solution needs more work as far as I can see to pull off full query capabilities (like sub queries, join using(field) syntax and the like), but for his Gaelyk project apparently not necessary.

EDIT

As a workaround to achieving pure LINQ syntax, I have decided to def the aliases. Not a huge deal, and removes a major hurdle that would likely require complex AST transforms to pull off.

So, instead of:

from   c as Composite
join   t as Teams
...

I now define the aliases (note: need to cast to get auto complete on fields):

def(Teams t,Composite c,Schools s) = [Teams.new(),Composite.new(),Schools.new()]

and use map syntax for from, join, etc.

from    c:Composite
join    t:Teams
...

To solve issue #2 (see original below), add instance level getProperty methods to each pogo alias (whose scope is limited to ORM closure in which it is called, nice). We just return the string property name as we're building an sql statement.

[t,c,s].each{Object o-> o.metaClass.getProperty = { String k-> k } }

Making "good" progress ;-)

Now to figure out what to do about "=", that is tricky since set property is void. May have to go with eq, neq, gt, etc. but would really prefer the literal symbols, makes for closer-to-sql readability.

If interested, LINQ is doing quite a bit behind the scenes. Jon Skeet (praise his name) has a nice SO reply: How LINQ works internally?

ORIGINAL

Have been chec开发者_如何转开发king out LINQ, highly impressed.

// LINQ example
var games =
    from t in Teams
    from g in t.Games
    where g.gameID = 212
    select new { g.gameDate,g.gameTime };


// Seeking Groovy Nirvana
latest { Integer teamID->
    from   c as Composite
    join   t as Teams
    join   s as Schools on ( schoolID = {
                     from   Teams
                     where  t.schoolID = s.schoolID } )

    where   t.teamID = "$teamID"
    select  c.location, c.gameType, s.schoolName
    group   c.gameID
    order   c.gameDate, c.gameTime
}

The proposed Groovy version compiles fine and if I def the aliases c,t,s with their corresponding POGO, I get strong typed IDE auocomplete on fields, nice. However, nowhere near LINQ, where there are no (visible) variable definitions other than the query itself, totally self contained and strongly typed, wow.

OK, so can it be done in Groovy? I think (hope) yes, but am hung up on 2 issues:

1) How to implicitly populate alias variable without def'ing? Currently I am overriding asType() on String so in "from c as Composite", c gets cast to Composite. Great, but the IDE "thinks" that in closure scope undefined c is a string and thus no autocomplete on POGO fields ;-(

2) Since #1 is not solved, I am def'ing the aliases as per above so I can get autocomplete. Fine, hacked (compared to LINQ), but does the trick. Problem here is that in "select c.location, c.gameType...", I'd like the fields to not be evaluated but simply return "c.location" to the ORM select method, and not null (which is its default value). getProperty() should work here, but I need it to only apply to pogo fields when called from ORM scope (e.g. orm field specific methods like select, order, group, etc.). Bit lost there, perhaps there's a way to annotate orm methods, or only invoke "special" pogo getProperty via orm method calls (which is the closure's delegate in above nirvana query).

Should point out that I am not looking to create a comprehensive LINQ for Groovy, but this one particular subset of LINQ I would love to see happen.


One of the biggest reasons for Guillaume to use an AST transform is because of the problem with "=". Even if you use == for the compare as normally done in Groovy, from the compareTo method that is called for it, you cannot make out a difference between ==, !=, <=, >=, <, >. There are two possible paths for this in later versions of Groovy that are in discussion. One is to use for each of those compares a different method, the other is to store a minimal AST which you can access at runtime. This goes in the direction of C# and is a quite powerful tool. The problem is more about how to do this efficiently.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜