1 module uim.core.datatypes.json; 2 3 @safe: 4 import uim.core; 5 6 /// Checks if every key is in json object 7 bool hasAllKeys(Json json, string[] keys, bool deepSearch = false) { 8 foreach(key; keys) { 9 if (!hasKey(json, key, deepSearch)) return false; 10 } 11 return true; 12 } 13 /// 14 unittest { 15 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 16 assert(json.hasAllKeys(["a", "c"])); 17 assert(json.hasAllKeys(["a", "d"], true)); 18 } 19 20 /// Check if Json has key 21 bool hasAnyKey(Json json, string[] keys, bool deepSearch = false) { 22 foreach(key; keys) 23 if (hasKey(json, key, deepSearch)) return true; 24 return false; 25 } 26 /// 27 unittest { 28 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 29 assert(json.hasAnyKey(["a"])); 30 assert(json.hasAnyKey(["d"], true)); 31 } 32 33 /// Searching key in json, if depth = true also in subnodes 34 bool hasKey(Json json, string key, bool deepSearch = false) { 35 if (json.type == Json.Type.object) { 36 foreach(kv; json.byKeyValue) { 37 if (kv.key == key) return true; 38 if (deepSearch) { 39 auto result = kv.value.hasKey(key, deepSearch); 40 if (result) return true; 41 } 42 } 43 } 44 if (deepSearch) { 45 if (json.type == Json.Type.array) { 46 for(size_t i = 0; i < json.length; i++) { 47 const result = json[i].hasKey(key, deepSearch); 48 if (result) return true; 49 } 50 } 51 } 52 return false; 53 } 54 /// 55 unittest { 56 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 57 assert(json.hasKey("a")); 58 assert(json.hasKey("d", true)); 59 } 60 61 bool hasAllValues(Json json, Json[] values, bool deepSearch = false) { 62 foreach(value; values) if (!hasValue(json, value, deepSearch)) return false; 63 return true; 64 } 65 /// 66 unittest { 67 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}], "i":"j"}`); 68 assert(json.hasAllValues([Json("b"), Json("j")])); 69 assert(json.hasAllValues([Json("h"), Json(1)], true)); 70 } 71 72 bool hasAnyValue(Json json, Json[] values, bool deepSearch = false) { 73 foreach(value; values) if (hasValue(json, value, deepSearch)) return true; 74 return false; 75 } 76 /// 77 unittest { 78 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}], "i":"j"}`); 79 assert(json.hasAllValues([Json("b"), Json("j")])); 80 assert(json.hasAllValues([Json("h"), Json(1)], true)); 81 } 82 83 /// Searching for value in Json 84 bool hasValue(Json json, Json value, bool deepSearch = false) { 85 if (json.type == Json.Type.object) { 86 foreach(kv; json.byKeyValue) { 87 if (kv.value == value) return true; 88 if (deepSearch) { 89 auto result = kv.value.hasValue(value, deepSearch); 90 if (result) return true; 91 } 92 } 93 } 94 if (deepSearch) { 95 if (json.type == Json.Type.array) { 96 for(size_t i = 0; i < json.length; i++) { 97 const result = json[i].hasValue(value, deepSearch); 98 if (result) return true; 99 } 100 } 101 } 102 return false; 103 } 104 /// 105 unittest { 106 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 107 assert(json.hasValue(Json("b"))); 108 assert(json.hasValue(Json("h"), true)); 109 assert(!json.hasValue(Json("x"))); 110 assert(!json.hasValue(Json("y"), true)); 111 } 112 113 /// Check if jsonPath exists 114 bool hasPath(Json json, string path) { 115 if (json.type != Json.Type.object) return false; 116 117 auto items = path.split("/"); 118 if (items.length > 1) return hasPath(json, items[1..$]); 119 return false; 120 } 121 /// 122 unittest { 123 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 124 assert(json.hasPath("/c/d")); 125 } 126 127 /// Check if jsonPath items exists 128 bool hasPath(Json json, string[] pathItems) { 129 if (json.type != Json.Type.object) return false; 130 131 auto j = json; 132 foreach(pathItem; pathItems) { 133 if (pathItem in j) { 134 if (pathItems.length > 1) return hasPath(j[pathItem], pathItems[1..$]); 135 else return true; 136 } 137 else return false; 138 } 139 return true; 140 } 141 /// 142 unittest { 143 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 144 assert(json.hasPath(["c", "d"])); 145 } 146 147 /// Reduce Json Object to keys (remove others) 148 Json reduceKeys(Json json, string[] keys) { 149 if (json.type == Json.Type.object) { 150 Json result = Json.emptyObject; 151 foreach(key; keys) if (json.hasKey(key)) result[key] = json[key]; 152 return result; 153 } 154 return Json(null); // Not object or keys 155 } 156 unittest { 157 version(uim_core) { /// TODO 158 writeln("test uim_core"); 159 } 160 } 161 162 /// Remove keys from Json Object 163 Json removeKeys(Json json, string[] delKeys...) { return removeKeys(json, delKeys); } 164 Json removeKeys(Json json, string[] delKeys) { 165 auto result = json; 166 foreach(delKey; delKeys) result.removeKey(delKey); 167 return result; 168 } 169 unittest { 170 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 171 assert(json.hasValue(Json("b"))); 172 assert(json.hasValue(Json("h"), true)); 173 } 174 175 /// Remove key from Json Object 176 Json removeKey(Json json, string delKey) { 177 if (json.type != Json.Type.object) return json; 178 179 Json result = Json.emptyObject; 180 foreach(kv; json.byKeyValue) if (kv.key != delKey) result[kv.key] = kv.value; 181 return result; 182 } 183 unittest { 184 auto json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 185 assert(json.hasKey("a")); 186 assert(!json.removeKey("a").hasKey("a")); 187 188 json = parseJsonString(`{"a":"b", "c":{"d":1}, "e":["f", {"g":"h"}]}`); 189 assert(!json.hasKey("x")); 190 assert(!json.removeKey("x").hasKey("x")); 191 assert(json.removeKey("x").hasKey("a")); 192 } 193 194 /// Merge jsons objects to one 195 Json mergeJsons(Json[] jsons...) { return mergeJsons(jsons); } 196 /// Merge jsons objects in array to one 197 Json mergeJsons(Json[] jsons) { 198 Json result = Json.emptyObject; 199 foreach(json; jsons) if (json.type == Json.Type.object) { 200 foreach (kv; json.byKeyValue) result[kv.key] = kv.value; 201 } 202 return result; 203 } 204 /// 205 unittest { 206 auto json0 = parseJsonString(`{"a":"b", "c":{"d":1}}`); 207 auto json1 = parseJsonString(`{"e":["f", {"g":"h"}]}`); 208 auto mergeJson = mergeJsons(json0, json1); 209 assert(mergeJson.hasKey("a") && mergeJson.hasKey("e")); 210 } 211 212 /// Load existing json files in directories 213 Json[] loadJsonsFromDirectories(string[] dirNames) { 214 Json[] results; 215 foreach(dir; dirNames.filter!(a => a.exists)) if (dir.exists) results ~= loadJsonsFromDirectory(dir); 216 return results; 217 } 218 unittest { 219 version(uim_core) { 220 /// TODO 221 } 222 } 223 224 /// Load existing json file in directories 225 Json[] loadJsonsFromDirectory(string dirName) { 226 // debug writeln("In loadJsonsFromDirectory("~dirName~")"); 227 // debug writeln("Found ", fileNames(dirName).length, " files"); 228 return loadJsons(fileNames(dirName, true)); 229 } 230 unittest { 231 version(uim_core) { 232 /// TODO 233 } 234 } 235 236 Json[] loadJsons(string[] fileNames) { 237 // debug writeln("Found ", fileNames.length, " names -> ", fileNames); 238 return fileNames.map!(a => loadJson(a)).filter!(a => a != Json(null)).array; 239 } 240 unittest { 241 version(uim_core) { 242 /// TODO 243 } 244 } 245 246 Json loadJson(string name) { 247 // debug writeln("In loadJson("~name~")"); 248 // debug writeln(name, " exists? ", name.exists); 249 return name.exists ? parseJsonString(readText(name)) : Json(null); 250 } 251 unittest { 252 version(uim_core) { 253 /// TODO 254 } 255 } 256 257 Json maxJson(T)(Json[] jsons, string key) { 258 Json result = Json(null); 259 foreach(j; jsons) { 260 if (result == Json(null) && key in j) { result = j; break; }} 261 foreach(j; jsons) { 262 if (key in j && j[key].get!T > result[key].get!T) result = j; } 263 return result; 264 } 265 unittest { 266 version(uim_core) { 267 /// TODO 268 } 269 } 270 271 Json minJson(T)(Json[] jsons, string key) { 272 Json result = Json(null); 273 foreach(j; jsons) { 274 if (result == Json(null) && key in j) { results = j; break; }} 275 foreach(j; jsons) { 276 if (key in j && j[key].get!T < result[key].get!T) result = j; } 277 return result; 278 } 279 unittest { 280 version(uim_core) { 281 /// TODO 282 } 283 } 284 285 Json toJson(STRINGAA data) { 286 Json json = Json.emptyObject; 287 foreach (k, v; data) json[k] = v; 288 return json; 289 } 290 unittest { 291 version(uim_core) { 292 /// TODO 293 } 294 } 295 296 Json toJson(string key, string value) { 297 Json json = Json.emptyObject; 298 json[key] = value; 299 return json; 300 } 301 unittest { 302 version(uim_core) { 303 /// TODO 304 } 305 } 306 307 /// Special case for managing entities 308 Json toJson(UUID id, size_t versionNumber = 0LU) { 309 Json json = Json.emptyObject; 310 json["id"] = id.toString; 311 json["versionNumber"] = versionNumber > 0 ? versionNumber : 1; 312 return json; 313 } 314 unittest { 315 version(uim_core) { 316 /// TODO 317 } 318 }