Files
payg/layout/json.cfm
T

154 lines
5.7 KiB
Plaintext

<cfsilent>
<cfparam name="ATTRIBUTES.qRead" type="query"/>
<cfparam name="ATTRIBUTES.convertSnakeToCamel" type="boolean" default=true/>
<!---<cfdump var=#qRead#/>
<cfdump var=#ATTRIBUTES.titleMap#/>
<cfabort/>--->
<cffunction name="snake2camel"
returntype="string"
output="false"
hint="convert snake style name to camel style name">
<cfargument name="snake" type="string" required="true" />
<cfreturn #reReplace(ARGUMENTS.snake,"_([a-z])","\u\1","ALL")#/>
</cffunction>
<cffunction name="camel2snake"
returntype="string"
output="false"
hint="convert camel style name to snake style name">
<cfargument name="camel" type="string" required="true" />
<cfreturn #reReplace(ARGUMENTS.camel,"([A-Z])","_\l\1","ALL")#/>
</cffunction>
<!--- <cffunction name="escape4json"
returntype="string"
output="false"
hint="escape string for json format">
<cfargument name="s" type="string" required="true" />
<cfreturn #reReplace(ARGUMENTS.camel,"([A-Z])","_\l\1","ALL")#/>
</cffunction> --->
<!--- <cffunction name="query2array">
<cfargument name="qry" type="query" required="true"/><!--- column names should not contain commas --->
<cfargument name="convertSnakeToCamel" type="boolean" default=true/><cfsilent>
</cffunction> --->
<!--- <cffunction name="query2json"
output="true"
hint="print query in json format as array of structures">
<cfargument name="qry" type="query" required="true"/><!--- column names should not contain commas --->
<cfargument name="convertSnakeToCamel" type="boolean" default=true/><cfsilent>
<cfset var columnsIn=#qry.columnList()#/>
<cfset var columnsOut=""/>
<cfif arguments.convertSnakeToCamel>
<cfloop list=#columnsIn# item="col">
<cfset columnsOut=listAppend(columnsOut,snake2camel(col))/>
</cfloop>
<cfelse>
<cfset columnsOut=#columnsIn#/>
</cfif>
</cfsilent>[<cfoutput query=#qry#>{<cfloop index="i" from="1" to=#listLen(columnsOut)#>"#listGetAt(#columnsOut#,i)#":"#qry[listGetAt(#columnsIn#,i)]#"<cfif #i# LT #listLen(columnsOut)#>,</cfif></cfloop>}<cfif #qry.currentRow()# LT #qry.recordCount()#>,</cfif></cfoutput>]
</cffunction> --->
<cffunction name="query2json"
output="false"
hint="print query in json format as array of structures">
<cfargument name="qry" type="query" required="true"/><!--- column names should not contain commas --->
<cfargument name="convertSnakeToCamel" type="boolean" default=true/>
<cfset var columnsIn=#arguments.qry.columnList()#/>
<cfset var columnsOut=""/>
<cfif arguments.convertSnakeToCamel>
<cfloop list=#columnsIn# item="col">
<cfset columnsOut=listAppend(columnsOut,snake2camel(col))/>
</cfloop>
<cfset var outArray=arrayNew(1)/>
<!--- //copy fields to structure, renaming fields, this preserves data type --->
<cfloop query=#arguments.qry#>
<cfset var structRow=structNew()/>
<cfloop index="i" from="1" to=#listLen(columnsOut)#>
<cfset structInsert(structRow,"#listGetAt(#columnsOut#,i)#",arguments.qry["#listGetAt(#columnsIn#,i)#"])/>
</cfloop>
<cfset arrayAppend(outArray,structRow)/>
</cfloop>
<cfreturn customJson(outArray)/>
<cfelse>
<cfreturn customJson(arguments.qry,"struct")/>
</cfif>
</cffunction>
<!--- <cfset request.camel2snake = camel2snake/> --->
<!---<cfsavecontent variable="strXmlData">--->
<!--- <cfif ATTRIBUTES.snake2camel>
<cfloop collection=#ATTRIBUTES.qRead.columnList# item="col">
<cfset queryRenameColumn(ATTRIBUTES.qRead,col,snake2camel(col))/>
<cfset ATTRIBUTES.qREAD.
</cfloop>
</cfif> --->
<cfset msStartAt=getTickCount()/>
</cfsilent><cfcontent
type="application/json"
/><cfoutput>#query2json(ATTRIBUTES.qRead,ATTRIBUTES.convertSnakeToCamel)#</cfoutput><!---
,<cfoutput>"duration":"#(getTickCount()- msStartAt)#"</cfoutput>} --->
<cfexit method="exittag"/>
<!--- *** еще добиться форматирования null, true, false
https://www.bennadel.com/blog/2165-returning-null-values-in-json-using-serializejson-and-coldfusion.htm
--->
<cfscript>
public string function customJson(required any data) {
return serializeJson(formatDatesToIso(arguments.data));
}
private any function formatDatesToIso(required any input) {
// 1. Handle Dates (Strict verification using isValid and checking underlying type)
// Lucee dates are typically objects (java.util.Date / java.time).
// This prevents strings like "12345" or "Yes" from being treated as dates.
if (isDate(arguments.input) && (isObject(arguments.input) || !isValid("integer", arguments.input))) {
return dateTimeFormat(arguments.input, "iso8601");
}
// 2. Handle Structs (Preserve case-sensitivity using [:] syntax)
if (isStruct(arguments.input)) {
var newStruct = [Ordered: true]; // Lucee/CF literal for preserving key case
for (var key in arguments.input) {
newStruct[key] = formatDatesToIso(arguments.input[key]);
}
return newStruct;
}
// 3. Handle Arrays
if (isArray(arguments.input)) {
var newArray = [];
for (var item in arguments.input) {
arrayAppend(newArray, formatDatesToIso(item));
}
return newArray;
}
// 4. Handle Queries
if (isQuery(arguments.input)) {
var queryArray = [];
var columns = arguments.input.getColumnNames(); // Returns correct case array
loop query="arguments.input" {
var rowStruct = [Ordered: true];
loop array="#columns#" index="col" {
// Safely grab cell using row coordinates
rowStruct[col] = formatDatesToIso(arguments.input[col][arguments.input.currentRow]);
}
arrayAppend(queryArray, rowStruct);
}
return queryArray;
}
// 5. Return everything else untouched (Strings, Numbers, Booleans, etc.)
return arguments.input;
}
</cfscript>