<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>No, I am better than that! &#187; ColdFusion</title>
	<atom:link href="http://rickosborne.org/blog/tag/coldfusion/feed/" rel="self" type="application/rss+xml" />
	<link>http://rickosborne.org/blog</link>
	<description>Striving to subdue the mediocrity.</description>
	<lastBuildDate>Sun, 21 Aug 2011 23:27:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Yes, Virginia, that&#8217;s automated SQL to MongoDB MapReduce</title>
		<link>http://rickosborne.org/blog/2010/02/yes-virginia-thats-automated-sql-to-mongodb-mapreduce/</link>
		<comments>http://rickosborne.org/blog/2010/02/yes-virginia-thats-automated-sql-to-mongodb-mapreduce/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 23:42:10 +0000</pubDate>
		<dc:creator>Rick Osborne</dc:creator>
				<category><![CDATA[ColdFusion]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[derby]]></category>
		<category><![CDATA[mapreduce]]></category>
		<category><![CDATA[mongodb]]></category>
		<guid isPermaLink="false">http://rickosborne.org/blog/?p=1174</guid>
		<description><![CDATA[I have to admit, I&#8217;m pretty darn proud of this one. This is a righteous hack. I can now write SQL against MongoDB with ColdFusion. My project today was to take this SQL statement: SELECT "goalType", SUM("distancekm") AS "totalkm", COUNT(*) AS "workouts", COUNT("powerSongAlbum") AS "songcount", AVG("distancekm") AS "avgkm", MAX("distancekm") AS "maxkm", MIN("distancekm") AS "minkm" FROM [...]]]></description>
			<content:encoded><![CDATA[<p>I have to admit, I&#8217;m pretty darn proud of this one.  This is a righteous hack.  I can now write SQL against MongoDB with ColdFusion.</p>
<p>My project today was to take this SQL statement:</p>
<pre class="sql">SELECT "goalType",
  SUM("distancekm") AS "totalkm",
  COUNT(*) AS "workouts",
  COUNT("powerSongAlbum") AS "songcount",
  AVG("distancekm") AS "avgkm",
  MAX("distancekm") AS "maxkm",
  MIN("distancekm") AS "minkm"
FROM "workouts"
GROUP BY "goalType"</pre>
<p>&#8230; and create a set of ColdFusion components to transform that query into a MapReduce function that would run on MongoDB.  <a href="/blog/index.php/2010/02/09/infographic-migrating-from-sql-to-mapreduce-with-mongodb/">Mapping basic SQL to MongoDB MapReduce</a> isn&#8217;t too hard.  Getting the <a href="/blog/index.php/2010/02/19/derby-svn-coldfusion-sql-parser/">SQL parser from Derby working within ColdFusion</a> was significantly harder.</p>
<p>But I did it.  This is the <strong>completely automated</strong> result:</p>
<pre class="javascript">db.runCommand({
mapreduce: "workouts",
map: function () { emit(
  this.goalType,
  {
    '_cfcount': 1,
    'distancekm_cfsum': isNaN(this.distancekm) ? null : this.distancekm,
    'distancekm_cfnum': isNaN(this.distancekm) ? 0 : 1,
    'powerSongAlbum_cfcount': (this.powerSongAlbum == null) ? 0 : 1,
    'distancekm_cfmax': isNaN(this.distancekm) ? null : this.distancekm,
    'distancekm_cfmin': isNaN(this.distancekm) ? null : this.distancekm
  }
); },
reduce: function (key,vals) {
  var ret = {
    'distancekm_cfmax': null,
    'distancekm_cfsum': null,
    'distancekm_cfmin': null,
    'distancekm_cfnum': 0,
    'powerSongAlbum_cfcount': 0,
    '_cfcount': 0
  };
  for(var i = 0; i < vals.length; i++) {
    var v = vals[i];
    ret['distancekm_cfnum'] += v['distancekm_cfnum'];
    if(!isNaN(v['distancekm_cfmax'])) ret['distancekm_cfmax'] = (ret['distancekm_cfmax'] == null) ? v['distancekm_cfmax'] : (ret['distancekm_cfmax'] > v['distancekm_cfmax']) ? ret['distancekm_cfmax'] : v['distancekm_cfmax'];
    ret['_cfcount'] += v['_cfcount'];
    if(!isNaN(v['distancekm_cfmin'])) ret['distancekm_cfmin'] = (ret['distancekm_cfmin'] == null) ? v['distancekm_cfmin'] : (v['distancekm_cfmin'] > ret['distancekm_cfmin']) ? ret['distancekm_cfmin'] : v['distancekm_cfmin'];
    ret['powerSongAlbum_cfcount'] += v['powerSongAlbum_cfcount'];
    if(!isNaN(v['distancekm_cfsum'])) ret['distancekm_cfsum'] = v['distancekm_cfsum'] + (ret['distancekm_cfsum'] == null ? 0 : ret['distancekm_cfsum']);
  }
  return ret;
},
finalize: function (key,val) {
  return {
    'totalkm'   : val['distancekm_cfsum'],
    'workouts'  : val['_cfcount'],
    'songcount' : val['powerSongAlbum_cfcount'],
    'avgkm'     : (isNaN(val['distancekm_cfnum']) || isNaN(val['distancekm_cfsum'])) ? null : val['distancekm_cfsum'] / val['distancekm_cfnum'],
    'maxkm'     : val['distancekm_cfmax'],
    'minkm'     : val['distancekm_cfmin']
  };
},
out: "s2mr",
verbose: true
});</pre>
<p>And here&#8217;s the output when I run that against my MongoDB collection:</p>
<pre class="coldfusion">{ "_id" : null, "value" : {
    "totalkm" : 451.6752000000001,
    "workouts" : 54,
    "songcount" : 53,
    "avgkm" : 8.364355555555557,
    "maxkm" : 19.7502,
    "minkm" : 0.0194
} }
{ "_id" : "Distance", "value" : {
    "totalkm" : 304.76879999999994,
    "workouts" : 27,
    "songcount" : 27,
    "avgkm" : 11.287733333333332,
    "maxkm" : 26.2581,
    "minkm" : 4.0486
} }
{ "_id" : "Time", "value" : {
    "totalkm" : 19.221,
    "workouts" : 2,
    "songcount" : 2,
    "avgkm" : 9.6105,
    "maxkm" : 9.9224,
    "minkm" : 9.2986
} }</pre>
<p>w00t!</p>
<p>I&#8217;ve left the code modular enough that I can make a CouchDB version <em>almost</em> as easily.</p>
<p><em>Update:</em> Better yet, I can now get all the way to an actual query data type:</p>
<table style="border-color: #884488 ; border-collapse: collapse; border-color: #884488;" border="2">
<tr>
<th style="background-color: #aa66aa;" colspan="8">query</th>
</tr>
<tr bgcolor="eeaaaa" >
<td style="background-color: #ffddff ;">&nbsp;</td>
<td style="background-color: #ffddff ;">AVGKM</td>
<td style="background-color: #ffddff ;">MAXKM</td>
<td style="background-color: #ffddff ;">MINKM</td>
<td style="background-color: #ffddff ;">SONGCOUNT</td>
<td style="background-color: #ffddff ;">TOTALKM</td>
<td style="background-color: #ffddff ;">WORKOUTS</td>
<td style="background-color: #ffddff ;">_ID</td>
</tr>
<tr >
<td style="background-color: #ffddff ;">1</td>
<td valign="top"> 8.3644 </td>
<td valign="top">19.7502 </td>
<td valign="top">0.0194 </td>
<td valign="top">53 </td>
<td valign="top">451.6752 </td>
<td valign="top">54 </td>
<td valign="top">[empty string] </td>
</tr>
<tr >
<td style="background-color: #ffddff ;">2</td>
<td valign="top">11.2877 </td>
<td valign="top">26.2581 </td>
<td valign="top">4.0486 </td>
<td valign="top">27 </td>
<td valign="top">304.7688 </td>
<td valign="top">27 </td>
<td valign="top">Distance </td>
</tr>
<tr >
<td style="background-color: #ffddff ;">3</td>
<td valign="top">9.6105 </td>
<td valign="top">9.9224 </td>
<td valign="top">9.2986 </td>
<td valign="top">2 </td>
<td valign="top">19.221 </td>
<td valign="top">2 </td>
<td valign="top">Time </td>
</tr>
</table>
<p>(Note for potential cynics: no, I&#8217;m <em>not</em> missing the point.  This is <em>not</em> meant as a production tool&mdash;it&#8217;s a learning tool.  If my students can start with SQL and see the end result in MapReduce, then they have that much better chance of grokking all of it.)</p>
]]></content:encoded>
			<wfw:commentRss>http://rickosborne.org/blog/2010/02/yes-virginia-thats-automated-sql-to-mongodb-mapreduce/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ColdFusion FW/1 MVC framework</title>
		<link>http://rickosborne.org/blog/2009/12/coldfusion-fw1-mvc-framework/</link>
		<comments>http://rickosborne.org/blog/2009/12/coldfusion-fw1-mvc-framework/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 02:04:19 +0000</pubDate>
		<dc:creator>Rick Osborne</dc:creator>
				<category><![CDATA[ColdFusion]]></category>
		<category><![CDATA[School]]></category>
		<category><![CDATA[full sail]]></category>
		<category><![CDATA[fw/1]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[orm]]></category>
		<category><![CDATA[teaching]]></category>
		<guid isPermaLink="false">http://rickosborne.org/blog/?p=1045</guid>
		<description><![CDATA[I hacked around for a few hours last night with Sean Corfield&#8217;s FW/1. The site makes the following claim: &#8220;Intended to require near-zero configuration, FW/1 lets you build your application without worrying about a framework getting in your way.&#8221; This is mostly dead-on. I&#8217;m not a frameworks guy, and even I thought FW/1 was pretty [...]]]></description>
			<content:encoded><![CDATA[<p>I hacked around for a few hours last night with Sean Corfield&#8217;s <a href="http://fw1.riaforge.org/">FW/1</a>.  The site makes the following claim:</p>
<blockquote><p>&ldquo;Intended to require near-zero configuration, FW/1 lets you build your application without worrying about a framework getting in your way.&rdquo;</p></blockquote>
<p>This is <em>mostly</em> dead-on.  I&#8217;m not a frameworks guy, and even I thought FW/1 was pretty simple to get up and running around with.  It wasn&#8217;t perfect&mdash;but it was noticeably easier than the other CF frameworks I&#8217;ve used.</p>
<p>As I mentioned in my previous post, in the ColdFusion courses I teach <a href="/blog/index.php/2009/11/10/cf9-done/">the two final lectures are on ORM and Frameworks</a>.  Both lectures use a simple blog front-end as example code.  I translated that code over to FW/1, mostly via copy-and-paste.  You can download it, if you like:</p>
<p><a href="/blog/wp-content/uploads/2009/12/blog-fw1-20091209.zip" style="display: block; color: #090; border: 1px solid #090; padding: 0.5em 1em 0.5em 48px; background: #dfd url(/images/download-watermark.png) 8px center no-repeat; text-indent: 0 !important; text-decoration: none;">Simple Blog Front-End using CF9 ORM and FW/1<br/>Zip Archive, 12KB</a></p>
<p>There&#8217;s not much to it, really.  I suspect you&#8217;d gain more from Ray&#8217;s <a href="http://www.coldfusionjedi.com/index.cfm/2009/11/30/Simple-example-of-processing-a-form-in-FW1">posts</a> on the <a href="http://www.coldfusionjedi.com/index.cfm/2009/11/28/Framework-One">subject</a>.</p>
<p>I ran into the same problem that Ray initially had: the default method is named &ldquo;<kbd>default</kbd>&rdquo;, which is a reserved word in CFScript.  This code breaks:</p>
<pre class="coldfusion">public function default(required struct rc) {</pre>
<p>  This means you&#8217;re limited to either CFML-based Controllers or you need to be extra careful about using defaults.  I admit that the new CFScript is growing on me&mdash;especially for Controllers, Models, and Services&mdash;so this is a bit of a drawback.  (Hacking your local copy of the framework to use <kbd>defaultItem</kbd> instead of <kbd>default</kbd> may not be a horrible idea, but may potentially limit the distributability of your code &#8230; if you care about such things.)</p>
<p>My other nitpick is that the FW/1 documentation is upside-down.  The Controller examples show how to add service calls to the queue:</p>
<pre class="coldfusion">variables.fw.service( "myservice.myaction", "myresult" );</pre>
<p>But it&#8217;s not until you get to the very end of that page that you find out that to get this variable you have to set it up yourself&mdash;it&#8217;s not one of the magic variables that the framework provides:</p>
<pre class="coldfusion">function init(fw) { variables.fw = fw; }</pre>
<p>I spent half of my time banging my head against the wall with <kbd>writeDump()</kbd> statements trying to figure out what I was doing wrong &#8230; before I scrolled down to see that.</p>
<p>Beyond those two relatively minor nitpicks, it&#8217;s not a bad framework.  All of the implicit invocation is nice, and the structure is logical and easy to work with.  I love the way the Service objects are called with <kbd>argumentCollection</kbd> so that they don&#8217;t have to care about the framework.  I&#8217;m not a huge fan of the way Views are done, though: there&#8217;s too much hand-wavey magic.  Personally, I&#8217;d prefer to code Views as functions, too, if only to have nice, explicit arguments like the Services do.  But I admit that might just be my OCD kicking in.  The fallback for Views and Layouts is nice.</p>
<p>In all, FW/1 doesn&#8217;t suck.  That&#8217;s high praise coming from an anti-framework guy like me.</p>
]]></content:encoded>
			<wfw:commentRss>http://rickosborne.org/blog/2009/12/coldfusion-fw1-mvc-framework/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>CF9 + E4X + C4X</title>
		<link>http://rickosborne.org/blog/2009/05/cf9-e4x-c4x/</link>
		<comments>http://rickosborne.org/blog/2009/05/cf9-e4x-c4x/#comments</comments>
		<pubDate>Tue, 19 May 2009 16:55:56 +0000</pubDate>
		<dc:creator>Rick Osborne</dc:creator>
				<category><![CDATA[ColdFusion]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[cf9]]></category>
		<category><![CDATA[cfscript]]></category>
		<category><![CDATA[e4x]]></category>
		<guid isPermaLink="false">http://rickosborne.org/blog/?p=919</guid>
		<description><![CDATA[Sean Corfield called for comments about how to embed tag collections into cfscript. I proposed an E4X-style solution, where chunks of old-style CF code could be embedded without any conversion to objects or other flourishes. What is it that makes ColdFusion into ColdFusion? For me, it&#8217;s that it&#8217;s not tied down into boring object-imperative code: [...]]]></description>
			<content:encoded><![CDATA[<p>Sean Corfield <a href="http://corfield.org/blog/index.cfm/do/blog.entry/entry/Help_the_CFML_Advisory_Committee">called for comments about how to embed tag collections into cfscript</a>.  I proposed an E4X-style solution, where chunks of old-style CF code could be embedded without any conversion to objects or other flourishes.</p>
<p>What is it that makes ColdFusion into ColdFusion?  For me, it&#8217;s that <strong>it&#8217;s not</strong> tied down into boring object-imperative code:</p>
<pre>var m = new cfmail();
m.from    = "whatever";
m.to      = "whoever";
m.subject = "however";
m.body    = "blah blah blah";
m.send();</pre>
<p>Ugh.  That kind of blocky syntax makes it look and feel like ASP.  If I wanted to code for ASP, I&#8217;d code for ASP.  (And get a lobotomy.)</p>
<p>The beauty and elegance of ColdFusion is its declarative nature.  I don&#8217;t create an email object or new() up a query object, I just declare that I want an email or a query.  Done.  I think declarative E4X-style literals&mdash;turning XML and CF tags into primitives like strings and numbers&mdash;keeps the &#8220;just give it to me&#8221; feel in CF.</p>
<p>CF was built for moving data between web pages and databases.  Upgrading XML fragments to first-class primitives fits with that theme.  Once you&#8217;ve got that in your head, it&#8217;s not hard to see CF code fragments as primitives, too.</p>
<p>Here&#8217;s a more detailed example of <a href="/blog/index.php/2009/02/05/cfscript-v2-as-told-by-jeff-atwood/">the kind of cfscript I&#8217;d love to see</a>:</p>
<pre>import org.rickosborne.util.*;
component extends="CachedObject" {
    public query queryUserByID( id, userType = "" ) {
        // Return a query of the user information
        var ret = cachePeek(id);
        if(isQuery(ret) and (ret.recordCount gt 0)) return ret;
        ret = <strong style="color:maroon">&lt;cfquery datasource="#this.dsn#"&gt;</strong>
          SELECT *
          FROM users
          WHERE (id = <strong style="color:maroon">&lt;cfqueryparam value="#arguments.id#" cfsqltype="CF_SQL_INTEGER"&gt;</strong>)
            <strong style="color:maroon">&lt;cfif structKeyExists(arguments, "userType") and (arguments.userType neq "")&gt;</strong>
            AND (type = <strong style="color:maroon">&lt;cfqueryparam value="#arguments.type#" cfsqltype="CF_SQL_VARCHAR"&gt;</strong>)
            <strong style="color:maroon">&lt;/cfif&gt;</strong>
          <strong style="color:maroon">&lt;/cfquery&gt;;</strong>
        if(ret.recordCount gt 0) cachePoke(id, ret);
        return ret;
    } // getUserByID
    public xml xmlUserByID( id ) {
        // Return an XML representation of user data
        // which can then be transformed with XSLT
        var ret = <strong style="color:navy">&lt;user /&gt;</strong>;
        var user = queryUserByID(arguments.id);
        var colName = "";
        if(!(isQuery(user) and (user.recordCount eq 1))) return ret;
        for(colName in listToArray(user.columnList)) {
            ret.appendChild(<strong style="color:olive">&lt;#lcase(colName)#&gt;#xmlFormat(user[colName][1])#&lt;/#lcase(colName)#&gt;</strong>);
            // or maybe ...
            ret.childNodes += <strong style="color:olive">&lt;#lcase(colName)#&gt;#xmlFormat(user[colName][1])#&lt;/#lcase(colName)#&gt;</strong>;
            // or if that's too hard on the parser, go the long way around
            ret.appendChild(xmlParse("&lt;#lcase(colName)#&gt;#xmlFormat(user[colName][1])#&lt;/#lcase(colName)#&gt;"));
        } // for colName
        return ret;
    } // formatUser
} // component</pre>
<p>(But, honestly, at that point why start with a ColdFusion engine?  Why not just start with a JavaScript/EcmaScript engine such as <a href="http://www.mozilla.org/rhino/">Rhino</a>, then just extend it to support CF functions and objects?)</p>
]]></content:encoded>
			<wfw:commentRss>http://rickosborne.org/blog/2009/05/cf9-e4x-c4x/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

