avanov / graphql-dsl

Compose GraphQL queries by composing Python types!
https://graphql-dsl.rtfd.io/
MIT License
5 stars 2 forks source link

Field aliases #10

Open iwconfig opened 1 year ago

iwconfig commented 1 year ago

Is it possible to set aliases to fields?

Such as this

query HeroAndDroid($droidId: ID!) {
  MYHERO: hero {
    name
  }
  droid(id: $droidId) {
    name
  }
}

I was looking through the source code and found https://github.com/avanov/graphql-dsl/blob/6bcd393c30882d41a1fe777877e5dc8b24f862a9/graphql_dsl/dsl.py#L185

What is Binding.variable_alias meant for?

If this is not already possible, maybe reading NamedTuple._field_defaults should suffice? Like so:

class HeroAndDroid(NamedTuple):
    droid: Droid
    hero: Hero = 'MYHERO'

Or might this already be on the roadmap?

EDIT: Ah ok Binding.variable_alias and input_attr_name=alias if alias else attr_name, is for * AS * 'my_alias'

iwconfig commented 1 year ago

EDIT: No, it does not. And I am blind!

I poked around a bit

dsl.py

class ResolvedBinding(NamedTuple):
    ...
    attr_name_alias: str

...

class GraphQLQueryConstructor(NamedTuple):
    ...
    def prepare_bindings(self, expr: Expr) -> Mapping[str, Iterable[ResolvedBinding]]:
            ...
            rv[resolved_expr].append(resolved_input)
        return rv

    def resolve_binding(self, typ: Type[Any], field: FieldReference, alias: Optional[str]) -> ResolvedBinding:
        ...
        return ResolvedBinding(attr_name=overrider(name),
                               attr_name_alias=typ._field_defaults.get(attr_name),
                               input_attr_name=alias if alias else attr_name,
                               type_name=type_name,
                               is_optional=is_optional)

translator.py

def translate_begin_type(x: Token, bindings: Mapping[Any, Any]) -> str:
    if bindings:
        expr_bindings = next(iter(bindings))
        python_name_alias = expr_bindings.attr_name_alias
        all_input_bindings = chain.from_iterable(bindings.values())

    ...

    if python_name_alias:
        return f'{python_name_alias}{x.python_name}{vars}{{'
    return f'{x.python_name}{vars}{{'
  1. typ._field_defaults.get(attr_name) is assigned to dsl.ResolvedBinding.attr_name_alias in dsl.GraphQLQueryConstructor.resolve_binding.
  2. To the defaultdict returned by dsl.GraphQLQueryConstructor.prepare_bindings, the whole resolved_expr instance is passed as a key instead of only resolved_expr.attr_name,
  3. which is then used by translator.translate_begin_type.

I'm not sure if this is a good solution but it works.