1 module graphql.schema.typeconversions; 2 3 import std.array : empty; 4 import std.algorithm.searching : canFind; 5 import std.conv : to; 6 import std.stdio; 7 import std.traits; 8 import std.meta; 9 import std.typecons : Nullable, nullable; 10 import std.range : ElementEncodingType; 11 12 import vibe.data.json; 13 14 import nullablestore; 15 16 import graphql.schema.types; 17 import graphql.traits; 18 import graphql.uda; 19 import graphql.constants; 20 21 private enum memsToIgnore = ["__ctor", "toString", "toHash", "opCmp", 22 "opEquals", "Monitor", "factory", "opAssign"]; 23 @safe: 24 25 template typeToTypeEnum(Type) { 26 static if(isAggregateType!Type && hasUDA!(Type, GQLDUdaData) 27 && getUDAs!(Type, GQLDUdaData)[0].typeKind != TypeKind.UNDEFINED) 28 { 29 enum udas = getUDAs!(Type, GQLDUdaData); 30 static assert(udas.length == 1); 31 enum GQLDUdaData u = udas[0]; 32 enum typeToTypeEnum = to!string(u.typeKind); 33 } else static if(is(Type == enum)) { 34 enum typeToTypeEnum = "ENUM"; 35 } else static if(is(Type == bool)) { 36 enum typeToTypeEnum = "SCALAR"; 37 } else static if(is(Type : GQLDCustomLeaf!Fs, Fs...)) { 38 enum typeToTypeEnum = "SCALAR"; 39 } else static if(isFloatingPoint!(Type)) { 40 enum typeToTypeEnum = "SCALAR"; 41 } else static if(isIntegral!(Type)) { 42 enum typeToTypeEnum = "SCALAR"; 43 } else static if(isSomeString!Type) { 44 enum typeToTypeEnum = "SCALAR"; 45 } else static if(is(Type == void)) { 46 enum typeToTypeEnum = "SCALAR"; 47 } else static if(is(Type == union)) { 48 enum typeToTypeEnum = "UNION"; 49 } else static if(isAggregateType!Type) { 50 enum typeToTypeEnum = "OBJECT"; 51 } else { 52 static assert(false, Type.stringof ~ " not handled"); 53 } 54 } 55 56 template typeToTypeName(Type) { 57 import graphql.uda : GQLDCustomLeaf; 58 static if(is(Type == enum)) { 59 enum typeToTypeName = Type.stringof; 60 } else static if(is(Type == bool)) { 61 enum typeToTypeName = "Boolean"; 62 } else static if(is(Type == GQLDCustomLeaf!Fs, Fs...)) { 63 enum typeToTypeName = Fs[0].stringof; 64 } else static if(isFloatingPoint!(Type)) { 65 enum typeToTypeName = "Float"; 66 } else static if(isIntegral!(Type)) { 67 enum typeToTypeName = "Int"; 68 } else static if(isSomeString!Type) { 69 enum typeToTypeName = "String"; 70 } else { 71 enum typeToTypeName = Type.stringof; 72 } 73 } 74 75 unittest { 76 import std.datetime : Date; 77 78 string tS(Date d) { 79 return ""; 80 } 81 Date fromS(string s) { 82 return Date.init; 83 } 84 static assert(typeToTypeName!(GQLDCustomLeaf!(Date, tS, fromS)) == "Date"); 85 } 86 87 template typeToParameterTypeName(Type) { 88 template level2(Type) { 89 static if(is(Type : Nullable!F, F)) { 90 enum level2 = typeToTypeName!F; 91 } else { 92 enum level2 = typeToTypeName!Type ~ "!"; 93 } 94 } 95 96 template level1(Type) { 97 static if(isArray!Type && !isSomeString!Type) { 98 enum level1 = "[" ~ level2!(ElementEncodingType!Type) ~ "]"; 99 } else { 100 enum level1 = typeToTypeName!Type; 101 } 102 } 103 104 template level0(Type) { 105 static if(is(Type : Nullable!F, F)) { 106 enum level0 = level1!F; 107 } else { 108 enum level0 = level1!Type ~ "!"; 109 } 110 } 111 112 template levelM1(Type) { 113 static if(is(Type : NullableStore!F, F)) { 114 enum levelM1 = level0!F; 115 } else { 116 enum levelM1 = level0!Type; 117 } 118 } 119 120 enum typeToParameterTypeName = levelM1!Type; 121 } 122 123 unittest { 124 import std.datetime : Date; 125 string tS(Date d) { 126 return ""; 127 } 128 Date fS(string s) { 129 return Date.init; 130 } 131 static assert(typeToParameterTypeName!(int) == "Int!"); 132 static assert(typeToParameterTypeName!(Nullable!int) == "Int"); 133 static assert(typeToParameterTypeName!(double) == "Float!"); 134 static assert(typeToParameterTypeName!(Nullable!double) == "Float"); 135 static assert(typeToParameterTypeName!(double[]) == "[Float!]!"); 136 static assert(typeToParameterTypeName!(Nullable!(double)[]) == "[Float]!"); 137 static assert(typeToParameterTypeName!(Nullable!(Nullable!(double)[])) == 138 "[Float]"); 139 static assert(typeToParameterTypeName!(GQLDCustomLeaf!(Date,tS,fS)) 140 == "Date!"); 141 } 142 143 unittest { 144 enum AEnum { 145 one, 146 two, 147 three 148 } 149 static assert(typeToParameterTypeName!(AEnum) == "AEnum!"); 150 static assert(typeToParameterTypeName!(Nullable!AEnum) == "AEnum"); 151 static assert(typeToParameterTypeName!(Nullable!(AEnum)[]) == "[AEnum]!"); 152 static assert(typeToParameterTypeName!(Nullable!(Nullable!(AEnum)[])) == 153 "[AEnum]"); 154 } 155 156 template isScalarType(Type) { 157 static if(is(Type == bool)) { 158 enum isScalarType = true; 159 } else static if(is(Type == GQLDCustomLeaf!Fs, Fs...)) { 160 enum isScalarType = true; 161 } else static if(isFloatingPoint!(Type)) { 162 enum isScalarType = true; 163 } else static if(isIntegral!(Type)) { 164 enum isScalarType = true; 165 } else static if(isSomeString!Type) { 166 enum isScalarType = true; 167 } else static if(is(Type == enum)) { 168 enum isScalarType = true; 169 } else { 170 enum isScalarType = false; 171 } 172 } 173 174 template typeToFieldType(Type) { 175 static if(isArray!Type && !isSomeString!Type) { 176 enum typeToFieldType = "__listType"; 177 } else static if(is(Type : Nullable!F, F)) { 178 enum typeToFieldType = F.stringof; 179 } else static if(is(Type : NullableStore!F, F)) { 180 enum typeToFieldType = Type.TypeValue.stringof; 181 } else { 182 enum typeToFieldType = "__nonNullType"; 183 } 184 } 185 186 Json typeFields(T)() { 187 import graphql.uda; 188 Json ret = Json.emptyArray(); 189 bool[string] fieldsAlreadyIn; 190 alias TplusParents = AliasSeq!(T, InheritedClasses!T); 191 static foreach(Type; TplusParents) {{ 192 static foreach(mem; __traits(allMembers, Type)) {{ 193 enum GQLDUdaData udaData = getUdaData!(Type, mem); 194 static if(!canFind(memsToIgnore, mem) 195 && udaData.ignore != Ignore.yes) 196 { 197 if(mem !in fieldsAlreadyIn) { 198 fieldsAlreadyIn[mem] = true; 199 Json tmp = Json.emptyObject(); 200 tmp[Constants.name] = mem; 201 // needed for interfacesForType 202 tmp[Constants.__typename] = "__Field"; 203 tmp[Constants.description] = 204 udaData.description.getText().empty 205 ? Json(null) 206 : Json(udaData.description.getText()); 207 208 tmp[Constants.isDeprecated] = 209 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 210 ? true 211 : false; 212 213 tmp[Constants.deprecationReason] = 214 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 215 ? Json(udaData.deprecationInfo.deprecationReason) 216 : Json(null); 217 218 tmp[Constants.args] = Json.emptyArray(); 219 static if(isCallable!(__traits(getMember, Type, mem))) { 220 alias RT = ReturnType!(__traits(getMember, Type, mem)); 221 alias RTS = stripArrayAndNullable!RT; 222 //tmp[Constants.typenameOrig] = typeToTypeName!(RT); 223 tmp[Constants.typenameOrig] = typeToParameterTypeName!(RT); 224 225 // InputValue 226 alias paraNames = ParameterIdentifierTuple!( 227 __traits(getMember, Type, mem) 228 ); 229 alias paraTypes = Parameters!( 230 __traits(getMember, Type, mem) 231 ); 232 alias paraDefs = ParameterDefaults!( 233 __traits(getMember, Type, mem) 234 ); 235 static foreach(idx; 0 .. paraNames.length) {{ 236 Json iv = Json.emptyObject(); 237 iv[Constants.name] = paraNames[idx]; 238 // needed for interfacesForType 239 iv[Constants.__typename] = Constants.__InputValue; 240 iv[Constants.description] = Json(null); 241 static if(__traits(compiles, __traits(getAttributes, 242 Parameters!(__traits(getMember, Type, 243 mem))[idx .. idx + 1]))) 244 { 245 iv[Constants.description] = Json(null); 246 alias udad = __traits(getAttributes, 247 Parameters!(__traits(getMember, Type, 248 mem))[idx .. idx + 1]); 249 static if(udad.length == 1) { 250 enum F = udad[0]; 251 static if(is(typeof(F) == GQLDUdaData)) { 252 iv[Constants.description] = 253 F.description.text; 254 } 255 } 256 } 257 iv[Constants.typenameOrig] = 258 typeToParameterTypeName!(paraTypes[idx]); 259 static if(!is(paraDefs[idx] == void)) { 260 iv[Constants.defaultValue] = serializeToJson( 261 paraDefs[idx] 262 ) 263 .toString(); 264 } else { 265 iv[Constants.defaultValue] = Json(null); 266 } 267 tmp[Constants.args] ~= iv; 268 }} 269 } else { 270 static if(!isType!(__traits(getMember, Type, mem))) { 271 tmp[Constants.typenameOrig] = 272 typeToParameterTypeName!( 273 //typeToTypeName!( 274 typeof(__traits(getMember, Type, mem)) 275 ); 276 } 277 } 278 ret ~= tmp; 279 } 280 } 281 }} 282 }} 283 //writefln("%s %s", __LINE__, ret.toPrettyString()); 284 return ret; 285 } 286 287 Json inputFields(Type)() { 288 Json ret = Json.emptyArray(); 289 alias types = FieldTypeTuple!Type; 290 alias names = FieldNameTuple!Type; 291 static foreach(idx; 0 .. types.length) {{ 292 enum GQLDUdaData udaData = getUdaData!(types[idx]); 293 Json tmp = Json.emptyObject(); 294 tmp[Constants.name] = names[idx]; 295 tmp[Constants.description] = udaData.description.getText().empty 296 ? Json(null) 297 : Json(udaData.description.getText()); 298 299 // needed for interfacesForType 300 tmp[Constants.__typename] = Constants.__InputValue; 301 302 //tmp[Constants.typenameOrig] = typeToTypeName!(types[idx]); 303 tmp[Constants.typenameOrig] = typeToParameterTypeName!(types[idx]); 304 auto t = __traits(getMember, Type.init, names[idx]); 305 tmp[Constants.defaultValue] = serializeToJson(t); 306 ret ~= tmp; 307 }} 308 return ret; 309 } 310 311 Json emptyType() { 312 Json ret = Json.emptyObject(); 313 ret[Constants.name] = Json(null); 314 ret[Constants.description] = Json(null); 315 ret[Constants.fields] = Json(null); 316 ret[Constants.interfacesNames] = Json(null); 317 ret[Constants.possibleTypesNames] = Json(null); 318 ret[Constants.enumValues] = Json(null); 319 ret["ofType"] = Json(null); 320 return ret; 321 } 322 323 Json removeNonNullAndList(Json j) { 324 immutable string t = j["kind"].get!string(); 325 if(t == "NON_NULL" || t == "LIST") { 326 return removeNonNullAndList(j["ofType"]); 327 } else { 328 return j; 329 } 330 } 331 332 // remove the top nullable to find out if we have a NON_NULL or not 333 Json typeToJson(Type,Schema)() { 334 static if(is(Type : Nullable!F, F)) { 335 return typeToJson1!(F,Schema,Type)(); 336 } else static if(is(Type : NullableStore!F, F)) { 337 return typeToJson1!(Type.TypeValue,Schema,Type)(); 338 } else { 339 Json ret = emptyType(); 340 ret["kind"] = "NON_NULL"; 341 ret[Constants.__typename] = "__Type"; 342 ret["ofType"] = typeToJson1!(Type,Schema,Type)(); 343 return ret; 344 } 345 } 346 347 // remove the array is present 348 Json typeToJson1(Type,Schema,Orig)() { 349 static if(isArray!Type && !isSomeString!Type && !is(Type == enum)) { 350 Json ret = emptyType(); 351 ret["kind"] = "LIST"; 352 ret[Constants.__typename] = "__Type"; 353 ret["ofType"] = typeToJson2!(ElementEncodingType!Type, Schema, Orig)(); 354 return ret; 355 } else { 356 return typeToJsonImpl!(Type, Schema, Orig)(); 357 } 358 } 359 360 // remove another nullable 361 Json typeToJson2(Type,Schema,Orig)() { 362 static if(is(Type : Nullable!F, F)) { 363 return typeToJsonImpl!(F, Schema, Orig)(); 364 } else static if(is(Type : NullableStore!F, F)) { 365 return typeToJsonImpl!(Type.TypeValue, Schema, Orig)(); 366 } else { 367 Json ret = emptyType(); 368 ret["kind"] = "NON_NULL"; 369 ret[Constants.__typename] = "__Type"; 370 ret["ofType"] = typeToJsonImpl!(Type, Schema, Orig)(); 371 return ret; 372 } 373 } 374 375 template notNullOrArray(T,S) { 376 static if(is(Nullable!F : T, F)) { 377 alias notNullOrArray = S; 378 } else static if(isArray!T) { 379 alias notNullOrArray = S; 380 } else { 381 alias notNullOrArray = T; 382 } 383 } 384 385 Json typeToJsonImpl(Type,Schema,Orig)() { 386 Json ret = Json.emptyObject(); 387 enum string kind = typeToTypeEnum!(stripArrayAndNullable!Type); 388 ret["kind"] = kind; 389 ret[Constants.__typename] = "__Type"; 390 ret[Constants.name] = typeToTypeName!Type; 391 392 alias TypeOrig = notNullOrArray!(Type,Orig); 393 enum GQLDUdaData udaData = getUdaData!(TypeOrig); 394 enum des = udaData.description.text; 395 ret[Constants.description] = des.empty 396 ? Json(null) 397 : Json(des); 398 399 ret[Constants.isDeprecated] = 400 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 401 ? true 402 : false; 403 404 ret[Constants.deprecationReason] = 405 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 406 ? Json(udaData.deprecationInfo.deprecationReason) 407 : Json(null); 408 409 // fields 410 static if((is(Type == class) || is(Type == interface) || is(Type == struct)) 411 && !is(Type : Nullable!K, K) && !is(Type : NullableStore!K, K) 412 && !is(Type : GQLDCustomLeaf!Ks, Ks...)) 413 { 414 ret[Constants.fields] = typeFields!Type(); 415 } else { 416 ret[Constants.fields] = Json(null); 417 } 418 419 // inputFields 420 static if(kind == Constants.INPUT_OBJECT) { 421 ret[Constants.inputFields] = inputFields!Type(); 422 } else { 423 ret[Constants.inputFields] = Json(null); 424 } 425 426 // needed to resolve interfaces 427 static if(is(Type == class) || is(Type == interface)) { 428 ret[Constants.interfacesNames] = Json.emptyArray(); 429 static foreach(interfaces; InheritedClasses!Type) {{ 430 ret[Constants.interfacesNames] ~= interfaces.stringof; 431 }} 432 } else { 433 ret[Constants.interfacesNames] = Json(null); 434 } 435 436 // needed to resolve possibleTypes 437 static if(is(Type == class) || is(Type == union) || is(Type == interface)) { 438 static if(is(Type == union)) { 439 ret[Constants.possibleTypesNames] = Json.emptyArray(); 440 static foreach(pt; Filter!(isAggregateType, FieldTypeTuple!Type)) { 441 ret[Constants.possibleTypesNames] ~= pt.stringof; 442 } 443 } else { 444 import graphql.reflection; 445 // need to search for all types that we support that are derived 446 // from this type 447 ret[Constants.possibleTypesNames] = Json.emptyArray(); 448 foreach(tname; 449 SchemaReflection!Schema.instance.derivatives.get(typeid(Type), 450 null)) 451 { 452 ret[Constants.possibleTypesNames] ~= tname; 453 } 454 } 455 } else { 456 ret[Constants.possibleTypesNames] = Json(null); 457 } 458 459 // enumValues 460 static if(is(Type == enum)) { 461 ret[Constants.enumValues] = Json.emptyArray(); 462 static foreach(mem; EnumMembers!Type) {{ 463 enum memUdaData = getUdaData!(Type, to!string(mem)); 464 Json tmp = Json.emptyObject(); 465 tmp[Constants.__TypeKind] = Constants.__EnumValue; 466 tmp[Constants.name] = Json(to!string(mem)); 467 tmp[Constants.description] = memUdaData.description.text; 468 tmp[Constants.isDeprecated] = (memUdaData.deprecationInfo.isDeprecated == IsDeprecated.yes); 469 tmp[Constants.deprecationReason] = (memUdaData.deprecationInfo.isDeprecated == IsDeprecated.yes) 470 ? Json(memUdaData.deprecationInfo.deprecationReason) 471 : Json(null); 472 ret[Constants.enumValues] ~= tmp; 473 }} 474 } else { 475 ret[Constants.enumValues] = Json(null); 476 } 477 478 // needed to resolve ofType 479 static if(is(Type : Nullable!F, F)) { 480 ret[Constants.ofTypeName] = F.stringof; 481 } else static if(is(Type : NullableStore!F, F)) { 482 ret[Constants.ofTypeName] = F.stringof; 483 } else static if(is(Type : GQLDCustomLeaf!Fs, Fs...)) { 484 ret[Constants.ofTypeName] = Fs[0].stringof; 485 } else static if(isArray!Type) { 486 ret[Constants.ofTypeName] = ElementEncodingType!(Type).stringof; 487 } 488 489 return ret; 490 } 491 492 @safe unittest { 493 import std.format : format; 494 Json r = typeToJson!(string,void)(); 495 Json e = parseJsonString(` 496 { 497 "__typename": "__Type", 498 "possibleTypesNames": null, 499 "enumValues": null, 500 "interfacesNames": null, 501 "kind": "NON_NULL", 502 "name": null, 503 "ofType": { 504 "__typename": "__Type", 505 "possibleTypesNames": null, 506 "enumValues": null, 507 "interfacesNames": null, 508 "kind": "SCALAR", 509 "isDeprecated": false, 510 "deprecationReason": null, 511 "name": "String", 512 "description": null, 513 "inputFields": null, 514 "ofTypeName": "immutable(char)", 515 "fields": null 516 }, 517 "description": null, 518 "fields": null 519 } 520 `); 521 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 522 r.toPrettyString())); 523 } 524 525 @safe unittest { 526 enum FooBar { 527 @GQLDUda(GQLDDescription("important")) 528 foo, 529 @GQLDUda( 530 GQLDDeprecated(IsDeprecated.yes, "not foo enough"), 531 GQLDDescription("unimportant") 532 ) 533 bar 534 } 535 536 import std.format : format; 537 Json r = typeToJson!(FooBar,void)(); 538 Json e = parseJsonString(` 539 { 540 "__typename": "__Type", 541 "possibleTypesNames": null, 542 "enumValues": null, 543 "interfacesNames": null, 544 "kind": "NON_NULL", 545 "name": null, 546 "ofType": { 547 "__typename": "__Type", 548 "possibleTypesNames": null, 549 "enumValues": [ 550 { 551 "description": "important", 552 "deprecationReason": null, 553 "__TypeKind": "__EnumValue", 554 "isDeprecated": false, 555 "name": "foo" 556 }, 557 { 558 "description": "unimportant", 559 "deprecationReason": "not foo enough", 560 "__TypeKind": "__EnumValue", 561 "isDeprecated": true, 562 "name": "bar" 563 } 564 ], 565 "interfacesNames": null, 566 "kind": "ENUM", 567 "isDeprecated": false, 568 "deprecationReason": null, 569 "name": "FooBar", 570 "description": null, 571 "inputFields": null, 572 "fields": null 573 }, 574 "description": null, 575 "fields": null 576 } 577 `); 578 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 579 r.toPrettyString())); 580 } 581 @safe unittest { 582 import std.format : format; 583 Json r = typeToJson!(Nullable!string,void)(); 584 Json e = parseJsonString(` 585 { 586 "__typename": "__Type", 587 "possibleTypesNames": null, 588 "enumValues": null, 589 "interfacesNames": null, 590 "kind": "SCALAR", 591 "isDeprecated": false, 592 "deprecationReason": null, 593 "name": "String", 594 "description": null, 595 "inputFields": null, 596 "ofTypeName": "immutable(char)", 597 "fields": null 598 } 599 `); 600 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 601 r.toPrettyString())); 602 } 603 604 @safe unittest { 605 import std.format : format; 606 Json r = typeToJson!(Nullable!string,void)(); 607 Json e = parseJsonString(` 608 { 609 "__typename": "__Type", 610 "possibleTypesNames": null, 611 "enumValues": null, 612 "interfacesNames": null, 613 "kind": "SCALAR", 614 "isDeprecated": false, 615 "deprecationReason": null, 616 "name": "String", 617 "description": null, 618 "inputFields": null, 619 "ofTypeName": "immutable(char)", 620 "fields": null 621 } 622 `); 623 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 624 r.toPrettyString())); 625 } 626 627 Json directivesToJson(Directives)() { 628 import std.string : stripLeft; 629 Json ret = Json.emptyArray(); 630 alias TplusParents = AliasSeq!(Directives, InheritedClasses!Directives); 631 static foreach(Type; TplusParents) {{ 632 static foreach(mem; __traits(allMembers, Type)) {{ 633 static if(!canFind(memsToIgnore, mem)) { 634 Json tmp = Json.emptyObject(); 635 enum GQLDUdaData udaData = getUdaData!(Type, mem); 636 tmp[Constants.name] = mem; 637 // needed for interfacesForType 638 tmp[Constants.__typename] = Constants.__Directive; 639 tmp[Constants.description] = udaData.description.getText().empty 640 ? Json(null) 641 : Json(udaData.description.text); 642 643 tmp[Constants.isDeprecated] = 644 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 645 ? true 646 : false; 647 648 tmp[Constants.deprecationReason] = 649 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 650 ? Json(udaData.deprecationInfo.deprecationReason) 651 : Json(null); 652 653 //tmp[Constants.description] = Json(null); 654 tmp[Constants.locations] = Json.emptyArray(); 655 tmp[Constants.args] = Json.emptyArray(); 656 static if(isCallable!(__traits(getMember, Type, mem))) { 657 // InputValue 658 alias paraNames = ParameterIdentifierTuple!( 659 __traits(getMember, Type, mem) 660 ); 661 alias paraTypes = Parameters!( 662 __traits(getMember, Type, mem) 663 ); 664 alias paraDefs = ParameterDefaults!( 665 __traits(getMember, Type, mem) 666 ); 667 static foreach(idx; 0 .. paraNames.length) {{ 668 Json iv = Json.emptyObject(); 669 // TODO remove the strip left. Its in because the 670 // two default directives of GraphQL skip and include 671 // both have one parameter named "if". 672 iv[Constants.name] = stripLeft(paraNames[idx], "_"); 673 iv[Constants.description] = Json(null); 674 // needed for interfacesForType 675 iv[Constants.__typename] = Constants.__InputValue; 676 iv[Constants.typenameOrig] = typeToTypeName!(paraTypes[idx]); 677 //iv[Constants.typenameOrig] = typeToParameterTypeName!(paraTypes[idx]); 678 static if(!is(paraDefs[idx] == void)) { 679 iv[Constants.defaultValue] = serializeToJson(paraDefs[idx]) 680 .toString(); 681 } else { 682 iv[Constants.defaultValue] = Json(null); 683 } 684 tmp[Constants.args] ~= iv; 685 }} 686 } 687 ret ~= tmp; 688 } 689 }} 690 }} 691 return ret; 692 } 693 694 Json getField(Json j, string name) { 695 import graphql.constants; 696 697 if(j.type != Json.Type.object || Constants.fields !in j 698 || j[Constants.fields].type != Json.Type.array) 699 { 700 return Json.init; 701 } 702 703 foreach(it; j[Constants.fields].byValue) { 704 immutable string itName = it[Constants.name].get!string(); 705 if(itName == name) { 706 return it; 707 } 708 } 709 return Json.init; 710 } 711 712 Json getIntrospectionField(string name) { 713 import std.format : format; 714 Json ret = Json.emptyObject(); 715 ret[Constants.typenameOrig] = name == Constants.__typename 716 ? "String" 717 : name == Constants.__schema 718 ? "__Schema" 719 : name == Constants.__type 720 ? "__Type" 721 : format("Not known introspection name '%s'", name); 722 return ret; 723 }