--->
[{"#listGetAt(#columnsOut#,i)#":"#qry[listGetAt(#columnsIn#,i)]#",},]
--->
#query2json(ATTRIBUTES.qRead,ATTRIBUTES.convertSnakeToCamel)#
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;
}