Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/advanced/dsl_module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,14 @@ this can be written in a concise manner::
DSLInlineFragment().on(ds.Human).select(ds.Human.homePlanet)
)

Alternatively, you can use the DSL shortcut syntax to create an inline fragment by
passing the string ``"..."`` directly to the :meth:`__call__ <gql.dsl.DSLSchema.__call__>` method::

query_with_inline_fragment = ds.Query.hero.args(episode=6).select(
ds.Character.name,
ds("...").on(ds.Human).select(ds.Human.homePlanet)
)

Meta-fields
^^^^^^^^^^^

Expand All @@ -384,6 +392,15 @@ you can use the :class:`DSLMetaField <gql.dsl.DSLMetaField>` class::
DSLMetaField("__typename")
)

Alternatively, you can use the DSL shortcut syntax to create the same meta-field by
passing the ``"__typename"`` string directly to the :meth:`__call__ <gql.dsl.DSLSchema.__call__>` method::

query = ds.Query.hero.select(
ds.Character.name,
ds("__typename")
)


Directives
^^^^^^^^^^

Expand Down
35 changes: 17 additions & 18 deletions gql/dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,36 +323,35 @@ def __call__(
self, shortcut: Literal["..."]
) -> "DSLInlineFragment": ... # pragma: no cover

@overload
def __call__(
self, shortcut: Literal["fragment"], name: str
) -> "DSLFragment": ... # pragma: no cover

@overload
def __call__(self, shortcut: Any) -> "DSLDirective": ... # pragma: no cover

def __call__(
self, shortcut: str, name: Optional[str] = None
) -> Union["DSLMetaField", "DSLInlineFragment", "DSLFragment", "DSLDirective"]:
"""Factory method for creating DSL objects.
self, shortcut: str
) -> Union["DSLMetaField", "DSLInlineFragment", "DSLDirective"]:
"""Factory method for creating DSL objects from a shortcut string.

Currently, supports creating DSLDirective instances when name starts with '@'.
Future support planned for meta-fields (__typename), inline fragments (...),
and fragment definitions (fragment).
The shortcut determines which DSL object is created:

:param shortcut: the name of the object to create
* "__typename", "__schema", "__type" -> :class:`DSLMetaField`
* "..." -> :class:`DSLInlineFragment`
* "@<name>" -> :class:`DSLDirective`

:param shortcut: The shortcut string identifying the DSL object.
:type shortcut: str

:return: :class:`DSLDirective` instance
:return: A DSL object corresponding to the given shortcut.
:rtype: DSLMetaField | DSLInlineFragment | DSLDirective

:raises ValueError: if shortcut format is not supported
:raises ValueError: If the shortcut is not recognized.
"""

if shortcut in ("__typename", "__schema", "__type"):
return DSLMetaField(name=shortcut)
if shortcut == "...":
return DSLInlineFragment()
if shortcut.startswith("@"):
return DSLDirective(name=shortcut[1:], dsl_schema=self)
# Future support:
# if name.startswith("__"): return DSLMetaField(name)
# if name == "...": return DSLInlineFragment()
# if name.startswith("fragment "): return DSLFragment(name[9:])

raise ValueError(f"Unsupported shortcut: {shortcut}")

Expand Down
17 changes: 17 additions & 0 deletions tests/starwars/test_dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from gql import Client, gql
from gql.dsl import (
DSLDirective,
DSLField,
DSLFragment,
DSLFragmentSpread,
Expand Down Expand Up @@ -1297,6 +1298,22 @@ def test_legacy_fragment_with_variables(ds):
assert print_ast(query.document) == expected


@pytest.mark.parametrize(
"shortcut,expected",
[
("__typename", DSLMetaField("__typename")),
("__schema", DSLMetaField("__schema")),
("__type", DSLMetaField("__type")),
("...", DSLInlineFragment()),
("@skip", DSLDirective(name="skip", dsl_schema=DSLSchema(StarWarsSchema))),
],
)
def test_dsl_schema_call_shortcuts(ds, shortcut, expected):
actual = ds(shortcut)
assert getattr(actual, "name", None) == getattr(expected, "name", None)
assert isinstance(actual, type(expected))


def test_dsl_schema_call_validation(ds):
with pytest.raises(ValueError, match="(?i)unsupported shortcut"):
ds("foo")
Expand Down
Loading