diff --git a/docs/advanced/dsl_module.rst b/docs/advanced/dsl_module.rst index c6ee035a..e30655b5 100644 --- a/docs/advanced/dsl_module.rst +++ b/docs/advanced/dsl_module.rst @@ -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__ ` 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 ^^^^^^^^^^^ @@ -384,6 +392,15 @@ you can use the :class:`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__ ` method:: + + query = ds.Query.hero.select( + ds.Character.name, + ds("__typename") + ) + + Directives ^^^^^^^^^^ diff --git a/gql/dsl.py b/gql/dsl.py index da4cf64c..2e6d3967 100644 --- a/gql/dsl.py +++ b/gql/dsl.py @@ -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` + * "@" -> :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}") diff --git a/tests/starwars/test_dsl.py b/tests/starwars/test_dsl.py index a3d1ef8c..7f042a07 100644 --- a/tests/starwars/test_dsl.py +++ b/tests/starwars/test_dsl.py @@ -23,6 +23,7 @@ from gql import Client, gql from gql.dsl import ( + DSLDirective, DSLField, DSLFragment, DSLFragmentSpread, @@ -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")