I have a query running to gather an adjacency list and then generate an XML object of that list as a tree. Next I need to output that tree as a simple HTML.
I would like my output of XML document to be:
<ul>
<li margin="5">Title
<ul>
<li margin="10">Title</li>
</ul>
</li>
</ul>
Here is what I have coded so far:
<cfquery name="nodeTable" datasource="#database.ds#">
SELECT [mc_location].[id],[mc_location].[title], [mc_location].[parent_id] FROM [mc_location]
LEFT JOIN [mc_location_type] ON [mc_location].[id] = [mc_location_type].[location_id]
WHERE [mc_location_type].[category] = 'staff'
</cfquery>
<cffunction name="outputChildNodes" access="public" returntype="void" output="true">
<cfargument name="nodeTable" type="query" required="true" hint="I am the node query object."/>
<cfargument name="parent_id" type="numeric" required="false" default="0"/>
<cfset var local = {}/>
<cfquery name="local.childNodes" dbtype="query">
SELECT id, parent_id, title
FROM arguments.nodeTable
WHERE parent_id = <cfqueryparam value="#arguments.parent_id#" cfsqltype="cf_sql_integer" />
ORDER BY id ASC
</cfquery>
<cfloop query="local.childNodes">
<child id="#local.childNodes.id#" parent-id="#local.childNodes.parent_id#" name="#local.childNodes.title#">
<cfset outputChildNodes(arguments.nodeTable, local.childNodes.id)/>
</child>
</cfloop>
<cfreturn/>
</cffunction>
<!--- Build the node XML document recursively. --->
<cfxml variable="nodeTree">
<childern>
<!--- Output the root-level nodes. --->
<cfset outputChildNodes( nodeTable ) />
</childern>
</cfxml>
<!--- Render the XML document. --->
<cfloop index="childern" array="#nodeTree.childern#">
<cfloop index="child" array="#childern#">
<cfif isStruct(child.XmlAttributes)>
<cfdump var="#child[1].XmlAttributes#"/>
</cfif>
</cfloop>
</cfloop>
Thank you!
The problem I was experiencing had to do with not properly defining variable scopes (e.g. using "var" in cfset, using arguments.parameter, etc.), which was necessary in order to recursively call a function. Presented below is a brief solution.
<!--- query for parent child tree --->
<cfquery name="tree_nodes" datasource="#sonis.ds#">
SELECT [location].[id],[location].[title], [location].[parent_id] FROM [location]
LEFT JOIN [location_category] ON [location].[id] = [location_category].[location_id]
WHERE [location_category].[category] = 'staff'
</cfquery>
<!--- build tree from adjacency list function --->
<cffunction name="build_tree" access="public" output="true">
<cfargument var name="tree_nodes" type="query" required="true"/>
<cfargument var name="parent_id" type="numeric" required="false" default="0"/>
<cfargument var name="depth" type="numeric" required="false" default="0"/>
<cfset var local = {}/>
<cfquery name="local.child_node" dbtype="query">
SELECT id, parent_id, title
FROM arguments.tree_nodes
WHERE parent_id = <cfqueryparam value="#arguments.parent_id#" cfsqltype="cf_sql_integer" />
ORDER BY id ASC
</cfquery>
<cfset var branch = {}/>
<cfset var counter = 1/>
<cfloop query="local.child_node">
<cfset local.depth = arguments.depth/>
<cfset branch[counter++] = {
'id' = '#local.child_node.id#',
'title' = '#local.child_node.title#',
'parent_id' = '#local.child_node.parent_id#',
'depth' = local.depth,
'children' = build_tree(arguments.tree_nodes, local.child_node.id,++local.depth)
} />
</cfloop>
<cfreturn branch/>
</cffunction>
<!--- print tree as select box function --->
<cffunction name="print_tree_select" access="public" output="true">
<cfargument var name="tree" type="struct" required="true"/>
<cfargument var name="selected" type="numeric" required="false" default="0"/>
<cfargument var name="child" type="numeric" required="false" default="0"/>
<cfif child eq '0'><select name="select_tree"><option value="null"></option></cfif>
<cfloop from="1" to="#StructCount(arguments.tree)#" index="a">
<option value="#arguments.tree[a]['id']#"<cfif #arguments.selected# eq #arguments.tree[a]['id']#> selected</cfif>>
<cfif #arguments.tree[a]['depth']# GT 0>
#RepeatString('--', arguments.tree[a]['depth'])#
</cfif>
#arguments.tree[a]['title']#
</option>
<cfif StructKeyExists(arguments.tree[a], 'children') AND StructCount(arguments.tree[a]['children']) GT 0>
#print_tree_select(arguments.tree[a]['children'],arguments.selected, 1)#
</cfif>
</cfloop>
<cfif child eq '0'></select></cfif>
</cffunction>
<!--- print tree as list function --->
<cffunction name="print_tree_list" access="public" output="true">
<cfargument var name="tree" type="struct" required="true"/>
<ul style="list-style-type: circle;">
<cfloop from="1" to="#StructCount(arguments.tree)#" index="local.i">
<li>
<cfform method="post" name="edit">
#arguments.tree[local.i]['title']#
<cfinput type="hidden" name="id" value="#arguments.tree[local.i]['id']#"/>
<cfinput type="Submit" name="command" value="Edit"/>
</cfform>
<cfif StructKeyExists(arguments.tree[local.i], 'children') AND StructCount(arguments.tree[local.i]['children']) GT 0>
#print_tree_list(arguments.tree[local.i]['children'])#
</cfif>
</li>
</cfloop>
</ul>
</cffunction>
working on REST web-service, i don't have much experience coldfusion web-services.It is very basic web-service.Please if you guys can point me, what im doing wrong. it will be great help.
Application Server : Lucee 4.5.2.018 (Linux)
Please find below my code.
Component-Function/ Web-Service.
<cfcomponent rest="true" restpath="/hello">
<cffunction name="formPost" access="remote" returnType="struct" httpMethod="POST" restPath="/name" hint="POST Method" produces="application/json">
<cfargument name="firstname" type="String" restArgSource="Form">
<cfargument name="lastname" type="String" restArgSource="Form">
<cfset myStruct = structnew()>
<cfset myStruct.FirstName = firstname>
<cfset myStruct.LastName = lastname>
<cfquery name="Qry" datasource="myDSN">
select col1,col2 from myTableData
</cfquery>
<cfset myJsonVar = serializeJSON(Qry) />
<cfreturn myJsonVar>
</cffunction>
</cfcomponent>
Calling web-service
<cfhttp url="http://mydev:8888/rest/Example/hello/name" method="POST" result="res" port="8888" >
<cfhttpparam type="header" name="Accept" value="application/json">
<cfhttpparam type="formfield" name="firstname" value="Dan">
<cfhttpparam type="formfield" name="lastname" value="Gates">
</cfhttp>
<cfdump var="#res#">
Problem:
When defining returnType="struct" Error string can't cast String [{"COLUMNS":["COL1","COL2"],"DATA":[["0","7777777"],["0","888888"]]}] to a value of type [struct]
When defining returnType="string" No error coming "{\"COLUMNS\":[\"COL1\",\"COL2\"],\"DATA\":[[\"0\",\"7777777\"],[\"0\",\"888888\"]]}"
Trying get [DATA] values in loop
<cfloop from="1" to="#ArrayLen(d.DATA)#" index="i">
<cfloop from="1" to=#ArrayLen(d.DATA[i])# index="j">
<cfset resultSrt =d.COLUMNS[j]&" = " &d.DATA[i][j]>
#resultSrt#<br>
</cfloop>
</cfloop>
Message: No matching property [DATA] found in [string]
Stacktrace:The Error Occurred in
/opt/lucee/tomcat/webapps/ROOT/calling.cfm: line 52
50:
51:
52: <cfloop from="1" to="#ArrayLen(d.DATA)#" index="i">
53: <cfloop from="1" to=#ArrayLen(d.DATA[i])# index="j">
54: <cfset resultSrt =d.COLUMNS[j]&" = " &d.DATA[i][j]>
First of all since you are returning a query, you should set returnType to Query.
If you have set produces attribute of cffunction to application/json, in that case you don't need to perform explicit JSON serialization while returning data. ColdFusion will automatically do it for you. You can just write:
<cfreturn Qry />
To read the result returned from the service you need to deserialize the data. Like this:
<cfdump var="#deserializeJson(res.filecontent)#">
I have the following JSON response and am really lost on how to insert that into a ColdFusion query using a loop.
The response is like this:
{
"status":"OK",
"data":{
"group_id":1522413460,
"0":{
"id":"1522413460-1",
"customid":"",
"customid1":"",
"customid2":"",
"mobile":"0000000000",
"status":"AWAITED-DLR"
},
"1":{
"id":"1522413460-2",
"customid":null,
"customid1":null,
"customid2":null,
"mobile":"0000000000",
"status":"AWAITED-DLR"
},
"2":{
"id":"1522413460-3",
"customid":null,
"customid1":null,
"customid2":null,
"mobile":"0000000000",
"status":"AWAITED-DLR"
},
"3":{
"id":"1522413460-4",
"customid":null,
"customid1":null,
"customid2":null,
"mobile":"",
"status":"INV-NUMBER"
}
},
"message":"Campaign of 4 numbers Submitted successfully."
}
I am using a jsondecode function from cflib to decode the response of JSON into a nested structure:
<cffunction name="jsonencode" access="remote" returntype="string" output="No" hint="Converts data from CF to JSON format">
<cfargument name="data" type="any" required="Yes" />
<cfargument name="queryFormat" type="string" required="No" default="query" /> <!-- query or array -->
<cfargument name="queryKeyCase" type="string" required="No" default="lower" /> <!-- lower or upper -->
<cfargument name="stringNumbers" type="boolean" required="No" default=false >
<cfargument name="formatDates" type="boolean" required="No" default=false >
<cfargument name="columnListFormat" type="string" required="No" default="string" > <!-- string or array -->
<cfset var jsonString = "" />
<cfset var tempVal = "" />
<cfset var arKeys = "" />
<cfset var colPos = 1 />
<cfset var i = 1 />
<cfset var column = ""/>
<cfset var datakey = ""/>
<cfset var recordcountkey = ""/>
<cfset var columnlist = ""/>
<cfset var columnlistkey = ""/>
<cfset var dJSONString = "" />
<cfset var escapeToVals = "\\,\"",\/,\b,\t,\n,\f,\r" />
<cfset var escapeVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#" />
<cfset var _data = arguments.data />
<!--- BOOLEAN --->
<cfif IsBoolean(_data) AND NOT IsNumeric(_data) AND NOT ListFindNoCase("Yes,No", _data)>
<cfreturn LCase(ToString(_data)) />
<!--- NUMBER --->
<cfelseif NOT stringNumbers AND IsNumeric(_data) AND NOT REFind("^0+[^\.]",_data)>
<cfreturn ToString(_data) />
<!--- DATE --->
<cfelseif IsDate(_data) AND arguments.formatDates>
<cfreturn '"#DateFormat(_data, "medium")# #TimeFormat(_data, "medium")#"' />
<!--- STRING --->
<cfelseif IsSimpleValue(_data)>
<cfreturn '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"' />
<!--- ARRAY --->
<cfelseif IsArray(_data)>
<cfset dJSONString = createObject('java','java.lang.StringBuffer').init("") />
<cfloop from="1" to="#ArrayLen(_data)#" index="i">
<cfset tempVal = jsonencode( _data[i], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat ) />
<cfif dJSONString.toString() EQ "">
<cfset dJSONString.append(tempVal) />
<cfelse>
<cfset dJSONString.append("," & tempVal) />
</cfif>
</cfloop>
<cfreturn "[" & dJSONString.toString() & "]" />
<!--- STRUCT --->
<cfelseif IsStruct(_data)>
<cfset dJSONString = createObject('java','java.lang.StringBuffer').init("") />
<cfset arKeys = StructKeyArray(_data) />
<cfloop from="1" to="#ArrayLen(arKeys)#" index="i">
<cfset tempVal = jsonencode( _data[ arKeys[i] ], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat ) />
<cfif dJSONString.toString() EQ "">
<cfset dJSONString.append('"' & arKeys[i] & '":' & tempVal) />
<cfelse>
<cfset dJSONString.append("," & '"' & arKeys[i] & '":' & tempVal) />
</cfif>
</cfloop>
<cfreturn "{" & dJSONString.toString() & "}" />
<!--- QUERY --->
<cfelseif IsQuery(_data)>
<cfset dJSONString = createObject('java','java.lang.StringBuffer').init("") />
<!--- Add query meta data --->
<cfif arguments.queryKeyCase EQ "lower">
<cfset recordcountKey = "recordcount" />
<cfset columnlistKey = "columnlist" />
<cfset columnlist = LCase(_data.columnlist) />
<cfset dataKey = "data" />
<cfelse>
<cfset recordcountKey = "RECORDCOUNT" />
<cfset columnlistKey = "COLUMNLIST" />
<cfset columnlist = _data.columnlist />
<cfset dataKey = "data" />
</cfif>
<cfset dJSONString.append('"#recordcountKey#":' & _data.recordcount) />
<cfif arguments.columnListFormat EQ "array">
<cfset columnlist = "[" & ListQualify(columnlist, '"') & "]" />
<cfset dJSONString.append(',"#columnlistKey#":' & columnlist) />
<cfelse>
<cfset dJSONString.append(',"#columnlistKey#":"' & columnlist & '"') />
</cfif>
<cfset dJSONString.append(',"#dataKey#":') />
<!--- Make query a structure of arrays --->
<cfif arguments.queryFormat EQ "query">
<cfset dJSONString.append("{") />
<cfset colPos = 1 />
<cfloop list="#_data.columnlist#" delimiters="," index="column">
<cfif colPos GT 1>
<cfset dJSONString.append(",") />
</cfif>
<cfif arguments.queryKeyCase EQ "lower">
<cfset column = LCase(column) />
</cfif>
<cfset dJSONString.append('"' & column & '":[') />
<cfloop from="1" to="#_data.recordcount#" index="i">
<!--- Get cell value; recurse to get proper format depending on string/number/boolean data type --->
<cfset tempVal = jsonencode( _data[column][i], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat ) />
<cfif i GT 1>
<cfset dJSONString.append(",") />
</cfif>
<cfset dJSONString.append(tempVal) />
</cfloop>
<cfset dJSONString.append("]") />
<cfset colPos = colPos + 1 />
</cfloop>
<cfset dJSONString.append("}") />
<!--- Make query an array of structures --->
<cfelse>
<cfset dJSONString.append("[") />
<cfloop query="_data">
<cfif CurrentRow GT 1>
<cfset dJSONString.append(",") />
</cfif>
<cfset dJSONString.append("{") />
<cfset colPos = 1 />
<cfloop list="#columnlist#" delimiters="," index="column">
<cfset tempVal = jsonencode( _data[column][CurrentRow], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat ) />
<cfif colPos GT 1>
<cfset dJSONString.append(",") />
</cfif>
<cfif arguments.queryKeyCase EQ "lower">
<cfset column = LCase(column) />
</cfif>
<cfset dJSONString.append('"' & column & '":' & tempVal) />
<cfset colPos = colPos + 1 />
</cfloop>
<cfset dJSONString.append("}") />
</cfloop>
<cfset dJSONString.append("]") />
</cfif>
<!--- Wrap all query data into an object --->
<cfreturn "{" & dJSONString.toString() & "}" />
<!--- UNKNOWN OBJECT TYPE --->
<cfelse>
<cfreturn '"' & "unknown-obj" & '"' />
</cfif>
</cffunction>
Update #1: with DeserializeJSON, I get the following screen shot. If I loop over results called data, how to nest the inside ones?
JSON / CFML - Looping over an array of structs
I asked something similar recently.
Looks like you have an array of structs. You can deserialize the JSON as others have described and loop through it as shown in my link.
Edit just for clarity's sake
Here's the code that worked for me. I've edited out one step since the response you're getting doesn't seem to contain encoded characters.
<cfset requestBody = #(toString(getHttpRequestData().content)/>
<cfset ArrayOfStructs = deserializeJson(requestBody)>
<cfloop array="#ArrayOfStructs#" index="i">
<cfquery name="doodoodoo" datasource="CRM">
INSERT INTO TimeAppTest
(
EmployeeID,
lat,
long,
TimoStampo
)
VALUES
(
'#i.barcode#',
'#i.lat#',
'#i.long#',
'#i.time#'
)
</cfquery>
</cfloop>
The JSON was something like so, explaining the different variable names.
{"barcode":"CSS1035","scannerID":"3e81b04aa521a05e","time":"2015-08-11 08:30:27.232","lat":32.4001579,"long":-110.0403455},
{"barcode":"CSS1959","scannerID":"3e81b04aa521a05e","time":"2015-08-11 08:30:29.366","lat":32.4001579,"long":-110.0403455},
{"barcode":"CSS1649","scannerID":"3e81b04aa521a05e","time":"2015-08-11 08:30:31.642","lat":32.4001579,"long":-110.0403455}
use DeserializeJSON() to convert to a struct result.
loop through the result.data with <cfloop>
use <cfquery> to construct a SQL INSERT statement, pass values by <cfqueryparam>
ColdFusion doc:
https://wikidocs.adobe.com/wiki/display/coldfusionen/Home
I'm trying to create pagination for search results using MySQL and ColdFusion. My intention is to only retrieve the queries that can be displayed on a single page, thus making the process efficient. I tried using two queries in my function, but I could not return two variables to the cfinvoke.
The following code does not paginate, but it displays the result search results using a CFC:
<!---DEFINE DEFAULT STATE--->
<cfparam name="variables.searchResponse" default="">
<cfparam name="URL.titleName" default="">
<cfparam name="URL.genreID" default="">
<cfparam name="URL.platformID" default="">
<!---TitleName can only be blank if one or both genre and platform are selected--->
<cfif StructKeyExists(URL, "searchQuery") AND (Len(Trim(URL.titleName)) LTE 2 AND Len(URL.genreID) IS 0 AND Len(URL.platformID) IS 0)>
<cfset variables.searchResponse = "invalidString">
<cfelseif StructKeyExists(URL, "searchQuery")>
<cfinvoke component="gz.cfcomp.test" method="searchGames" returnvariable="resultData" argumentcollection="#URL#">
<cfset variables.searchResponse = "hasResult">
</cfif>
<cfif searchResponse EQ "hasResult" AND resultData.RecordCount EQ 0>
<cfset variables.searchResponse = "noResult">
</cfif>
Using this logic, I can display what I need to display on the page:
<cfif searchResponse EQ "invalidString">
<cfoutput>Invalid search</cfoutput>
</cfif>
<cfif searchResponse EQ "noResult">
<cfoutput>No results found</cfoutput>
</cfif>
<cfif searchResponse EQ "hasResult">
<cfoutput>Display Results</cfoutput>
</cfif>
If I were executing the queries on the same page, it would be easy to follow the many tutorials out there. But the queries are executing in a function. Displaying the data is easy, but paginating it has become a nightmare for me. Here is my function:
<cffunction name="searchGames" access="public" output="false">
<cfargument name="titleName" required="no" type="string">
<cfargument name="genreID" required="no" type="string">
<cfargument name="platformID" required="no" type="string">
<!--- DEFINE LOCAL VARIABLES--->
<cfset var resultData = "">
<!---GET DATA--->
<cfquery name="resultData" datasource="myDSN">
SELECT *
<!---JOINS FOR GENRE/PLATFORM GO HERE--->
WHERE
<!---CONDITIONS GO HERE--->
</cfquery>
<!---RETURN VARIABLE--->
<cfreturn resultData>
</cffunction>
To paginate, I thought about modifying my function to the following (a new query using a count statement):
<!--- DEFINE LOCAL VARIABLES--->
<cfset var resultCount = "">
<!---GET DATA--->
<cfquery name="resultCount" datasource="myDSN">
SELECT COUNT(gameID) AS rowsFound FROM GAMES
<!---JOINS FOR GENRE/PLATFORM GO HERE--->
WHERE
<!---CONDITIONS GO HERE--->
</cfquery>
<!---RETURN VARIABLE--->
<cfreturn resultCount>
Then I figured if there is a result to return, I would execute a nested query and create the pagination variables:
<cfif resultCount.rowsFound GTE 0>
<cfparam name="pageNumber" default="1">
<cfset var recordsPerPage = 5>
<cfset var numberOfPages = Int(resultCount.RecordCount / recordsPerPage)>
<cfset var recordsToSkip = pageNumber * recordsPerPage - recordsPerPage>
<!---DEFINE LOCAL VARIABLE--->
<cfset var resultData = "">
<cfquery name="resultData" datasource="myDSN">
<!---GET DATA AND SEND IT BACK USING LIMIT WITH #recordsToSkip# and #RecordsPerPage#--->
</cfquery>
<!---RETURN VARIABLE--->
<cfreturn resultData>
</cffunction>
I figured I would return two variables: resultCount and resultData. I would use #resultCount# to build my pagination, and #resultData# to display the output. The problem is I can't return two variables in the same cfinvoke tag. Any ideas of how to approach the the right way? I'm totally lost as to the logic I need to follow.
EDIT: I'm using the following code to paginate now (the only problem is now I have to repass all the search filters back into the URL because using #CGI.SCRIPT_NAME# clears them):
<cfif searchResponse EQ "hasResult">
<!---BASICALLY, IF resultCount.rowsFound is not 0, execute this method--->
<cfinvoke component="gz.cfcomp.test" method="getResult" returnvariable="resultData" argumentcollection="#URL#">
<cfif URL.currentPage IS 1>
--
<cfelse>
Prev Page
</cfif>
<cfif URL.currentPage * recordsPerPage LT resultCount.rowsFound>
Next Page
<cfelse>
--
</cfif>
</cfif>
If your results is not huge, you can stay with the same SQL that returns everything and use
<cfoutput query="data" startrow="#url.start#" maxrows="#recordsPerPage#">
when you display it, see: http://www.coldfusionjedi.com/index.cfm/2006/4/24/ColdFusion-and-Pagination. No Query of Query is needed.
To answer your question
The problem is I can't return two
variables in the same cfinvoke tag.
WHY do you want to return two variables in the same cfinvoke? Instead, write 2 functions: countResult() and getResultData(page, RecordsPerPage)
<cffunction name="countResult" output="false" returntype="numeric">
<cfset var resultCount = "">
<cfquery name="resultCount" datasource="myDSN">
SELECT COUNT(gameID) AS rowsFound FROM GAMES
<!---JOINS FOR GENRE/PLATFORM GO HERE--->
WHERE
<!---CONDITIONS GO HERE--->
</cfquery>
<cfreturn resultCount.rowsFound>
</cffunction>
For getResultData(page, RecordsPerPage) using true paging in DB level:
If you want to do true pagnation in DB level, use LIMIT and OFFSET in MySQL.
<cffunction name="getResultData" output="false" returntype="Query">
<cfargument name="page" type="numeric" default="1">
<cfargument name="recordsPerPage" type="numeric" default="5">
<cfset var resultData = "">
<cfset var offset = (page-1) * RecordsPerPage>
<cfquery name="resultData" datasource="myDSN">
SELECT * LIMIT #recordsPerPage# OFFSET #offset#
<!---JOINS FOR GENRE/PLATFORM GO HERE--->
WHERE
<!---CONDITIONS GO HERE--->
</cfquery>
<cfreturn resultData>
</cffunction>
To figure out how many pages there are:
totalNumOfPages = ceiling(countResult() / recordsPerPage);
Any other question?
Rather than have two functions and two database calls, I've done it like this before (not in MySQL however):
<cffunction name="getResultData" output="false" returntype="Query">
<cfargument name="page" type="numeric" default="1">
<cfargument name="recordsPerPage" type="numeric" default="5">
<cfset var resultData = "">
<cfset var offset = (page-1) * RecordsPerPage>
<cfquery name="resultData" datasource="myDSN">
SELECT *,
(
SELECT COUNT(gameID) AS rowsFound
FROM
<!---JOINS FOR GENRE/PLATFORM GO HERE--->
WHERE
<!---CONDITIONS GO HERE--->
) AS rowsFound
LIMIT #recordsPerPage# OFFSET #offset#
<!---JOINS FOR GENRE/PLATFORM GO HERE--->
WHERE
<!---CONDITIONS GO HERE--->
</cfquery>
<cfreturn resultData>
</cffunction>
It adds a column to the returned recordset called 'rowsFound'.
Not very normalized, but not a big deal. Might be worth it to minimize the DB hits.
I think it's referred to as 'subquery as a scalar operand':
http://dev.mysql.com/doc/refman/5.1/en/scalar-subqueries.html
Tony
I have a Function in CFC file, which will be called from .cfm file like below
<cffunction name="cftest" access="public" returntype="query" output="true" hint="Function returns Records">
<cfquery name="qryTest" datasource="DBTest">
select * from emp_tab;
</cfquery>
<cfreturn selectRecordsResultSet />
</cffunction>
How can I handle DB Exception using cftry? as this is returning Query, Is it possible to catch the DB Exception and pass the Details to the other page from where it is called?
Thanks
Here is an example of my usual implementation of this:
<cffunction name="getCurrentRecordsCount" access="public" output="false" returntype="any" hint="Get total history records count">
<cfargument name="filters" type="struct" required="false" default="#StructNew()#" hint="Filtering rules">
<cfset var qGetRecordCount = "" />
<cftry>
<cfquery datasource="#variables.dsn#" name="qGetRecordCount">
SELECT COUNT(*) AS cnt FROM ....
</cfquery>
<cfreturn qGetRecordCount.cnt />
<cfcatch type="any">
<cfreturn error(cfcatch.message, cfcatch.detail) />
</cfcatch>
</cftry>
</cffunction>
If you want to handle only database errors, change type to the database.
Errors handling and reporting performed using these three methods:
<cffunction name="error" access="private" output="false" returntype="boolean" hint="Set error status and message">
<cfargument name="message" type="string" required="true" hint="Error message text" />
<cfargument name="detail" type="string" required="false" default="" hint="Error detail text" />
<cfset variables.fError = true />
<cfset variables.fErrorText = arguments.message />
<cfif Len(arguments.detail)>
<cfset variables.fErrorText = variables.fErrorText & " [" & arguments.detail & "]" />
</cfif>
<cfreturn false />
</cffunction>
<cffunction name="gotError" access="public" output="false" returntype="boolean" hint="Return latest error flag state">
<cfreturn variables.fError />
</cffunction>
<cffunction name="getError" access="public" output="false" returntype="string" hint="Return latest error text and reset the flag">
<cfset var txt = variables.fErrorText />
<cfset variables.fError = false />
<cfset variables.fErrorText = "" />
<cfreturn txt />
</cffunction>
Please note that for methods with returntype="void" I use cfset instead of cfreturn:
<cfset error(cfcatch.message, cfcatch.detail) />
So in code I can do the following (cfscript):
// calculate filtered records count
totalLogCount = request.loggingService.getCurrentRecordsCount(filters);
// check if error was thrown
if (request.loggingService.gotError()) {
// report the error details somehow
WriteOutput(request.loggingService.getError());
}