├── .gitignore ├── Contributing.md ├── JSONAdditions.fmp12 ├── LICENSE ├── README.md ├── docs.md └── functions ├── JSON.ArrayConcat.fmfn ├── JSON.ArrayFromRelated.fmfn ├── JSON.ArrayLength.fmfn ├── JSON.ArraySort.fmfn ├── JSON.ContainsProperty.fmfn ├── JSON.FilterByExpression.fmfn ├── JSON.Format.fmfn ├── JSON.GetValuesAtPath.fmfn ├── JSON.IsValid.fmfn ├── JSON.Merge.fmfn ├── JSON.Pluck.From.fmfn ├── JSON.Pluck.Prop.fmfn ├── JSON.Pluck.fmfn ├── JSON.Push.fmfn ├── JSON.Transform.ISODates.fmfn ├── JSON.Transform.This.fmfn ├── JSON.Transform.fmfn └── JSON.Transformation.fmfn /.gitignore: -------------------------------------------------------------------------------- 1 | import.log 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | We welcome feedback, bug reports, and bug fixes. Please help us incorporate your contributions by following this guide. 4 | 5 | We know that github is a new thing for many of you FileMaker users, but don't worry. In this cases we aren't using any of the merging features of git. No pull requests, no committing. We are just using this as an Issue Queue, and a code repository. 6 | 7 | ## Use Github Issues 8 | Please use the Issue Queue here in Github for all feedback. Please label your issue with either, bug, question, question, or enhancement depending on the type of issue it is. 9 | 10 | ### Include Tests 11 | All functions in this library are tested. We do not fix a bug or add a feature without writing tests to prove that the new changes work, and do not break existing code. If you have a bug report, it will get fixed faster if you include Tests. If you have a new feature idea, it will get included faster if you include a test file that show it passing all tests 12 | 13 | #### How to Include Tests 14 | 15 | Download the JSONAdditions.fmp12 file. and open it. Each record on that opening screen is a test. Press the Run all Tests button at the top of the screen. All tests should pass. 16 | 17 | There first text field is for Test JSON that you can use in your Test. The second text field is for you to put your FileMaker expression that IS the test. The third text box is the result of your test. It will populate when you run the test. The final text field on the right is the Expected Result. You need to put the correct result your test should return. 18 | 19 | Write your test that *should* pass if your bug is fixed or your new feature is added. Run all tests again. Your new test or tests should fail. 20 | 21 | If that is all you can do; if you don't know how to fix the bug or solve the feature, then just go ahead and attach your file with the new test to the new issue you are creating. 22 | 23 | #### Contributing New Features or Fixes 24 | 25 | If you know how to fix the bug, or add the feature, please go ahead and add it to the file. Make sure it passes your new test and all the others. Once you have it working, attach this file to the Github Issue you created for this feature or bug. 26 | 27 | #### Fixing Bugs in the Queue 28 | 29 | If you see an issue that you think you can fix. Please download the Test file attached to the issue. Make the changes you think will fix it, and run the tests. If all tests Pass, add your fixed test file, back to the issue as a comment. -------------------------------------------------------------------------------- /JSONAdditions.fmp12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proofgeist/fm-json-additions/eb1ecd6395adc5c7e8ca31af90603e5eee048533/JSONAdditions.fmp12 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Geist Interactive 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fm-json-additions 2 | 3 | Extra functions for working with JSON in FileMaker. These use on the new native functions in FM 16. Each function has tests for correctness. 4 | 5 | ## Using 6 | Please see the test file for example on how the functions work. You can also just look at the [function listing](/docs.md) 7 | 8 | 9 | ## Contributing 10 | 11 | We love contributions and bug reports. Please read the [Contributing Guide](/Contributing.md) for more info on how to do that. Your issues and bug reports and new feature ideas, have an order of magnitude higher probability of getting solved if this Contributing Guide is followed. -------------------------------------------------------------------------------- /docs.md: -------------------------------------------------------------------------------- 1 | ## JSON.ArrayConcat ( firstArray;secondArray) 2 | ``` 3 | /** 4 | * 5 | * JSON.ArrayConcat ( firstArray ; secondArray ) 6 | * 7 | * RETURNS: 8 | * a longer array of the first & second concatinated 9 | * 10 | * @param {array} firstArray 11 | * @param {array} secondArray 12 | * 13 | * @returns {array} 14 | * 15 | * @module fm-json-additions 16 | * @see https://github.com/geistinteractive/fm-json-additions 17 | * 18 | * @history 2017-05-07, cdelfs@delfsengineering.ca 19 | * 20 | */ 21 | ``` 22 | ## JSON.ArrayFromRelated ( JSONField) 23 | ``` 24 | /** 25 | * 26 | * JSON.ArrayFromRelated( JSONField ) 27 | * 28 | *@params {reference} JSONField a reference to the field 29 | * 30 | *@returns {array} array containng the values from the related field 31 | * 32 | * @module fm-json-additions 33 | * @see https://github.com/geistinteractive/fm-json-additions 34 | * 35 | * @history 2017-06-01, todd@geistinteractive.com, created 36 | * 37 | */ 38 | ``` 39 | ## JSON.ArrayLength ( array;path) 40 | ``` 41 | /* 42 | * 43 | * JSONArrayLength ( array ; path) 44 | * 45 | * @param {array} array a valid JSON Array 46 | * @param {string} path the path to the array if it is nested 47 | * 48 | * @returns {number} 49 | * 50 | * @module fm-json-additions 51 | * @see https://github.com/geistinteractive/fm-json-additions 52 | * 53 | * @history 2017-04-09, todd@geistinteractive.com, created 54 | * 55 | * ===================================== 56 | */ 57 | ``` 58 | ## JSON.ArraySort ( array;sortChildren) 59 | ``` 60 | /** 61 | * 62 | * Sort an array 63 | * 64 | * @param {array} array a valid JSON array 65 | * @param {string} sortChildren 66 | * 67 | * @returns {array} 68 | * 69 | * @module fm-json-additions 70 | * @see https://github.com/geistinteractive/fm-json-additions 71 | * 72 | * @history 2017-06-20, michael.wallace@rcconsulting.com , gh #12 73 | * 74 | */ 75 | ``` 76 | ## JSON.ContainsProperty ( json;name) 77 | ``` 78 | /** 79 | * ===================================== 80 | * 81 | * Test if the JSON contains the give property 82 | * 83 | * @param {object} json a valid JSON object 84 | * @param {string} name the property to test (can be in form body.path.item) 85 | * 86 | * @returns {boolean} 87 | * 88 | * @module fm-json-additions 89 | * @see https://github.com/geistinteractive/fm-json-additions 90 | * 91 | * @history 2017-10-12, todd@geistinteractive.com, fixed depth gh #14 92 | * @history 2017-05-16, john@e-rwu.com, added path depth, gh #3 93 | * @history 2017-04-09, todd@geistinteractive.com 94 | * 95 | * ===================================== 96 | */ 97 | ``` 98 | ## JSON.FilterByExpression ( array;expression) 99 | ``` 100 | /** 101 | * 102 | * filters the array by a FileMaker expression 103 | * 104 | *@param {array} array a valid JSON Array 105 | *@param {string} expression a valid FileMaker Expression. 106 | * It can use 107 | * "$item" to access the array item for use 108 | * in the filter calculation. 109 | * 110 | * @returns {array} 111 | * 112 | * @module fm-json-additions 113 | * @see https://github.com/geistinteractive/fm-json-additions 114 | * 115 | * @history, 2017-06-20, michael.wallace@rcconsulting.com 116 | * @history 2017-04-01, todd@geistinteractive.com 117 | * 118 | */ 119 | ``` 120 | ## JSON.Format ( text;descriptor) 121 | ``` 122 | /** 123 | * 124 | * Formats the JSON for readability and 125 | * checks if it is valid. 126 | * designed for the start of scripts 127 | * 128 | * @param {string} text the string to to test 129 | * @param {string} descriptor the error descriptor to use if there is one. 130 | * 131 | * @module fm-json-additions 132 | * @see https://github.com/geistinteractive/fm-json-additions 133 | * 134 | * @history 2017–11-24 created, todd@geistinteractive.com 135 | * 136 | */ 137 | ``` 138 | ## JSON.GetValuesAtPath ( array;path) 139 | ``` 140 | /** 141 | * 142 | * returns list containing only the values at that path 143 | * 144 | * @param {array} array a valid JSON Array of objects 145 | * @param {string} the path to the property you want to list 146 | * 147 | * @module fm-json-additions 148 | * @see https://github.com/geistinteractive/fm-json-additions 149 | * 150 | * @history 2017-05-16, john@e-rwu.com, fixes gh #5, #4 151 | * @history 2017-04-01, todd@geistinteractive.com, created 152 | * 153 | * ===================================== 154 | */ 155 | ``` 156 | ## JSON.IsValid ( json) 157 | ``` 158 | /** 159 | * 160 | * Tests to see if the JSON object is valid 161 | * 162 | * @param {object} json the JSON object to to test 163 | 164 | * @module fm-json-additions 165 | * @see https://github.com/geistinteractive/fm-json-additions 166 | * 167 | * @history 2017–11-29 updated doc block for clarity, dave@geistinteractive.com 168 | * @history 2017–11-23 created, todd@geistinteractive.com 169 | * 170 | */ 171 | ``` 172 | ## JSON.Merge ( target;source) 173 | ``` 174 | /** 175 | * 176 | * performs a shallow merge on two JSONObjects 177 | * 178 | * @param {object} target the object to merge into 179 | * @param {object} source the object to merge from 180 | * 181 | * @module fm-json-additions 182 | * @see https://github.com/geistinteractive/fm-json-additions 183 | * 184 | * @history 2017–05-15 fixed gh# 1, todd@geistinteractive.com 185 | * @history 2017–04-04 created, todd@geistinteractive.com 186 | * 187 | */ 188 | ``` 189 | ## JSON.Pluck ( PluckList) 190 | ``` 191 | /** 192 | * ===================================== 193 | * 194 | * Applies a list of JSON.PluckProps. to a $JSON.Pluck.From 195 | * 196 | * @param {list} PluckList the list of Plucks to apply 197 | * 198 | * @module fm-json-additions 199 | * @see https://github.com/geistinteractive/fm-json-additions 200 | * 201 | * @history 2017-09-01 created, todd@geistinteractive.com 202 | * 203 | * ===================================== 204 | */ 205 | ``` 206 | ## JSON.Pluck.From ( JSON) 207 | ``` 208 | /** 209 | * ===================================== 210 | * 211 | * helper function that store the source json to a known var 212 | * $JSON.Pluck.From 213 | * 214 | * @param {object} the json to Pluck from 215 | * 216 | * @module fm-json-additions 217 | * @see https://github.com/geistinteractive/fm-json-additions 218 | * 219 | * @history 2017-09-01 created, todd@geistinteractive.com 220 | * 221 | */ 222 | ``` 223 | ## JSON.Pluck.Prop ( PropToPluck;JSONType;As) 224 | ``` 225 | /** 226 | * ===================================== 227 | * 228 | * Plucks the prop from the source JSON and puts in the new JSON 229 | * 230 | * @param {string} PropToPluck the name of the prop to pluck from the souce JSON 231 | * @param {number} [JSONType], JSONType, use the provided constants, defaults to "" which means it will guess 232 | * @param {string} [As=PropToPluck] an optional name to use instead of the original name defaults to PropToPluck 233 | * 234 | * @module fm-json-additions 235 | * @see https://github.com/geistinteractive/fm-json-additions 236 | * 237 | * @history 2017-09-01 created, todd@geistinteractive.com 238 | * 239 | * ===================================== 240 | */ 241 | ``` 242 | ## JSON.Push ( target;source;type) 243 | ``` 244 | /** 245 | * 246 | * JSON.Push ( target ; source ; type ) 247 | * 248 | * Pushes a new object onto the end of the array 249 | * 250 | * @param {object} source : the object to push 251 | * @param {array} target : the array receiving the object 252 | * @param {constant} type : a valid JSON type constant (e.g., JSONString) 253 | * 254 | * @requires {function} JSON.ArrayLength 255 | * 256 | * @module fm-json-additions 257 | * @see https://github.com/geistinteractive/fm-json-additions 258 | * 259 | * @history 2017-11-30 dave@geistinteractive.com 260 | * - Validate target instead of source 261 | * - Allow for empty target 262 | * - Added JSON type constant to accept source with all valid JSON elements 263 | * @history 2017-11-29 created, dave@geistinteractive.com 264 | * 265 | */ 266 | ``` 267 | ## JSON.Transform ( TransformationList) 268 | ``` 269 | /** 270 | * ===================================== 271 | * 272 | * Applies a list of JSON.Transformation. to $JSON.Pluck.This 273 | * 274 | * @param {list} TransformationList the list of Transformations to apply 275 | * 276 | * @module fm-json-additions 277 | * @see https://github.com/geistinteractive/fm-json-additions 278 | * @history 2017-11-17 created, todd@geistinteractive.com 279 | * 280 | * ===================================== 281 | */ 282 | ``` 283 | ## JSON.Transform.ISODates ( path;Type) 284 | ``` 285 | /** 286 | * ===================================== 287 | * 288 | * Performs an ISO Date and Time transform on the given property 289 | * 290 | * @param {string} path the path to the value to be transformed 291 | * @param {string} [Type] A type of transform to apply. Must be one of "Date.ToISO", "Date.FromISO", "Time.FromISO", "Time.ToISO", "TimeStamp.ToISO", "TimeStamp.FromISO", 292 | * 293 | * @module fm-json-additions 294 | * @see https://github.com/geistinteractive/fm-json-additions 295 | * 296 | * @history 2017-11-17 created, todd@geistinteractive.com 297 | * ===================================== 298 | */ 299 | ``` 300 | ## JSON.Transform.This ( JSON) 301 | ``` 302 | /** 303 | * ===================================== 304 | * 305 | * helper function that store the source json to a known var 306 | * $JSON.Pluck.This 307 | * 308 | * @param {object} the json to Transform 309 | * 310 | * @module fm-json-additions 311 | * @see https://github.com/geistinteractive/fm-json-additions 312 | * @history 2017-11-17 created, todd@geistinteractive.com 313 | * 314 | */ 315 | ``` 316 | -------------------------------------------------------------------------------- /functions/JSON.ArrayConcat.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * JSON.ArrayConcat ( firstArray ; secondArray ) 4 | * 5 | * RETURNS: 6 | * a longer array of the first & second concatinated 7 | * 8 | * @param {array} firstArray 9 | * @param {array} secondArray 10 | * 11 | * @returns {array} 12 | * 13 | * @module fm-json-additions 14 | * @see https://github.com/geistinteractive/fm-json-additions 15 | * 16 | * @history 2017-05-07, cdelfs@delfsengineering.ca 17 | * 18 | */ 19 | 20 | 21 | Let( 22 | [ 23 | // enable to test in data viewer 24 | //firstArray = " [\"some value\",2,3,4,5] "; 25 | //secondArray = "[6,7,8,9,10]"; 26 | 27 | // remove spaces n squares 28 | firstArray = Trim(firstArray); 29 | firstArray = Right ( firstArray ; Length ( firstArray ) -1 ); 30 | firstArray = Left ( firstArray ; Length ( firstArray )-1 ); 31 | 32 | secondArray = Trim(secondArray); 33 | secondArray = Right ( secondArray ; Length ( secondArray ) -1 ); 34 | secondArray = Left ( secondArray ; Length ( secondArray )-1 ); 35 | 36 | separator = If( firstArray ="" or secondArray = "" ; "" ; ", " ); 37 | finalArray = "[" & firstArray & separator & secondArray & "]" 38 | 39 | ]; 40 | 41 | //wrapping in JSONGetElement to remove any lingering white space 42 | JSONGetElement(finalArray; "" ) 43 | 44 | ) -------------------------------------------------------------------------------- /functions/JSON.ArrayFromRelated.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * JSON.ArrayFromRelated( JSONField ) 4 | * 5 | *@params {reference} JSONField a reference to the field 6 | * 7 | *@returns {array} array containng the values from the related field 8 | * 9 | * @module fm-json-additions 10 | * @see https://github.com/geistinteractive/fm-json-additions 11 | * 12 | * @history 2017-06-01, todd@geistinteractive.com, created 13 | * 14 | */ 15 | 16 | 17 | "[" & 18 | 19 | Substitute( 20 | List(JSONField) ; 21 | "¶" ; "," 22 | ) 23 | 24 | & 25 | 26 | "]" -------------------------------------------------------------------------------- /functions/JSON.ArrayLength.fmfn: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * JSONArrayLength ( array ; path) 4 | * 5 | * @param {array} array a valid JSON Array 6 | * @param {string} path the path to the array if it is nested 7 | * 8 | * @returns {number} 9 | * 10 | * @module fm-json-additions 11 | * @see https://github.com/geistinteractive/fm-json-additions 12 | * 13 | * @history 2017-04-09, todd@geistinteractive.com, created 14 | * 15 | * ===================================== 16 | */ 17 | 18 | 19 | Let ( [ 20 | _array = Substitute ( array ; [ "\r" ; "" ] ; [ "\n" ; "" ]; ["null" ; "\"NULL\""] ); 21 | _values = JSONListValues ( _array ; path ); 22 | _array = JSONGetElement ( _array ; path ); 23 | isArray = ( Left ( _array ; 1 ) & Right ( _array ; 1 ) = "[]" ) 24 | ]; 25 | 26 | Case ( 27 | not isArray ; 0 ; 28 | Left ( _values ; 1 ) = "?" ; 0 ; 29 | ValueCount ( _values ) 30 | ) //end case 31 | 32 | ) //end let -------------------------------------------------------------------------------- /functions/JSON.ArraySort.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Sort an array 4 | * 5 | * @param {array} array a valid JSON array 6 | * @param {string} sortChildren 7 | * 8 | * @returns {array} 9 | * 10 | * @module fm-json-additions 11 | * @see https://github.com/geistinteractive/fm-json-additions 12 | * 13 | * @history 2017-06-20, michael.wallace@rcconsulting.com , gh #12 14 | * 15 | */ 16 | 17 | Case ( 18 | Left ( array ; 1 ) ≠ "[" ; 19 | "? * Line 1, Column 1¶ Expected a JSON Array. Invalid parameter" ; 20 | Right ( array ; 1 ) ≠ "]" ; 21 | "? * Line 1, Column " & Length ( array ) & "¶ Expected a JSON Array. Invalid parameter" ; 22 | Left ( JSONGetElement ( array ; "" ) ; 1 ) = "?" ; 23 | JSONGetElement ( array ; "" ) ; 24 | // Passed checks 25 | 26 | Let([ 27 | ~array = array 28 | 29 | /* DEVELOPER TESTING CREATE COMPLEX ARRAY (UNCOMMENT TO TEST IN DATA VIEWER)*/ 30 | /* 31 | ; ~array = JSONGetElement ( "[\"apples\",\"\",\"12:35 AM\",null,\"oranges\rpears\",[\"foo\",\"bar\"],\"bananas\",{\"hello\":\"world\"},[1.5,\"$1.50\"],4000,456,1,\"3:15 PM\"]" ; "" ) 32 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; Quote ( GetAsText ( Get ( CurrentTimestamp ) - 60*60*24*365.25*35.75 ) ) ; "JSONString" ) 33 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; Quote ( GetAsText ( Get ( CurrentDate ) ) ) ; "JSONString" ) 34 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; "{\"firstName\":\"Michael\"}" ; "JSONObject" ) 35 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; Quote ( GetAsText ( Get ( CurrentDate ) - 22578 ) ) ; "JSONString" ) 36 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; Quote ( GetAsText ( Get ( CurrentTimestamp ) ) ) ; "JSONString" ) 37 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; Quote ( GetAsText ( Get ( CurrentTimestamp ) - 60*60*24*365.25*15.02 ) ) ; "JSONString" ) 38 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; "{\"lastName\":\"Wallace\"}" ; "JSONObject" ) 39 | ; ~array = JSONSetElement ( ~array ; ValueCount ( JSONListKeys ( ~array ; "" ) ) ; Quote ( GetAsText ( Get ( CurrentDate ) - 1257 ) ) ; "JSONString" ) 40 | ; sortChildren = false 41 | */ 42 | 43 | ; sortChildren = If ( IsEmpty ( sortChildren ) ; False ; sortChildren ) 44 | 45 | /* HANDLE MULTIPLE VALUES PER ARRAY VALUE AND TREAT ALL MULTIPLE VALUE ITEMS AS TEXT IN THE SORT */ 46 | ; ~r = GetContainerAttribute ( "\r" ; "MD5" ) & GetAsText ( Ceiling ( Random * 10000 ) ) 47 | ; ~n = GetContainerAttribute ( "\n" ; "MD5" ) & GetAsText ( Ceiling ( Random * 10000 ) ) 48 | ; ~arrayNew = Substitute ( ~array ; ["\r";~r] ; ["\n";~n] ) 49 | 50 | 51 | /* SPLIT OUT NUMBERS AND SORT THEM INTO THEIR OWN ARRAY */ 52 | ; ~isNumber = "GetAsNumber(Filter($item;\"0123456789.-\"))=$item and 53 | PatternCount ( $item ; \".\" )<2 and 54 | PatternCount ( $item ; \"-\" )<2" 55 | 56 | ; ~numArray = JSON.FilterByExpression ( ~arrayNew ; ~isNumber ) 57 | ; ~numbers = JSONListValues ( ~numArray ; "" ) 58 | ; ~sortedNumbers = If ( ~numbers ; SortValues ( ~numbers ; 2 ) ) 59 | ; ~sortedNumbers = If ( ~numbers ; If ( Right ( ~sortedNumbers ; 1 ) = "¶" ; Left ( ~sortedNumbers ; Length ( ~sortedNumbers ) - 1 ) ; ~sortedNumbers ) ) 60 | ; ~sortedNumbersArray = If ( ~numbers ; Substitute ( "[" & ~sortedNumbers & "]" ; ["¶";","]) ; "[]" ) 61 | 62 | 63 | /* SPLIT OUT ARRAYS AND SORT THEM INTO THEIR OWN ARRAY */ 64 | ; ~isArray = "Left($item;1)=\"[\" and JSONGetElement ( $item ; \"\" )=$item" 65 | ; ~arrayArray = JSON.FilterByExpression ( ~arrayNew ; ~isArray ) 66 | ; ~arrays = If ( ~arrayArray≠"[]" ; JSONListValues ( ~arrayArray ; "" ) ) 67 | 68 | /* sort child arrays if sortChildren flag is true */ 69 | ; ~arraysEscaped = If ( sortChildren ; Substitute ( ~arrays ; "\"" ; "\\\"" ) ) 70 | ; ~calcStart = "JSON.ArraySort(\"" 71 | ; ~calcEnd = "\";False);" 72 | ; ~sortChildrenCalc = If ( sortChildren ; "List( " & ~calcStart & Substitute ( ~arraysEscaped ; "¶" ; ~calcEnd & ~calcStart ) & ~calcEnd & "\"\" )" ) 73 | ; ~arrays = If ( sortChildren ; Evaluate ( ~sortChildrenCalc ) ; ~arrays ) 74 | 75 | ; ~sortedArrays = If ( ~arrayArray≠"[]" ; SortValues ( ~arrays ; 1 ) ) 76 | ; ~sortedArrays = If ( ~arrayArray≠"[]" ; If ( Right ( ~sortedArrays ; 1 ) = "¶" ; Left ( ~sortedArrays ; Length ( ~sortedArrays ) - 1 ) ; ~sortedArrays ) ) 77 | ; ~sortedArrayArray = If ( ~arrayArray≠"[]" ; Substitute ( "[\"" & ~sortedArrays & "\"]" ; ["¶";"\",\""]; [~r;"\r"]; [~n;"\n"]; ["\"[";"["]; ["]\"";"]"] ) ; "[]" ) 78 | 79 | 80 | /* SPLIT OUT OBJECTS AND SORT THEM INTO THEIR OWN ARRAY */ 81 | ; ~isObject = "Left($item;1)=\"{\" and JSONGetElement ( $item ; \"\" )=$item" 82 | ; ~objectArray = JSON.FilterByExpression ( ~arrayNew ; ~isObject ) 83 | ; ~objects = If ( ~objectArray≠"[]" ; JSONListValues ( ~objectArray ; "" ) ) 84 | ; ~sortedObjects = If ( ~objectArray≠"[]" ; SortValues ( ~objects ; 1 ) ) 85 | ; ~sortedObjects = If ( ~objectArray≠"[]" ; If ( Right ( ~sortedObjects ; 1 ) = "¶" ; Left ( ~sortedObjects ; Length ( ~sortedObjects ) - 1 ) ; ~sortedObjects ) ) 86 | ; ~sortedObjectsArray = If ( ~objectArray≠"[]" ; Substitute ( "[\"" & ~sortedObjects & "\"]" ; ["¶";"\",\""]; [~r;"\r"]; [~n;"\n"]; ["\"{";"{"]; ["}\"";"}"] ) ; "[]" ) 87 | 88 | 89 | /* SPLIT OUT TIMESTAMPS AND SORT THEM INTO THEIR OWN ARRAY */ 90 | /* These must be converted to numbers to sort and then converted back again */ 91 | ; ~isTimestamp = "GetAsTimestamp($item) ≠ \"?\" and 92 | PatternCount($item;\":\") and 93 | ( PatternCount($item;\"/\") or PatternCount($item;\"-\") ) and 94 | Filter($item ; \"0123456789 :/-AMP\")=$item" 95 | ; ~timestampArray = JSON.FilterByExpression ( ~arrayNew ; ~isTimestamp ) 96 | ; ~timestamps = If ( ~timestampArray≠"[]" ; JSONListValues ( ~timestampArray ; "" ) ) 97 | ; ~calcStart = "GetAsNumber( GetAsTimeStamp( \"" 98 | ; ~calcEnd = "\" ) ) ; " 99 | ; ~timestampscalc = "List( " & ~calcStart & Substitute ( ~timeStamps ; "¶" ; ~calcEnd & ~calcStart ) & ~calcEnd & "\"\" )" 100 | ; ~timestampsAsNumbers = If ( ~timestampArray≠"[]" ; Evaluate ( ~timestampscalc ) ) 101 | ; ~sortedTimestampsAsNumbers = If ( ~timestampArray≠"[]" ; SortValues ( ~timestampsAsNumbers ; 2 ) ) 102 | ; ~sortedTimestampsAsNumbers = If ( ~timestampArray≠"[]" ; If ( Right ( ~sortedTimestampsAsNumbers ; 1 ) = "¶" ; Left ( ~sortedTimestampsAsNumbers ; Length ( ~sortedTimestampsAsNumbers ) - 1 ) ; ~sortedTimestampsAsNumbers ) ) 103 | ; ~calcStart = "GetAsTimeStamp( " 104 | ; ~calcEnd = " ) ; " 105 | ; ~timestampscalc = "List( " & ~calcStart & Substitute ( ~sortedTimestampsAsNumbers ; "¶" ; ~calcEnd & ~calcStart ) & ~calcEnd & "\"\" )" 106 | ; ~sortedTimestamps = If ( ~timestampArray≠"[]" ; Evaluate ( ~timestampscalc ) ) 107 | ; ~sortedTimestampsArray = If ( ~timestampArray≠"[]" ; Substitute ( "[\"" & ~sortedTimestamps & "\"]" ; ["¶";"\",\""]; [~r;"\r"]; [~n;"\n"] ) ; "[]" ) 108 | 109 | 110 | /* SPLIT OUT TIMES AND SORT THEM INTO THEIR OWN ARRAY */ 111 | /* These must be converted to numbers to sort and then converted back again */ 112 | ; ~isTime = "GetAsTime($item) ≠ \"?\" and 113 | PatternCount($item;\":\") and 114 | Filter($item ; \"0123456789 :AMP\")=$item" 115 | ; ~timeArray = JSON.FilterByExpression ( ~arrayNew ; ~isTime ) 116 | ; ~times = If ( ~timeArray≠"[]" ; JSONListValues ( ~timeArray ; "" ) ) 117 | ; ~calcStart = "GetAsNumber( GetAsTime( \"" 118 | ; ~calcEnd = "\" ) ) ; " 119 | ; ~timescalc = "List( " & ~calcStart & Substitute ( ~times ; "¶" ; ~calcEnd & ~calcStart ) & ~calcEnd & "\"\" )" 120 | ; ~timesAsNumbers = If ( ~timeArray≠"[]" ; Evaluate ( ~timescalc ) ) 121 | ; ~sortedTimesAsNumbers = If ( ~timeArray≠"[]" ; SortValues ( ~timesAsNumbers ; 2 ) ) 122 | ; ~sortedTimesAsNumbers = If ( ~timeArray≠"[]" ; If ( Right ( ~sortedTimesAsNumbers ; 1 ) = "¶" ; Left ( ~sortedTimesAsNumbers ; Length ( ~sortedTimesAsNumbers ) - 1 ) ; ~sortedTimesAsNumbers ) ) 123 | ; ~calcStart = "Let([~time = GetAsTime( " 124 | ; ~calcEnd = " );~hr=Mod(hour(~time);12);~hr=If(~hr;~hr;12);~min=Right(\"0\"&Minute(~time);2);~sec=Right(\"0\"&Seconds(~time);2);~pm=Div(hour(~time);12)];~hr&\":\"&~min&if(~sec;\":\"&~sec)&if(~pm;\" PM\";\" AM\")); " 125 | ; ~timescalc = "List( " & ~calcStart & Substitute ( ~sortedTimesAsNumbers ; "¶" ; ~calcEnd & ~calcStart ) & ~calcEnd & "\"\" )" 126 | ; ~sortedTimes = If ( ~timeArray≠"[]" ; Evaluate ( ~timescalc ) ) 127 | ; ~sortedTimesArray = If ( ~timeArray≠"[]" ; Substitute ( "[\"" & ~sortedTimes & "\"]" ; ["¶";"\",\""]; [~r;"\r"]; [~n;"\n"] ) ; "[]" ) 128 | 129 | 130 | /* SPLIT OUT DATES AND SORT THEM INTO THEIR OWN ARRAY */ 131 | /* These must be converted to numbers to sort and then converted back again */ 132 | ; ~isDate = "GetAsDate($item) ≠ \"?\" and 133 | ( PatternCount($item;\"/\") or PatternCount($item;\"-\") ) and 134 | Filter($item ; \"0123456789 /-\")=$item" 135 | ; ~dateArray = JSON.FilterByExpression ( ~arrayNew ; ~isDate ) 136 | ; ~dates = If ( ~dateArray≠"[]" ; JSONListValues ( ~dateArray ; "" ) ) 137 | ; ~calcStart = "GetAsNumber( GetAsDate( \"" 138 | ; ~calcEnd = "\" ) ) ; " 139 | ; ~datescalc = "List( " & ~calcStart & Substitute ( ~dates ; "¶" ; ~calcEnd & ~calcStart ) & ~calcEnd & "\"\" )" 140 | ; ~datesAsNumbers = If ( ~dateArray≠"[]" ; Evaluate ( ~datescalc ) ) 141 | ; ~sortedDatesAsNumbers = If ( ~dateArray≠"[]" ; SortValues ( ~datesAsNumbers ; 2 ) ) 142 | ; ~sortedDatesAsNumbers = If ( ~dateArray≠"[]" ; If ( Right ( ~sortedDatesAsNumbers ; 1 ) = "¶" ; Left ( ~sortedDatesAsNumbers ; Length ( ~sortedDatesAsNumbers ) - 1 ) ; ~sortedDatesAsNumbers ) ) 143 | ; ~calcStart = "GetAsDate( " 144 | ; ~calcEnd = " ) ; " 145 | ; ~datescalc = "List( " & ~calcStart & Substitute ( ~sortedDatesAsNumbers ; "¶" ; ~calcEnd & ~calcStart ) & ~calcEnd & "\"\" )" 146 | ; ~sortedDates = If ( ~dateArray≠"[]" ; Evaluate ( ~datescalc ) ) 147 | ; ~sortedDatesArray = If ( ~dateArray≠"[]" ; Substitute ( "[\"" & ~sortedDates & "\"]" ; ["¶";"\",\""]; [~r;"\r"]; [~n;"\n"] ) ; "[]" ) 148 | 149 | 150 | /* HANDLE THE REST AS TEXT AND SPLIT THEM OUT INTO THEIR OWN SORTED ARRAY */ 151 | ; ~isText = "not (" & ~isNumber & ") and not (" & ~isTimestamp & ") and not (" & ~isTime & ") and not (" & ~isDate & ") and not (" & ~isArray & ") and not (" & ~isObject & ")" 152 | ; ~textArray = JSON.FilterByExpression ( ~arrayNew ; ~isText ) 153 | ; ~text = JSONListValues ( ~textArray ; "" ) 154 | ; ~sortedText = SortValues ( ~text ; 1 ) 155 | ; ~sortedText = If ( Right ( ~sortedText ; 1 ) = "¶" ; Left ( ~sortedText ; Length ( ~sortedText ) - 1 ) ; ~sortedText ) 156 | ; ~sortedTextArray = If ( ~textArray≠"[]" ; Substitute ( "[\"" & ~sortedText & "\"]" ; ["¶";"\",\""]; [~r;"\r"]; [~n;"\n"]; ["\"{";"{"]; ["}\"";"}"] ) ; "[]" ) 157 | 158 | 159 | /* RECOMBINE INTO A SINGLE OBJECT */ 160 | // Set order here... 161 | ; ~first = ~sortedNumbersArray 162 | ; ~second = ~sortedTextArray 163 | ; ~third = ~sortedDatesArray 164 | ; ~fourth = ~sortedTimesArray 165 | ; ~fifth = ~sortedTimestampsArray 166 | ; ~sixth = ~sortedArrayArray 167 | ; ~seventh = ~sortedObjectsArray 168 | 169 | ; ~result = JSON.ArrayConcat ( JSON.ArrayConcat ( JSON.ArrayConcat ( JSON.ArrayConcat ( JSON.ArrayConcat ( JSON.ArrayConcat ( ~first ; ~second ) ; ~third ) ; ~fourth ) ; ~fifth ) ; ~sixth ) ; ~seventh ) 170 | 171 | ]; 172 | ~result 173 | )// End Let 174 | )// End Case -------------------------------------------------------------------------------- /functions/JSON.ContainsProperty.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * Test if the JSON contains the give property 5 | * 6 | * @param {object} json a valid JSON object 7 | * @param {string} name the property to test (can be in form body.path.item) 8 | * 9 | * @returns {boolean} 10 | * 11 | * @module fm-json-additions 12 | * @see https://github.com/geistinteractive/fm-json-additions 13 | * 14 | * @history 2017-10-12, todd@geistinteractive.com, fixed depth gh #14 15 | * @history 2017-05-16, john@e-rwu.com, added path depth, gh #3 16 | * @history 2017-04-09, todd@geistinteractive.com 17 | * 18 | * ===================================== 19 | */ 20 | 21 | 22 | Case ( PatternCount ( name ; "." ) > 0 and Length ( name ) >= 3 ; 23 | 24 | JSON.ContainsProperty ( JSONGetElement ( json ; GetValue ( Substitute ( name ; "." ; ¶ ) ; 1 ) ) ; Middle ( name ; Position ( name ; "." ; 1 ; 1 ) + 1 ; Length ( name ) ) ) 25 | 26 | ; 27 | 28 | Let ( [ 29 | 30 | keys = JSONListKeys ( json ; "" ) 31 | 32 | ] ; 33 | 34 | not IsEmpty ( FilterValues ( name ; keys ) ) 35 | 36 | ) 37 | ) -------------------------------------------------------------------------------- /functions/JSON.FilterByExpression.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * filters the array by a FileMaker expression 4 | * 5 | *@param {array} array a valid JSON Array 6 | *@param {string} expression a valid FileMaker Expression. 7 | * It can use 8 | * "$item" to access the array item for use 9 | * in the filter calculation. 10 | * 11 | * @returns {array} 12 | * 13 | * @module fm-json-additions 14 | * @see https://github.com/geistinteractive/fm-json-additions 15 | * 16 | * @history, 2017-06-20, michael.wallace@rcconsulting.com 17 | * @history 2017-04-01, todd@geistinteractive.com 18 | * 19 | */ 20 | 21 | Let( 22 | [ 23 | 24 | // start a newArray if one is already in place 25 | $newArray = Case ( IsEmpty ($newArray) ; "[]" ; $newArray ); 26 | 27 | notValid = Left(JSONFormatElements(array);1) = "?" ; 28 | c = ValueCount( JSONListValues ( array ; "" )); 29 | 30 | // store the current item in a var so it can be used in the expression 31 | $item = JSONGetElement ( array ; 0 ); 32 | 33 | //evaluate the expresion 34 | passed = GetAsBoolean( Evaluate( expression ) ); 35 | 36 | // determine the type of the element to be added if it is time, timestamp, or date 37 | // as these are not being handled correctly by FileMaker's default functionality 38 | isTimestamp = If ( passed ; GetAsTimestamp($item) ≠ "?" and 39 | PatternCount($item;":") and 40 | ( PatternCount($item;"/") or PatternCount($item;"-") ) and 41 | Filter($item ; "0123456789 :/-AMP")=$item ) ; 42 | 43 | isTime = If ( passed ; GetAsTime($item) ≠ "?" and 44 | PatternCount($item;":") and 45 | Filter($item ; "0123456789 :AMP")=$item ) ; 46 | 47 | isDate = If ( passed ; GetAsDate($item) ≠ "?" and 48 | ( PatternCount($item;"/") or PatternCount($item;"-") ) and 49 | Filter($item ; "0123456789 /-")=$item ) ; 50 | 51 | // add thisItem to the new array if it passes 52 | n = ValueCount( JSONListValues ( $newArray ; "" )); 53 | $newArray = Case ( passed and c >0 and ( isTimestamp or isTime or isDate ) ; 54 | JSONSetElement ( $newArray; n ; Quote ( $item ) ; "JSONString" ) ; 55 | passed and c >0 ; 56 | JSONSetElement ( $newArray; n ; $item ; "" ) ; 57 | // default not (passed and c >0) 58 | $newArray ) ; 59 | 60 | //update the array for use in the next round 61 | array = JSONDeleteElement(array ;0 ) ; 62 | 63 | //clear this for the next round 64 | $item = "" 65 | 66 | ]; 67 | Case( 68 | 69 | c < 1 or notValid ; $newArray & Let($newArray=""; "" ); // return the newArray and clear the var 70 | JSON.FilterByExpression (array ; expression ) 71 | 72 | 73 | ) 74 | 75 | ) -------------------------------------------------------------------------------- /functions/JSON.Format.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Formats the JSON for readability and 4 | * checks if it is valid. 5 | * designed for the start of scripts 6 | * 7 | * @param {string} text the string to to test 8 | * @param {string} descriptor the error descriptor to use if there is one. 9 | * 10 | * @module fm-json-additions 11 | * @see https://github.com/geistinteractive/fm-json-additions 12 | * 13 | * @history 2017–11-24 created, todd@geistinteractive.com 14 | * 15 | */ 16 | 17 | Let( 18 | [ 19 | 20 | formatted = JSONFormatElements ( text ); 21 | isValidJSON = Left(formatted; 3 ) <> "? *" 22 | ]; 23 | 24 | If ( 25 | isValidJSON ; formatted ; 26 | 27 | JSONSetElement ( "" ; 28 | 29 | ["errorCode" ; -2 ; JSONNumber ]; 30 | ["errorMessage" ; formatted ; JSONString ]; 31 | ["type" ; "JSON" ; JSONString ]; 32 | ["descriptor" ; descriptor ; JSONString ] 33 | 34 | ) 35 | 36 | ) 37 | 38 | ) -------------------------------------------------------------------------------- /functions/JSON.GetValuesAtPath.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * returns list containing only the values at that path 4 | * 5 | * @param {array} array a valid JSON Array of objects 6 | * @param {string} the path to the property you want to list 7 | * 8 | * @module fm-json-additions 9 | * @see https://github.com/geistinteractive/fm-json-additions 10 | * 11 | * @history 2017-05-16, john@e-rwu.com, fixes gh #5, #4 12 | * @history 2017-04-01, todd@geistinteractive.com, created 13 | * 14 | * ===================================== 15 | */ 16 | 17 | 18 | Let ( [ 19 | 20 | notValid = Left ( JSONFormatElements ( array ) ; 1 ) = "?" ; 21 | c = ValueCount ( JSONListValues ( array ; "" ) ) ; 22 | 23 | thisItem = JSONGetElement ( array ; c - 1 ) ; 24 | newArray = JSONDeleteElement ( array ; c - 1 ) ; 25 | prop = JSONGetElement ( thisItem ; path ) ; 26 | prop = If ( Left ( prop ; 1 ) = "?" ; ""; prop ) 27 | 28 | ]; 29 | 30 | Case ( 31 | c < 1 or notValid ; "" ; 32 | List ( JSON.GetValuesAtPath ( newArray ; path ) ; prop ) 33 | ) //end case 34 | 35 | ) //end let -------------------------------------------------------------------------------- /functions/JSON.IsValid.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Tests to see if the JSON object is valid 4 | * 5 | * @param {object} json the JSON object to to test 6 | 7 | * @module fm-json-additions 8 | * @see https://github.com/geistinteractive/fm-json-additions 9 | * 10 | * @history 2017–11-29 updated doc block for clarity, dave@geistinteractive.com 11 | * @history 2017–11-23 created, todd@geistinteractive.com 12 | * 13 | */ 14 | 15 | 16 | Left( 17 | JSONGetElement ( json ; "doesnotmatterwhatishere" ); 3 18 | ) 19 | <>"? *" -------------------------------------------------------------------------------- /functions/JSON.Merge.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * performs a shallow merge on two JSONObjects 4 | * 5 | * @param {object} target the object to merge into 6 | * @param {object} source the object to merge into 7 | * 8 | * @module fm-json-additions 9 | * @see https://github.com/geistinteractive/fm-json-additions 10 | * 11 | * @history 2017–05-15 fixed gh# 1, todd@geistinteractive.com 12 | * @history 2017–04-04 created, todd@geistinteractive.com 13 | * 14 | */ 15 | 16 | 17 | Let( 18 | [ 19 | 20 | sourceKeys = JSONListKeys ( source ; "" ); 21 | targetKeys = JSONListKeys ( target ; "" ) 22 | 23 | ]; 24 | Case( 25 | 26 | //look for error ans exit 27 | Left(sourceKeys; 1) = "?" ; sourceKeys & " In Source."; 28 | Left(targetKeys; 1) = "?" ; targetKeys & " In Target." ; 29 | Left( JSONGetElement (source ; "" ) ;1) = "[" ; "? * Array in Source. Must be an object" ; 30 | 31 | // look for the last recusion and exit 32 | ValueCount(sourceKeys) < 1 ; target ; // done 33 | 34 | 35 | Let( 36 | [ 37 | 38 | // merge this rounds key into the target 39 | thisKey = GetValue(sourceKeys ; 1 ); 40 | thisValue = JSONGetElement( source; thisKey ); 41 | firstChar = Left(thisValue; 1); 42 | needToCheckForNumber = Filter(firstChar ; "0123456789") = firstChar ; 43 | JSONType = If( needToCheckForNumber and GetAsText(thisValue) <> GetAsNumber(thisValue) ; JSONString ; "") ; 44 | 45 | newTarget = JSONSetElement ( target ; thisKey ; thisValue ; JSONType ); 46 | 47 | // remove this rounds key from the source 48 | newSource = JSONDeleteElement ( source ; thisKey ) 49 | ]; 50 | 51 | // repeat 52 | JSON.Merge(newTarget ; newSource ) 53 | ) 54 | ) 55 | 56 | ) -------------------------------------------------------------------------------- /functions/JSON.Pluck.From.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * helper function that store the source json to a known var 5 | * $JSON.Pluck.From 6 | * 7 | * @param {object} the json to Pluck from 8 | * 9 | * @module fm-json-additions 10 | * @see https://github.com/geistinteractive/fm-json-additions 11 | * 12 | * @history 2017-09-01 created, todd@geistinteractive.com 13 | * 14 | */ 15 | 16 | 17 | Let( 18 | [ 19 | $JSON.Pluck.From = JSON 20 | ]; 21 | "" 22 | ) -------------------------------------------------------------------------------- /functions/JSON.Pluck.Prop.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * Plucks the prop from the source JSON and puts in the new JSON 5 | * 6 | * @param {string} PropToPluck the name of the prop to pluck from the souce JSON 7 | * @param {number} [JSONType], JSONType, use the provided constants, defaults to "" which means it will guess 8 | * @param {string} [As=PropToPluck] an optional name to use instead of the original name defaults to PropToPluck 9 | * 10 | * @module fm-json-additions 11 | * @see https://github.com/geistinteractive/fm-json-additions 12 | * 13 | * @history 2017-09-01 created, todd@geistinteractive.com 14 | * 15 | * ===================================== 16 | */ 17 | 18 | If( 19 | JSON.ContainsProperty ( $JSON.Pluck.From ; PropToPluck ); 20 | 21 | 22 | Let( 23 | [ 24 | value = JSONGetElement($JSON.Pluck.From ; PropToPluck ); 25 | As = If( IsEmpty (As) ; PropToPluck ; As); 26 | $JSON.Pluck.Result = JSONSetElement($JSON.Pluck.Result; As ; value ; JSONType ) 27 | ]; 28 | "" 29 | ) 30 | 31 | 32 | ) -------------------------------------------------------------------------------- /functions/JSON.Pluck.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * Applies a list of JSON.PluckProps. to a $JSON.Pluck.From 5 | * 6 | * @param {list} PluckList the list of Plucks to apply 7 | * 8 | * @module fm-json-additions 9 | * @see https://github.com/geistinteractive/fm-json-additions 10 | * 11 | * @history 2017-09-01 created, todd@geistinteractive.com 12 | * 13 | * ===================================== 14 | */ 15 | 16 | 17 | Let( 18 | [ 19 | 20 | result = $JSON.Pluck.Result ; 21 | $JSON.Pluck.From = ""; 22 | $JSON.To.Pluck = "" 23 | ]; 24 | result 25 | ) -------------------------------------------------------------------------------- /functions/JSON.Push.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * JSON.Push ( target ; source ; type ) 4 | * 5 | * Pushes a new object onto the end of the array 6 | * 7 | * @param {object} source : the object to push 8 | * @param {array} target : the array receiving the object 9 | * @param {constant} type : a valid JSON type constant (e.g., JSONString) 10 | * 11 | * @requires {function} JSON.ArrayLength 12 | * 13 | * @module fm-json-additions 14 | * @see https://github.com/geistinteractive/fm-json-additions 15 | * 16 | * @history 2017-11-30 dave@geistinteractive.com 17 | * - Validate target instead of source 18 | * - Allow for empty target 19 | * - Added JSON type constant to accept source with all valid JSON elements 20 | * @history 2017-11-29 created, dave@geistinteractive.com 21 | * 22 | */ 23 | 24 | 25 | 26 | 27 | Let ( [ 28 | 29 | /* if target is null, create an empty array */ 30 | 31 | target = If ( IsEmpty ( target ) ; "[]" ; target ) 32 | 33 | ] ; 34 | 35 | 36 | Case ( 37 | 38 | /* validate */ 39 | 40 | Left ( target ; 1 ) <> "[" or 41 | Right ( target ; 1 ) <> "]" ; 42 | 43 | "? target is not a valid array" ; 44 | 45 | 46 | /* insert */ 47 | 48 | JSONSetElement ( 49 | target ; 50 | JSON.ArrayLength ( target ; "" ) ; // index 51 | source ; 52 | type 53 | ) 54 | 55 | 56 | ) 57 | 58 | ) -------------------------------------------------------------------------------- /functions/JSON.Transform.ISODates.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * Performs an ISO Date and Time transform on the given property 5 | * 6 | * @param {string} path the path to the value to be transformed 7 | * @param {string} [Type] A type of transform to apply. Must be one of "Date.ToISO", "Date.FromISO", "Time.FromISO", "Time.ToISO", "TimeStamp.ToISO", "TimeStamp.FromISO", 8 | * 9 | * @module fm-json-additions 10 | * @see https://github.com/geistinteractive/fm-json-additions 11 | * 12 | * @history 2017-11-17 created, todd@geistinteractive.com 13 | * ===================================== 14 | */ 15 | 16 | If( 17 | JSON.ContainsProperty ( $JSON.Transform.This ; path ); 18 | 19 | 20 | Let( 21 | [ 22 | value = JSONGetElement($JSON.Transform.This ; path ); 23 | 24 | value = 25 | Case( 26 | Type = "Date.FromISO" ; Date.FromISO ( value ); 27 | Type = "Date.ToISO" ; Date.ToISO ( value ); 28 | Type = "Time.ToISO" ; Time.ToISO ( value ); 29 | Type = "Time.FromISO" ; Time.FromISO ( value ); 30 | Type = "TimeStamp.FromISO" ; Timestamp.FromISO ( value ); 31 | Type = "TimeStamp.ToISO" ; Timestamp.ToISO ( value ); 32 | value 33 | ); 34 | 35 | 36 | $JSON.Transform.This = JSONSetElement($JSON.Transform.This; path ; value ; JSONString ) 37 | ]; 38 | "" 39 | ) 40 | 41 | 42 | ) -------------------------------------------------------------------------------- /functions/JSON.Transform.This.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * helper function that store the source json to a known var 5 | * $JSON.Pluck.This 6 | * 7 | * @param {object} the json to Transform 8 | * 9 | * @module fm-json-additions 10 | * @see https://github.com/geistinteractive/fm-json-additions 11 | * @history 2017-11-17 created, todd@geistinteractive.com 12 | * 13 | */ 14 | 15 | 16 | Let( 17 | [ 18 | $JSON.Transform.This = JSON 19 | ]; 20 | "" 21 | ) -------------------------------------------------------------------------------- /functions/JSON.Transform.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * Applies a list of JSON.Transformation. to $JSON.Pluck.This 5 | * 6 | * @param {list} TransformationList the list of Transformations to apply 7 | * 8 | * @module fm-json-additions 9 | * @see https://github.com/geistinteractive/fm-json-additions 10 | * @history 2017-11-17 created, todd@geistinteractive.com 11 | * 12 | * ===================================== 13 | */ 14 | 15 | 16 | Let( 17 | [ 18 | 19 | result = $JSON.Transform.This ; 20 | $JSON.Transform.This = ""; 21 | $JSON.To.Transform = "" 22 | ]; 23 | result 24 | ) -------------------------------------------------------------------------------- /functions/JSON.Transformation.fmfn: -------------------------------------------------------------------------------- 1 | /** 2 | * ===================================== 3 | * 4 | * Plucks the prop from the source JSON and puts in the new JSON 5 | * 6 | * @param {string} path the path to the value to be transformed 7 | * @param {string} [Type] A type of transform to apply. Must be one of "Date.ToISO", "Date.FromISO", "Time.FromISO", "Time.ToISO", "TimeStamp.ToISO", "TimeStamp.FromISO", 8 | * 9 | * @module fm-json-additions 10 | * @see https://github.com/geistinteractive/fm-json-additions 11 | * 12 | * @history 2017-11-17 created, todd@geistinteractive.com 13 | * ===================================== 14 | */ 15 | 16 | If( 17 | JSON.ContainsProperty ( $JSON.Transform.This ; path ) or 1; 18 | 19 | 20 | Let( 21 | [ 22 | value = JSONGetElement($JSON.Transform.This ; path ); 23 | 24 | value = 25 | Case( 26 | Type = "Date.FromISO" ; Date.FromISO ( value ); 27 | Type = "Date.ToISO" ; Date.ToISO ( value ); 28 | Type = "Time.ToISO" ; Time.ToISO ( value ); 29 | Type = "Time.FromISO" ; Time.FromISO ( value ); 30 | Type = "TimeStamp.FromISO" ; Timestamp.FromISO ( value ); 31 | Type = "TimeStamp.ToISO" ; Timestamp.ToISO ( value ); 32 | value 33 | ); 34 | 35 | 36 | $JSON.Transform.This = JSONSetElement($JSON.Transform.This; path ; value ; JSONString ) 37 | ]; 38 | "" 39 | ) 40 | 41 | 42 | ) --------------------------------------------------------------------------------