Using cfloop with queryfilter function - coldfusion

I am new to ColdFusion and trying to use cfloop for the below code:
<cfscript>
var origRate = 0;
var toRate = 0;
rates = myQuery.filter(function (obj) {
return (obj.code == arguments.origCode || obj.code ==
arguments.toCode)
})
</cfscript>
I modified below, the original code and inserted the above new code to avoid the inline sql queries:
<cfquery name="rates" dbtype="query">
select code, rate
from myQuery
where code = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.origCode#" />
or code = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.toCode#" />
</cfquery>
I tried using cfloop without changing to the previous code as below but it is not working:
<cfloop query="rates">
<cfscript>
if (code == arguments.origCode) origRate = rate;
if (code == arguments.toCode) toRate = rate;
</cfscript>
</cfloop>
Once the second block of code was inserted by commenting out the first block of code above, it did not load the page. If anyone has an idea, I really appreciate it. Thank you in advance!

There were some missing details about the application and data, so I made a couple of assumptions. It appears that you have a query object that you want to filter and pull rates from for an origCode and a toCode. Without knowing more about your data structure and what you plan to do with it, I can only make some general suggestions. I still maintain that it would be much better to filter in the query, but I understand the limitation. Since you have to filter inside your application, both the bulk of the base data you initially return and the processing to filter those records will negatively impact the performance.
First thing I did was to set up a fake query object. This is where my first assumption comes into play. I assumed that your code won't be any duplicated in your table, and that the code will have a rate associated with it.
myQuery = queryNew(
"code, rate",
"integer, integer",
[
{ "code" : 1 , "rate" : 10 } ,
{ "code" : 2 , "rate" : 15 } ,
{ "code" : 3 , "rate" : 20 } ,
{ "code" : 4 , "rate" : 25 } ,
{ "code" : 5 , "rate" : 30 }
]
);
I would not recommend a Query of Query here, because it's a lot of overhead for something that can be accomplished fairly easily.
I created a function that you can pass in your origCode and the toCode, and it will return you a structure of the origRate and the toRate. I included some comments in the code, so you will be able to see what I was doing. The bulk of the function is using the filter() closure to filter the query records down. If you are able to filter through SQL, you'll be able to eliminate this block.
function returnNewRates( required Numeric origCode, required Numeric toCode ) {
local.ratesStruct = { "origRate":-1, "toRate":-1 } ;
// This will be our query. If we _have_ to use an existing query, pass it in and duplicate() it. (Pass by Reference!)
local.qry = duplicate( myQuery ) ;
/////////////
// Closure to filter the query. This should be done in SQL.
// https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-m-r/queryfilter.html
local.filteredQuery = qry
.filter( function (obj) {
return ( obj.code == origCode || obj.code == toCode ) ;
} ) ;
// Now assign new rates. NOTE: The query shouldn't return more than 2 rows. We can validate if needed.
for ( var r IN filteredQuery ) {
if( r.code == arguments.origCode ) { ratesStruct.origRate = r.rate ; }
if( r.code == arguments.toCode ) { ratesStruct.toRate = r.rate ; }
}
return ratesStruct ;
}
To assign the origRate and toRate, we first create a ratesStruct return value to hold the structure of the rates. After we filter our query, we just loop through those filtered results and check to see if the code in the row matches with our input variables. Another one of my assumptions was that the database would return no more than two records (one origCode and one toCode, or neither). If it is possible to return more than one row for a code, then the output codes will be overwritten by the last related row in the query. If there are other rows appropriate for sorting, then they can be used and only select the top row for the needed rate. I also defaulted the returned rates to a -1 to signify that no rate was found for the code. That can be changed if needed.
After that, I just ran a few tests to make sure we didn't get any wonkiness. Code is at https://trycf.com/gist/c3b87ca7c508562fd36f3ba6c73829c7/acf2016?theme=monokai.
And again, I think this can all probably be done within the database itself. Probably by giving you access to a stored procedure that you can pass origCode and toCode to.

If you are receiving an error about an invalid construct it is because the version of CF does not support the == operator. For Adobe ColdFusion, until recently the only supported equals operators have been eq, is or various comparison functions depending on the variables and intentions involved.
<cfloop query="rates">
<cfscript>
if (code eq arguments.origCode) origRate = rate;
if (code eq arguments.toCode) toRate = rate;
</cfscript>
</cfloop>

Related

cfscript and queryExecute() using like instead of equals

I'm curious if this is the correct method to use the like operator when using queryExecute() in a cfscript function.
if( len(arguments?.lastName) ){
local.sqlWhere & = " AND t_lastname LIKE :lName";
local.sqlParams.lName = { value : arguments.lastName & '%', cfsqltype:'cf_sql_varchar'};
};
Is it just appended like a string with & '%'?
I've just go through your issue. In coldfusion & symbol always concatenation the two string. So we could not able to use like that. Here I've wrote some sample code for you please check that. I hope it will more help full to wrote a script based query.
local.MyQry = "SELECT * FROM Users WHERE 1=1 ";
I've used same condition from you. Not sure about your conditions
if( len(arguments?.lastName) ){
local.MyQry &= " AND Email like :email"
}
Here concatenate the query with previous one if the condition is true. And mentioned :(colon as we are going to use as queryparam)
local.qry = new Query( datasource = 'your DB name' , sql = Local.MyQry);
if( len(arguments?.lastName) ){
local.qry.addParam( name="email", value="%#Arguments.email#%", cfsqltype="cf_sql_varchar");
}
return local.qry.execute();
You can give the % symbol here based on your scenario . Ex %#Arguments.email#. or %#Arguments.email#%
I hope this will help you more. Thanks

getting result metadata from coldfusion newQuery() in cfscript

Documentation on CFscript is a bit sparse in the docs, and searching for a cfscript specific answer gets lost in CF tag answers. So here's my question:
How do I get the result metadata from a query that was performed using script? Using tags I can add result="myNamedResultVar" to my cfquery. I can then refer to the query name for data, or myNamedResultVar for some metadata. However, now I'm trying to write everything in script, so my component is script based, top-to-bottom. What I'm ultimately after is the last inserted Id from a MySQL insert. That ID exists in the result metadata.
myNamedResultVar.getPrefix().generatedkey
Here's my query code:
public any function insertUser( required string name, required string email, required string pass ) {
// insert user
var sql = '';
var tmp = '';
var q = new query();
q.setDatasource( application.dsn );
q.addParam(
name='name'
,value='#trim( arguments.name )#'
,cfsqltype='CF_SQL_VARCHAR'
);
q.addParam(
name='email'
,value='#trim( arguments.email )#'
,cfsqltype='CF_SQL_VARCHAR'
);
q.addParam(
name='pass'
,value='#hashMyString( arguments.pass )#'
,cfsqltype='CF_SQL_VARCHAR'
);
sql = 'INSERT INTO
users
(
name
,email
,pass
,joined
,lastaccess
)
VALUES
(
:name
,:email
,:pass
,CURRENT_TIMESTAMP
,CURRENT_TIMESTAMP
);
';
tmp = q.execute( sql=sql );
q.clearParams();
}
How do I specify the result data? I've tried something like this:
...
tmp = q.execute( sql=sql );
var r = tmp.getResult();
r = r.getPrefix().generatedkey;
q.clearParams();
return r;
However, on an insert the getResult() returns a NULL as best I can tell. So the r.getPrefix().generatedkey does NOT work after an insert. I get r is undefined
You are getting the result property of the query first and then from that you are trying to get the prefix property in result. But this is not the case. You can directly get the prefix property and then the generated key like this:
tmp.getPrefix().generatedkey;
For reference you can check this blog entry: Getting the Generated Key From A Query in ColdFusion (Including Script Based Queries)
after some futzing... THIS seems to work
... tmp = q.execute( sql=sql );
var r = tmp.getPrefix( q ).generatedkey;
q.clearParams();
return r;

QueryAddRow throwing error in Coldfusion Webservice

I am facing a weird issue.
When I am consuming the below snippet of code as a webservice residing in a CF9 server I am getting the error "The value coldfusion.runtime.Struct cannot be converted to a number."
The call returns an array of structures. I would like to create a query from this array of structure. When I place this code as a standalone code in my local server(CF10) it works fine. But as soon i place it in the remote server to be invoked i get the error.
I almost pulled out my hair when I got the same error message even when I replaced the variable 'tempstruct' with a hard coded structure. As soon I remove the QueryAddRow I am able to return anything.
Any help is appreciated.
<cfset myquery=querynew("category,category_id,event_description","varchar,integer,varchar")>
<cfinvoke
webservice="http://199.99.99.999/vod_queries.cfc?wsdl"
method="getAllCategoryByResort"
returnvariable="arrAllSpaEvents"
refreshwsdl="true" >
<cfinvokeargument name="Resort" value="SRB" >
</cfinvoke>
<cfif arraylen(arrAllSpaEvents) GT 0>
<cfloop array="#arrAllSpaEvents#" index="cur_row">
<cfset tempstruct=StructNew()>
<cfset tempstruct.CATEGORY=cur_row.CATEGORY>
<cfset tempstruct.CATEGORY_ID=cur_row.CATEGORY_ID>
<cfset tempstruct.EVENT_DESCRIPTION=cur_row.EVENT_DESCRIPTION>
<cfset QueryAddRow(myquery,#tempstruct#)>
</cfloop>
</cfif>
<cfreturn myquery>
You almost got.
However, indeed you are using new CF10 overloading in CF9. What's more, if you were using CF10, it looks like you could stuff the whole top array in with looping like that.
But you can almost do the same thing. CF9 will take an array overload for the value.
Not quite as clean as CF10 but you do what you can.
Also, the extra # signs are superfluous.
Here is an example with something that your data might look like:
<cfscript> // I did this all in a cfscript block for simplicity
Your retrieved data might look something like this guessin from example
arrAllSpaEvents = [
{category='fun', category_id=1, event_description='massage'},
{category='work', category_id=2, event_description='spinning'},
{category='beauty', category_id=3, event_description='mani'},
{category='beauty', category_id=3, event_description='pedi'}
];
Create a more useful struct to build the query dynamically
s = {
category = {colType = 'varchar', colVals = []},
category_id = {colType = 'integer', colVals = []},
event_description = {colType = 'varchar', colVals = []}
};
This is looping the data to fill the colVals arrays
for(c = 1; c <= arrAllSpaEvents.size(); c++ ) {
for(k in arrAllSpaEvents[c]) {
s[k].colVals[c] = arrAllSpaEvents[c][k];
}
}
This is the short form of the same double loop above in a single line
for(c = 1; c <= arrAllSpaEvents.size(); c++ ) for(k in arrAllSpaEvents[c]) s[k].colVals[c] = arrAllSpaEvents[c][k];
Now build your query. Start with an empty query (pass in a blank);
q = queryNew('');
Then loop your struct and using the keys for the column names (for simplicity they are the same key)
for(k in s ) queryAddColumn(q,k,s[k].colType,s[k].colVals);
Verify your struct and query:
writedump(s);
writedump(q);
</cfscript>
I ran this in CF9 so should work fine for you.
This should get you going.

Coldfusion: Can't reference var from query result set

Using cfscript, trying to set the ID of the newly inserted question so that I can use it in my answer insert to build the relationship. I've done this a million times outside of cfscript. setName seems to be the proper method to call to create the query name.
I'm receiving the error that "theQuestionID" does not exist in qryQuestion
i = 1;
while ( structKeyExists( form, "question" & i ) )
{
q = new Query();
q.setDatasource("kSurvey");
q.setName("qryQuestion");
q.setSQL("
set nocount on
insert into question (question)
values('#form["question#i#"]#')
select ##IDENTITY AS theQuestionID
set NOCOUNT off
");
q.execute();
writeOutput("Question"&i&"<br>");
j = 1;
while ( structKeyExists( form, "question" & i & "_answer" & j) ) {
q = new Query();
q.setDatasource("kSurvey");
q.setSQL("
insert into answer (answer,questionid)
values('#form["question#i#_answer#j#"]#',#qryQuestion.theQuestionID#)
");
q.execute();
writeOutput("Answer"&j&"<br>");
j++;
}
i++;
}
Theres a better way to accomplish this without having to select ##identity (which in itself isn't the best way to get it from sql server, using scope_identity is the best practice way to do this in sql server. http://msdn.microsoft.com/en-us/library/ms190315.aspx
Fortunately ColdFusion makes this even easier:
<cfscript>
insertQuery = new query();
insertQuery.setDatasource("datasourcename");
insertQuery.setSql("insert into contact(firstname, lastname)
values('ryan','anklam')");
result = insertQuery.Execute();
theKey = result.getPrefix().generatedkey;
</cfscript>

CFGRID - replace data store or filter on more than one column

ColdFusion 8
I have a cfgrid that that is based on a query. It is not bound to a cfc function because I want a scrolling grid, not a paged grid (you must supply the page number and page size if you use BIND).. I can figure out how to make it filter on one column by using the following code, but I really need to filter on three columns...
grid.getDataSource().filter("OT_MILESTONE",t1);
Adding more to the filter string does not do the trick...it ignores anything more than the first pair of values..
so..I thought if I called a function that passes the three values and returned the query results to me, I could replace the Data Store for the grid..but I cannot figure out the syntax to get it to replace.
The returned variable for the query has the following format:
{"COLUMNS":["SEQ_KEY","ID","OT_MILESTONE"],"DATA":[[63677,"x","y"]]}
Any ideas?
have you looked at queryconvertforgrid()?
http://www.cfquickdocs.com/cf9/#queryconvertforgrid
Update: have you looked at these?
http://www.danvega.org/blog/index.cfm/2008/3/10/ColdFusion-8-Grid-Filtering
http://www.coldfusion-ria.com/Blog/index.cfm/2009/1/13/Playing-with-cfgrid--Filter-showhide-Columns-and-using-the-YUI-Buttons-library
http://cfsilence.com/blog/client/index.cfm/2007/8/9/Filtering-Records-In-An-Ajax-Grid
after much blood, sweat, tears and swearing..here's the answer, in case anyone else might need to filter a cfgrid by more than one variable:
var w1 = ColdFusion.getElementValue('wbs');
var t1 = ColdFusion.getElementValue('task');
var p1 = ColdFusion.getElementValue('project');
grid = ColdFusion.Grid.getGridObject('data');
store = grid.getDataSource();
store.clearFilter();
store.filterBy(function myfilter(record) {
var wantit = true;
if (trim(w1) != '') {
if(record.get('WBS_ID') != w1) {
wantit = false;
}}
if (trim(t1) != '') {
if(record.get('OT_MILESTONE') != t1) {
wantit = false;
}}
if (trim(p1) != '') {
if(record.get('PROJECT') != p1) {
wantit = false;
}}
return wantit;
});
ColdFusion.Grid.refresh('data',false);
you will need a JS trim function...
Make sure the column names are caps...