Describe aggregates and projections

See gh-264
This commit is contained in:
Mark Paluch
2022-01-19 13:58:44 +01:00
committed by rstoyanchev
parent 50b794cae0
commit f34da2589b

View File

@@ -1,5 +1,5 @@
= Spring for GraphQL Documentation
Brian Clozel; Andreas Marek; Rossen Stoyanchev
Brian Clozel; Andreas Marek; Rossen Stoyanchev; Mark Paluch
include::attributes.adoc[]
@@ -480,6 +480,58 @@ assertThat(books.get(0).getName()).isEqualTo("...");
[[data]]
== Data Integration
Spring for GraphQL is, in contrast to other GraphQL technologies that surface persistent
data, not a data gateway that translates GraphQL queries into SQL or JSON queries.
Instead, Spring for GraphQL is an API gateway that leverages existing Spring technology
following common programming models to expose underlying data sources through GraphQL.
Domain-driven design is the suggested approach to manage complexity when using Spring Data.
So by design, a GraphQL API built on top of Spring Data can leverage only what's already
provided by an application.
It, therefore, must adhere to the constraints of an aggregate.
By definition, an aggregate is only valid if it is loaded in its entirety.
Partially loaded aggregates may impose a limitation on aggregate functionality.
With Spring Data you can choose whether you want to let your aggregate participate as
an underlying data model to be directly exposed as a GraphQL result, or whether you want to
apply projections to your data model before returning it as a GraphQL operation result.
The advantage of using aggregates is that you do not require additional code to expose
data through repositories. When processing a GraphQL operation, the integration layer
transforms the field selection set into property paths. It provides these hints of which
properties to materialize to the underlying Spring Data module that limits the field
(or column) selection.
Sometimes, an already reduced set of fields can be useful when exposing data. Also, some
arrangements might require transformations to be applied before data is returned for a
GraphQL operation. Spring Data supports for these scenarios projections: Interface and DTO
Projections.
Interface projections define a fixed set of properties to expose. Properties may or may
not be `null`, depending on the query result. A plain, https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.closed[closed interface projection]
can be useful if you cannot partially materialize the aggregate object but you still
want to expose a subset of properties.
You can use interface projections to apply a lightweight set of data transformations,
such as concatenations, computations or applying a static function to a property.
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.open[Open projections]
leverage Spring's `@Value` annotation and
{spring-framework-ref-docs}/core.html#expressions[SpEL expressions]for transformations.
In both cases, interface projections define which properties to load from the underlying
data source.
DTO projections offer the highest possible level of customization as you can place your
transformation code either in the constructor or the getter method.
DTO projections materialize from a query where the individual properties are
determined by the projection itself. DTO projections are commonly used with full-args
constructors (e.g. Java records) and therefore they can only be constructed if all
required fields (or columns) are part of the database query result.
[[data-querydsl]]
=== Querydsl
@@ -607,6 +659,36 @@ building a `QuerydslDataFetcher` you will need to use builder methods to apply i
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[interface and DTO projections]
to transform query results before returning these for further GraphQL processing.
To use Spring Data projections with Querydsl repositories, create either a projection interface
or a target DTO class and configure it through the `projectAs` method to obtain a
`DataFetcher` producing the target type:
[source,java,indent=0,subs="verbatim,quotes"]
----
class Account {
String name, identifier, description;
Person owner;
}
interface AccountProjection {
String getName();
String getIdentifier();
}
// For single result queries
DataFetcher<AccountProjection> dataFetcher =
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).single();
// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
----
[[data-querydsl-registration]]
==== Auto Registration
@@ -685,6 +767,36 @@ it is supported, so no extra setup is required to enable it.
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[interface and DTO projections]
to transform query results before returning these for further GraphQL processing.
To use Spring Data projections with Query by Example repositories, create either a projection interface
or a target DTO class and configure it through the `projectAs` method to obtain a
`DataFetcher` producing the target type:
[source,java,indent=0,subs="verbatim,quotes"]
----
class Account {
String name, identifier, description;
Person owner;
}
interface AccountProjection {
String getName();
String getIdentifier();
}
// For single result queries
DataFetcher<AccountProjection> dataFetcher =
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).single();
// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
----
[[data-querybyexample-registration]]
==== Auto Registration