Gary Bentley wrote:
Hi Jonathan,
The original aim of the request was to allow a JoSQL statement to be
used directly within Velocity. More specifically it would be that the
WHERE clause, ORDER BY clause and potentially the GROUP BY clause (and
as a further extension the LIMIT and GROUP BY ORDER clauses) could be used.
Well, okay, but then, frankly, you didn't formulate your original
question very well. What you're wanting above is something very general,
and I answered the question as specifically how do you do the specific
example you gave in FreeMarker.
The thing is that it so happened that the specific example you used
could be written directly using FreeMarker without exposing anything
extra from the java side -- or interacting with josql, and of course,
your whole motive is to interact with josql, but that was not at all
clear from the question. Never mind, nobody's perfect. :-)
The freemarker code I gave simply used ?sort_by which is a freemarker
built-in See:
http://freemarker.org/docs/ref_builtins_sequence.html#ref_builtin_sort_by
FreeMarker currently doesn't have built-ins that replicate all of an SQL
SELECT statement, like GROUP BY and HAVING and so on. (Of course, as a
practical matter, a lot of SELECT queries are just about like that one,
with a sort key and a condition.)
But okay, what you want to do is expose josql functionality to FreeMarker...
To do this in Velocity I was going to do (I've written, the code but due
to personal reasons not had chance to go further with it yet):
#foreach ($v in $josql.filter ("name LIKE '/opt/%' order by dir, name",
$files))
This isn't as elegant as I'd like but it will work. I had looked at
modifying the Velocity grammar to support N arguments to a tool but I
ran into a number of problems with it.
Unfortunately, from what I've
seen, the Velocity grammar has hard coded support for the "foreach"
statement. Personally I'd like to see the grammar in the form:
<tool> [args]
Well, the basic way you could have that syntax in FreeMarker is along
the lines of the example I gave in the last message. Here is an
approximate possibility:
<#macro josqlIterator
sequence
where=[]
order_by=[]
group_by=[]
having=[]
descending=false
>
<#local results=josql.filter(where, order_by, group_by, having,
descending)>
<#list results as result>
<#nested result result_index+1 result_count>
</#list>
</#macro>
I guess it is assumed that you receive a sequence as a required
parameter and the other named parameters are optional and default to the
empty sequence, except for descending which defaults to false.
So here would be a possible invocation of the above macro.
<@josqlIterator sequence=files
where=["LIKE '/opt/%'"]
order_by=["dir", "name"] ; row, index
>
<tr>
<td>
${index}. ${flogger.getPromo(row)}
</td>
</tr>
</@josqlIterator>
Note that in the above example, unlike the one I gave in the last
messsage, I had the invocation of the loop pass in three loop variables,
the row and its 1-based index, and the total row count. This, besides
being a fairly realistic scenario that you'd need something like that,
gives you an idea of the flexibility of the macro system.
And then have the tool invoked with the arguments passed to it. But
that's not for me to decide.
What do you mean, it's not for you to decide? If you mean that it's not
technically feasible with Velocity, well, use a tool that has the
flexibility to do it how you want to.
As for it's implementation in FreeMarker, I would like to do that in
time (I wasn't aware of FreeMarker before), but again having a "native"
implementation for the statement would be preferable to the special
macro you defined. When I get around to a FreeMarker implementation
I'll let you know and you can tell me the possibilities!
Well, I've given you a flavor of it here. Obviously you have a lot more
possibilities than you do with Velocity. Frankly, I think it's like
night and day...
But let me say, that if you get into doing this with FreeMarker, in this
case, I really think you'd be better off using the code from the SVN
HEAD. You can get the latest greatest here:
http://freemarker.org:8085/browse/FM-TRUNK
And then you click on the "COMPLETED BUILDS" tab and choose the latest
one. (At the moment that is:)
http://freemarker.org:8085/browse/FM-TRUNK-153
and then you click on the Artifacts tab and pick up the freemarker.jar.
The reason to use the 2.4 codebase (the stable release is 2.3.x) is that
there are specifically some very nice new features for exposing java
methods to the template layer. It's annotation based, so that, even
though java doesn't support optional and default parameters, or invoking
parameters by name,you can add an annotation on the java side so that
it effectively has optional and default parameters and invocation by
name when you call it from the template layer.
Like you write a method with the annotation like so:
@freemarker.template.Parameters("sequence where=[] order_by=[]
group_by=[] having=[] descending=false")
public List filter(List sequence, List where, List order_by, List
group_by, List having, boolean descending) {
....
}
So, you see the annotation above allows you to call the method from your
template leaving out the optional parameters, and do an invocation with
a named parameter list.
But that's not in FreeMarker 2.3.x. It's also that if you run into some
issues, (you do have a fairly complex, interesting usage scenario) we
could well add certain features that you need, since 2.4 is still
_somewhat_ in flux.
Well, just as a final point, if you get me back to me on this, you
should do so on a FreeMarker mailing list. :-) (The Velocity guys have
enough of an inferiority complex as it is... ;-))
Cheers,
Jonathan Revusky
--
lead developer, FreeMarker project, http://freemarker.org/
Velocity or FreeMarker: Looking at 5 Years of Practical Experience
http://freemarker.blogspot.com/2007/12/velocity-of-freemarker-looking-at-5.html
Gary
Jonathan Revusky wrote:
Gary Bentley wrote:
Hi,
I'm the developer of JoSQL (http://josql.sf.net) and I've had a
request from a user to extend the foreach directive to include JoSQL
processing facilities.
Along the lines of:
#foreach( $mud in $mudsOnSpecial where $customer.hasPurchased($mud)
order by $mud.price)
<tr>
<td>
$flogger.getPromo( $mud )
</td>
</tr>
Hi, Gary, since you wrote me that note about trying to get in with ASF
(thanks but no thanks) I looked back on your participation in this
list. I see you posed the above question.
Here's how you do the above in FreeMarker:
<#--
Special foreach replacement macro that
sorts the sequence by a fieldname (the orderByField parameter)
and executes the associated nested block if
the condition is satisfied, where the condition parameter
is a function or method that operates on the item in
the sequence and returns a boolean
-->
<#macro specialForeach sequence condition orderByField>
<#list sequence?sort_by(orderByField) as item>
<#if condition(item)>
<#nested item>
</#if>
</#list>
</#macro>
Example usage:
<@specialForeach sequence=mud condition=customer.hasPurchased
orderByField="price" ; item>
<tr>
<td>
${flogger.getPromo(item)}
</td>
</tr>
</@specialForEach>
Now, I didn't have time to look into how you do this in Velocity.
There's a fairly long discussion after this. Could you summarize it?
How do you do the above in Velocity? You can answer in private or on
the list, but really, it should be the latter, since other people
might want to know, and after all, that's what these lists are for,
right?
Cheers,
Jonathan Revusky
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]