Enough of the rhetoric, here's some code. I'm having a look at the new member functions in ColdFusion 11 today. And have some samples, observations and suggestions.
Here's a quick (and terribly contrived) example of using string / list member functions in ColdFusion 11:
s = "The";
s = s.append("quick brown fox", " ")
.append("jumps over the lazy dog", " ")
.ucase()
.reverse();
writeOutput(s);
Output:
GOD YZAL EHT REVO SPMUJ XOF NWORB KCIUQ EHT
Here I'm showing the member-function-version of
listAppend()
, ucase()
and reverse()
. I also demonstrate that - because string functions return the resultant string - how member functions can be chained together. This example is a dumb usage of that, but you can possibly see the potential there, and it's great that it's good object-oriented code instead of the old-school procedural stuff we've had to use in ColdFusion until now.One thing one cannot do with the current implementation is to apply member functions to literal values, eg this JavaScript:
"my string".toUpperCase()
But we're still in beta, so there's time for that yet: 3712122.
We can also use member functions with the rest of the CFML datatypes. Here's some stuff using query member functions:
rainbow = queryNew("");
rainbow.addColumn("id", "integer", [1,2,3,4,5,6,7]);
rainbow.addColumn("en", "varchar", ["red","orange","yellow","green","blue","indigo","violet"]);
rainbow.addColumn("mi", "varchar", ["whero","karaka","kowhai","kakariki","kikorangi","tawatawa","mawhero"]);
writeDump(rainbow);
Output:
query | |||
---|---|---|---|
EN | ID | MI | |
1 | red | 1 | whero |
2 | orange | 2 | karaka |
3 | yellow | 3 | kowhai |
4 | green | 4 | kakariki |
5 | blue | 5 | kikorangi |
6 | indigo | 6 | tawatawa |
7 | violet | 7 | mawhero |
This is cool, but I'd like to make two observations. We still have to use a bit of procedural code here to create the query in the first place, and to generate its dump. I'm less concerned about the latter, but I think we need some tweaking of the former. Also, due to the very literal way the Adobe ColdFusion bods have implemented the member functions, we can't chain these query functions together as they don't return the query, they return a boolean (which was always a stupid thing for the procedural functions to return, too).
Here's some CFML-written proof of concept code which could improve things a bit. The CFC is simply a series of stub functions which demonstrate the techniques, but I am not suggesting it is part of a solution. I just can't write Java well enough to do a proper job of it. Here's the CFC:
//Q.cfc
component{
Q function new(required string cols, string types="", any data=[]){
this.records = queryNew(cols, types, data);
return this;
}
Q function addColumn(required string col, required string type, required array data){
this.records.addColumn(col, type, data);
return this;
}
Q function addRow(numeric rows=1, array data){
if (structKeyExists(arguments, "data")){
this.records.addRow(col);
}else{
this.records.addRow(col, data);
}
return this;
}
Q function setCell(required string col, required any value, numeric row){
if (structKeyExists(arguments, "row")){
this.records.setCell(col, value, row);
}else{
this.records.setCell(col, value);
}
return this;
}
Q function execute(required string sql, any params=[], struct options){
if (structKeyExists(arguments, "options")){
this.records = queryExecute(sql, params, options);
}else{
this.records = queryExecute(sql, params);
}
return this;
}
string function dump(){
var result="";
savecontent variable="result" {
writeDump(var=this.records, attributeCollection=arguments);
}
return result;
}
string function toJson(){
return serializeJson(this.records);
}
}
And, more importantly, the code using it:
query = new Q()
.new("")
.addColumn("id", "integer", [1,2,3,4,5,6,7])
.addColumn("en", "varchar", ["red","orange","yellow","green","blue","indigo","violet"])
.addColumn("mi", "varchar", ["whero","karaka","kowhai","kakariki","kikorangi","tawatawa","mawhero"])
.execute("SELECT * FROM this.records WHERE id = ?", [1], {dbtype="query"})
;
writeOutput(query.dump());
writeOutput(query.toJson());
Output:
query | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
RESULTSET |
| ||||||||||||
CACHED | false | ||||||||||||
EXECUTIONTIME | 3 | ||||||||||||
SQL | SELECT * FROM this.records WHERE id = ? | ||||||||||||
SQLPARAMETERS |
|
Now... I'll repeat this: the CFC is just stub code, and intended solely to facilitate the second bit of code actually working. I am not suggesting we should need to go
query = new Q()
, or access the data via query.records
, nor should the solution be a CFC. That is just to hopefully short-circuit some "missing the point entirely" comments I might end up with.The key points are:
- creating a new query should be object-oriented too. We should not rely on an old procedural function to facilitate OO code. How should we do this? I think the query class should have a static method
new()
, which we'd call thus:query = Query.new();
whereQuery
is the class, not the object (3712126). - Likewise the Query class should have a static method
execute()
, which acts the wayqueryExecute()
currently does. This would either hit the database for data, or perhaps act upon itself (FROM [self]
, or something, in the SQL?) (3712127). - The member functions that manipulate the query data should return the query data, so subsequent methods can be chained to it (3712125).
- There are other functions which currently act on a query object, like
serializeJson()
,toString()
,writeDump()
, WDDXifying, etc, which should also be member functions of theQuery
class (3712128).
NB: I did not check the struct or array (etc) member functions, but assume they - likewise - can't be chained because they don't return useful values. Obviously this should be dealt with too.
I'll obviously post more observations as they come to mind.
--
Adam