Repository navigation
Releases: hecht-a/graphql-orm
Releases · hecht-a/graphql-orm
Release list
v5.13.0
Added
-
operation_names: true, at the root or for a manager, names each query after its entity and the method sending it
(query Task_findBy { ... },mutation flush { ... }), for the logs and the monitoring of the API; off by default,
as it changes the text of the queries.GraphqlQueryBuilder::name()names a query whatever the option. -
The PHPStan extension tells that the mapped properties are written by the hydration and read by
flush(): a
readonlyidentifier needs no constructor.
Changed
phpstan/phpdoc-parser2.3.1 or later is required, rather than 2.2: the tests of the PHPStan extension of the bundle
failed with 2.2 and 2.3.0, whose nodes cannot be read back from the cache of PHPStan.- The hydration and
flush()bypass the hooks of the properties, as Doctrine does: thesethooks no longer run when
an entity is hydrated, andflush()sends the value a property holds rather than the one itsgethook returns.
A virtual property, holding no value of its own, can no longer be mapped: anInvalidArgumentExceptionsays so.
Fixed
- A
readonlyproperty is no longer written again when another query returns the entity: an entity with a readonly
identifier threwCannot modify readonly propertyonce met by a second query.
v5.12.0
Added
graphqlorm:find --dry-runshows the query as it would be sent, with its variables, the manager and the dialect,
without sending it;--format=jsongives them as an object.GraphqlEntityRepository::createFindByQuery()gives the queryfindBy()sends, not sent yet: to read its GraphQL,
keep its response in the result cache or send it with others throughGraphqlQuery::concurrently().- A cookbook in the documentation: from HttpClient to the bundle, when to use it and when not, a paginated list, a form
creating an entity, and speeding up a slow page.
Changed
- 4.x and the versions before it are no longer maintained: they get no release, fixes included. Their documentation
stays online under/4.x/, marked as unmaintained.
v5.11.0
Changed
- Faster queries and hydration, measured with the benchmarks of
tests/Benchmark: a query no longer copies the shared
identity map, so that its cost no longer grows with the entities known (5,000 known: 160 µs down to 25 µs); the
query is exported and masked for the query events only when they have listeners; the reflection of the hydrated and
tracked properties, of the value objects, of the DTOs and of the lazy ghosts is read once; a response is decoded
once. Hydrating 1,000 rows takes about 10% less time.
Added
- The walkers extending
AbstractGraphqlWalkerformat the arguments asDefaultGraphqlWalkerdid: a dialect overrides
formatEnum()to print a backed enum as an enum literal, andomitsArgument()to leave out the arguments its API
refuses.
Fixed
- Data API Builder fetches the page after any cursor,
"0"included, rather than the first page again. - A count or an aggregate missing from a response, or not a number, says so and names it, rather than
expected array, got "array":InvalidGraphqlResponseException::expectedNumber(). - The queries sent together with
GraphqlQuery::concurrently()share their entities through the identity map: the
second no longer creates another instance of an entity the first hydrated.
v5.10.2
Fixed
- The numeric options whose null turns them off accept null once written:
profiler.max_queries,
profiler.max_query_time,slow_query_threshold(at the root or for a manager, which then reports no slow query
whatever the root) and thelifetimeof a second-level cache region. They threw anInvalidTypeExceptionat boot.
v5.10.1
Fixed
GraphqlEntityRepository::countMatching(), which counts the entities a filter of the query builder matches, is no
longer internal: a test stubbing a repository no longer gets a deprecation from the debug class loader.
v5.9.0
Added
- The profiler suggests
->with()for a relation loaded one entity at a time,select(),hydrateAs()or
enableResultCache()for a slow query or a large response, and the second-level cache for an entity found or loaded
3 times or more. - A "Callers" tab of the profiler groups the queries by the line of the application sending them, the costliest
first. - A "Replay" button of the profiler sends a query of the profile again and shows its response, in debug mode, for a
query whose values are not masked (redact_query_values: false) and which is not a mutation. It needs the routes of
the bundle. - The
profileroptions set the alerts of the profiler:max_queries, the queries of a request beyond which its
toolbar turns yellow (50 by default, as Doctrine),max_query_time, the milliseconds waited for GraphQL beyond which
it does, andrepeated_queries, the times from which repeated queries, lazy loads and entities worth the
second-level cache are reported (3 by default). - An "Export JSON" button of the profiler downloads the metrics, the queries and the findings of a profile, their
values masked unlessredact_query_valuesis false.
Changed
- The timeline of the profiler shows the origin, the entity and the duration of each query, its hydration apart from
the network, a graduated axis, and the time of the request before the first query.
Fixed
- The time in GraphQL of the profiler and of its toolbar counts once the queries sent together, which the request
waited for at the same time; their sum is shown apart. - The profiler describes the entities read by the queries sent after the response (a
kernel.terminatelistener, a
streamed response), and marks these queries "after the response". - The profiler marks the queries of a sub-request (a fragment, a forward) with its path.
- A profile keeps the detail of the first 500 queries only: the others are counted in the metrics and the alerts,
without their text, variables, AST nor response, so that a page sending thousands of queries does not bloat it.
v5.8.1
Changed
graphqlorm:make:entitygenerates the mapping attributes through a namespace alias, as Doctrine:
use GraphqlOrm\Mapping as GraphqlOrm;and#[GraphqlOrm\Entity(name: 'tasks', repositoryClass: ...)]. The
documentation maps the entities the same way.- The messages of the exceptions, of the commands and of the profiler name the mapping attributes the same way:
#[GraphqlOrm\Cache],#[GraphqlOrm\Embedded]...
v5.8.0
Added
$repository->with('assignee.company')names the relationsfind(),findOneBy(),findBy()andfindAll()load,
aswith()of the query builder: it gives a copy of the repository, which is left as it is.graphqlorm:query --hydrate=Taskhydrates the response as the entity and prints the entities asgraphqlorm:find,
as a table or JSON (--format=json).- The profiler tells the relations a query loads: those named by
with(), or up tomax_depth. - The schema validation reports a property typed with a value object that no type converter converts, and checks the
fields a converter converts use one of the scalars of its#[AsTypeConverter(..., scalars: ['Int'])]. graphqlorm:make:entity --from-schematypes a custom scalar of the API with the value object of the type converter
telling it (scalars: ['Siret']).- Value objects spread over several fields, as the embeddables of Doctrine: a class marked
#[Embeddable], its fields
mapped with#[Field], held by a property mapped with#[Embedded], a GraphQL object (price { amount currency })
or fields of the entity with#[Embedded(prefix: 'total_')]. Created through its constructor, selected, filtered
and ordered by the path of its fields (total.amount), kept in the second-level cache, hydrated for the DTOs, checked
by the schema validation and the PHPStan rules, listed by the profiler.
v5.7.1
Fixed
- The
#[AfterHydrate]hooks of an entity completed after being hydrated in part threw aPartialEntityExceptionwith
PHP 8.4, whoseReflectionProperty::isInitialized()runs the initializer of a lazy object. - No deprecation with symfony/dependency-injection 8.1, which deprecates the index and priority methods of the tagged
iterators given by position.
v5.7.0
Added
with()on the query builder names the relations a query loads, nested ones by their path
(with('assignee.company', 'label')), in place ofmax_depth: the relations not named only get their identifier
selected. A relation mapped withFetch::Lazyis loaded when named, and the relations named are added to the fields
ofselect().graphqlorm:querysends a raw GraphQL query to the API of a manager (--manager), with its variables
(--variables='{"id": 1}') or from the standard input, and prints the JSON response. A response holding errors fails
the command; the query is logged and profiled, its values masked there as any other.hydrateAs()on the query builder hydrates the result as read-only DTOs, created through their constructor, rather
than entities: the query selects their fields only. A parameter maps the field of its name, or another one with
#[MapFrom('assignee.name')]; one typed with a class maps a relation to a nested DTO, an array typedlist<Dto>a
collection. Neither identity map nor second-level cache; pagination,indexBy()and the result cache work as with
entities. The profiler tells the queries hydrated as DTOs, with the DTO and the number created.- Type converters turn a scalar of the API into a value object (
Money,Email,Siret) and back: a service
implementingTypeConverterInterface, autoconfigured, converts the properties typed with the class of its
#[AsTypeConverter], or those whose#[Field(converter: ...)]names it. The values of the entities and of the DTOs
are converted, and the value objects of the filters, criteria andindexBysent back. The "Entities" tab of the
profiler tells the converter of each field. graphqlorm:cache:warmup [entity]loads the entities marked#[Cache]into the second-level cache, page by page
(--batch-size, 100 by default), those of an entity or every one, of a manager (--manager) or all, and tells how
many were hydrated and kept.GraphqlCache::evictQueryResults()evicts every result of a manager, with any pool, even shared: the results get a new
key, as the entities withevictEntityRegion(). The results kept before stay valid until a first eviction.graphqlorm:cache:clearevicts the result cache and the second-level cache: both by default, or--results,
--key=...,--entities,--class=..., of a manager (--manager) or all.graphqlorm:cache:statsdescribes the caches of each manager: the pool, adapter and lifetime of the result cache and
of each region, the entities marked#[Cache], and how many times they were evicted.