Here's the basics of what the Arf! provides:

* JDBC metadata based reflection:  not database specific

* Creates ActiveRecord API'd instances out of CFCs that extend a base ActiveRecord component

* Implements hasMany() and belongsTo() methods for establishing Record properties that point to other tables

* Allows for overloading any of the automagically generated methods to add custom business logic

* Automagic methods on Records include GetInstance(), Create(), Read(), Update(), Delete(), Save() [smart create/update], List(orderBy, whereClause), Validate() [does type and length checking], and SetNNN()/GetNNN() methods for each DB column


<strong>Code Demo: Arf! in Ten Steps</strong>

So, here's Arf! It's not ready for release yet, but I'd like to introduce it by showing how it'd be used to manipulate a two-table database in ten steps.  If you like what you see, please let me know if you'd like to be on the alpha tester list.

<strong>Step 1:  Create a database, tables, and datasource</strong>

I start by creating a database called "arfblog" (in any JDBC-compliant database, I've tested MySQL and MS SQL Server).  I give it two tables:  blogEntry (blogEntryId, title, body) and comment (commentId, blogEntryId, and message).  The primary keys (blogEntryId and commentId) can be auto-incrementing numeric or VARCHAR(35) - if you go the VARCHAR route, Arf! will automagically use UUIDs for the key values.  I then create a ColdFusion datasource pointing to the database and call it "arfblog"

<strong>Step 2:  Configure an Arf! datasource bean</strong>

This'd be best done in ColdSpring or ChiliBeans (or your IoC container of choice), but you start by creating an Arf! datasource.  It's just a little bean:

<div class="code"><FONT COLOR=MAROON>&lt;cfset ds = createObject(<FONT COLOR=BLUE>"component"</FONT>, <FONT COLOR=BLUE>"net.clearsoftware.arf.Datasource"</FONT>).init() /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset ds.setDSN(<FONT COLOR=BLUE>"arfblog"</FONT>) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset ds.setDatabase(<FONT COLOR=BLUE>"arfblog"</FONT>) /&gt;</FONT></div>

<strong>Step 3:  Create an Arf! RecordFactory</strong>

Next, we create an instance of the Arf! RecordFactory itself.  This is the CFC that performs the Arf! magic.

<div class="code"><FONT COLOR=MAROON>&lt;cfset rf = createObject(<FONT COLOR=BLUE>"component"</FONT>, <FONT COLOR=BLUE>"net.clearsoftware.arf.RecordFactory"</FONT>).init(ds, true) /&gt;</FONT></div>

<strong>Step 4: Create an ActiveRecord extension</strong>

Now, we need to create a CFC that extends the base Arf! ActiveRecord CFC.  It's pretty simple.  I create a BlogEntry.cfc and Comment.cfc from the ActiveRecordTemplate.cfc that comes with Arf!.  There's a single line of code that *must* be in the CFC, not in the base ActiveRecord:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- BlogEntry.cfc ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cfcomponent extends=<FONT COLOR=BLUE>"net.clearsoftware.arf.ActiveRecord"</FONT> output=<FONT COLOR=BLUE>"false"</FONT>&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Don't remove this line of code ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"getFinalSuper"</FONT> access=<FONT COLOR=BLUE>"private"</FONT>&gt;</FONT><FONT COLOR=MAROON>&lt;cfreturn super /&gt;</FONT><FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Add statements like &lt;cfset hasMany() /&gt; and &lt;cfset belongsTo() /&gt; here ---&gt;</I></FONT><br>
<br>
<FONT COLOR=MAROON>&lt;/cfcomponent&gt;</FONT></div>

<em>Comment.cfc is identical to BlogEntry.cfc at this point</em>

<strong>Step 5: Tell the classes about each other</strong>

A comment belongsTo an entry, and an entry hasMany comments, so we add the appropriate lines to each CFC, telling it what to relate to, and what CFC to use when getting related records.

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- BlogEntry.cfc ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cfcomponent extends=<FONT COLOR=BLUE>"net.clearsoftware.arf.ActiveRecord"</FONT> output=<FONT COLOR=BLUE>"false"</FONT>&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Don't remove this line of code ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"getFinalSuper"</FONT> access=<FONT COLOR=BLUE>"private"</FONT>&gt;</FONT><FONT COLOR=MAROON>&lt;cfreturn super /&gt;</FONT><FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Add statements like &lt;cfset hasMany() /&gt; and &lt;cfset belongsTo() /&gt; here ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cfset hasMany(<FONT COLOR=BLUE>"comment"</FONT>, <FONT COLOR=BLUE>"net.clearsoftware.arf.test.Comment"</FONT>) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cfcomponent&gt;</FONT></div>

Now, we do the same for the Comment:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- Comment.cfc ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cfcomponent extends=<FONT COLOR=BLUE>"net.clearsoftware.arf.ActiveRecord"</FONT> output=<FONT COLOR=BLUE>"false"</FONT>&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Don't remove this line of code ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"getFinalSuper"</FONT> access=<FONT COLOR=BLUE>"private"</FONT>&gt;</FONT><FONT COLOR=MAROON>&lt;cfreturn super /&gt;</FONT><FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Add statements like &lt;cfset hasMany() /&gt; and &lt;cfset belongsTo() /&gt; here ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cfset belongsTo(<FONT COLOR=BLUE>"blogEntry"</FONT>, <FONT COLOR=BLUE>"net.clearsoftware.arf.test.BlogEntry"</FONT>) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cfcomponent&gt;</FONT></div>

<strong>Step 6: Create a new blogEntry</strong>

Ok, I can ask my factory for some classes now.  Let's ask for a new blogEntry.

<div class="code"><FONT COLOR=MAROON>&lt;cfset blogEntry = rf.makeRecord(<FONT COLOR=BLUE>"net.clearsoftware.arf.test.BlogEntry"</FONT>) /&gt;</FONT></div>

That gives us an ActiveRecord.  It's got CRUD/S methods, get/set methods for each column in the blogEntry table, a getComment() method added by the hasMany() statement, a validate() method that'll check each property for NULL, length, and type, as well as a list() statement that has optional ORDER BY and WHERE arguments, and a getInstance() method that'll show us internal instance data (by value, where type makes it possible).

<strong>Step 7: Populate and save a blogEntry, showing that it's added with list()</strong>

<div class="code"><FONT COLOR=MAROON>&lt;cfset blogEntry.setTitle(<FONT COLOR=BLUE>"Some new entry"</FONT>) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset blogEntry.setBody(<FONT COLOR=BLUE>"A really great blog entry!"</FONT>) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset blogEntry.save() /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfdump var=<FONT COLOR=BLUE>"#blogEntry.list()#"</FONT>&gt;</FONT></div>

Not much to it, eh?

<strong>Step 8: Create a related comment</strong>

Now we'll create a related comment, and commit it.

<div class="code"><FONT COLOR=MAROON>&lt;cfset comment = rf.makeRecord(<FONT COLOR=BLUE>"net.clearsoftware.arf.test.Comment"</FONT>) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset comment.setBlogEntryId(blogEntry.getBlogEntryId()) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset comment.setMessage(<FONT COLOR=BLUE>"I'm a wiseacre comment."</FONT>) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset comment.save() /&gt;</FONT></div>

Notice that we set its BlogEntryId property to the BlogEntryId value of the BlogEntry we made.

<strong>Step 9: Show our relation properties</strong>

Now, we'll see where those belongsTo() and hasMany() come into play.  Remember saying that the comment belongsTo() a BlogEntry?  Adding the following line of code asks the comment for its entry:

<div class="code"><FONT COLOR=MAROON>&lt;cfset commentsEntry = comment.getBlogEntry() /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfdump var=<FONT COLOR=BLUE>"#commentsEntry#"</FONT> /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfdump var=<FONT COLOR=BLUE>"#commentsEntry.getInstance()#"</FONT> /&gt;</FONT></div>

The first CFDump shows that getBlogEntry() returns a BlogEntry, and the second shows that its instance data is the data for the BlogEntry.

Now, hasMany() relationships can return more than one instance, so a simple QueryIterator is returned.  It's got a pretty straightforward API, and you can get to its underlying query using QueryIterator.getQuery().  Here it is in action:

<div class="code"><FONT COLOR=MAROON>&lt;cfset entryComments = blogEntry.getComment() /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfdump var=<FONT COLOR=BLUE>"#entryComments.getQuery()#"</FONT>&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfset firstComment = entryComments.next() /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cfdump var=<FONT COLOR=BLUE>"#firstComment.getInstance()#"</FONT> /&gt;</FONT></div>

The first CFDump shows the query of related comments coming back, the second shows that that we can get a Comment instance from that query, and ask it for its instance data.  We could also manipulate its data and save() it because its a fully-operational instance of our net.clearsoftware.arf.test.Comment CFC that extends ActiveRecord.

<strong>Step 10: Overriding methods</strong>

Because our "shell" CFCs (BlogEntry and Comment) extend ActiveRecord, we can alter the functionality of the default methods that are created for us.  If we wanted to change the getTitle() method of BlogEntry to always come back in upper-case, we'd change our BlogEntry.cfc to the following:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- BlogEntry.cfc ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cfcomponent extends=<FONT COLOR=BLUE>"net.clearsoftware.arf.ActiveRecord"</FONT> output=<FONT COLOR=BLUE>"false"</FONT>&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Don't remove this line of code ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"getFinalSuper"</FONT> access=<FONT COLOR=BLUE>"private"</FONT>&gt;</FONT><FONT COLOR=MAROON>&lt;cfreturn super /&gt;</FONT><FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT><br>
<br>
<FONT COLOR=GRAY><I>&lt;!--- Add statements like &lt;cfset hasMany() /&gt; and &lt;cfset belongsTo() /&gt; here ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cfset hasMany(<FONT COLOR=BLUE>"comment"</FONT>, <FONT COLOR=BLUE>"net.clearsoftware.arf.test.Comment"</FONT>) /&gt;</FONT><br>
<br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"getTitle"</FONT>&gt;</FONT><br>
&nbsp;&nbsp;&nbsp;<FONT COLOR=MAROON>&lt;cfreturn uCase(super.getTitle()) /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT><br>
<br>
<FONT COLOR=MAROON>&lt;/cfcomponent&gt;</FONT></div>

Now, to show it works:

<div class="code"><FONT COLOR=MAROON>&lt;cfoutput&gt;</FONT><br>
#blogEntry.getTitle()#<br>
<FONT COLOR=MAROON>&lt;/cfoutput&gt;</FONT></div>

Ah, now that's good and annoying!

<strong>Conclusion</strong>

So, we've got a beginning of an ActiveRecord API / Generator working in ColdFusion.  There's more to the API than what I've  covered here.  Hopefully, I'll get it documented and out the door before too long.  If you'd like a copy to play with, please leave me a comment and I'll put you on the "alpha" tester list.  I should have the code (it'll be LGPL, like Model-Glue) into the clearsoftware.net SVN repo before too long.