Skip to content

Commit

Permalink
Add a skeleton for the macro expansion system. (#181)
Browse files Browse the repository at this point in the history
* Add a skeleton for the macro expansion system.

* Add copyright lines.
  • Loading branch information
obi1kenobi committed Feb 5, 2019
1 parent 8ce65a1 commit 35e6b12
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 0 deletions.
85 changes: 85 additions & 0 deletions graphql_compiler/macros/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright 2019-present Kensho Technologies, LLC.
from collections import namedtuple

from .macro_edge import make_macro_edge_definition


MacroRegistry = namedtuple(
'MacroRegistry', (
'macro_edges', # Dict[str, Dict[str, MacroEdgeDefinition]] mapping:
# class name -> (macro edge name -> MacroEdgeDefinition)
# Any other macro types we may add in the future go here.
)
)


def create_macro_registry():
"""Create and return a new empty macro registry."""
return MacroRegistry(macro_edges=dict())


def register_macro_edge(macro_registry, schema, macro_edge_graphql, macro_edge_args,
type_equivalence_hints=None):
"""Add the new macro edge definition to the provided MacroRegistry object, mutating it.
Args:
macro_registry: MacroRegistry object containing macro definitions, where the new macro edge
definition should be added.
schema: GraphQL schema object, created using the GraphQL library
macro_edge_graphql: string, GraphQL defining how the new macro edge should be expanded
macro_edge_args: dict mapping strings to any type, containing any arguments the macro edge
requires in order to function.
type_equivalence_hints: optional dict of GraphQL interface or type -> GraphQL union.
Used as a workaround for GraphQL's lack of support for
inheritance across "types" (i.e. non-interfaces), as well as a
workaround for Gremlin's total lack of inheritance-awareness.
The key-value pairs in the dict specify that the "key" type
is equivalent to the "value" type, i.e. that the GraphQL type or
interface in the key is the most-derived common supertype
of every GraphQL type in the "value" GraphQL union.
Recursive expansion of type equivalence hints is not performed,
and only type-level correctness of this argument is enforced.
See README.md for more details on everything this parameter does.
*****
Be very careful with this option, as bad input here will
lead to incorrect output queries being generated.
*****
"""
class_name, macro_edge_name, macro_definition = make_macro_edge_definition(
schema, macro_edge_graphql, macro_edge_args,
type_equivalence_hints=type_equivalence_hints)

# Ensure this new macro edge does not conflict with any previous definition.
macro_edges_for_class = macro_registry.macro_edges.get(class_name, dict())
existing_definition = macro_edges_for_class.get(macro_edge_name, None)

if existing_definition is not None:
raise AssertionError(
u'Attempting to redefine an already registered macro edge: '
u'class {}, macro edge {}, new GraphQL definition {}, new args {}.'
.format(class_name, macro_edge_name, macro_edge_graphql, macro_edge_args))

# TODO(predrag): Write a more stringent check that makes sure that two types A and B,
# where A is a superclass of B, cannot define the same macro edge.
# Right now, both A and B can independently define a macro edge out_Foo,
# which would result in an illegal schema as B would be required to have
# two different definitions of the same out_Foo edge.

macro_registry.macro_edges.setdefault(class_name, dict())[macro_edge_name] = macro_definition


def perform_macro_expansion(schema, macro_registry, graphql_with_macro, graphql_args):
"""Return a new GraphQL query string and args, after expanding any encountered macros.
Args:
schema: GraphQL schema object, created using the GraphQL library
macro_registry: MacroRegistry, the registry of macro definitions used for expansion
graphql_with_macro: string, GraphQL query that potentially requires macro expansion
graphql_args: dict mapping strings to any type, containing the arguments for the query
Returns:
tuple (new_graphql_string, new_graphql_args) containing the rewritten GraphQL query and
its new args, after macro expansion. If the input GraphQL query contained no macros,
the returned values are guaranteed to be identical to the input query and args.
"""
raise NotImplementedError()
42 changes: 42 additions & 0 deletions graphql_compiler/macros/macro_edge/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2019-present Kensho Technologies, LLC.
from collections import namedtuple


MacroEdgeDefinition = namedtuple(
'MacroEdgeDefinition', (
'expansion_ast', # GraphQL AST object defining how the macro edge should be expanded
'macro_args', # Dict[str, Any] containing any arguments that the macro requires
)
)


def make_macro_edge_definition(schema, macro_edge_graphql, macro_edge_args,
type_equivalence_hints=None):
"""Validate the GraphQL macro edge definition, and return it in a form suitable for storage.
Args:
schema: GraphQL schema object, created using the GraphQL library
macro_edge_graphql: string, GraphQL defining how the new macro edge should be expanded
macro_edge_args: dict mapping strings to any type, containing any arguments the macro edge
requires in order to function.
type_equivalence_hints: optional dict of GraphQL interface or type -> GraphQL union.
Used as a workaround for GraphQL's lack of support for
inheritance across "types" (i.e. non-interfaces), as well as a
workaround for Gremlin's total lack of inheritance-awareness.
The key-value pairs in the dict specify that the "key" type
is equivalent to the "value" type, i.e. that the GraphQL type or
interface in the key is the most-derived common supertype
of every GraphQL type in the "value" GraphQL union.
Recursive expansion of type equivalence hints is not performed,
and only type-level correctness of this argument is enforced.
See README.md for more details on everything this parameter does.
*****
Be very careful with this option, as bad input here will
lead to incorrect output queries being generated.
*****
Returns:
tuple (class name, macro edge name, MacroEdgeDefinition) suitable for inclusion into the
GraphQL macro registry
"""
raise NotImplementedError()

0 comments on commit 35e6b12

Please sign in to comment.