Example #1
0
 async def test_generate_multiple_objects(self):
     graphql = await hasura.insert(
         "flow",
         objects=[{
             "a": 1
         }, {
             "b": "2"
         }],
         selection_set={"returning": {"id"}},
         run_mutation=False,
     )
     expected_query = """
         insert: insert_flow(objects: $insert_objects) {
             returning {
                 id
             }
         }
     """
     assert parse_graphql(
         graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(
             name="insert_objects",
             type="[flow_insert_input!]!",
             value=[{
                 "a": 1
             }, {
                 "b": "2"
             }],
         )
     ]
Example #2
0
    def graphql(self,
                query: Any,
                raise_on_error: bool = True,
                **variables: Union[bool, dict, str, int]) -> GraphQLResult:
        """
        Convenience function for running queries against the Prefect GraphQL API

        Args:
            - query (Any): A representation of a graphql query to be executed. It will be
                parsed by prefect.utilities.graphql.parse_graphql().
            - raise_on_error (bool): if True, a `ClientError` will be raised if the GraphQL
                returns any `errors`.
            - **variables (kwarg): Variables to be filled into a query with the key being
                equivalent to the variables that are accepted by the query

        Returns:
            - dict: Data returned from the GraphQL query

        Raises:
            - ClientError if there are errors raised by the GraphQL mutation
        """
        result = self.post(
            path="",
            query=parse_graphql(query),
            variables=json.dumps(variables),
            server=self.graphql_server,
        )

        if raise_on_error and "errors" in result:
            raise ClientError(result["errors"])
        else:
            return as_nested_dict(result, GraphQLResult)  # type: ignore
Example #3
0
def test_parse_graphql_dedents_and_strips():
    query = """

        hi
            there

    """
    assert parse_graphql(query) == "hi\n    there"
Example #4
0
 async def test_on_conflict_string(self):
     graphql = await hasura_client.insert(
         "tenant", objects=[], on_conflict="{ constraint: pk1 }", run_mutation=False
     )
     expected_query = """
         insert: insert_tenant(objects: $insert_objects, on_conflict: { constraint: pk1 }) {
             affected_rows
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
Example #5
0
 async def test_generate_selection_set(self):
     graphql = await hasura_client.insert(
         "tenant", objects=[], selection_set="affected_rows", run_mutation=False
     )
     expected_query = """
         insert: insert_tenant(objects: $insert_objects) {
             affected_rows
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
Example #6
0
 async def test_generate_gql_delete_tenants(self):
     graphql = await hasura_client.delete("tenant", where={}, run_mutation=False)
     expected_query = """
         delete: delete_tenant(where: $delete_where) {
             affected_rows
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="delete_where", type="tenant_bool_exp!", value={})
     ]
Example #7
0
 async def test_generate_gql_insert_tenants(self):
     graphql = await hasura_client.insert("tenant", objects=[], run_mutation=False)
     expected_query = """
         insert: insert_tenant(objects: $insert_objects) {
             affected_rows
         }
     """
     expected_defs = "$insert_objects: [tenant_insert_input!]!"
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="insert_objects", type="[tenant_insert_input!]!", value=[])
     ]
Example #8
0
 async def test_generate_gql_delete_tenants_selection_set(self):
     graphql = await hasura_client.delete(
         "tenant", where={}, selection_set={"returning": {"id"}}, run_mutation=False
     )
     expected_query = """
         delete: delete_tenant(where: $delete_where) {
             returning {
                 id
             }
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
Example #9
0
 async def test_generate_gql_update_tenants_increment(self):
     graphql = await hasura_client.update(
         "tenant", where={}, increment={"age": 1}, run_mutation=False
     )
     expected_query = """
         update: update_tenant(where: $update_where, _inc: $update_inc) {
             affected_rows
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="update_where", type="tenant_bool_exp!", value={}),
         Variable(name="update_inc", type="tenant_inc_input", value={"age": 1}),
     ]
Example #10
0
 async def test_alias(self):
     graphql = await hasura.insert("flow",
                                   objects=[],
                                   alias="x",
                                   run_mutation=False)
     expected_query = """
         x: insert_flow(objects: $x_objects) {
             affected_rows
         }
     """
     assert parse_graphql(
         graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="x_objects", type="[flow_insert_input!]!", value=[])
     ]
Example #11
0
 async def test_alias(self):
     graphql = await hasura.delete("flow",
                                   where={},
                                   alias="x",
                                   run_mutation=False)
     expected_query = """
         x: delete_flow(where: $x_where) {
             affected_rows
         }
     """
     assert parse_graphql(
         graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="x_where", type="flow_bool_exp!", value={})
     ]
Example #12
0
 async def test_generate_selection_set_returning(self):
     graphql = await hasura_client.insert(
         "tenant",
         objects=[],
         selection_set={"returning": {"id"}},
         run_mutation=False,
     )
     expected_query = """
         insert: insert_tenant(objects: $insert_objects) {
             returning {
                 id
             }
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
Example #13
0
 async def test_generate_gql_update_tenants_selection_set(self):
     graphql = await hasura_client.update(
         "tenant",
         where={},
         set={"name": "x"},
         selection_set={"returning": {"id"}},
         run_mutation=False,
     )
     expected_query = """
         update: update_tenant(where: $update_where, _set: $update_set) {
             returning {
                 id
             }
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
Example #14
0
    def graphql(
        self,
        query: Any,
        raise_on_error: bool = True,
        headers: Dict[str, str] = None,
        variables: Dict[str, JSONLike] = None,
        token: str = None,
    ) -> GraphQLResult:
        """
        Convenience function for running queries against the Prefect GraphQL API

        Args:
            - query (Any): A representation of a graphql query to be executed. It will be
                parsed by prefect.utilities.graphql.parse_graphql().
            - raise_on_error (bool): if True, a `ClientError` will be raised if the GraphQL
                returns any `errors`.
            - headers (dict): any additional headers that should be passed as part of the
                request
            - variables (dict): Variables to be filled into a query with the key being
                equivalent to the variables that are accepted by the query
            - token (str): an auth token. If not supplied, the `client.access_token` is used.

        Returns:
            - dict: Data returned from the GraphQL query

        Raises:
            - ClientError if there are errors raised by the GraphQL mutation
        """
        result = self.post(
            path="",
            server=self.api_server,
            headers=headers,
            params=dict(query=parse_graphql(query),
                        variables=json.dumps(variables)),
            token=token,
        )

        if raise_on_error and "errors" in result:
            if "UNAUTHENTICATED" in str(result["errors"]):
                raise AuthorizationError(result["errors"])
            elif "Malformed Authorization header" in str(result["errors"]):
                raise AuthorizationError(result["errors"])
            raise ClientError(result["errors"])
        else:
            return GraphQLResult(result)  # type: ignore
Example #15
0
 async def test_on_conflict(self):
     graphql = await hasura_client.insert(
         "tenant", objects=[], on_conflict={"constraint": "pk1"}, run_mutation=False
     )
     expected_query = """
         insert: insert_tenant(objects: $insert_objects, on_conflict: $insert_on_conflict) {
             affected_rows
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="insert_objects", type="[tenant_insert_input!]!", value=[]),
         Variable(
             name="insert_on_conflict",
             type="tenant_on_conflict",
             value={"constraint": "pk1"},
         ),
     ]
Example #16
0
 async def test_generate_gql_update_flows_set(self):
     graphql = await hasura.update("flow",
                                   where={},
                                   set={"name": "x"},
                                   run_mutation=False)
     expected_query = """
         update: update_flow(where: $update_where, _set: $update_set) {
             affected_rows
         }
     """
     assert parse_graphql(
         graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="update_where", type="flow_bool_exp!", value={}),
         Variable(name="update_set",
                  type="flow_set_input",
                  value={"name": "x"}),
     ]
Example #17
0
 async def test_generate_gql_update_tenants_delete_elem(self):
     graphql = await hasura_client.update("tenant",
                                          where={},
                                          delete_elem={"settings": 2},
                                          run_mutation=False)
     expected_query = """
         update: update_tenant(where: $update_where, _delete_elem: $update_delete_elem) {
             affected_rows
         }
     """
     assert parse_graphql(
         graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="update_where", type="tenant_bool_exp!", value={}),
         Variable(
             name="update_delete_elem",
             type="tenant_delete_elem_input",
             value={"settings": 2},
         ),
     ]
Example #18
0
 async def test_alias(self):
     graphql = await hasura_client.update(
         "tenant",
         where={},
         alias="x",
         set={"name": "x"},
         increment={"age": 1},
         run_mutation=False,
     )
     expected_query = """
         x: update_tenant(where: $x_where, _set: $x_set, _inc: $x_inc) {
             affected_rows
         }
     """
     assert parse_graphql(graphql["query"]) == dedent(expected_query).strip()
     assert graphql["variables"] == [
         Variable(name="x_where", type="tenant_bool_exp!", value={}),
         Variable(name="x_set", type="tenant_set_input", value={"name": "x"}),
         Variable(name="x_inc", type="tenant_inc_input", value={"age": 1}),
     ]
Example #19
0
    def graphql(
        self,
        query: Any,
        raise_on_error: bool = True,
        headers: Dict[str, str] = None,
        variables: Dict[str, JSONLike] = None,
    ) -> GraphQLResult:
        """
        Convenience function for running queries against the Prefect GraphQL API

        Args:
            - query (Any): A representation of a graphql query to be executed. It will be
                parsed by prefect.utilities.graphql.parse_graphql().
            - raise_on_error (bool): if True, a `ClientError` will be raised if the GraphQL
                returns any `errors`.
            - headers (dict): any additional headers that should be passed as part of the
                request
            - variables (dict): Variables to be filled into a query with the key being
                equivalent to the variables that are accepted by the query

        Returns:
            - dict: Data returned from the GraphQL query

        Raises:
            - ClientError if there are errors raised by the GraphQL mutation
        """
        result = self.post(
            path="",
            server=self.graphql_server,
            headers=headers,
            params=dict(query=parse_graphql(query),
                        variables=json.dumps(variables)),
        )

        if raise_on_error and "errors" in result:
            raise ClientError(result["errors"])
        else:
            return as_nested_dict(result, GraphQLResult)  # type: ignore
Example #20
0
    async def execute(
        self,
        query: Union[str, Dict[str, Any]],
        variables: Dict[str, Any] = None,
        headers: dict = None,
        raise_on_error: bool = True,
        as_box=True,
    ) -> dict:
        """
        Args:
            - query (Union[str, dict]): either a GraphQL query string or objects that are compatible
                with prefect.utilities.graphql.parse_graphql().
            - variables (dict): GraphQL variables
            - headers (dict): Headers to include with the GraphQL request
            - raise_on_error (bool): if True, a `ValueError` is raised whenever the GraphQL
                result contains an `errors` field.
            - as_box (bool): if True, a `box.Box` object is returned, which behaves like a dict
                but allows "dot" access in addition to key access.

        Returns:
            - dict: a dictionary of GraphQL info. If `as_box` is True, it will be a Box (dict subclass)

        Raises:
            - GraphQLSyntaxError: if the provided query is not a valid GraphQL query
            - ValueError: if `raise_on_error=True` and there are any errors during execution.
        """
        if not isinstance(query, str):
            query = parse_graphql(query)

        # validate query
        if prefect_server.config.debug:
            ariadne.gql(query)

        # timeout of 30 seconds
        response = await httpx.post(
            self.url,
            json=dict(query=query, variables=variables or {}),
            headers=headers or self.headers,
            timeout=30,
        )
        try:
            result = response.json()
        except json.decoder.JSONDecodeError as exc:
            self.logger.error("JSON Decode Error on {}".format(
                response.content.decode()))
            self.logger.error(exc)
            raise exc

        if raise_on_error and "errors" in result:
            if prefect_server.config.debug:
                self.log_query_debug_info(
                    query=query,
                    variables=variables or {},
                    errors=result["errors"],
                    headers=headers or self.headers,
                )
            raise ValueError(result["errors"])

        # convert to box
        if as_box:
            result = Box(result)

        return result
Example #21
0
def verify(query, expected):
    assert parse_graphql(query) == dedent(expected).strip()