Coverage for graphqler / compiler / resolvers / resolver.py: 82%

45 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-20 10:09 -0400

1from .utils import find_closest_string 

2from graphqler.utils.parser_utils import get_base_oftype 

3 

4 

5class Resolver: 

6 def __init__(self): 

7 pass 

8 

9 def get_inputs_related_to_ids(self, inputs: dict, input_objects: dict) -> dict: 

10 """Recursively finds any inputs that has ID in its name as that would imply it references other objects 

11 

12 Args: 

13 inputs (dict): An inputs 

14 input_objects (dict): The input objects to be used for recursive search 

15 

16 Returns: 

17 dict: A dictionary of id and if it's NON_NULL or not IE. {'userId': False, 'clientId': True} 

18 """ 

19 if inputs is None: 

20 return {} 

21 else: 

22 found_ids = {} 

23 for input_name, input in inputs.items(): 

24 if self.is_input_an_id(input): 

25 found_ids[input_name] = input["kind"] == "NON_NULL" 

26 elif self.is_input_object(input): 

27 input_object_name = input["ofType"]["name"] 

28 input_object = input_objects[input_object_name] 

29 found_ids.update(self.get_inputs_related_to_ids(input_object["inputFields"], input_objects)) 

30 return found_ids 

31 

32 def resolve_inputs_related_to_ids_to_objects(self, endpoint_name: str, inputs_related_to_ids: dict, objects: dict) -> dict: 

33 """Resolves inputs related to IDs by looking at the name of the parameter after the ID string is removed 

34 

35 Args: 

36 endpoint_name (str): The name of the query or mutation for these inputs 

37 inputs_related_to_ids (dict): The inputs name (IE: userId) 

38 objects (dict): All the possible objects for this API 

39 

40 Returns: 

41 dict: Input parameters to the objects and the required / not required mappings 

42 """ 

43 input_id_object_mapping = {"hardDependsOn": {}, "softDependsOn": {}} 

44 

45 for input_name, required in inputs_related_to_ids.items(): 

46 # Get the object's name 

47 object_name = input_name 

48 if input_name.lower() == "id": 

49 guessed_object_name = find_closest_string(objects.keys(), endpoint_name) 

50 elif input_name.lower() == "ids": 

51 guessed_object_name = find_closest_string(objects.keys(), endpoint_name) 

52 elif input_name[-2:].lower() == "id": 

53 object_name = object_name[:-2] 

54 guessed_object_name = find_closest_string(objects.keys(), object_name) 

55 elif input_name[-3:].lower() == "ids": 

56 object_name = object_name[:-3] 

57 guessed_object_name = find_closest_string(objects.keys(), object_name) 

58 else: 

59 guessed_object_name = "" 

60 

61 # Check if the object's name is in the object listing 

62 if guessed_object_name in objects: 

63 assigned_dependency_name = guessed_object_name 

64 else: 

65 assigned_dependency_name = "UNKNOWN" 

66 

67 # Now assign it either a hardDependsOn or softDependsOn 

68 if required: 

69 input_id_object_mapping["hardDependsOn"][input_name] = assigned_dependency_name 

70 else: 

71 input_id_object_mapping["softDependsOn"][input_name] = assigned_dependency_name 

72 return input_id_object_mapping 

73 

74 def is_input_object(self, input: dict) -> bool: 

75 return input["ofType"] and input["ofType"]["kind"] == "INPUT_OBJECT" 

76 

77 def is_input_an_id(self, input: dict) -> bool: 

78 """Checks if the input is an ID field 

79 

80 Args: 

81 input (dict): The input field to check 

82 

83 Returns: 

84 bool: True if the field is an ID, False otherwise 

85 """ 

86 if input["ofType"]: 

87 input = get_base_oftype(input["ofType"]) 

88 

89 return input["kind"] == "SCALAR" and input["type"] == "ID"