This is something I mentioned a little while ago on the Team Macromedia list (maybe on cf-community too), because I was really excited about it and felt like I had to share. :)
I just recently released version 2.4 of the onTap framework after a fair amount of refactoring to remove code that supported ColdFusion 5, along with version 3.0 of the Members onTap plugin for member management and application security. What I'm probably most excited about currently however, in spite of quite a bit of improvement in the member plugin (thanks to a new OO encapsulated model layer) is a complete rewrite of the SQL-abstraction API in the core framework. Unfortunately it wasn't really feasible to maintain many of the existing tag and function-based tools for SQL-abstraction due to a change in syntactical metaphor, so any application(s) using the previous version will need to be updated (the same is also true of the member plugin). I think however that in this case the switch is well worth the effort. The public site is updated with the latest documentation, and you can see the sql-abstraction syntax at: http://fusiontap.com/docs/index.cfm?netaction=quickstart/dba This new syntax being entirely object-based has a number of advantages in spite of being a little mechanically heavier. The most notable in my opinion is that when compared to the previous tag and function based syntaxes it's much more compact and much more legible respectively (which I suspect is a really good thing given comments about the framework being difficult to learn prior). Previously a select statement would be generated via one of these methods: <cfmodule template="#request.tapi.db.select()#" table="mytable" return="query"> <cfmodule template="#request.tapi.db.join()#" table="alttable" required="true" /> <cfmodule template="#request.tapi.db.filter()#" column="alttable.x" content="%#x#%" /> </cfmodule> or <cfset query = request.tapi.sql.select("mytable","*","", request.tapi.sql.join("alttable",required, request.tapi.sql.filter("alttable.x","%#x#%")))> Either of these would have replaced this ad-hoc query: <cfquery name="query" datasource="primary" username="..." password="..."> select * from mytable inner join alttable on (alttable.fk = mytable.pk) where alttable.x like '%#x#%' </cfquery> The syntax may or may not have saved me any keystrokes, but it was able to mitigate the differences between the big 4 databases (ms sql, oracle, mysql, ms access), and that was enough for me at the time. Now compare these to the new syntax: <cfset select = datasource.getStatement("select").init("mytable")> <cfset select.join("alttable",required).filter("x","%#x#%","LIKE")> <cfset query = select.execute()> This new metaphor for abstraction represents both fewer keystrokes and much more powerful and flexible abstraction. For example: <cfset select.collectionFilter(url)> <cfset select.dateFilter(column,startdate,enddate)> <cfset select.timeSpanFilter(startcolumn,endcolumn,startdate,enddate)> (for fetching records which represent an overlapping period of time) <cfset select.andOrCollectionFilter(form)> (for more powerful advanced search features) Here's something that shows up on the CF-talk list a few times every year: "is there a way I can get the sql syntax from a query I just executed?" And I believe there are ways to accomplish that with native CF via some of the more potent and cryptic black-magic of the serviceFactory, but none so simple as this: <cfoutput><pre>#statement.getSyntax()#</pre></cfoutput> One last thing, for folks like Matt Woodward :) who say "all this to avoid a little SQL" ... The statement objects can have listeners attached to them, and in the case of select statements, listeners can filter the result set returned from the statement object. The beauty of this is in things like the member search page and the log search page of the member plugin, both of which allow you to search on or sort by data which isn't accessible to the database server, and allow you to do this without any need to know or understand that either XML/XSLT or Java are being used to accomplish this when you execute the statement. In the case of member search, the resultant query can be sorted by language, but the names of languages are locale specific, i.e. German to an English speaker or Deutsch to a German speaker. The MemberSearch object is retrieved from the MemberFactory (request.tap.memberFactory.getSearchStatement()) which attaches a listener to the returned statement. When you then specify statement.sort("languagename").execute() the listener creates the languagename column (from member locale) and resorts the query all using Java and you didn't need to know any of it, just sort().execute(). :) The log search filters the result query by member name data stored in an XML packet using an XSLT transformation -- which is ultimately conceptually the same as the member search, all you have to know is that when you specify a "membername" attribute to fetch the log-search object, it will return only records with that data in some portion of the member's name (or email address). Anyway, that's enough hawking for the day. :) I'm excited to know what everyone thinks. (p.s. there's some new ajax-y stuff in the member plugin too -- check out the member tab of the edit-role form, then log out, disable javascript before logging in again and notice how section-508-ready the whole thing is) s. isaac dealey 434.293.6201 new epoch : isn't it time for a change? add features without fixtures with the onTap open source framework http://www.fusiontap.com http://coldfusion.sys-con.com/author/4806Dealey.htm ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| Message: http://www.houseoffusion.com/lists.cfm/link=i:4:232049 Archives: http://www.houseoffusion.com/cf_lists/threads.cfm/4 Subscription: http://www.houseoffusion.com/lists.cfm/link=s:4 Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=11502.10531.4 Donations & Support: http://www.houseoffusion.com/tiny.cfm/54