Custom resolvers
When a generated field cannot express a query, write the resolver yourself and keep Strawchemy's data access by calling a repository from it.
Fetching one record
Called as a function, strawchemy.field() builds a repository-backed resolver for you. Decorate your own method with @strawchemy.field to build that repository yourself and add your own logic around it — a lookup by title, say, which strawchemy.field() alone has no argument for:
from sqlalchemy import select
from strawchemy import StrawchemySyncRepository
@strawberry.type
class Query:
@strawchemy.field
def get_post_by_title(self, info: strawberry.Info, title: str) -> PostType | None:
repo = StrawchemySyncRepository(PostType, info, filter_statement=select(Post).where(Post.title == title))
return repo.get_one_or_none().graphql_type_or_none()filter_statement narrows the query before Strawchemy's own filtering, ordering and field-selection logic runs on top of it. A statement that only adds WHERE clauses to select(Post) has them copied into the query; any other statement is joined on the primary key, so its own ORDER BY doesn't order the result. The repository takes none of the field's arguments or the mapper's configuration: pass query_hook, execution_options or deterministic_ordering to it when you need them. get_one_or_none() runs it and returns a GraphQLResult; graphql_type_or_none() converts that into PostType | None.
Fetching by primary key needs no filter_statement: pass the key as a keyword argument to get_by_id():
@strawchemy.field
def get_post_by_id(self, info: strawberry.Info, id: int) -> PostType:
repo = StrawchemySyncRepository(PostType, info)
return repo.get_by_id(id=id).graphql_type()get_by_id() takes the primary key's field name and value as keyword arguments — here id, matching Post.id. graphql_type() is the non-optional counterpart to graphql_type_or_none(): it raises instead of returning None when there's no match.
Returning a list
@strawchemy.field
def published_posts(self, info: strawberry.Info) -> list[PostType]:
repo = StrawchemySyncRepository(PostType, info, filter_statement=select(Post).where(Post.published_at.is_not(None)))
return repo.list().graphql_list()The repository has four methods for fetching data, each paired with its own conversion call:
get_one(),get_one_or_none()— return at most one result, and raiseMultipleResultsFoundif several rows match;graphql_type()then raisesQueryResultErroron no match, whilegraphql_type_or_none()returnsNoneget_by_id()— returns a single result filtered on primary keylist()— returns every matching result
instance and instances on the returned GraphQLResult give the model instances instead. Relationships the GraphQL query selected are not set on them: declare the ones your code reads in QueryHook(load=...).
See async sessions for the same resolvers written against StrawchemyAsyncRepository.
See query hooks for constraining every query against a type, and for loading data a custom field needs.