DataFaucet ORM!!!
DataFaucet is an ORM tool.
Why DataFaucet? Well two reasons, first it originated with the onTap framework and I like the pun.
Secondly the goal of DataFaucet is to make ORM as easy as getting a glass of water from the tap in your kitchen.
Another ORM? Really? Why?
To give you a little history, my friend Doug Boude, who's been doing a lot of work with Model-Glue in the past couple years had posted a blog the other day about his experiences with ORM. I can't say that I "feel his pain" because honestly, I've never worked with any of the recent ORM frameworks for ColdFusion outside of my own. But my own is an integrated part of the onTap framework... and perhaps largely as a result of that, few people have really looked at it. Doug had asked me once a couple years ago if I could split it out into a separate project - actually several people have over the years - and I've always replied "yes", but just never bothered to do it. So when Doug asked, particularly after having just finished the first draft of the Galleon ports project, I decided to go ahead and split it out for everyone. Doug of course wants to use it with Model-Glue because that's the framework he and his team work with. And that's fine. OnTap has always been open source, so I never had any objection to that, but nobody else was undertaking the task of splitting it out.
A year or so ago I found myself explaining some of the features of the SQL abstraction library to a coworker who said to me "you know Transfer already does all that"... umm... sure... and Transfer wasn't even a twinkle in Mark Mandel's eye when I started working on my SQL abstraction tools... and it's as far as I know still not as robust. Nor is Reactor, in spite of Sean Corfield's comment when I spoke at cf.Objective a couple years ago that it "reminded me of the things we can do with Reactor". I'm not saying this to be derogatory here, I'm just trying to establish a baseline. I started working on ORM with ColdFusion 5, before there even were CFCs. At the time it was HIDEOUS and SLOW and required custom-tags as its syntax. But it did work. It wasn't until much later after the release of ColdFusion MX that I grabbed up the Java API docs and learned how to work with JDBC through reflection and wrote the cover article for the ColdFusion Developer's Journal titled Leveraging JDBC or Just Fetching Coffee. That article, my first for the journal, almost didn't get published. When I originally proposed it the editor at the time felt it would be too advanced for the average ColdFusion programmer. Someone else recommended that I reword the proposal and resubmit it and I suspect they also put a bug in the guy's ear themselves and it got accepted and made its way to the cover. Where it quickly became one of their more popular articles. As far as I know that was still before either Transfer or Reactor had been conceived. It wasn't until still a while later that I finally rewrote the entire SQL abstraction library using CFCs instead of custom tags.
What struck me about Doug's comments about their experiences with ORM is that none of the things he described as being major headaches with their choice of ORM would have been an issue if they'd been using the onTap framework. And that really may have been the thing that finally convinced me to go ahead and do the leg-work to separate these tools for everyone. It is a little more work than I'd expected, but not much. I'll be done with the initial draft in a few more hours.
Two of Doug's comments in particular are especially important to note here. The first is his comment about what he calls "gluttony" -- the ORM components being "resource hogs" and slow as hell... While I've never been the first to champion the cause of performance tuning, I told Doug that, "gee when I tested them, they only added about 35ms per query over the top of Ray's original ad-hoc sql" (from Galleon) -- which he said sounded reasonable, leading me to believe that it's more efficient than the ORM they chose. That's really interesting because the ORM they chose was a code-generator like Reactor or I presume Transfer. I don't know which one they chose. But the conventional wisdom is that generated code is more efficient... apparently except when compared to mine. DataFaucet will not be a code-generator -- it abstracts SQL on the fly at run-time, and in truth, a number of its features like and/or keyword search filtering could not be accomplished with generated code.
The second thing and probably more important than the performance question, is something I'll actually quote from Doug's blog:
And ah, the grandest reason of them all that I pretty much despise ORMs: losing my beloved sql. Now, I wouldn't have a problem with losing sql as long as my ORM provides me with a suitable substitute. But it does not. The task of translating a simple sql statement into "ORM-speak" is far, far from simple, my friend. I and others I know have quite literally spent an entire DAY trying to figure out how to write the code, leveraging our ORM, to execute a simple join.
You mean like this?
statement = ds.getStatement("select").init("products"); // query the product table
cat = statement.join("productcategories",true,"productcategoryid"); // join the category table
cat.filter("productcategoryid",rc.productcategoryid); // filter products by category
query = statement.execute(); // run the query
</cfscript>
hmmm... makes me wonder what ORM-speak looks like... must be hideous... which brings me back to the name... DataFaucet -- relax, have a drink. :)
I actually wrote an article that's included with my ports of Ray's Galleon Forums about having converted Ray's business objects to use the DataFaucet CFCs and cataloged all the changes in an Excel spreadsheet. Overall I found that in addition to a goodly amount of decoupling (it's not limited to the big-4 databases anymore), I was also able to remove about 600 lines of code with a negligible change in performance. In fact, it's unlikely you would even notice the difference as a forum user.
Anyway, all this stuff is already built -- it has been for a while now... all I gotta do is decouple a few leftover helpers (half of which were holdovers from CF5). The other half were just because I didn't want to duplicate code. Although I'm going to have to put up with some duplicated code because if I'm going to support both projects then I'm not going to branch the code, I'm gonna have to rewrite some of the onTap framework core to use the new version of DataFaucet.
UPDATE: So it's actually approved on RIAForge now. There's some code in the SVN repository, but it's in an ugly state right now. You can look, but don't say I didn't warn you. :)
As I've been working on separating it from the framework I've also realized that, as clean and simple as I thought the syntax was before, there are several ways I can improve it even further, so I'm going to be adding some new methods to make those short query builds even smaller as a matter of syntax sugar. For simple queries, you'll be able to do something like <return ds.select(table="mytable",filters=arguments).execute() />. And since the project is already approved (thanks Ray) :) I posted a syntax sample on the DataFaucet blog.
