omar2535/GraphQLer

View on GitHub
graphqler/compiler/resolvers/resolver.py

Summary

Maintainability
A
2 hrs
Test Coverage
from .utils import find_closest_string
from graphqler.utils.parser_utils import get_base_oftype


class Resolver:
    def __init__(self):
        pass

    def get_inputs_related_to_ids(self, inputs: dict, input_objects: dict) -> dict:
        """Recursively finds any inputs that has ID in its name as that would imply it references other objects

        Args:
            inputs (dict): An inputs
            input_objects (dict): The input objects to be used for recursive search

        Returns:
            dict: A dictionary of id and if it's NON_NULL or not IE. {'userId': False, 'clientId': True}
        """
        if inputs is None:
            return {}
        else:
            found_ids = {}
            for input_name, input in inputs.items():
                if self.is_input_an_id(input):
                    found_ids[input_name] = input["kind"] == "NON_NULL"
                elif self.is_input_object(input):
                    input_object_name = input["ofType"]["name"]
                    input_object = input_objects[input_object_name]
                    found_ids.update(self.get_inputs_related_to_ids(input_object["inputFields"], input_objects))
            return found_ids

    def resolve_inputs_related_to_ids_to_objects(self, endpoint_name: str, inputs_related_to_ids: dict, objects: dict) -> dict:
        """Resolves inputs related to IDs by looking at the name of the parameter after the ID string is removed

        Args:
            endpoint_name (str): The name of the query or mutation for these inputs
            inputs_related_to_ids (dict): The inputs name (IE: userId)
            objects (dict): All the possible objects for this API

        Returns:
            dict: Input parameters to the objects and the required / not required mappings
        """
        input_id_object_mapping = {"hardDependsOn": {}, "softDependsOn": {}}

        for input_name, required in inputs_related_to_ids.items():
            # Get the object's name
            object_name = input_name
            if input_name.lower() == "id":
                guessed_object_name = find_closest_string(objects.keys(), endpoint_name)
            elif input_name.lower() == "ids":
                guessed_object_name = find_closest_string(objects.keys(), endpoint_name)
            elif input_name[-2:].lower() == "id":
                object_name = object_name[:-2]
                guessed_object_name = find_closest_string(objects.keys(), object_name)
            elif input_name[-3:].lower() == "ids":
                object_name = object_name[:-3]
                guessed_object_name = find_closest_string(objects.keys(), object_name)
            else:
                guessed_object_name = ""

            # Check if the object's name is in the object listing
            if guessed_object_name in objects:
                assigned_dependency_name = guessed_object_name
            else:
                assigned_dependency_name = "UNKNOWN"

            # Now assign it either a hardDependsOn or softDependsOn
            if required:
                input_id_object_mapping["hardDependsOn"][input_name] = assigned_dependency_name
            else:
                input_id_object_mapping["softDependsOn"][input_name] = assigned_dependency_name
        return input_id_object_mapping

    def is_input_object(self, input: dict) -> bool:
        return input["ofType"] and input["ofType"]["kind"] == "INPUT_OBJECT"

    def is_input_an_id(self, input: dict) -> bool:
        """Checks if the input is an ID field

        Args:
            input (dict): The input field to check

        Returns:
            bool: True if the field is an ID, False otherwise
        """
        if input["ofType"]:
            input = get_base_oftype(input["ofType"])

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