├── ArrayCollection.cfc ├── ArrayCollection.md ├── DataTables.cfc ├── DataTables.md ├── README.md └── docs ├── _config.yml └── index.md /ArrayCollection.cfc: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Adrian J. Moreno 3 | * @website http://iknowkungfoo.com 4 | * @Twitter: @iknowkungfoo 5 | * @hint: A custom JSON render object for ColdFusion queries. 6 | * @Repo: https://github.com/iknowkungfoo/cfquery-to-json 7 | * @version 4.0 8 | * @requirements ColdFusion 9.0+ or Railo 4+ 9 | * @BlogPost: http://cfml.us/Ce 10 | */ 11 | 12 | component output="false" accessors="true" { 13 | 14 | /** 15 | * @required true 16 | * @setter false 17 | * @hint The query object to convert to JSON. 18 | */ 19 | property query data; 20 | /** 21 | * @required false 22 | * @default "json" 23 | * @hint Sets the content-type for the response. 24 | */ 25 | property string contentType; 26 | /** 27 | * @required false 28 | * @default true 29 | * @hint Prefix the content with keys. 30 | */ 31 | property boolean dataHandle; 32 | /** 33 | * @required false 34 | * @default "data" 35 | * @hint The key for the data contained in the response. 36 | */ 37 | property string dataHandleName; 38 | /** 39 | * @required false 40 | * @default true 41 | * @hint Return data as 42 | * true: an array of objects with data in name/value pairs 43 | * false: an array of arrays with data as unnamed elements 44 | * @example true: [{"id": 1, "value": "yes"}], false: [["1", "yes"]] 45 | */ 46 | property boolean dataKeys; 47 | /** 48 | * @required false 49 | * @default false 50 | * @hint Data return formst, overrides dataHandle property. 51 | * true: return data content only, setDataHandle(false) 52 | * false: return standard data packet, setDataHandle(true) 53 | */ 54 | property boolean dataOnly; 55 | /** 56 | * @required false 57 | * @default "lower" 58 | * @hint return data keys in "upper"- or "lower"-case. 59 | */ 60 | property string dataKeyCase; 61 | 62 | /** 63 | * Setup JSON response packet. 64 | * @return ArrayCollection 65 | */ 66 | public ArrayCollection function init() { 67 | variables.stData = { 68 | "success": true 69 | , "message": "Array Collection created." 70 | , "meta": { 71 | "offset": 0 72 | , "pageSize": 0 73 | , "totalRecords": 0 74 | } 75 | , "data": [] 76 | }; 77 | return this; 78 | } 79 | 80 | /** 81 | * Setup query object to convert with related data as needed. 82 | * @param required query data Query Object 83 | * @param numeric offset Query record offset 84 | * @param numeric pageSize Query record limit 85 | * @param numeric totalRecords Query total records is data set 86 | * @param boolean success 87 | * @param string message 88 | */ 89 | public ArrayCollection function setData( required query data, numeric offset, numeric pageSize, numeric totalRecords, boolean success, string message ) { 90 | variables.data = arguments.data; 91 | variables.stData.meta["offset"] = structKeyExists(arguments, "offset") ? arguments.offset : 0; 92 | variables.stData.meta["pageSize"] = structKeyExists(arguments, "pageSize") ? arguments.pageSize : arguments.data.recordcount; 93 | variables.stData.meta["totalRecords"] = structKeyExists(arguments, "totalRecords") ? arguments.totalRecords : arguments.data.recordcount; 94 | structKeyExists(arguments, "message") ? setMessage(arguments.message) : setMessage("Array Collection populated."); 95 | if (structKeyExists(arguments, "success")) { setSuccess(arguments.success); } 96 | return this; 97 | } 98 | 99 | /** 100 | * Overrides the DataHandle property. Returns on the data array. 101 | * @param required boolean dataOnly 102 | */ 103 | public ArrayCollection function setDataOnly(required boolean dataOnly ) { 104 | setDataHandle(!arguments.dataOnly); 105 | return this; 106 | } 107 | 108 | /** 109 | * Reset data to an empty query object. 110 | * @param required array columns Array of columns from original query object. 111 | */ 112 | public ArrayCollection function resetData(required array columns) { 113 | setData(data: querynew(arrayToList(arguments.columns))); 114 | return this; 115 | } 116 | 117 | /** 118 | * Was the query successful or not? 119 | * @param required boolean success 120 | */ 121 | public ArrayCollection function setSuccess(required boolean success) { 122 | variables.stData.success = arguments.success; 123 | return this; 124 | } 125 | 126 | /** 127 | * Set a message to be returned to the client. 128 | * @param required string message 129 | */ 130 | public ArrayCollection function setMessage(required string message) { 131 | variables.stData.message = arguments.message; 132 | return this; 133 | } 134 | 135 | /** 136 | * Set other data in the meta object. Will not overwrite default keys. 137 | * @param required string key meta struct key 138 | * @param required any value meta struct key value 139 | */ 140 | public ArrayCollection function setMetaKey(required string key, required any value) { 141 | if (!structKeyExists(variables.stData.meta, arguments.key)) { 142 | variables.stData.meta[arguments.key] = arguments.value; 143 | } 144 | return this; 145 | } 146 | 147 | /** 148 | * Change the existing columns names of the query object to a supplied array. 149 | * @param required array names Array of columns names, must match original column order and length 150 | * @return ArrayCollection 151 | */ 152 | public ArrayCollection function changeColumnNames( required array names ) { 153 | if (!arrayIsEmpty(arguments.names)) { 154 | var aOriginalNames = getData().getColumnNames(); 155 | if (arraylen(aOriginalNames) NEQ arrayLen(arguments.names)) { 156 | resetData(aOriginalNames) 157 | .setSuccess(false) 158 | .setMessage("Requested column names array length does not match the number of query columns.") 159 | .setMetaKey("originalNames", aOriginalNames) 160 | .setMetaKey("requestedNames", arguments.names); 161 | } else { 162 | getData().setColumnNames(arguments.names); 163 | } 164 | } 165 | return this; 166 | } 167 | 168 | /** 169 | * Render the collection data structure as JSON 170 | * @return json 171 | */ 172 | public string function $renderdata() { 173 | var aData = []; 174 | if (getDataKeys()){ 175 | aData = arrayOfStructs(); 176 | } else { 177 | aData = arrayOfArrays(); 178 | } 179 | if (getDataHandle()) { 180 | variables.stData[getDataHandleName()] = aData; 181 | return serializeJSON(variables.stData); 182 | } else { 183 | return serializeJSON(aData); 184 | } 185 | } 186 | 187 | /** 188 | * Returns the column list ordered alphabetically and in the case requested. 189 | * @return string 190 | */ 191 | private string function getColumnList() { 192 | var columns = listSort( getData().columnlist, "textnocase" ); 193 | if ( getDataKeyCase() IS "lower" ) { 194 | return lcase( columns ); 195 | } else { 196 | return ucase( columns ); 197 | } 198 | } 199 | 200 | /** 201 | * Convert n query object to an array of structs. 202 | * @return array 203 | */ 204 | private array function arrayOfStructs() { 205 | var results = []; 206 | var temp = {}; 207 | var q = getData(); 208 | var rc = q.recordCount; 209 | var fields = listToArray(getColumnList()); 210 | var fc = arrayLen(fields); 211 | var x = 0; 212 | var y = 0; 213 | var fieldName = ""; 214 | 215 | for ( x = 1; x LTE rc; x++ ){ 216 | temp = {}; 217 | for ( y = 1; y LTE fc; y++ ) { 218 | fieldName = fields[y]; 219 | temp[fieldName] = q[fieldName][x]; 220 | } 221 | arrayAppend( results, temp ); 222 | } 223 | return results; 224 | } 225 | 226 | /** 227 | * Convert a query object to an array of arrays. 228 | * @return array 229 | */ 230 | private array function arrayOfArrays() { 231 | var results = []; 232 | var temp = []; 233 | var q = getData(); 234 | var rc = q.recordCount; 235 | var fields = listToArray(getColumnList()); 236 | var fc = arrayLen(fields); 237 | var x = 0; 238 | var y = 0; 239 | 240 | for ( x = 1; x LTE rc; x++ ) { 241 | temp = []; 242 | for ( y = 1; y LTE fc; y++ ) { 243 | arrayAppend( temp, q[fields[y]][x] ); 244 | } 245 | arrayAppend( results, temp ); 246 | } 247 | return results; 248 | } 249 | 250 | } 251 | -------------------------------------------------------------------------------- /ArrayCollection.md: -------------------------------------------------------------------------------- 1 | ArrayCollection 2 | =============== 3 | 4 | A custom JSON render object for ColdFusion queries 5 | 6 | Details at blog post: 7 | 8 | http://iknowkungfoo.com/blog/index.cfm/2012/5/11/ArrayCollectioncfc-a-custom-JSON-renderer-for-ColdFusion-queries 9 | 10 | **Simple example** 11 | 12 | ``` 13 | 14 | 15 | 16 | 17 | SELECT DISTINCT 18 | bookid, 19 | title, 20 | genre 21 | FROM 22 | books 23 | WHERE 24 | title LIKE 25 | ORDER BY 26 | genre, title 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 36 | **ColdBox Handler** 37 | 38 | ``` 39 | 40 | 41 | 42 | 43 | ``` 44 | 45 | **Output: Version 4** 46 | ``` 47 | { 48 | "data": [ 49 | { 50 | "bookid": 8, 51 | "genre": "Fiction", 52 | "title": "Apparition Man" 53 | }, 54 | { 55 | "bookid": 2, 56 | "genre": "Non-fiction", 57 | "title": "Shopping Mart Mania" 58 | } 59 | ], 60 | "message": "Array Collection populated.", 61 | "meta": { 62 | "offset": 0, 63 | "pageSize": 2, 64 | "totalRecords": 2 65 | }, 66 | "success": true 67 | } 68 | ``` 69 | 70 | **New in Version 4** 71 | 72 | Refactored script CFC 73 | 74 | Added additional keys: 75 | * "message": String 76 | * "meta": object containing "offset", "pageSize" and "totalRecords" 77 | * "success": boolean 78 | 79 | If you trigger setDataOnly(true), the only the contents of the "data" key are returned. 80 | 81 | **Output: Versions 1 - 3** 82 | ``` 83 | { 84 | "data": [ 85 | { 86 | "bookid": 8, 87 | "genre": "Fiction", 88 | "title": "Apparition Man" 89 | }, 90 | { 91 | "bookid": 2, 92 | "genre": "Non-fiction", 93 | "title": "Shopping Mart Mania" 94 | } 95 | ] 96 | } 97 | ``` 98 | 99 | **New in Version 3** 100 | 101 | Converted to a script CFC 102 | 103 | Renamed queryToArrayOfStructs to arrayOfStructs. 104 | 105 | Renamed queryToArrayOfArrays to arrayOfArrays. 106 | 107 | Added the property "dataFormat" to convert between array or struct output. 108 | 109 | **New in Version 2** 110 | 111 | The function setDataKeys() triggers the return of an array of structs (true) or an array of arrays (false). 112 | 113 | The function setDataKeyCase() changes the column names (keys) in the structs from lowercase (default) to uppercase. 114 | 115 | **Depricated** 116 | 117 | The function setDataType() was replaced with setDataKeys(). 118 | -------------------------------------------------------------------------------- /DataTables.cfc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @author Adrian J. Moreno 4 | * @email amoreno@iknowkungfoo.com 5 | * @description Custom JSON renderer used to convert CFML application queries for use with jQuery DataTables. 6 | * @version 3.0 7 | * @requirements ColdFusion 9.0+ or Railo 4+ 8 | * @Repo: https://github.com/iknowkungfoo/cfquery-to-json 9 | * 10 | */ 11 | 12 | component output="false" extends="ArrayCollection" accessors="true" { 13 | 14 | property type="numeric" name="echo" default="-1"; 15 | property type="numeric" name="totalRecords" default="0"; 16 | property type="numeric" name="totalDisplayRecords" default="0"; 17 | 18 | public DataTables function init() { 19 | setContentType("json"); 20 | setDataHandle(false); 21 | setDataFormat("array"); 22 | setDataKeyCase("lower"); 23 | setEcho(-1); 24 | setTotalRecords(0); 25 | setTotalDisplayRecords(0); 26 | return this; 27 | } 28 | 29 | public void function setData( required query data ){ 30 | variables.data = arguments.data; 31 | if (structKeyExists(arguments.data, "total_records")){ 32 | setTotalRecords( val(arguments.data.total_records) ); 33 | setTotalDisplayRecords( val(arguments.data.total_records) ); 34 | } else { 35 | setTotalRecords( arguments.data.recordcount ); 36 | setTotalDisplayRecords( arguments.data.recordcount ); 37 | } 38 | 39 | } 40 | 41 | public string function $renderdata(){ 42 | var rs = {}; 43 | if (getEcho() GTE 0) { 44 | rs["sEcho"] = val(getEcho()); 45 | } 46 | if (getTotalRecords() GT 0) { 47 | rs["iTotalRecords"] = getTotalRecords(); 48 | } 49 | if (getTotalDisplayRecords() GT 0) { 50 | rs["iTotalDisplayRecords"] = getTotalDisplayRecords(); 51 | } 52 | if (getDataFormat() IS "array") { 53 | rs["aaData"] = arrayOfArrays(); 54 | } else { 55 | rs["aaData"] = arrayOfStructs(); 56 | } 57 | return serializeJSON(rs); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /DataTables.md: -------------------------------------------------------------------------------- 1 | DataTables.cfc 2 | =============== 3 | 4 | A custom JSON render object to convert ColdFusion queries for use with [jQuery DataTables](http://datatables.net/). 5 | 6 | Requires ArrayCollection.cfc from this repo. 7 | 8 | More example code can be found in the [KungFooGallery ColdBox Applicaiton](https://github.com/iknowkungfoo/KungFooGallery-Simple-ColdBox). 9 | 10 | **Simple Example** 11 | ``` 12 | 13 | 14 | 15 | 16 | SELECT 17 | a.artist_id, 18 | a.first_name, 19 | a.last_name, 20 | b.artwork_id, 21 | b.title, 22 | b.img_thumb 23 | FROM 24 | ARTISTS a 25 | INNER JOIN 26 | ARTWORK b ON b.artist_id = a.artist_id 27 | 28 | WHERE a.artist_id = 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ``` 38 | 39 | **Output** 40 | ``` 41 | { 42 | "iTotalDisplayRecords": 16, 43 | "iTotalRecords": 16, 44 | "aaData": [ 45 | [1, 1, "Doug", "8318007055_fa1c3dc930_t.jpg", 88888, "Flower"], 46 | [1, 2, "Doug", "2808827891_223469fd22_t.jpg", 88888, "Yellow flowers"], 47 | [1, 3, "Doug", "3086318277_8ee7912476_t.jpg", 88888, "Passion flower"], 48 | [1, 4, "Doug", "3575863689_f88082c56d_t.jpg", 88888, "Ouch"], 49 | [1, 5, "Doug", "3428958441_426d432137_t.jpg", 88888, "Yellow"], 50 | [1, 6, "Doug", "3495905775_b54f784b73_t.jpg", 88888, "Little yellow"], 51 | [1, 7, "Doug", "3067955110_aab017ef9a_t.jpg", 88888, "Burn Baby Burn"], 52 | [1, 8, "Doug", "4524800461_30334688bb_t.jpg", 88888, "Earth laughs in Flowers"], 53 | [1, 9, "Doug", "2913745445_81f10d0b3c_t.jpg", 88888, "Yellow"], 54 | [1, 10, "Doug", "3545922423_cffb4ecb04_t.jpg", 88888, "Yellow flower"], 55 | [1, 11, "Doug", "3122503680_6975c6faaf_t.jpg", 88888, "The blues and the greens"], 56 | [1, 12, "Doug", "3103809905_607649a798_t.jpg", 88888, "Sing the Blues"], 57 | [1, 13, "Doug", "4530628192_1427fd44d9_t.jpg", 88888, "Canon T2i Flower"], 58 | [1, 14, "Doug", "3757385629_b58653d59b_t.jpg", 88888, "Macro flower experiment"], 59 | [1, 15, "Doug", "4522243047_1815f626bd_t.jpg", 88888, "The Daisy"], 60 | [1, 16, "Doug", "3555700749_ddbb69293e_t.jpg", 88888, "Precious Gift"] 61 | ] 62 | } 63 | ``` 64 | 65 | **Alternate Output** 66 | 67 | If we change the code to ourput as a struct. 68 | ``` 69 | 70 | 71 | 72 | 73 | ``` 74 | 75 | The output returns like so: 76 | 77 | ``` 78 | { 79 | "iTotalDisplayRecords": 16, 80 | "iTotalRecords": 16, 81 | "aaData": [{ 82 | "img_thumb": "8318007055_fa1c3dc930_t.jpg", 83 | "first_name": "Doug", 84 | "artwork_id": 1, 85 | "artist_id": 1, 86 | "last_name": 88888, 87 | "title": "Flower" 88 | }, { 89 | "img_thumb": "2808827891_223469fd22_t.jpg", 90 | "first_name": "Doug", 91 | "artwork_id": 2, 92 | "artist_id": 1, 93 | "last_name": 88888, 94 | "title": "Yellow flowers" 95 | }, 96 | 97 | // etc. 98 | 99 | { 100 | "img_thumb": "3555700749_ddbb69293e_t.jpg", 101 | "first_name": "Doug", 102 | "artwork_id": 16, 103 | "artist_id": 1, 104 | "last_name": 88888, 105 | "title": "Precious Gift" 106 | }] 107 | } 108 | ``` 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cfquery-to-json 2 | =============== 3 | 4 | A collection of JSON converters for ColdFusion query objects. 5 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | A collection of tools to convert ColdFusion query objects to structs and arrays, then serialize those to varous forms of JSON. 4 | --------------------------------------------------------------------------------