Flatten any variable type in ColdFusion

I created a function that flattens different types of complex (nested) variables, like structures, arrays and queries. The function is based on the flattenStruct (https://cflib.org/udf/flattenStruct) UDF by Tom de Manincor.

<cffunction name="flattenAnything" access="public" output="true" returntype="struct" hint="Flattens structures, arrays  and queries">
    <cfargument name="in" type="any" required="true" hint="struct, array or query to flatten">
    <cfargument name="delimiter" required="false" type="string" default="." />
    <cfargument name="prefix_string" type="string" default="" required="false" hint="result struct, returned at the end">
    <cfargument name="out" type="struct" default="#StructNew()#" required="false" hint=" used in the processing, stores the preceding struct names in the current branch, ends in a delimeter">

    <Cfset var local = {}>

    <Cfif isStruct(in)>
        <cfset local.keyArray = StructKeyArray(in)>
        <cfloop from=1 to=#arrayLen(local.keyArray)# index="local.x">

            <Cfif isStruct(in[local.keyArray[x]])>
                <cfset out = flattenAnything(in[local.keyArray[x]],delimiter, prefix_string & local.keyArray[x] & delimiter,out)>
            <Cfelseif isArray(in[local.keyArray[x]])>
                <cfset out = flattenAnything(in[local.keyArray[x]],delimiter, prefix_string & local.keyArray[x] & delimiter,out)>
            <Cfelseif isQuery(in[local.keyArray[x]])>
                <cfset out = flattenAnything(in[local.keyArray[x]],delimiter, prefix_string & local.keyArray[x] & delimiter,out)>
            <cfelse>
              	<cfset out[prefix_string & local.keyArray[local.x]] = in[local.keyArray[local.x]]>
            </cfif>
        </cfloop>
	<Cfelseif isArray(in)>
        <cfloop from=1 to=#arrayLen(in)# index="local.y">
            <cfset out = flattenAnything({"#local.y#":in[local.y]},delimiter, prefix_string,out)>
        </cfloop>
	<cfelseif isQuery(in)>
		<Cfset local.q.columnLabels = in.columnList>
		<Cfset local.q.array = []>

        <cfloop from=1 to=#in.recordcount# index="local.y">
			<Cfloop list="#local.q.columnLabels#" item="local.q.columnName">
	            <cfset local.q.array[local.y][local.q.columnName] = in[local.q.columnName][local.y] >
			</cfloop>
        </cfloop>
		<Cfset local.q.prefix_string = prefix_string>
		<cfif local.q.prefix_string eq delimiter><Cfset local.q.prefix_string = ""></cfif>
		 <cfset out = flattenAnything(local.q.array,delimiter, local.q.prefix_string,out)>
    <Cfelseif isSimpleValue(in)>
	    <Cfset out = {"SimpleValue":in}>
    <Cfelse>
	    <Cfset out = {"UnkownVariable":in}>
	</cfif>

    <cfreturn out>
</cffunction>

Below a simple example:

<cfscript>
str = structNew();
str.query = people = queryNew("id, firstName, lastName, email, country, ip_address","integer, varchar, varchar, varchar, varchar, varchar",[
	{  "id": 1,  "firstName": "John",  "lastName": "Do",  "email": "some@one.com",  "country": "Poland",  "ip_address": "10.0.0.1"}, 
	{  "id": 2,  "firstName": "Jane",  "lastName": "Do",  "email": "mail@address.org",  "country": "Iceland",  "ip_address": "10.0.0.2"}
]);
str.alpha = structNew();
str.alpha.alpha = true;
str.alpha.beta = true;
str.alpha.gamma = true;
str.alpha.delta = structNew();
str.alpha.delta.alpha = 'test';
str.alpha.epsilon = ['alpha','beta','gamma',{"alpha":"1","beta":[1,2,3,4]}];
str.alpha.zeta = [1,2,3,4];
str.alpha.eta = [[1,2,3,4],['a','b','c','d']];
</cfscript>
<cfdump var="#flattenAnything(str)#">

https://cffiddle.org/app/file?filepath=080b6a18-4dd3-4358-b504-05397e085fc6/e6fbab74-7eb8-4b23-aa66-907ce1c7df78/ab358cc3-f8d8-4463-b124-790c509aef5c.cfm

Leave a Reply

Your email address will not be published. Required fields are marked *