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]

Reply via email to