1from typing import List, Optional, Union 2 3from tartiflette.coercers.common import Path 4from tartiflette.language.ast import ( 5 ArgumentNode, 6 BooleanValueNode, 7 DirectiveNode, 8 DocumentNode, 9 EnumValueNode, 10 FieldNode, 11 FloatValueNode, 12 FragmentDefinitionNode, 13 FragmentSpreadNode, 14 InlineFragmentNode, 15 IntValueNode, 16 ListTypeNode, 17 ListValueNode, 18 Location, 19 NamedTypeNode, 20 NameNode, 21 NonNullTypeNode, 22 NullValueNode, 23 ObjectFieldNode, 24 ObjectValueNode, 25 OperationDefinitionNode, 26 SelectionSetNode, 27 StringValueNode, 28 VariableDefinitionNode, 29 VariableNode, 30) 31from tartiflette.language.validators import Validators 32from tartiflette.language.validators.query import RULE_SET 33from tartiflette.language.validators.query.utils import ( 34 get_schema_field_type_name, 35) 36 37__all__ = ("document_from_ast_json",) 38 39 40def _parse_location(location_ast: dict) -> "Location": 41 """ 42 Creates and returns a Location instance from a location's JSON AST 43 libgraphqlparser representation. 44 :param location_ast: location's JSON AST libgraphqlparser representation 45 :type location_ast: dict 46 :return: a Location instance equivalent to the JSON AST representation 47 :rtype: Location 48 """ 49 return Location( 50 line=location_ast["start"]["line"], 51 column=location_ast["start"]["column"], 52 line_end=location_ast["end"]["line"], 53 column_end=location_ast["end"]["column"], 54 ) 55 56 57def _parse_name(name_ast: dict) -> "NameNode": 58 """ 59 Creates and returns a NameNode instance from a name's JSON AST 60 libgraphqlparser representation. 61 :param name_ast: name's JSON AST libgraphqlparser representation 62 :type name_ast: dict 63 :return: a NameNode instance equivalent to the JSON AST representation 64 :rtype: NameNode 65 """ 66 return NameNode( 67 value=name_ast["value"], location=_parse_location(name_ast["loc"]) 68 ) 69 70 71def _parse_named_type(named_type_ast: dict) -> "NamedTypeNode": 72 """ 73 Creates and returns a NamedTypeNode instance from a named type's JSON AST 74 libgraphqlparser representation. 75 :param named_type_ast: named type's JSON AST libgraphqlparser 76 representation 77 :type named_type_ast: dict 78 :return: a NamedTypeNode instance equivalent to the JSON AST representation 79 :rtype: NamedTypeNode 80 """ 81 return NamedTypeNode( 82 name=_parse_name(named_type_ast["name"]), 83 location=_parse_location(named_type_ast["loc"]), 84 ) 85 86 87def _parse_variable( 88 variable_ast: dict, validators: Validators, *_ 89) -> "VariableNode": 90 """ 91 Creates and returns a VariableNode instance from a variable's JSON AST 92 libgraphqlparser representation. 93 :param variable_ast: variable's JSON AST libgraphqlparser representation 94 :type variable_ast: dict 95 :param validators: the validators to use in order to validate this definition 96 :type validators: Validators 97 :param _: Ignored parameters 98 :return: a VariableNode instance equivalent to the JSON AST representation 99 :rtype: VariableNode 100 """ 101 102 variable = VariableNode( 103 name=_parse_name(variable_ast["name"]), 104 location=_parse_location(variable_ast["loc"]), 105 ) 106 107 if not validators.ctx.get("in_variable_definitions", False): 108 if validators.ctx["in_operation"]: 109 validators.ctx["per_operation"][ 110 validators.ctx["current_operation_name"] 111 ].setdefault("used_vars", []).append(variable) 112 else: 113 validators.ctx["per_fragment"][ 114 validators.ctx["current_fragment_name"] 115 ].setdefault("used_vars", []).append(variable) 116 117 return variable 118 119 120def _parse_boolean_value(boolean_value_ast: dict, *_) -> "BooleanValueNode": 121 """ 122 Creates and returns a BooleanValueNode instance from a boolean value's JSON 123 AST libgraphqlparser representation. 124 :param boolean_value_ast: boolean value's JSON AST libgraphqlparser 125 representation 126 :param _: Ignored parameter 127 :type boolean_value_ast: dict 128 :return: a BooleanValueNode instance equivalent to the JSON AST 129 representation 130 :rtype: BooleanValueNode 131 """ 132 return BooleanValueNode( 133 value=boolean_value_ast["value"], 134 location=_parse_location(boolean_value_ast["loc"]), 135 ) 136 137 138def _parse_enum_value(enum_value_ast: dict, *_) -> "EnumValueNode": 139 """ 140 Creates and returns an EnumValueNode instance from an enum value's JSON AST 141 libgraphqlparser representation. 142 :param enum_value_ast: enum value's JSON AST libgraphqlparser 143 representation 144 :param _: Ignored parameter 145 :type enum_value_ast: dict 146 :return: an EnumValueNode instance equivalent to the JSON AST 147 representation 148 :rtype: EnumValueNode 149 """ 150 return EnumValueNode( 151 value=enum_value_ast["value"], 152 location=_parse_location(enum_value_ast["loc"]), 153 ) 154 155 156def _parse_float_value(float_value_ast: dict, *_) -> "FloatValueNode": 157 """ 158 Creates and returns a FloatValueNode instance from a float value's JSON AST 159 libgraphqlparser representation. 160 :param float_value_ast: float value's JSON AST libgraphqlparser 161 representation 162 :param _: Ignored parameter 163 :type float_value_ast: dict 164 :return: a FloatValueNode instance equivalent to the JSON AST 165 representation 166 :rtype: FloatValueNode 167 """ 168 return FloatValueNode( 169 value=float_value_ast["value"], 170 location=_parse_location(float_value_ast["loc"]), 171 ) 172 173 174def _parse_int_value(int_value_ast: dict, *_) -> "IntValueNode": 175 """ 176 Creates and returns an IntValueNode instance from an int value's JSON AST 177 libgraphqlparser representation. 178 :param int_value_ast: int value's JSON AST libgraphqlparser representation 179 :type int_value_ast: dict 180 :param _: Ignored parameter 181 :return: an IntValueNode instance equivalent to the JSON AST representation 182 :rtype: IntValueNode 183 """ 184 return IntValueNode( 185 value=int_value_ast["value"], 186 location=_parse_location(int_value_ast["loc"]), 187 ) 188 189 190def _parse_values( 191 values_ast: Optional[List[dict]], validators: Validators, path: Path 192) -> List[ 193 Union[ 194 "BooleanValueNode", 195 "EnumValueNode", 196 "FloatValueNode", 197 "IntValueNode", 198 "ListValueNode", 199 "NullValueNode", 200 "ObjectValueNode", 201 "StringValueNode", 202 "VariableNode", 203 ] 204]: 205 """ 206 Creates and returns a list of ValueNode instances from a list of value's 207 JSON AST libgraphqlparser representation. 208 :param values_ast: list of value's JSON AST libgraphqlparser representation 209 :type values_ast: Optional[List[dict]] 210 :param validators: the validators to use in order to validate this definition 211 :type validators: Validators 212 :param path: a Path object that contains the current field path 213 :type path: Path 214 :return: a list of ValueNode instances equivalent to the JSON AST 215 representation 216 :rtype: List[Union[BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, ListValueNode, NullValueNode, ObjectValueNode, StringValueNode, VariableNode]] 217 """ 218 if values_ast: 219 return [_parse_value(value, validators, path) for value in values_ast] 220 return [] 221 222 223def _parse_list_value( 224 list_value_ast: dict, validators: Validators, path: Path 225) -> "ListValueNode": 226 """ 227 Creates and returns a ListValueNode instance from a list value's JSON AST 228 libgraphqlparser representation. 229 :param list_value_ast: list value's JSON AST libgraphqlparser 230 representation 231 :type list_value_ast: dict 232 :param validators: the validators to use in order to validate this definition 233 :type validators: Validators 234 :param path: a Path object that contains the current field path 235 :type path: Path 236 :return: a ListValueNode instance equivalent to the JSON AST representation 237 :rtype: ListValueNode 238 """ 239 return ListValueNode( 240 values=_parse_values(list_value_ast["values"], validators, path), 241 location=_parse_location(list_value_ast["loc"]), 242 ) 243 244 245def _parse_null_value(null_value_ast: dict, *_) -> "NullValueNode": 246 """ 247 Creates and returns a NullValueNode instance from a null value's JSON AST 248 libgraphqlparser representation. 249 :param null_value_ast: null value's JSON AST libgraphqlparser 250 representation 251 :type null_value_ast: dict 252 :param _: Ignored parameter 253 :return: a NullValueNode instance equivalent to the JSON AST representation 254 :rtype: NullValueNode 255 """ 256 return NullValueNode(location=_parse_location(null_value_ast["loc"])) 257 258 259def _parse_object_field( 260 object_field_ast: dict, validators: Validators, path: Path 261) -> "ObjectFieldNode": 262 """ 263 Creates and returns an ObjectFieldNode instance from an object field's JSON 264 AST libgraphqlparser representation. 265 :param object_field_ast: object field's JSON AST libgraphqlparser 266 representation 267 :type object_field_ast: dict 268 :param validators: the validators to use in order to validate this definition 269 :type validators: Validators 270 :param path: a Path object that contains the current field path 271 :type path: Path 272 :return: an ObjectFieldNode instance equivalent to the JSON AST 273 representation 274 :rtype: ObjectFieldNode 275 """ 276 return ObjectFieldNode( 277 name=_parse_name(object_field_ast["name"]), 278 value=_parse_value(object_field_ast["value"], validators, path), 279 location=_parse_location(object_field_ast["loc"]), 280 ) 281 282 283def _parse_object_fields( 284 object_fields_ast: Optional[List[dict]], validators: Validators, path: Path 285) -> List["ObjectFieldNode"]: 286 """ 287 Creates and returns a list of ObjectFieldNode instances from a list of 288 object field's JSON AST libgraphqlparser representation. 289 :param object_fields_ast: list of object field's JSON AST libgraphqlparser 290 representation 291 :param validators: the validators to use in order to validate this definition 292 :type validators: Validators 293 :param path: a Path object that contains the current field path 294 :type path: Path 295 :type object_fields_ast: Optional[List[dict]] 296 :return: a list of ObjectFieldNode instances equivalent to the JSON AST 297 representation 298 :rtype: List[ObjectFieldNode] 299 """ 300 if object_fields_ast: 301 object_fields = [ 302 _parse_object_field(object_field, validators, path) 303 for object_field in object_fields_ast 304 ] 305 306 validators.validate( 307 "input-object-field-uniqueness", 308 input_fields=object_fields, 309 path=path, 310 ) 311 312 return object_fields 313 return [] 314 315 316def _parse_object_value( 317 object_value_ast: dict, validators: Validators, path: Path 318) -> "ObjectValueNode": 319 """ 320 Creates and returns an ObjectValueNode instance from an object value's JSON 321 AST libgraphqlparser representation. 322 :param object_value_ast: object value's JSON AST libgraphqlparser 323 representation 324 :type object_value_ast: dict 325 :param validators: the validators to use in order to validate this definition 326 :type validators: Validators 327 :param path: a Path object that contains the current field path 328 :type path: Path 329 :return: an ObjectValueNode instance equivalent to the JSON AST 330 representation 331 :rtype: ObjectValueNode 332 """ 333 return ObjectValueNode( 334 fields=_parse_object_fields( 335 object_value_ast["fields"], validators, path 336 ), 337 location=_parse_location(object_value_ast["loc"]), 338 ) 339 340 341def _parse_string_value(string_value_ast: dict, *_) -> "StringValueNode": 342 """ 343 Creates and returns a StringValueNode instance from a string value's JSON 344 AST libgraphqlparser representation. 345 :param string_value_ast: string value's JSON AST libgraphqlparser 346 representation 347 :type string_value_ast: dict 348 :param _: Ignored parameter 349 :return: a StringValueNode instance equivalent to the JSON AST 350 representation 351 :rtype: StringValueNode 352 """ 353 return StringValueNode( 354 value=string_value_ast["value"], 355 location=_parse_location(string_value_ast["loc"]), 356 ) 357 358 359_VALUE_PARSER_MAPPING = { 360 "BooleanValue": _parse_boolean_value, 361 "EnumValue": _parse_enum_value, 362 "FloatValue": _parse_float_value, 363 "IntValue": _parse_int_value, 364 "ListValue": _parse_list_value, 365 "NullValue": _parse_null_value, 366 "ObjectValue": _parse_object_value, 367 "StringValue": _parse_string_value, 368 "Variable": _parse_variable, 369} 370 371 372def _parse_value( 373 value_ast: Optional[dict], validators: Validators, path: Path 374) -> Optional[ 375 Union[ 376 "BooleanValueNode", 377 "EnumValueNode", 378 "FloatValueNode", 379 "IntValueNode", 380 "ListValueNode", 381 "NullValueNode", 382 "ObjectValueNode", 383 "StringValueNode", 384 "VariableNode", 385 ] 386]: 387 """ 388 Creates and returns a ValueNode instance from a value's JSON AST 389 libgraphqlparser representation. 390 :param value_ast: value's JSON AST libgraphqlparser representation 391 :type value_ast: Optional[dict] 392 :param validators: the validators to use in order to validate this definition 393 :type validators: Validators 394 :param path: a Path object that contains the current field path 395 :type path: Path 396 :return: a ValueNode instance equivalent to the JSON AST representation 397 :rtype: Optional[Union[BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, ListValueNode, NullValueNode, ObjectValueNode, StringValueNode, VariableNode]] 398 """ 399 if value_ast: 400 return _VALUE_PARSER_MAPPING[value_ast["kind"]]( 401 value_ast, validators, path 402 ) 403 return None 404 405 406def _parse_argument( 407 argument_ast: dict, validators: Validators, path: Path 408) -> "ArgumentNode": 409 """ 410 Creates and returns an ArgumentNode instance from an argument's JSON AST 411 libgraphqlparser representation. 412 :param argument_ast: argument's JSON AST libgraphqlparser representation 413 :type argument_ast: dict 414 :param validators: the validators to use in order to validate this definition 415 :type validators: Validators 416 :param path: a Path object that contains the current field path 417 :type path: Path 418 :return: an ArgumentNode instance equivalent to the JSON AST representation 419 :rtype: ArgumentNode 420 """ 421 arg = ArgumentNode( 422 name=_parse_name(argument_ast["name"]), 423 value=_parse_value(argument_ast["value"], validators, path), 424 location=_parse_location(argument_ast["loc"]), 425 ) 426 427 if isinstance(arg.value, VariableNode): 428 loca = ( 429 validators.ctx["current_directive_name"] 430 if validators.ctx.get("in_directive", False) 431 else validators.ctx["current_field_name"] 432 ) 433 434 if validators.ctx["in_operation"]: 435 validators.ctx["per_operation"][ 436 validators.ctx["current_operation_name"] 437 ].setdefault("args_using_var", []).append( 438 { 439 "arg": arg, 440 "node_location": loca, 441 "is_directive": validators.ctx.get("in_directive", False), 442 "path": path, 443 } 444 ) 445 else: 446 validators.ctx["per_fragment"][ 447 validators.ctx["current_fragment_name"] 448 ].setdefault("args_using_var", []).append( 449 { 450 "arg": arg, 451 "node_location": loca, 452 "is_directive": validators.ctx.get("in_directive", False), 453 "path": path, 454 } 455 ) 456 457 return arg 458 459 460def _parse_arguments( 461 arguments_ast: Optional[List[dict]], validators: "Validators", path: "Path" 462) -> List["ArgumentNode"]: 463 """ 464 Creates and returns a list of ArgumentNode instances from a list of 465 argument's JSON AST libgraphqlparser representation. 466 :param arguments_ast: list of argument's JSON AST libgraphqlparser 467 representation 468 :type arguments_ast: Optional[List[dict]] 469 :param validators: the Validators object that will be used to validate these arguments 470 :param path: a Path object that contains the current field path 471 :type validators: Validators 472 :type path: Path 473 :return: a list of ArgumentNode instances equivalent to the JSON AST 474 representation 475 :rtype: List[ArgumentNode] 476 """ 477 if arguments_ast: 478 arguments = [ 479 _parse_argument(argument, validators, path) 480 for argument in arguments_ast 481 ] 482 validators.validate( 483 rule="argument-uniqueness", arguments=arguments, path=path 484 ) 485 return arguments 486 return [] 487 488 489def _parse_directive( 490 directive_ast: dict, validators: "Validators", path: "Path" 491) -> "DirectiveNode": 492 """ 493 Creates and returns a DirectiveNode instance from a directive's JSON AST 494 libgraphqlparser representation. 495 :param directive_ast: directive's JSON AST libgraphqlparser representation 496 :type directive_ast: dict 497 :param validators: the Validators object that will be used to validate these arguments 498 :param path: a Path object that contains the current field path 499 :type validators: Validators 500 :type path: Path 501 :return: a DirectiveNode instance equivalent to the JSON AST representation 502 :rtype: DirectiveNode 503 """ 504 name = _parse_name(directive_ast["name"]) 505 validators.ctx["in_directive"] = True 506 validators.ctx["current_directive_name"] = name.value 507 508 directive = DirectiveNode( 509 name=name, 510 arguments=_parse_arguments( 511 directive_ast["arguments"], validators, path 512 ), 513 location=_parse_location(directive_ast["loc"]), 514 ) 515 516 validators.ctx["in_directive"] = False 517 518 validators.validate( 519 rule="values-of-correct-type", node=directive, path=path 520 ) 521 522 validators.validate(rule="argument-names", node=directive, path=path) 523 524 validators.validate(rule="required-arguments", node=directive, path=path) 525 526 validators.validate( 527 rule="directives-are-defined", directive=directive, path=path 528 ) 529 530 return directive 531 532 533def _parse_directives( 534 directives_ast: Optional[List[dict]], 535 validators: "Validators", 536 path: "Path", 537) -> List["DirectiveNode"]: 538 """ 539 Creates and returns a list of DirectiveNode instances from a list of 540 directive's JSON AST libgraphqlparser representation. 541 :param directives_ast: list of directive's JSON AST libgraphqlparser 542 representation 543 :type directives_ast: Optional[List[dict]] 544 :param validators: the Validators object that will be used to validate these arguments 545 :param path: a Path object that contains the current field path 546 :type validators: Validators 547 :type path: Path 548 :return: a list of DirectiveNode instances equivalent to the JSON AST 549 representation 550 :rtype: List[DirectiveNode] 551 """ 552 if directives_ast: 553 directives = [ 554 _parse_directive(directive, validators, path) 555 for directive in directives_ast 556 ] 557 558 validators.validate( 559 rule="directives-are-unique-per-location", 560 directives=directives, 561 path=path, 562 ) 563 564 return directives 565 return [] 566 567 568def _parse_field( 569 field_ast: dict, validators: "Validators", path: "Path" 570) -> "FieldNode": 571 """ 572 Creates and returns a FieldNode instance from a field's JSON AST 573 libgraphqlparser representation. 574 :param field_ast: field's JSON AST libgraphqlparser representation 575 :type field_ast: dict 576 :param validators: the Validators object that will be used to validate these arguments 577 :param path: a Path object that contains the current field path 578 :type validators: Validators 579 :type path: Path 580 :return: a FieldNode instance equivalent to the JSON AST representation 581 :rtype: FieldNode 582 """ 583 584 name = _parse_name(field_ast["name"]) 585 path = Path(prev=path, key=name.value) 586 parent_type_name = validators.ctx["parent_type_name"] 587 588 validators.ctx["parent_type_name"] = get_schema_field_type_name( 589 parent_type_name, name.value, validators.schema 590 ) 591 592 validators.ctx["in_directive"] = False 593 validators.ctx["current_field_name"] = f"{parent_type_name}.{name}" 594 595 field = FieldNode( 596 alias=_parse_name(field_ast["alias"]) if field_ast["alias"] else None, 597 name=name, 598 arguments=_parse_arguments(field_ast["arguments"], validators, path), 599 directives=_parse_directives( 600 field_ast["directives"], validators, path 601 ), 602 selection_set=_parse_selection_set( 603 field_ast["selectionSet"], validators, path 604 ), 605 location=_parse_location(field_ast["loc"]), 606 ) 607 608 validators.ctx["parent_type_name"] = parent_type_name 609 610 validators.validate( 611 rule="directives-are-in-valid-locations", node=field, path=path 612 ) 613 614 validators.validate( 615 rule="field-selections-on-objects-interfaces-and-unions-types", 616 field=field, 617 path=path, 618 ) 619 620 validators.validate(rule="leaf-field-selections", field=field, path=path) 621 622 validators.validate(rule="values-of-correct-type", node=field, path=path) 623 624 validators.validate(rule="argument-names", node=field, path=path) 625 626 validators.validate(rule="required-arguments", node=field, path=path) 627 628 return field 629 630 631def _parse_fragment_spread( 632 fragment_spread_ast: dict, validators: "Validators", path: "Path" 633) -> "FragmentSpreadNode": 634 """ 635 Creates and returns a FragmentSpreadNode instance from a fragment spread's 636 JSON AST libgraphqlparser representation. 637 :param fragment_spread_ast: fragment spread's JSON AST libgraphqlparser 638 representation 639 :type fragment_spread_ast: dict 640 :param validators: the Validators object that will be used to validate these arguments 641 :param path: a Path object that contains the current field path 642 :type validators: Validators 643 :type path: Path 644 :return: a FragmentSpreadNode instance equivalent to the JSON AST 645 representation 646 :rtype: FragmentSpreadNode 647 """ 648 fragment_spead = FragmentSpreadNode( 649 name=_parse_name(fragment_spread_ast["name"]), 650 directives=_parse_directives( 651 fragment_spread_ast["directives"], validators, path 652 ), 653 location=_parse_location(fragment_spread_ast["loc"]), 654 ) 655 656 validators.validate( 657 rule="directives-are-in-valid-locations", 658 node=fragment_spead, 659 path=path, 660 ) 661 662 validators.ctx.setdefault("fragment_spreads", []).append(fragment_spead) 663 validators.ctx.setdefault("spreaded_in", {}).setdefault( 664 validators.ctx["parent_type_name"], [] 665 ).append({"spread": fragment_spead, "path": path}) 666 667 if validators.ctx["in_operation"]: 668 validators.ctx["per_operation"][ 669 validators.ctx["current_operation_name"] 670 ].setdefault("spreads", []).append(fragment_spead) 671 else: 672 validators.ctx["per_fragment"][ 673 validators.ctx["current_fragment_name"] 674 ].setdefault("spreads", []).append(fragment_spead) 675 676 return fragment_spead 677 678 679def _parse_inline_fragment( 680 inline_fragment_ast: dict, validators: "Validators", path: "Path" 681) -> "InlineFragmentNode": 682 """ 683 Creates and returns an InlineFragmentNode instance from an inline spread's 684 JSON AST libgraphqlparser representation. 685 :param inline_fragment_ast: inline spread's JSON AST libgraphqlparser 686 representation 687 :type inline_fragment_ast: dict 688 :param validators: the Validators object that will be used to validate these arguments 689 :param path: a Path object that contains the current field path 690 :type validators: Validators 691 :type path: Path 692 :return: an InlineFragmentNode instance equivalent to the JSON AST 693 representation 694 :rtype: InlineFragmentNode 695 """ 696 697 parent_type_name = validators.ctx["parent_type_name"] 698 699 type_cond = ( 700 _parse_named_type(inline_fragment_ast["typeCondition"]) 701 if inline_fragment_ast["typeCondition"] 702 else None 703 ) 704 if type_cond: 705 validators.ctx["parent_type_name"] = type_cond.name.value 706 707 inline_frag = InlineFragmentNode( 708 directives=_parse_directives( 709 inline_fragment_ast["directives"], validators, path 710 ), 711 type_condition=type_cond, 712 selection_set=_parse_selection_set( 713 inline_fragment_ast["selectionSet"], validators, path 714 ), 715 location=_parse_location(inline_fragment_ast["loc"]), 716 ) 717 718 validators.validate( 719 rule="directives-are-in-valid-locations", node=inline_frag, path=path 720 ) 721 722 validators.validate( 723 rule="fragment-spread-type-existence", fragment=inline_frag, path=path 724 ) 725 validators.validate( 726 rule="fragments-on-composite-types", fragment=inline_frag, path=path 727 ) 728 729 validators.ctx.setdefault("inlined_in", {}).setdefault( 730 validators.ctx["parent_type_name"], [] 731 ).append(inline_frag) 732 validators.ctx["parent_type_name"] = parent_type_name 733 734 return inline_frag 735 736 737_SELECTION_PARSER_MAPPING = { 738 "Field": _parse_field, 739 "FragmentSpread": _parse_fragment_spread, 740 "InlineFragment": _parse_inline_fragment, 741} 742 743 744def _parse_selection( 745 selection_ast: dict, validators: "Validators", path: "Path" 746) -> Union["FieldNode", "FragmentSpreadNode", "InlineFragmentNode"]: 747 """ 748 Creates and returns a SelectionNode instance from a selection's JSON AST 749 libgraphqlparser representation. 750 :param selection_ast: selection's JSON AST libgraphqlparser representation 751 :type selection_ast: dict 752 :param validators: the Validators object that will be used to validate these arguments 753 :param path: a Path object that contains the current field path 754 :type validators: Validators 755 :type path: Path 756 :return: a SelectionNode instance equivalent to the JSON AST representation 757 :rtype: Union[FieldNode, FragmentSpreadNode, InlineFragmentNode] 758 """ 759 return _SELECTION_PARSER_MAPPING[selection_ast["kind"]]( 760 selection_ast, validators, path 761 ) 762 763 764def _parse_selections( 765 selections_ast: Optional[List[dict]], validators: Validators, path: Path 766) -> List[Union["FieldNode", "FragmentSpreadNode", "InlineFragmentNode"]]: 767 """ 768 Creates and returns a list of SelectionNode instances from a list of 769 selection's JSON AST libgraphqlparser representation. 770 :param selections_ast: list of selection's JSON AST libgraphqlparser 771 representation 772 :type selections_ast: Optional[List[dict]] 773 :param validators: the Validators object that will be used to validate these arguments 774 :param path: a Path object that contains the current field path 775 :type validators: Validators 776 :type path: Path 777 :return: a list of SelectionNode instances equivalent to the JSON AST 778 representation 779 :rtype: List[Union[FieldNode, FragmentSpreadNode, InlineFragmentNode]] 780 """ 781 782 if selections_ast: 783 return [ 784 _parse_selection(selection, validators, path) 785 for selection in selections_ast 786 ] 787 return [] 788 789 790def _parse_selection_set( 791 selection_set_ast: Optional[dict], validators: Validators, path: Path 792) -> Optional["SelectionSetNode"]: 793 """ 794 Creates and returns a SelectionSetNode instance from a selection set's JSON 795 AST libgraphqlparser representation. 796 :param selection_set_ast: selection set's JSON AST libgraphqlparser 797 representation 798 :type selection_set_ast: Optional[dict] 799 :param validators: the Validators object that will be used to validate these arguments 800 :param path: a Path object that contains the current field path 801 :type validators: Validators 802 :type path: Path 803 :return: a SelectionSetNode instance equivalent to the JSON AST 804 representation 805 :rtype: Optional[SelectionSetNode] 806 """ 807 if selection_set_ast: 808 return SelectionSetNode( 809 selections=_parse_selections( 810 selection_set_ast["selections"], validators, path 811 ), 812 location=_parse_location(selection_set_ast["loc"]), 813 ) 814 return None 815 816 817def _parse_fragment_definition( 818 fragment_definition_ast: dict, validators: "Validators", path: Path 819) -> "FragmentDefinitionNode": 820 """ 821 Creates and returns a FragmentDefinitionNode instance from a fragment 822 definition's JSON AST libgraphqlparser representation. 823 :param fragment_definition_ast: fragment definition's JSON AST 824 libgraphqlparser representation 825 :type fragment_definition_ast: dict 826 :param validators: the Validators object that will be used to validate these arguments 827 :param path: a Path object that contains the current field path 828 :type validators: Validators 829 :type path: Path 830 :return: a FragmentDefinitionNode instance equivalent to the JSON AST 831 representation 832 :rtype: FragmentDefinitionNode 833 """ 834 835 parent_type_name = validators.ctx.get("parent_type_name") 836 name = _parse_name(fragment_definition_ast["name"]) 837 type_cond = _parse_named_type(fragment_definition_ast["typeCondition"]) 838 validators.ctx["parent_type_name"] = type_cond.name.value 839 validators.ctx["in_operation"] = False 840 validators.ctx["current_fragment_name"] = name.value 841 validators.ctx.setdefault("per_fragment", {}).setdefault(name.value, {}) 842 843 fragment = FragmentDefinitionNode( 844 name=name, 845 type_condition=type_cond, 846 directives=_parse_directives( 847 fragment_definition_ast["directives"], validators, path 848 ), 849 selection_set=_parse_selection_set( 850 fragment_definition_ast["selectionSet"], validators, path 851 ), 852 location=_parse_location(fragment_definition_ast["loc"]), 853 ) 854 855 validators.validate( 856 rule="directives-are-in-valid-locations", node=fragment, path=path 857 ) 858 859 validators.validate( 860 rule="fragment-spread-type-existence", fragment=fragment, path=path 861 ) 862 validators.validate( 863 rule="fragments-on-composite-types", fragment=fragment, path=path 864 ) 865 866 validators.ctx["parent_type_name"] = parent_type_name 867 868 return fragment 869 870 871def _parse_type( 872 type_ast: dict, 873) -> Union["ListTypeNode", "NonNullTypeNode", "NamedTypeNode"]: 874 """ 875 Creates and returns a TypeNode from a type's JSON AST libgraphqlparser 876 representation. 877 :param type_ast: type's JSON AST libgraphqlparser representation 878 :type type_ast: dict 879 :return: a TypeNode instance equivalent to the JSON AST representation 880 :rtype: Union[ListTypeNode, NonNullTypeNode, NamedTypeNode] 881 """ 882 if type_ast["kind"] == "ListType": 883 return ListTypeNode( 884 type=_parse_type(type_ast["type"]), 885 location=_parse_location(type_ast["loc"]), 886 ) 887 if type_ast["kind"] == "NonNullType": 888 return NonNullTypeNode( 889 type=_parse_type(type_ast["type"]), 890 location=_parse_location(type_ast["loc"]), 891 ) 892 return _parse_named_type(type_ast) 893 894 895def _parse_variable_definition( 896 variable_definition_ast: dict, validators: Validators, path: Path 897) -> "VariableDefinitionNode": 898 """ 899 Creates and returns a VariableDefinitionNode instance from a variable 900 definition's JSON AST libgraphqlparser representation. 901 :param variable_definition_ast: variable definition's JSON AST 902 libgraphqlparser representation 903 :type variable_definition_ast: dict 904 :param validators: the Validators object that will be used to validate these arguments 905 :param path: a Path object that contains the current field path 906 :type validators: Validators 907 :type path: Path 908 :return: a VariableDefinitionNode instance equivalent to the JSON AST 909 representation 910 :rtype: VariableDefinitionNode 911 """ 912 variable = VariableDefinitionNode( 913 variable=_parse_variable( 914 variable_definition_ast["variable"], validators 915 ), 916 type=_parse_type(variable_definition_ast["type"]), 917 default_value=_parse_value( 918 variable_definition_ast["defaultValue"], validators, path 919 ), 920 location=_parse_location(variable_definition_ast["loc"]), 921 ) 922 923 validators.validate( 924 rule="variables-are-input-types", variable=variable, path=path 925 ) 926 927 return variable 928 929 930def _parse_variable_definitions( 931 variable_definitions_ast: Optional[List[dict]], 932 validators: Validators, 933 path: Path, 934) -> List["VariableDefinitionNode"]: 935 """ 936 Creates and returns a list of VariableDefinitionNode instances from a list 937 of variable definition's JSON AST libgraphqlparser representation. 938 :param variable_definitions_ast: list of variable definition's JSON AST 939 libgraphqlparser representation 940 :type variable_definitions_ast: Optional[List[dict]] 941 :param validators: the Validators object that will be used to validate these arguments 942 :param path: a Path object that contains the current field path 943 :type validators: Validators 944 :type path: Path 945 :return: a list of VariableDefinitionNode instances equivalent to the JSON 946 AST representation 947 :rtype: List[VariableDefinitionNode] 948 """ 949 if variable_definitions_ast: 950 validators.ctx["in_variable_definitions"] = True 951 variables = [ 952 _parse_variable_definition(variable_definition, validators, path) 953 for variable_definition in variable_definitions_ast 954 ] 955 validators.ctx["in_variable_definitions"] = False 956 957 validators.validate( 958 rule="variable-uniqueness", 959 variable_definitions=variables, 960 path=path, 961 ) 962 963 return variables 964 return [] 965 966 967def _get_operation_type_name(operation_type, schema): 968 return getattr(schema, f"{operation_type.lower()}_operation_name") 969 970 971def _parse_operation_definition( 972 operation_definition_ast: dict, validators: "Validators", path: Path 973) -> "OperationDefinitionNode": 974 """ 975 Creates and returns an OperationDefinitionNode instance from an operation 976 definition's JSON AST libgraphqlparser representation. 977 :param operation_definition_ast: operation definition's JSON AST 978 libgraphqlparser representation 979 :type operation_definition_ast: dict 980 :param validators: the Validators object that will be used to validate these arguments 981 :param path: a Path object that contains the current field path 982 :type validators: Validators 983 :type path: Path 984 :return: an OperationDefinitionNode instance equivalent to the JSON AST 985 representation 986 :rtype: OperationDefinitionNode 987 """ 988 operation_type = operation_definition_ast["operation"] 989 name = ( 990 _parse_name(operation_definition_ast["name"]) 991 if operation_definition_ast["name"] 992 else None 993 ) 994 995 validators.ctx["parent_type_name"] = _get_operation_type_name( 996 operation_type, validators.schema 997 ) 998 validators.ctx["in_operation"] = True 999 validators.ctx["current_operation_name"] = name.value if name else "None" 1000 validators.ctx.setdefault("per_operation", {}).setdefault( 1001 name.value if name else "None", {} 1002 ) 1003 1004 operation = OperationDefinitionNode( 1005 operation_type=operation_type, 1006 name=name, 1007 variable_definitions=_parse_variable_definitions( 1008 operation_definition_ast["variableDefinitions"], validators, path 1009 ), 1010 directives=_parse_directives( 1011 operation_definition_ast["directives"], validators, path 1012 ), 1013 selection_set=_parse_selection_set( 1014 operation_definition_ast["selectionSet"], validators, path 1015 ), 1016 location=_parse_location(operation_definition_ast["loc"]), 1017 ) 1018 1019 validators.validate( 1020 rule="directives-are-in-valid-locations", node=operation, path=path 1021 ) 1022 1023 return operation 1024 1025 1026_DEFINITION_PARSER_MAPPING = { 1027 "FragmentDefinition": _parse_fragment_definition, 1028 "OperationDefinition": _parse_operation_definition, 1029} 1030 1031 1032def _parse_definition( 1033 definition_ast: dict, validators: "Validators", path: Path 1034) -> Union["FragmentDefinitionNode", "OperationDefinitionNode"]: 1035 """ 1036 Creates and returns a DefinitionNode instance from a definition's JSON AST 1037 libgraphqlparser representation. 1038 :param definition_ast: definition's JSON AST libgraphqlparser 1039 representation 1040 :type definition_ast: dict 1041 :param validators: the Validators object that will be used to validate these arguments 1042 :param path: a Path object that contains the current field path 1043 :type validators: Validators 1044 :type path: Path 1045 :return: a DefinitionNode instance equivalent to the JSON AST 1046 representation 1047 :rtype: Union[FragmentDefinitionNode, OperationDefinitionNode] 1048 """ 1049 return _DEFINITION_PARSER_MAPPING[definition_ast["kind"]]( 1050 definition_ast, validators, path 1051 ) 1052 1053 1054def _parse_definitions( 1055 definitions_ast: Optional[List[dict]], 1056 validators: Validators, 1057 path: Path = None, 1058) -> List[Union["FragmentDefinitionNode", "OperationDefinitionNode"]]: 1059 """ 1060 Creates and returns a list of DefinitionNode instances from a list of 1061 definition's JSON AST libgraphqlparser representation. 1062 :param definitions_ast: list of definition's JSON AST libgraphqlparser 1063 representation 1064 :type definitions_ast: Optional[List[dict]] 1065 :param validators: the Validators object that will be used to validate these arguments 1066 :param path: a Path object that contains the current field path 1067 :type validators: Validators 1068 :type path: Path 1069 :return: a list of DefinitionNode instances equivalent to the JSON AST 1070 representation 1071 :rtype: List[Union[FragmentDefinitionNode, OperationDefinitionNode]] 1072 """ 1073 1074 parsed_def = {"FragmentDefinition": [], "OperationDefinition": []} 1075 1076 if definitions_ast: 1077 for definition in definitions_ast: 1078 parsed_def[definition["kind"]].append( 1079 _parse_definition(definition, validators, path) 1080 ) 1081 1082 validators.validate( 1083 rule="fragment-spreads-must-not-form-cycles", 1084 fragments=parsed_def["FragmentDefinition"], 1085 path=None, 1086 ) 1087 1088 validators.validate( 1089 rule="operation-name-uniqueness", 1090 operations=parsed_def["OperationDefinition"], 1091 path=path, 1092 ) 1093 validators.validate( 1094 rule="lone-anonymous-operation", 1095 operations=parsed_def["OperationDefinition"], 1096 path=path, 1097 ) 1098 1099 validators.validate( 1100 rule="single-root-field", definitions=parsed_def, path=path 1101 ) 1102 1103 validators.validate( 1104 rule="fragment-name-uniqueness", 1105 fragments=parsed_def["FragmentDefinition"], 1106 path=path, 1107 ) 1108 1109 validators.validate( 1110 rule="fragment-spread-target-defined", 1111 fragments=parsed_def["FragmentDefinition"], 1112 path=path, 1113 ) 1114 1115 validators.validate( 1116 rule="fragment-must-be-used", 1117 fragments=parsed_def["FragmentDefinition"], 1118 path=path, 1119 ) 1120 1121 validators.validate( 1122 rule="fragment-spread-is-possible", 1123 fragments=parsed_def["FragmentDefinition"], 1124 path=path, 1125 ) 1126 1127 validators.validate( 1128 rule="all-variable-uses-defined", 1129 operations=parsed_def["OperationDefinition"], 1130 path=path, 1131 ) 1132 1133 validators.validate( 1134 rule="all-variables-used", 1135 operations=parsed_def["OperationDefinition"], 1136 path=path, 1137 ) 1138 1139 validators.validate( 1140 rule="all-variable-usages-are-allowed", 1141 operations=parsed_def["OperationDefinition"], 1142 path=path, 1143 ) 1144 1145 return parsed_def["FragmentDefinition"] + parsed_def["OperationDefinition"] 1146 1147 1148def document_from_ast_json( 1149 document_ast: dict, query: Union[str, bytes], schema: "GraphQLSchema" 1150) -> "DocumentNode": 1151 """ 1152 Creates and returns a DocumentNode instance from a document's JSON AST 1153 libgraphqlparser representation. 1154 :param document_ast: document's JSON AST libgraphqlparser representation 1155 :param query: query to parse and transform into a DocumentNode 1156 :param schema: the GraphQLSchema instance linked to the engine 1157 :type document_ast: dict 1158 :type query: Union[str, bytes] 1159 :type schema: GraphQLSchema 1160 :return: a DocumentNode instance equivalent to the JSON AST representation 1161 :rtype: DocumentNode 1162 1163 :Example: 1164 1165 >>> from tartiflette.language.parsers.libgraphqlparser.transformers import ( 1166 >>> document_from_ast_json 1167 >>> ) 1168 >>> 1169 >>> 1170 >>> document = document_from_ast_json({ 1171 >>> "kind": "Document", 1172 >>> "loc": { 1173 >>> "start": {"line": 2, "column": 13}, 1174 >>> "end": {"line": 4, "column": 14}, 1175 >>> }, 1176 >>> "definitions": [ 1177 >>> { 1178 >>> "kind": "OperationDefinition", 1179 >>> "loc": { 1180 >>> "start": {"line": 2, "column": 13}, 1181 >>> "end": {"line": 4, "column": 14}, 1182 >>> }, 1183 >>> "operation": "query", 1184 >>> "name": None, 1185 >>> "variableDefinitions": None, 1186 >>> "directives": None, 1187 >>> "selectionSet": { 1188 >>> "kind": "SelectionSet", 1189 >>> "loc": { 1190 >>> "start": {"line": 2, "column": 13}, 1191 >>> "end": {"line": 4, "column": 14}, 1192 >>> }, 1193 >>> "selections": [ 1194 >>> { 1195 >>> "kind": "Field", 1196 >>> "loc": { 1197 >>> "start": {"line": 3, "column": 15}, 1198 >>> "end": {"line": 3, "column": 20}, 1199 >>> }, 1200 >>> "alias": None, 1201 >>> "name": { 1202 >>> "kind": "Name", 1203 >>> "loc": { 1204 >>> "start": {"line": 3, "column": 15}, 1205 >>> "end": {"line": 3, "column": 20}, 1206 >>> }, 1207 >>> "value": "hello", 1208 >>> }, 1209 >>> "arguments": None, 1210 >>> "directives": None, 1211 >>> "selectionSet": None, 1212 >>> } 1213 >>> ], 1214 >>> }, 1215 >>> } 1216 >>> ], 1217 >>> }, 1218 >>> ''' 1219 >>> { 1220 >>> hello 1221 >>> } 1222 >>> ''') 1223 """ 1224 1225 validators = Validators(schema, RULE_SET) 1226 1227 definitions = _parse_definitions(document_ast["definitions"], validators) 1228 1229 validators.validate( 1230 rule="executable-definitions", definitions=definitions, path=None 1231 ) 1232 1233 return DocumentNode( 1234 definitions=definitions, 1235 validators=validators, 1236 hash_id=hash(query), 1237 location=_parse_location(document_ast["loc"]), 1238 ) 1239