1. CFML Features for More
Modern Coding
Download This Presentation:
Queries and Closures and loops…OH MY!
Download Original Presentation: http://bit.ly/2cIjXuI
2. CFML Features for
More Modern Coding
Queries and Closures and loops…OH MY!
Dan Fredericks
fmdano@gmail.com
@fmdano74
http://www.meetup.com/nvcfug/
Download This Presentation:
Download Original Presentation: http://bit.ly/2cIjXuI
3. What this Presentation will cover:
• CFScript Support
• QueryExecute() Function
• Member Functions
• Elvis Function
• Closures
• Map, Reduce, Filter, Each
• First Class Functions and Callbacks
• CF 2016 Special
Download Original Presentation: http://bit.ly/2cIjXuI
4.
5. QueryExecute
• CFQUERY has been the staple to query a database since day 1
• There have been a few attempts to query the database using script
• Here is the latest alternative for script based syntax
Syntax:
QueryExecute( sql_stmt, queryParams, queryOptions );
6. QueryExecute
Old Script Syntax
<cfscript>
q = new com.adobe.coldfusion.query();
q.setDatasource("cfartgallery");
q.setSQL("select * from art
where artname like :search or description like :search");
q.addParam(name="search",value="%e%",cfsqltype="cf_sql_varchar");
r = q.execute();
</cfscript>
7. QueryExecute
CFScript.me Script Syntax
cfquery( ) {
writeOutput("select id, firstname, lastname
from userTable
where lastname = 'Jones'");
}
Note: queryExecute() is the preferred syntax but this syntax is easier to
convert generically
This syntax comes from using CFScript.me to convert tag syntax to one
form of script syntax
8. QueryExecute
New Script Syntax
queryExecute( sql_stmt, queryParam, queryOptions);
Numbers =
(1) queryExecute(“
SELECT *
FROM art
WHERE artname like ‘%this%’
ORDER BY id“,
(2) {type={value=“number”, cfsqltype=“cf_sql_varchar”}},
or {value=“color”},
(3) {datasource = “scratch_mssql”}
);
9. QueryExecute
• This function simplifies the query execution in the CFScript block.
• This function lets you pass unnamed parameters to the query. Use '?'
(question mark) as the place-holder for the parameters. The values to
the parameters should be passed as an array toparams.
• If there are any Query parameters, they must be passed as the second
argument of the function. It can be either a struct or an array.
• If you need to provide additional attribute as a Query parameter (like
CFSQLType, list, and separator), you can pass these as struct against that
column name.
• The Query and datasource properties will be passed as the third argument.
10. QueryExecute
From Adobe Help
<cfset qoptions = {result="myresult", datasource="artGallery"}>
<cfset myquery = QueryExecute("select * from art where ARTID < 5", [] ,qoptions)>
<cfset myquery1 = QueryExecute("select * from art where ARTID < ?", [4] ,qoptions)>
<cfset myquery2 = QueryExecute("select * from art where ARTID < :artid and artistid=:aid
",
{artid={value=100}, aid=2} ,qoptions)>
Note: queryExecute is just a function so can be used in tags as well:
11. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Tag Syntax
<cfquery name=“qryResult”>
SELECT *
FROM Employees
</cfquery>
Script Syntax
qryResult = queryExecute(
"SELECT * FROM Employees“
);
12. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Parameters using Structure Syntax
Tag Syntax
<cfset country = “USA” />
<cfset empid = 1 />
<cfquery name=“qryResult”>
SELECT *
FROM Employees
WHERE empid = #empID#
AND country = #country#
</cfquery>
** Should use cfqueryparm
Script Syntax (Parameters using Struct)
qryResult = queryExecute(“
SELECT *
FROM Employees
WHERE empid = :empid
AND country = :country",
{country="USA", empid=1}
);
13. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Parameters using Array Syntax
Tag Syntax
<cfset country = “USA” />
<cfset empid = 1 />
<cfquery name=“qryResult”>
SELECT *
FROM Employees
WHERE empid = #empID#
AND country = #country#
</cfquery>
** Should use cfqueryparm
Script Syntax (Parameters using Array)
qryResult = queryExecute(“
SELECT *
FROM Employees
WHERE empid = ?
AND country = ?",
[1, “usa”]
);
14. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Parameters using Structs of Structs
Tag Syntax
<cfset country = “USA” />
<cfset empid = 1 />
<cfquery name=“qryResult”>
SELECT *
FROM Employees
WHERE empid = #empID#
AND country = #country#
</cfquery>
** Should use cfqueryparm
Script Syntax
qryResult =queryExecute(“
SELECT *
FROM Employees
WHERE empid = :empid
AND country = :country",
{country={value="USA",cfsqltype="cf_sql_varchar"},
empid={value=1, cfsqltype="cf_sql_integer"}
}
);
15. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Tag Syntax (Specify a datasource)
<cfquery name=“qryResult”
datasource = “myDatasourceName”>
SELECT *
FROM Employees
</cfquery>
Script Syntax (Specify a datasource)
qryResult = queryExecute(“
SELECT *
FROM Employees",
{},
{datasource= "myDataSourceName"}
);
16. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Tag Syntax (query with a subquery)
<cffunction name=“getEqMfg” returntype=“query” access=“public”>
<cfargument name=“dc” cfsqltype=“string” required=“true”>
<cfquery name=“ml” datasource=“myDSN”>
Select name, mfgCode, country
From mfgdetails_tbl
Where mfgcode in (
Select mfgCode
From mfg2devices_tbl
Where deviceCode =
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.dc#“
maxlength=“5”> )
Order By country, name
</cfquery>
<cfreturn ml >
</cffunction>
Script Syntax (query with a subquery)
public query function getEqMfg(required string dc){
var ml = queryExecute(“
Select name, mfgCode, country
From mfgdetails_tbl
Where mfgcode in (
Select mfgCode
From mfg2devices_tbl
Where deviceCode = :dcp
)
Order By country, name",
{dcp={value="dc",cfsqltype="CF_SQL_VARCHAR", maxlength=5 }},
{datasource = “myDSN”}
);
return ml;
}
17. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Tag Syntax
(Return a number/count or maxRows)
<cfquery name=“dsc”>
Select count(*) as qty
From generic_view”
</cfquery>
<cfquery name=“sc” maxrows=“#rc#”>
Select specialtyname, qty
From generic_view
Order by qty DESC, specialtyname
</cfquey>
Script Syntax
(Return a number/count or maxRows)
public numeric function getSpecialtyCount(){
var dsc = queryExecute("Select Count(*) as qty
From specialtycategorycount_view");
return dsc.qty;
}
query function getSpecialtyCodeChartData(required numeric rc=99){
var sc = queryExecute("Select specialtyname, qty
From specialtycategorycount_view
Order by qty DESC, specialtyname",
{},
{maxrows = "rc"});
return sc;
}
18. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
If you want to add if logic into your
query (just example logic):
Savecontent variable=“sql”{
SELECT *
FROM words
<cfif structKeyExists(URL, "type")>
WHERE type = :type
<cfset params = {type={value=URL.type,
cfsqltype="CF_SQL_VARCHAR"}}>
<cfelse>
<cfset params = {}>
</cfif>
ORDER BY id
}
Once you add the sql statement into a
saveContent/variable, just add the variable
name into the queryExecute statement:
numbers = queryExecute(sql,
params,
{datasource=“dsnName”});
19. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
public query function select ( struct criteria={} ) {
var SQLs = ‘’; var SQLw = ‘’; var SQLParams = {};
SQLs = "SELECT id, firstName, lastName, address1, city, state, zip, phoneNbr, email, active
FROM userTable";
SQLw = structIsEmpty( criteria ) ? "WHERE 1=0 " : "WHERE 1=1 ";
if ( structKeyExists( criteria, "lastName" ) ) {
SQLw &= "AND lastName = :lastName ";
SQLParams.append( { lastName={ value=criteria.lastName, cfsqltype="cf_sql_varchar", list=true } } );
}
if ( structKeyExists( criteria, "state" ) ) {
SQLw &= "AND state in (:state) ";
SQLParams.append( { state={ value=criteria.state, cfsqltype="cf_sql_varchar", list=true } } );
}
SQLs &= SQLw & " ORDER BY state DESC, lastName DESC";
return queryExecute( SQLs, SQLParams, { datasource=myDatasource } );
} }
20. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Different Select QueryExecute Syntax (borrowed from CFVonner)
public query function getAllBeers () {
return queryExecute(
"SELECT be.id
,be.breweryId
,be.name
,br.name AS breweryName
,be.type
,be.abv
,be.ibu
FROM Beer be
LEFT JOIN Brewery br ON be.breweryId = br.id
ORDER BY be.name ASC"
); // queryExecute equivalent to <cfquery>
}
public query function getBeer ( required numeric id ) {
return queryExecute(
"SELECT id
,breweryId
,name
,type
,abv
,ibu
FROM Beer
WHERE id = :id",
{ id = { value = arguments.id, cfsqltype = 'integer' } }
// equivalent to <cfqueryparam>
);
}
21. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Insert QueryExecute Syntax (borrowed from CFVonner)
var result = '';
queryExecute(
"INSERT INTO Beer
( name, breweryId, type, abv, ibu )
VALUES ( :name, :breweryId, :type, :abv, :ibu )",
{
name = { value = arguments.name, null = hs.isEmptyString( arguments.name ), cfsqltype = 'varchar' },
breweryId = { value = arguments.breweryId, null = hs.isEmptyString( arguments.breweryId ), cfsqltype =
'integer' },
type = { value = arguments.type, null = hs.isEmptyString( arguments.type ), cfsqltype = 'varchar' },
abv = { value = arguments.abv, cfsqltype = 'decimal' },
ibu = { value = arguments.ibu, cfsqltype = 'decimal' }
},
{ result = 'result'}
);
22. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Update QueryExecute Syntax (borrowed from CFVonner)
queryExecute(
"UPDATE Beer
SET name = :name
,breweryId = :breweryId
,type = :type
,abv = :abv
,ibu = :ibu
WHERE id = :id",
{
id = { value = arguments.id, cfsqltype = 'integer'},name = { value = arguments.name, null = hs.isEmptyString(
arguments.name ), cfsqltype = 'varchar' },
breweryId = { value = arguments.breweryId, null = hs.isEmptyString( arguments.breweryId ), cfsqltype =
'integer' },type = { value = arguments.type,
null = hs.isEmptyString( arguments.type ), cfsqltype = 'varchar' },
abv = { value = arguments.abv, cfsqltype = 'decimal' },
ibu = { value = arguments.ibu, cfsqltype = 'decimal' }
}
);
23. QueryExecute
queryExecute( sql_stmt, queryParam, queryOptions);
Delete QueryExecute Syntax (borrowed from CFVonner)
queryExecute(
"DELETE FROM Beer WHERE id = :id",
{ id={ value=arguments.id, cfsqltype='integer' } }
);
24. QueryExecute
For Review:
queryExecute( sql_stmt, queryParam, queryOptions);
Numbers =
(1) queryExecute(“
SELECT *
FROM art
WHERE artname like ‘%this%’
ORDER BY id“,
(2) {type={value=“number”, cfsqltype=“cf_sql_varchar”}},
or {value=“color”},
(3) {datasource = “scratch_mssql”}
);
27. Closures
• A Closure is a function which binds variable references at declaration
time not at use-time
• Callbacks are not Closures (inline callbacks are)
• That inner function has access to the var scope of the function it was
defined from. This is what a closure is. It knows about its origin and it
doesn't forget. It will always be tied to that same parent var scope.
28. Closures
From StackOverflow
https://softwareengineering.stackexchange.com/questions/285941/why-would-a-program-use-a-closure
Why write a closure? What specific task would a programmer be
performing that might be best served by a closure?
The purpose of closures is simply to preserve state; hence the name closure - it closes over state.
Closures allow you to instantiate functions.
Where closures really shine over other constructs is when using higher-order functions, when you
actually need to communicate state, and you can make it a one-liner…
OO is about data abstraction, and closures are the way to perform data abstraction.
29. Closures
From StackOverflow
Why write a closure? What specific task would a programmer be
performing that might be best served by a closure? Continued…
A couple of other examples:
Sorting
Most sort functions operate by comparing pairs of objects. Some comparison technique is needed. Restricting
the comparison to a specific operator means a rather inflexible sort. A much better approach is to receive a
comparison function as an argument to the sort function. Sometimes a stateless comparison function works
fine (e.g., sorting a list of numbers or names), but what if the comparison needs state?
Random numbers
The original rand() took no arguments. Pseudorandom number generators need state. Some (e.g., Mersenne
Twister) need lots of state. Even the simple but terrible rand() needed state. Read a math journal paper on a
new random number generator and you'll inevitably see global variables. That's nice for the developers of the
technique, not so nice for the callers. Encapsulating that state in a structure and passing the structure to the
random number generator is one way around the global data problem. This is the approach used in many non-
OO languages to making a random number generator reentrant. A closure hides that state from the caller. A
closure offers the simple calling sequence of rand() and the reentrancy of encapsulated state.
30. Closures
Example
A Classic jQuery Example of Closures:
$(function() {
var selections = [];
// this closure has access to the selections variable
$(".niners").click(function() {
// update the selections variable in the outer function's scope
selections.push (this.prop("name"));
});
});
31. Closures
javascript example (works in CF also)
Function outerFunction() {
var a = 3;
return function innerFunction(b){
var c = a + b;
return c;
}
}
(1) var foo = outerFunction()
(2) var result = foo(2);
(3) Console.log(result); //5
• We have an outer function with a
nested function which accepts a
parameter b
• (1)When you invoke the outer you
get the inner returned later.
• (2)Notice the outer function was
called but the a still has its value
and is used in the return function
(innerFunction).
• (3)That is why the result Is 5!
• http://taha-sh.com/blog/understanding-
closures-in-javascript
32. Closures
Example
var dwightSalary = (function() {
var salary = 60000;
function changeBy(amount) {
salary += amount;
}
return {
raise: function() {
changeBy(5000);
},
lower: function() {
changeBy(-5000);
},
currentAmount: function() {
return salary;
}
};
})();
alert(dwightSalary.currentAmount()); // $60,000
dwightSalary.raise();
alert(dwightSalary.currentAmount()); // $65,000
dwightSalary.lower();
dwightSalary.lower();
alert(dwightSalary.currentAmount()); // $55,000
dwightSalary.changeBy(10000) // TypeError:
undefined is not a function
33. Closures
ColdFusion Docs Example:
function helloTranslator(String helloWord) {
return function(String name) {
return "#helloWord#, #name#";
};
}
helloInHindi=helloTranslator("Namaste");
helloInFrench=helloTranslator("Bonjour");
writeoutput(helloInHindi("Anna"));
Namaste, Anna
writeoutput(helloInFrench("John"));
Bonjour, John
• In this case, using closure, two new functions are
created. One adds Namaste to the name. And the
second one adds Bonjour to the name.
• helloInHindi and helloInFrench are closures. They
have the same function body; however, store
different environments.
• The inner function is available for execution after
the outer function is returned. The outer function
returns the closure
• A closure is formed when the inner function is
available for execution. Meaning, it is formed when
it is defined, not when it is used.
34. Closures
• Ray Camden example (technically is, but more like a callback/inline function) :
Data = [“Neil Diamond”, “Depeche Mode”, “The Cure”, “Cher”, “Ace of Base”, “Frank
Sinatra”, The Church”];
arraySort(data, function(a,b){
var first = a;
var second = b;
first = replace(first, “The “, “”);
second = replace(second, “The “, “”);
return first gt second;
});
This code above will order the data array by names excluding THE.
Ace of Base, Cher, The Church, The Cure, Depeche Mode, Frank Sinatra, Neil Diamond
35. Closures
ColdFusion built in Functions that use Closures:
• CF10 Closure Functions:
• ArrayEach, StructEach
• ArrayFilter, StructFilter,ListFilter
• ArrayFindAt, ArrayFindAllNoCase
• CF11 Closure Functions:
• isClosure
• ArrayReduce, StructReduce, ListReduce
• ArrayMap, StructMap, ListMap
• CF 2016 added each, map, reduce & filter for Queries
36. Closures
Determines weather a value or expression
references a function via a function expression, as
opposed to a function statement.
isClosure(value)
square = function(x) {
return x * x;
};
writeDump(isClosure(square));
Answer: True
square = function(x) {
return x * x;
};
squared = square(5);
writeDump(isClosure(squared));
Answer: False
38. Closures
Example from Sean Corfield
Don’t look so much at all the details, but compare it to other simple examples of closures in this section, the next section and all the resources.
public numeric function createPendingMembershipAndTransaction( numeric amount, numeric rebillRate, any rate, string promocode, any user, any site,
string paymentAction = 'Rebilling', any adminUser = 0, string acct_type = "credit_card" ) {
return createPendingMembershipAndPartialTransaction(
amount, rebillRate, rate, promocode, user, site, paymentAction, adminUser,
"sbw",
function( string paymentAction, numeric amount, any tx ) {
var sbw = this.createSBWTransaction(
serviceType = paymentAction == "rebilling" ? "one_click" : lCase( paymentAction ),
acctType = acct_type,
billId = 0, // we'll update this after the sale
transactionId = tx.getId()
);
sbw.save();
}
);
}
39. Closures
Testbox: https://www.ortussolutions.com/product/testbox
• TestBox uses Closures
• Since the implementations of the describe()
and it() functions are closures, they can
contain executable code that is necessary to
implement the test. All ColdFusion rules of
scoping apply to closures, so please
remember them. We recommend always
using the variables scope for easy access and
distinction.
• A test suite begins with a call to our TestBox
describe() function with at least two
arguments: a title and a closure within the
life-cycle method called run(). The title is the
name of the suite to register and the function
is the block of code that implements the
suite.
function run() {
describe("A suite is a closure",
function() {
c = new Calculator();
it("and so is a spec", function() {
expect( c ).toBeTypeOf( 'component' );
});
});
}
40. Closures
Testbox: https://www.ortussolutions.com/product/testbox
• Show Example TestBox code.
• Describe – it
• Given – when - then
describe( “msg", function(){
scenario( "Get similar Orgs", function(){
given( "I have selected a specifc Orgname1", function(){
when( "I run the query …", function(){
then( "the result should be any other Orgs that have
similar names", function(){
expect( comOrgsVar.getLikeOrgNames('Orgname1
specific') ).toBeQuery();
});
});
});
});
})
41. Closures
• Some Example code online or resources:
• Sesame library inline functions/closures https://github.com/markmandel/Sesame
• Underscore.cfc ported from underscore.js https://github.com/russplaysguitar/UnderscoreCF
• TestBox gives the ability to use closures http://wiki.coldbox.org/wiki/TestBox.cfm
• Adam Tuttle presentation on closures
http://fusiongrokker.com/p/closures/#/
• Adam Cameron blog multiple Closure examples
http://blog.adamcameron.me/search/label/Closure
• JavaScript Closures Explained by Mailing a Package
https://medium.freecodecamp.com/javascript-closures-explained-by-mailing-a-package-
4f23e9885039#.y3xfusrpm
• Simple Closure example: http://ketanjetty.com/coldfusion/javascript/closures/
• Easy to follow JS Closure Example:
https://lawrencebarsanti.wordpress.com/2010/11/09/easy-to-follow-javascript-closure-
example/
42. Closures
• Ryan Guill example: https://github.com/ryanguill/emit/blob/master/lib/emit.cfc#L390
• Framework one use of Closures: https://github.com/framework-
one/fw1/blob/develop/framework/ioc.cfc#L100-L167
• Framework one example 2: https://github.com/framework-
one/fw1/blob/develop/framework/one.cfc#L1166-L1205
• Example from Sean Corfield:
https://gist.github.com/seancorfield/86e37a080df62a4c66db4075284de6d8
• Example from Sean Corfield #2:
https://gist.github.com/seancorfield/f6521edfb0b10ba406840080df58fff4
• Understanding JS closures: https://medium.com/dailyjs/i-never-understood-javascript-closures-
9663703368e8
44. Map, Reduce, Each, and Filter
• The map() functions iterate over the collection (be it a list, array or
struct), and returns a new object with an element for each of the ones in
the original collection. The callback returns the new element for the new
collection, which is derived from the original collection. It is important to
note that only the collections values are changed, it will still have the same
key/indexes.
• So it remaps the original collection
• ArrayMap, StructMap, ListMap, (query.map)
• The reduce() operation is slightly more complex. Basically it iterates over
the collection and from each element of the collection, derives one single
value as a result.
• ArrayReduce, StructReduce, ListReduce, (query.reduce)
45. Map and Reduce (and more)
• The Filter() function is similar to
map and reduce. It will iterate over
a given object and return a new
object but the original list is
unaffected. The callback returns a
Boolean to determine if the
element is returned in a new
object.
structEach(circles,function(key,value)
{
matchednames =
arrayfilter(value,function(obj)
{
return left(obj,1)=='d';
}
});
Example shows how to look at a struct
and if it begins with a D, return it.
46. Map and Reduce (and more)
• The each() function iterates over
a given object and calls a
callback for each element. This
can be used instead of a loop.
letters = ["a","b","c","d"];
arrayEach(letters, function()
{
writeDump(arguments);
});
Struct 1 a
struct 1 b
struct 1 c
struct 1 d
49. Map and Reduce (and more)
• ArrayMap Example ( next few examples from Adam Cameron):
dcSports = ["Redskins", "Capitals", "Nationals", "Wizards", "United"];
colourInList = arrayMap(dcSports, function(v,i,a){
return replace(a.toList(), v, ucase(v) );
}
);
writeDump([dcSports,colourInList]);
Will see an array of dcSports with 7 items each showing the next in the row all caps:
REDSKINS,Capitals,Nationals,Wizards,United
Redskins,CAPITALS,Nationals,Wizards,United
Redskins,Capitals,NATIONALS,Wizards,United
50. Map and Reduce (and more)
• StructMap()
original = {"one"={1="redskins"},"two"={2="capitals"},"three"={3="nationals"},"four"={4="wizards"}};
fixed = structMap(original, function(k,v)
{
return v[v.keyList()];
});
writeDump([ original, fixed]);
This just returns the digit as a key and sports team as a value
1 wizards
2 redskins
3 nationals
4 capitals
51. Map and Reduce (and more)
• listMap()
dcSports = "Redskins,Capitals,Nationals,Wizards,United";
externalList = "";
reverseSports = listMap( dcSports, function(v,i,l)
{
var newValue = "#i#:#v.reverse()#";
externalList = externalList.append(newValue);
return newValue;
});
writeDump([{dcSports=dcSports},{reverseSports=reverseSports},{externalList=externalList}]);
This should reverse the dcSports list and show it backwards with index.
1:sniksdeR,2:slatipaC,3:slanoitaN,4:zdraziW,5:detinU
52. Map and Reduce (and more)
colours = queryNew("id,en,mi", "integer,varchar,varchar", [
[1,"red","whero"],
[2,"orange","karaka"],
[3,"yellow","kowhai"],
[4,"green","kakariki"],
[5,"blue","kikorangi"],
[6,"indigo","poropango"],
[10,"violet","papura"]
]);
maoriColours = colours.map(function(colour, index, colours){
return {mi=colour.mi};
}, queryNew("mi","varchar"));
writeDump(var=maoriColours);
Notice that map takes a second argument which
Is a second query. This acts as a template for the
Remapped query.
55. Map and Reduce (and more)
• arrayReduce()
dcSports = ["Redskins", "Capitals", "Nationals", "Wizards", "United"];
ul = arrayReduce(dcSports, function(previousValue, value)
{
return previousValue & "<li>#value#</li>";
}, "<ul>"
) & "</ul>";
writeOutput(ul);
Result is just the Array turned into a list
• Redskins
• Capitals
• Nationals
• Wizzards
• United
56. Map and Reduce (and more)
• structReduce() -- StructReduce(struct, function(result, key, value [,struct]), initialVal)
rainbow = { "Red"= "Rojo", "Orange"= "Anaranjado", "Yellow"= "Amarillo", "Green"= "Verde" };
dl = structReduce( rainbow, function(previousValue, key, value)
{
return previousValue & "<dt>#key#</dt><dd>#value#</dd>";
}, "<dl>"
) & "</dl>";
writeOutput(dl);
Result is a two column list of the key and the value: Red Rojo
Red
Rojo
Orange
Anaranjado
Yellow
Amarillo
Green
Verde
57. Map and Reduce (and more)
Struct Reduce using member function syntax compared to same approach using loop (stack overflow question)
myStruct = { 'age'=24, 'hair'='Blond', 'sex'='female', 'height'='5 foot 5 inches’ };
CF9 compat, convert data to array and use delimiter to add commas
myArray = [];
for( key in myStruct ) {
arrayAppend( myArray, key & ' : ' & myStruct[ key ] );
}
writeOutput( arrayToList( myArray, ', ' ) );
Modern CFML. Use struct reduction closure to convert each key into an aggregated array which is then turned
into a list.
writeOutput( myStruct.reduce( function(r,k,v,s){
return r.append( k & ' : ' & s[ k ] );
}, [] ).toList( ', ' ) );
Answer for both examples above: hair : Blond, sex : female, height : 5 foot 5 inches, age : 24
58. Map and Reduce (and more)
• listReduce()
numbers = "1,2,3,4,5,6,7,8,9,10";
sum = listReduce(numbers, function(previousValue, value)
{
return previousValue + value;
}, 0);
writeOutput("The sum of the digits #numbers# is #sum#<br>");
The sum of the digits 1,2,3,4,5,6,7,8,9,10 is 55
59. Map and Reduce (and more)
week = queryNew("id,en,mi", "integer,varchar,varchar", [
[1,"Monday", "lunes"],
[2,"Tuesday", "martes"],
[3,"Wednesday", "miercoles"],
[4,"Thursday", "jueves"],
[5,"Friday", "vernes"],
[6,"Saturday", "sabado"],
[7,"Sunday", "domingo"]
]);
shortestMaoriDayName = week.reduce(function(shortest,number){
if (shortest.len() == 0) return number.mi;
return number.mi.len() < shortest.len() ? number.mi : shortest;
}, "");
writeOutput(shortestMaoriDayName);
Result (which spanish name is the smallest)
notice it is using the elvis operator:
lunes
60. Map and Reduce (and more)
Filter()
arrayFilter(
array,function(arrayElement,
[,index, array])
{return true|false;}
);
Note: CF 11 - the callback functions of all the
filters have access to the entire
array/list/struct apart from the current
element
• ArrayFilter
Filtered =
arrayFilter([“myNewBike”, “oldBike”], function(item)
{
return len(item) > 8;
});
Answer
=> [1]
63. Map and Reduce (and more)
listFilter(
list,function(listElement)
{return true|false;}
);
numbers = "1,2,3,4";
odds = listFilter(numbers, function(v){
return v MOD 2;
});
writeDump([odds=odds]);
Answer (ordered struct)
Odds 1,3
64. Map and Reduce (and more)
queryFilter(
query,function
);
teams = queryNew("id,en,mi", "integer,varchar,varchar", [
[1, "Washington", "Redskins"],
[2, "Washington", "Nationals"],
[3, "Washington", "Wizzards"]
]);
teamsWithoutK = teams.filter(function(teams, index, query){
return !teams.mi.find('k');
});
writeDump(teamsWithoutK);
Answer
Returns a query of teams that do not have a K in the name
68. Map and Reduce (and more)
listEach
listEach(
string,
function(string, delimeter)
{
}
);
listS = “Redskins, Nationals, Wizzards”;
listEach(listS, xClosure);
Function xClosure(empname, index)
{
writeoutput(empname & “ at index:” & index & “<br>”);
};
Answer:
Redskins at index: 1
Nationals at index: 2
Wizzards at index: 3
69. Map and Reduce (and more)
queryEach
queryEach(
query,
function
);
teams = queryNew("id,en,mi", "integer,varchar,varchar", [
[1, "Washington", "Redskins"],
[2, "Washington", “Nationals"],
[3, "Washington", "Wizzards"]
]);
function printQuery(any Obj){
WriteDump(Obj); }
WriteOutput("QueryEach: ");
QueryEach(teams, printQuery);
Answer:
Redskins
Nationals
Wizzards
70. Map and Reduce (and more)
• Resources
• map and reduce & more with adam: http://blog.adamcameron.me/2014/02/coldfusion-11-map-and-reduce.html
• map reduce: https://hacks.mozilla.org/2015/01/from-mapreduce-to-javascript-functional-programming/
• js working example of each: http://elijahmanor.com/reducing-filter-and-map-down-to-reduce/
• ColdFusion 2016 query iterations: http://blog.adamcameron.me/2016/02/coldfusion-2016-query-iteration.html
• Map/reduce and higher order functions: http://ryanguill.com/functional/higher-order-functions/2016/05/18/higher-
order-functions.html
• Member functions: https://cfdocs.org/member
71. Final Thoughts/Resources
• These topics were only some more modern concepts for CFML.
• Where to get more information from CFML Community
• Adobe Wiki/help docs
• CFDocs.org
• Cfblogger (put in aggregator like feedly)
• Slack Channel – 2000+ cfml users https://cfml.slack.com/
• Trycf.com (place to run examples)
• CFScript.me (convert tag – script)
• Twitter, Facebook, youTube, Vimeo and other social sites
Dan Fredericks @fmdano74 fmdano@gmail.com
I am on most social networks, twitter, facebook, G+, LinkedIn
Download Original Presentation: http://bit.ly/2cIjXuI
Special Thanks to Carl Von Stetten, Adam Cameron, Adam Tuttle, Ray Camden, Sean Corfield, and Brad Wood for examples