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

Reply via email to