Problem
When a relationship field is generated for a related SQLAlchemy model that also has an explicit GraphQL DTO name, Strawchemy can bind the relationship to the synthesized default DTO type instead of the explicitly registered DTO.
That means custom fields declared on the explicit DTO are not present on the relationship field type.
This is not module discovery: if the related DTO module is never imported/decorated, Strawchemy cannot know about it. The issue is the case where the explicit DTO exists, but relationship generation has already selected or synthesized the default related DTO name.
Minimal example
from sqlalchemy import ForeignKey, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from strawberry import Schema
from strawchemy import Strawchemy, StrawchemyConfig
class Base(DeclarativeBase):
pass
class Account(Base):
__tablename__ = "accounts"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
name: Mapped[str] = mapped_column(String)
class Template(Base):
__tablename__ = "templates"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
account_id: Mapped[int] = mapped_column(ForeignKey("accounts.id"))
account: Mapped[Account] = relationship()
sc = Strawchemy(StrawchemyConfig(dialect="postgresql"))
@sc.type(Template, name="TemplateNode", include=["id", "account"])
class TemplateNode:
pass
@sc.type(Account, name="AccountNode", include=["id", "name"])
class AccountNode:
@strawberry.field
def custom_label(self) -> str:
return "custom"
@strawberry.type
class Query:
template: TemplateNode | None = None
schema = Schema(query=Query)
print(schema.as_str())
Expected relationship field:
Observed with default DTO naming:
The AccountNode.customLabel field is therefore not available on TemplateNode.account.
Why deferred/schema-time resolution would help
If relationship fields stored a deferred reference keyed by the related model and DTO purpose/scope instead of immediately binding to the currently synthesized class/name, schema construction/finalization could resolve that reference to the explicit registered DTO when one exists.
That would avoid import-order workarounds such as registering otherwise-unused related-node imports purely so relationship fields bind to the desired type.
Possible direction
- Keep a registry keyed by
(model, purpose/mode, scope) that records explicit DTO registrations.
- Let relationship field generation emit a model-keyed deferred reference rather than an eagerly chosen default DTO class/name.
- At schema build or finalization time, resolve pending relationship references to the explicit registered DTO if present; otherwise fall back to generated defaults.
- If this is expected to be handled by the future
scope behavior mentioned in Walker auto-registers stub types that collide with subsequent @sc.type declarations (partial-port footgun) #159, document whether scope will also cover relationship-target resolution for explicitly named DTOs.
Workaround
In our app we can work around this by customizing DTO naming so synthesized relationship DTO names match our explicit *Node convention, but that is project-specific and feels like it should not be required for relationship fields to point at explicit registered DTOs.
Problem
When a relationship field is generated for a related SQLAlchemy model that also has an explicit GraphQL DTO name, Strawchemy can bind the relationship to the synthesized default DTO type instead of the explicitly registered DTO.
That means custom fields declared on the explicit DTO are not present on the relationship field type.
This is not module discovery: if the related DTO module is never imported/decorated, Strawchemy cannot know about it. The issue is the case where the explicit DTO exists, but relationship generation has already selected or synthesized the default related DTO name.
Minimal example
Expected relationship field:
Observed with default DTO naming:
The
AccountNode.customLabelfield is therefore not available onTemplateNode.account.Why deferred/schema-time resolution would help
If relationship fields stored a deferred reference keyed by the related model and DTO purpose/scope instead of immediately binding to the currently synthesized class/name, schema construction/finalization could resolve that reference to the explicit registered DTO when one exists.
That would avoid import-order workarounds such as registering otherwise-unused related-node imports purely so relationship fields bind to the desired type.
Possible direction
(model, purpose/mode, scope)that records explicit DTO registrations.scopebehavior mentioned in Walker auto-registers stub types that collide with subsequent @sc.type declarations (partial-port footgun) #159, document whetherscopewill also cover relationship-target resolution for explicitly named DTOs.Workaround
In our app we can work around this by customizing DTO naming so synthesized relationship DTO names match our explicit
*Nodeconvention, but that is project-specific and feels like it should not be required for relationship fields to point at explicit registered DTOs.