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 tmp[Constants.typenameOrig] = 271 typeToParameterTypeName!( 272 //typeToTypeName!( 273 typeof(__traits(getMember, Type, mem)) 274 ); 275 } 276 ret ~= tmp; 277 } 278 } 279 }} 280 }} 281 //writefln("%s %s", __LINE__, ret.toPrettyString()); 282 return ret; 283 } 284 285 Json inputFields(Type)() { 286 Json ret = Json.emptyArray(); 287 alias types = FieldTypeTuple!Type; 288 alias names = FieldNameTuple!Type; 289 static foreach(idx; 0 .. types.length) {{ 290 enum GQLDUdaData udaData = getUdaData!(types[idx]); 291 Json tmp = Json.emptyObject(); 292 tmp[Constants.name] = names[idx]; 293 tmp[Constants.description] = udaData.description.getText().empty 294 ? Json(null) 295 : Json(udaData.description.getText()); 296 297 // needed for interfacesForType 298 tmp[Constants.__typename] = Constants.__InputValue; 299 300 //tmp[Constants.typenameOrig] = typeToTypeName!(types[idx]); 301 tmp[Constants.typenameOrig] = typeToParameterTypeName!(types[idx]); 302 auto t = __traits(getMember, Type.init, names[idx]); 303 tmp[Constants.defaultValue] = serializeToJson(t); 304 ret ~= tmp; 305 }} 306 return ret; 307 } 308 309 Json emptyType() { 310 Json ret = Json.emptyObject(); 311 ret[Constants.name] = Json(null); 312 ret[Constants.description] = Json(null); 313 ret[Constants.fields] = Json(null); 314 ret[Constants.interfacesNames] = Json(null); 315 ret[Constants.possibleTypesNames] = Json(null); 316 ret[Constants.enumValues] = Json(null); 317 ret["ofType"] = Json(null); 318 return ret; 319 } 320 321 Json removeNonNullAndList(Json j) { 322 immutable string t = j["kind"].get!string(); 323 if(t == "NON_NULL" || t == "LIST") { 324 return removeNonNullAndList(j["ofType"]); 325 } else { 326 return j; 327 } 328 } 329 330 // remove the top nullable to find out if we have a NON_NULL or not 331 Json typeToJson(Type,Schema)() { 332 static if(is(Type : Nullable!F, F)) { 333 return typeToJson1!(F,Schema,Type)(); 334 } else static if(is(Type : NullableStore!F, F)) { 335 return typeToJson1!(Type.TypeValue,Schema,Type)(); 336 } else { 337 Json ret = emptyType(); 338 ret["kind"] = "NON_NULL"; 339 ret[Constants.__typename] = "__Type"; 340 ret["ofType"] = typeToJson1!(Type,Schema,Type)(); 341 return ret; 342 } 343 } 344 345 // remove the array is present 346 Json typeToJson1(Type,Schema,Orig)() { 347 static if(isArray!Type && !isSomeString!Type && !is(Type == enum)) { 348 Json ret = emptyType(); 349 ret["kind"] = "LIST"; 350 ret[Constants.__typename] = "__Type"; 351 ret["ofType"] = typeToJson2!(ElementEncodingType!Type, Schema, Orig)(); 352 return ret; 353 } else { 354 return typeToJsonImpl!(Type, Schema, Orig)(); 355 } 356 } 357 358 // remove another nullable 359 Json typeToJson2(Type,Schema,Orig)() { 360 static if(is(Type : Nullable!F, F)) { 361 return typeToJsonImpl!(F, Schema, Orig)(); 362 } else static if(is(Type : NullableStore!F, F)) { 363 return typeToJsonImpl!(Type.TypeValue, Schema, Orig)(); 364 } else { 365 Json ret = emptyType(); 366 ret["kind"] = "NON_NULL"; 367 ret[Constants.__typename] = "__Type"; 368 ret["ofType"] = typeToJsonImpl!(Type, Schema, Orig)(); 369 return ret; 370 } 371 } 372 373 template notNullOrArray(T,S) { 374 static if(is(Nullable!F : T, F)) { 375 alias notNullOrArray = S; 376 } else static if(isArray!T) { 377 alias notNullOrArray = S; 378 } else { 379 alias notNullOrArray = T; 380 } 381 } 382 383 Json typeToJsonImpl(Type,Schema,Orig)() { 384 Json ret = Json.emptyObject(); 385 enum string kind = typeToTypeEnum!(stripArrayAndNullable!Type); 386 ret["kind"] = kind; 387 ret[Constants.__typename] = "__Type"; 388 ret[Constants.name] = typeToTypeName!Type; 389 390 alias TypeOrig = notNullOrArray!(Type,Orig); 391 enum GQLDUdaData udaData = getUdaData!(TypeOrig); 392 enum des = udaData.description.text; 393 ret[Constants.description] = des.empty 394 ? Json(null) 395 : Json(des); 396 397 ret[Constants.isDeprecated] = 398 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 399 ? true 400 : false; 401 402 ret[Constants.deprecationReason] = 403 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 404 ? Json(udaData.deprecationInfo.deprecationReason) 405 : Json(null); 406 407 // fields 408 static if((is(Type == class) || is(Type == interface) || is(Type == struct)) 409 && !is(Type : Nullable!K, K) && !is(Type : NullableStore!K, K) 410 && !is(Type : GQLDCustomLeaf!Ks, Ks...)) 411 { 412 ret[Constants.fields] = typeFields!Type(); 413 } else { 414 ret[Constants.fields] = Json(null); 415 } 416 417 // inputFields 418 static if(kind == Constants.INPUT_OBJECT) { 419 ret[Constants.inputFields] = inputFields!Type(); 420 } else { 421 ret[Constants.inputFields] = Json(null); 422 } 423 424 // needed to resolve interfaces 425 static if(is(Type == class) || is(Type == interface)) { 426 ret[Constants.interfacesNames] = Json.emptyArray(); 427 static foreach(interfaces; InheritedClasses!Type) {{ 428 ret[Constants.interfacesNames] ~= interfaces.stringof; 429 }} 430 } else { 431 ret[Constants.interfacesNames] = Json(null); 432 } 433 434 // needed to resolve possibleTypes 435 static if(is(Type == class) || is(Type == union) || is(Type == interface)) { 436 static if(is(Type == union)) { 437 ret[Constants.possibleTypesNames] = Json.emptyArray(); 438 static foreach(pt; Filter!(isAggregateType, FieldTypeTuple!Type)) { 439 ret[Constants.possibleTypesNames] ~= pt.stringof; 440 } 441 } else { 442 import graphql.reflection; 443 // need to search for all types that we support that are derived 444 // from this type 445 ret[Constants.possibleTypesNames] = Json.emptyArray(); 446 foreach(tname; 447 SchemaReflection!Schema.instance.derivatives.get(typeid(Type), 448 null)) 449 { 450 ret[Constants.possibleTypesNames] ~= tname; 451 } 452 } 453 } else { 454 ret[Constants.possibleTypesNames] = Json(null); 455 } 456 457 // enumValues 458 static if(is(Type == enum)) { 459 ret[Constants.enumValues] = Json.emptyArray(); 460 static foreach(mem; EnumMembers!Type) {{ 461 enum memUdaData = getUdaData!(Type, to!string(mem)); 462 Json tmp = Json.emptyObject(); 463 tmp[Constants.__TypeKind] = Constants.__EnumValue; 464 tmp[Constants.name] = Json(to!string(mem)); 465 tmp[Constants.description] = memUdaData.description.text; 466 tmp[Constants.isDeprecated] = (memUdaData.deprecationInfo.isDeprecated == IsDeprecated.yes); 467 tmp[Constants.deprecationReason] = (memUdaData.deprecationInfo.isDeprecated == IsDeprecated.yes) 468 ? Json(memUdaData.deprecationInfo.deprecationReason) 469 : Json(null); 470 ret[Constants.enumValues] ~= tmp; 471 }} 472 } else { 473 ret[Constants.enumValues] = Json(null); 474 } 475 476 // needed to resolve ofType 477 static if(is(Type : Nullable!F, F)) { 478 ret[Constants.ofTypeName] = F.stringof; 479 } else static if(is(Type : NullableStore!F, F)) { 480 ret[Constants.ofTypeName] = F.stringof; 481 } else static if(is(Type : GQLDCustomLeaf!Fs, Fs...)) { 482 ret[Constants.ofTypeName] = Fs[0].stringof; 483 } else static if(isArray!Type) { 484 ret[Constants.ofTypeName] = ElementEncodingType!(Type).stringof; 485 } 486 487 return ret; 488 } 489 490 @safe unittest { 491 import std.format : format; 492 Json r = typeToJson!(string,void)(); 493 Json e = parseJsonString(` 494 { 495 "__typename": "__Type", 496 "possibleTypesNames": null, 497 "enumValues": null, 498 "interfacesNames": null, 499 "kind": "NON_NULL", 500 "name": null, 501 "ofType": { 502 "__typename": "__Type", 503 "possibleTypesNames": null, 504 "enumValues": null, 505 "interfacesNames": null, 506 "kind": "SCALAR", 507 "isDeprecated": false, 508 "deprecationReason": null, 509 "name": "String", 510 "description": null, 511 "inputFields": null, 512 "ofTypeName": "immutable(char)", 513 "fields": null 514 }, 515 "description": null, 516 "fields": null 517 } 518 `); 519 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 520 r.toPrettyString())); 521 } 522 523 @safe unittest { 524 enum FooBar { 525 @GQLDUda(GQLDDescription("important")) 526 foo, 527 @GQLDUda( 528 GQLDDeprecated(IsDeprecated.yes, "not foo enough"), 529 GQLDDescription("unimportant") 530 ) 531 bar 532 } 533 534 import std.format : format; 535 Json r = typeToJson!(FooBar,void)(); 536 Json e = parseJsonString(` 537 { 538 "__typename": "__Type", 539 "possibleTypesNames": null, 540 "enumValues": null, 541 "interfacesNames": null, 542 "kind": "NON_NULL", 543 "name": null, 544 "ofType": { 545 "__typename": "__Type", 546 "possibleTypesNames": null, 547 "enumValues": [ 548 { 549 "description": "important", 550 "deprecationReason": null, 551 "__TypeKind": "__EnumValue", 552 "isDeprecated": false, 553 "name": "foo" 554 }, 555 { 556 "description": "unimportant", 557 "deprecationReason": "not foo enough", 558 "__TypeKind": "__EnumValue", 559 "isDeprecated": true, 560 "name": "bar" 561 } 562 ], 563 "interfacesNames": null, 564 "kind": "ENUM", 565 "isDeprecated": false, 566 "deprecationReason": null, 567 "name": "FooBar", 568 "description": null, 569 "inputFields": null, 570 "fields": null 571 }, 572 "description": null, 573 "fields": null 574 } 575 `); 576 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 577 r.toPrettyString())); 578 } 579 @safe unittest { 580 import std.format : format; 581 Json r = typeToJson!(Nullable!string,void)(); 582 Json e = parseJsonString(` 583 { 584 "__typename": "__Type", 585 "possibleTypesNames": null, 586 "enumValues": null, 587 "interfacesNames": null, 588 "kind": "SCALAR", 589 "isDeprecated": false, 590 "deprecationReason": null, 591 "name": "String", 592 "description": null, 593 "inputFields": null, 594 "ofTypeName": "immutable(char)", 595 "fields": null 596 } 597 `); 598 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 599 r.toPrettyString())); 600 } 601 602 @safe unittest { 603 import std.format : format; 604 Json r = typeToJson!(Nullable!string,void)(); 605 Json e = parseJsonString(` 606 { 607 "__typename": "__Type", 608 "possibleTypesNames": null, 609 "enumValues": null, 610 "interfacesNames": null, 611 "kind": "SCALAR", 612 "isDeprecated": false, 613 "deprecationReason": null, 614 "name": "String", 615 "description": null, 616 "inputFields": null, 617 "ofTypeName": "immutable(char)", 618 "fields": null 619 } 620 `); 621 assert(r == e, format("exp:\n%s\ngot:\n%s", e.toPrettyString(), 622 r.toPrettyString())); 623 } 624 625 Json directivesToJson(Directives)() { 626 import std.string : stripLeft; 627 Json ret = Json.emptyArray(); 628 alias TplusParents = AliasSeq!(Directives, InheritedClasses!Directives); 629 static foreach(Type; TplusParents) {{ 630 static foreach(mem; __traits(allMembers, Type)) {{ 631 static if(!canFind(memsToIgnore, mem)) { 632 Json tmp = Json.emptyObject(); 633 enum GQLDUdaData udaData = getUdaData!(Type, mem); 634 tmp[Constants.name] = mem; 635 // needed for interfacesForType 636 tmp[Constants.__typename] = Constants.__Directive; 637 tmp[Constants.description] = udaData.description.getText().empty 638 ? Json(null) 639 : Json(udaData.description.text); 640 641 tmp[Constants.isDeprecated] = 642 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 643 ? true 644 : false; 645 646 tmp[Constants.deprecationReason] = 647 udaData.deprecationInfo.isDeprecated == IsDeprecated.yes 648 ? Json(udaData.deprecationInfo.deprecationReason) 649 : Json(null); 650 651 //tmp[Constants.description] = Json(null); 652 tmp[Constants.locations] = Json.emptyArray(); 653 tmp[Constants.args] = Json.emptyArray(); 654 static if(isCallable!(__traits(getMember, Type, mem))) { 655 // InputValue 656 alias paraNames = ParameterIdentifierTuple!( 657 __traits(getMember, Type, mem) 658 ); 659 alias paraTypes = Parameters!( 660 __traits(getMember, Type, mem) 661 ); 662 alias paraDefs = ParameterDefaults!( 663 __traits(getMember, Type, mem) 664 ); 665 static foreach(idx; 0 .. paraNames.length) {{ 666 Json iv = Json.emptyObject(); 667 // TODO remove the strip left. Its in because the 668 // two default directives of GraphQL skip and include 669 // both have one parameter named "if". 670 iv[Constants.name] = stripLeft(paraNames[idx], "_"); 671 iv[Constants.description] = Json(null); 672 // needed for interfacesForType 673 iv[Constants.__typename] = Constants.__InputValue; 674 iv[Constants.typenameOrig] = typeToTypeName!(paraTypes[idx]); 675 //iv[Constants.typenameOrig] = typeToParameterTypeName!(paraTypes[idx]); 676 static if(!is(paraDefs[idx] == void)) { 677 iv[Constants.defaultValue] = serializeToJson(paraDefs[idx]) 678 .toString(); 679 } else { 680 iv[Constants.defaultValue] = Json(null); 681 } 682 tmp[Constants.args] ~= iv; 683 }} 684 } 685 ret ~= tmp; 686 } 687 }} 688 }} 689 return ret; 690 } 691 692 Json getField(Json j, string name) { 693 import graphql.constants; 694 695 if(j.type != Json.Type.object || Constants.fields !in j 696 || j[Constants.fields].type != Json.Type.array) 697 { 698 return Json.init; 699 } 700 701 foreach(it; j[Constants.fields].byValue) { 702 immutable string itName = it[Constants.name].get!string(); 703 if(itName == name) { 704 return it; 705 } 706 } 707 return Json.init; 708 } 709 710 Json getIntrospectionField(string name) { 711 import std.format : format; 712 Json ret = Json.emptyObject(); 713 ret[Constants.typenameOrig] = name == Constants.__typename 714 ? "String" 715 : name == Constants.__schema 716 ? "__Schema" 717 : name == Constants.__type 718 ? "__Type" 719 : format("Not known introspection name '%s'", name); 720 return ret; 721 }