Skip to content

Commit f34da25

Browse files
mp911derstoyanchev
authored andcommitted
Describe aggregates and projections
See gh-264
1 parent 50b794c commit f34da25

File tree

1 file changed

+113
-1
lines changed

1 file changed

+113
-1
lines changed

spring-graphql-docs/src/docs/asciidoc/index.adoc

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
= Spring for GraphQL Documentation
2-
Brian Clozel; Andreas Marek; Rossen Stoyanchev
2+
Brian Clozel; Andreas Marek; Rossen Stoyanchev; Mark Paluch
33
include::attributes.adoc[]
44

55

@@ -480,6 +480,58 @@ assertThat(books.get(0).getName()).isEqualTo("...");
480480
[[data]]
481481
== Data Integration
482482

483+
Spring for GraphQL is, in contrast to other GraphQL technologies that surface persistent
484+
data, not a data gateway that translates GraphQL queries into SQL or JSON queries.
485+
Instead, Spring for GraphQL is an API gateway that leverages existing Spring technology
486+
following common programming models to expose underlying data sources through GraphQL.
487+
488+
Domain-driven design is the suggested approach to manage complexity when using Spring Data.
489+
So by design, a GraphQL API built on top of Spring Data can leverage only what's already
490+
provided by an application.
491+
It, therefore, must adhere to the constraints of an aggregate.
492+
By definition, an aggregate is only valid if it is loaded in its entirety.
493+
Partially loaded aggregates may impose a limitation on aggregate functionality.
494+
495+
With Spring Data you can choose whether you want to let your aggregate participate as
496+
an underlying data model to be directly exposed as a GraphQL result, or whether you want to
497+
apply projections to your data model before returning it as a GraphQL operation result.
498+
499+
The advantage of using aggregates is that you do not require additional code to expose
500+
data through repositories. When processing a GraphQL operation, the integration layer
501+
transforms the field selection set into property paths. It provides these hints of which
502+
properties to materialize to the underlying Spring Data module that limits the field
503+
(or column) selection.
504+
505+
Sometimes, an already reduced set of fields can be useful when exposing data. Also, some
506+
arrangements might require transformations to be applied before data is returned for a
507+
GraphQL operation. Spring Data supports for these scenarios projections: Interface and DTO
508+
Projections.
509+
510+
Interface projections define a fixed set of properties to expose. Properties may or may
511+
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]
512+
can be useful if you cannot partially materialize the aggregate object but you still
513+
want to expose a subset of properties.
514+
515+
You can use interface projections to apply a lightweight set of data transformations,
516+
such as concatenations, computations or applying a static function to a property.
517+
518+
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.open[Open projections]
519+
leverage Spring's `@Value` annotation and
520+
{spring-framework-ref-docs}/core.html#expressions[SpEL expressions]for transformations.
521+
522+
In both cases, interface projections define which properties to load from the underlying
523+
data source.
524+
525+
DTO projections offer the highest possible level of customization as you can place your
526+
transformation code either in the constructor or the getter method.
527+
528+
DTO projections materialize from a query where the individual properties are
529+
determined by the projection itself. DTO projections are commonly used with full-args
530+
constructors (e.g. Java records) and therefore they can only be constructed if all
531+
required fields (or columns) are part of the database query result.
532+
533+
534+
483535
[[data-querydsl]]
484536
=== Querydsl
485537

@@ -607,6 +659,36 @@ building a `QuerydslDataFetcher` you will need to use builder methods to apply i
607659
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[interface and DTO projections]
608660
to transform query results before returning these for further GraphQL processing.
609661

662+
To use Spring Data projections with Querydsl repositories, create either a projection interface
663+
or a target DTO class and configure it through the `projectAs` method to obtain a
664+
`DataFetcher` producing the target type:
665+
666+
[source,java,indent=0,subs="verbatim,quotes"]
667+
----
668+
class Account {
669+
670+
String name, identifier, description;
671+
672+
Person owner;
673+
}
674+
675+
interface AccountProjection {
676+
677+
String getName();
678+
679+
String getIdentifier();
680+
}
681+
682+
// For single result queries
683+
DataFetcher<AccountProjection> dataFetcher =
684+
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).single();
685+
686+
// For multi-result queries
687+
DataFetcher<Iterable<AccountProjection>> dataFetcher =
688+
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
689+
----
690+
691+
610692

611693
[[data-querydsl-registration]]
612694
==== Auto Registration
@@ -685,6 +767,36 @@ it is supported, so no extra setup is required to enable it.
685767
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[interface and DTO projections]
686768
to transform query results before returning these for further GraphQL processing.
687769

770+
To use Spring Data projections with Query by Example repositories, create either a projection interface
771+
or a target DTO class and configure it through the `projectAs` method to obtain a
772+
`DataFetcher` producing the target type:
773+
774+
[source,java,indent=0,subs="verbatim,quotes"]
775+
----
776+
class Account {
777+
778+
String name, identifier, description;
779+
780+
Person owner;
781+
}
782+
783+
interface AccountProjection {
784+
785+
String getName();
786+
787+
String getIdentifier();
788+
}
789+
790+
// For single result queries
791+
DataFetcher<AccountProjection> dataFetcher =
792+
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).single();
793+
794+
// For multi-result queries
795+
DataFetcher<Iterable<AccountProjection>> dataFetcher =
796+
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
797+
----
798+
799+
688800

689801
[[data-querybyexample-registration]]
690802
==== Auto Registration

0 commit comments

Comments
 (0)