Coverage for graphqler / compiler / resolvers / object_dependency_resolver.py: 100%
32 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-20 10:09 -0400
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-20 10:09 -0400
1"""This module will be used to create a object dependency resolver
2The representation of this will be essentially a text-based graph
4The dependencies will be generated from object - object
5while methods such as queries / mutations will be related to objects
6based on either output type or semantic understanding
7"""
9from graphqler.config import BUILT_IN_TYPES, BUILT_IN_TYPE_KINDS
12class ObjectDependencyResolver:
13 def __init__(self):
14 pass
16 def resolve(self, objects) -> dict:
17 """Resolve dependencies by adding the 'hardDependsOn' key and 'softDependsOn' key
18 hardDependsOn: the object must be created for this object to be instantiated
19 softDependsOn: the object can be null on instantiation of this object
21 Returns:
22 dict: The new enriched objects with an extra 'dependsOn' key
23 """
24 for gql_object_key, gql_object in objects.items():
25 objects[gql_object_key] = self.parse_gql_object(gql_object)
27 return objects
29 def get_base_oftype(self, oftype: dict) -> dict:
30 if "ofType" in oftype and oftype["ofType"] is not None:
31 return self.get_base_oftype(oftype["ofType"])
32 else:
33 return oftype
35 def parse_gql_object(self, gql_object: dict) -> dict:
36 """Parse a single object, noting down all of the other object this object depends on
37 hardDependsOn: Where the object has fields on other objects and it's kind is NON_NULL
38 softDependsOn: Where the object has fields on other objects and it can be NULL
41 !weird edge cases found from this method:
42 - when the field kind is a SCALAR, the ofType will be null
44 Args:
45 gql_object (dict): The graphql object
47 Returns:
48 dict: The enriched object with extra 'softDependsOn' key and 'hardDependsOn'
49 """
50 soft_dependent_objects = []
51 hard_dependent_objects = []
52 for field in gql_object["fields"]:
53 # There are 3 cases:
54 # - if the kind is SCALAR/OBJECT/INTERFACE/UNION/ENUM/INPUT_OBJECT,
55 # - if kind is NON_NULL
56 # - if kind is LIST
57 if field["kind"] in BUILT_IN_TYPE_KINDS and field["kind"] != "NON_NULL" and field["kind"] != "LIST":
58 if field["type"] not in BUILT_IN_TYPES:
59 soft_dependent_objects.append(field["type"])
60 if field["kind"] == "NON_NULL":
61 base_oftype = self.get_base_oftype(field["ofType"])
62 if base_oftype["kind"] not in BUILT_IN_TYPES:
63 hard_dependent_objects.append(base_oftype["name"])
64 elif field["kind"] == "LIST":
65 base_oftype = self.get_base_oftype(field["ofType"])
66 if base_oftype["kind"] not in BUILT_IN_TYPES:
67 # TODO: Figure out if lists can have hard dependencies (a non-zero lengthed list)
68 soft_dependent_objects.append(base_oftype["name"])
70 # TODO: Figure out a way see if we can handle custom scalars dynamically (?) - right now, they show up as none
71 # Remove nulls from dependency list and make them unique
72 soft_dependent_objects = list(set([o for o in soft_dependent_objects if o is not None]))
73 hard_dependent_objects = list(set([o for o in hard_dependent_objects if o is not None]))
75 gql_object["softDependsOn"] = soft_dependent_objects
76 gql_object["hardDependsOn"] = hard_dependent_objects
77 return gql_object