Skip to content

Commit

Permalink
feat(graphql)!: Input type auto-generation improvements (#127)
Browse files Browse the repository at this point in the history
Closes: #114
  • Loading branch information
LastDragon-ru authored Jan 29, 2024
2 parents df28261 + 88bd6da commit accd8bf
Show file tree
Hide file tree
Showing 98 changed files with 6,133 additions and 4,436 deletions.
22 changes: 21 additions & 1 deletion packages/graphql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,27 @@ Represents [JSON](https://json.org) string.
# Scout
[Scout](https://laravel.com/docs/scout) is also supported 🤩. You just need to add [`@search`](https://lighthouse-php.com/master/api-reference/directives.html#search) directive to an argument.
[Scout](https://laravel.com/docs/scout) is also supported 🤩. You just need to add [`@search`](https://lighthouse-php.com/master/api-reference/directives.html#search) directive to an argument. Please note that available operators depend on [Scout itself](https://laravel.com/docs/scout#where-clauses).
# Input type auto-generation
The type used with the Builder directives like `@searchBy`/`@sortBy` may be Explicit (when you specify the `input` name `field(where: InputTypeName @searchBy): [Object!]!`) or Implicit (when the `_` used, `field(where: _ @searchBy): [Object!]!`). They are processing a bit differently.
For Explicit type, all fields except unions and marked as ignored (if supported by the directive) will be included.
For Implicit type, the following rules are applied (in this order; concrete directive may have differences, please check its docs):
* Union? - exclude
* Has `Operator` of the concrete directive? - include
* Has `Nuwave\Lighthouse\Support\Contracts\FieldResolver`?
* Yes
* Is `Nuwave\Lighthouse\Schema\Directives\RelationDirective`? - Include if is the `type` or list of `type`
* Is `Nuwave\Lighthouse\Schema\Directives\RenameDirective`? - Include if is `scalar`/`enum` (not `type`) and no arguments
* Otherwise - exclude
* No
* Is `type` or has arguments - exclude
* Otherwise - include
* Ignored (if supported)? - exclude
# Builder property name
Expand Down
26 changes: 20 additions & 6 deletions packages/graphql/UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases)

[//]: # (end: c70a9a43c0a80bd2e7fa6010a9b2c0fbcab4cb4d536d7a498216d9df7431f7e2)

## Tips

> [!TIP]
>
> Maybe a good idea to add test (at least) with `LastDragon_ru\LaraASP\GraphQL\Testing\GraphQLAssertions::assertGraphQLSchemaEquals()` assertion before the upgrade 🤗
# Upgrade from v5

## General
Expand All @@ -39,6 +45,8 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases)

[//]: # (end: fd146cf51ef5a8d9d13e0317c09860f472c63cb3d60d02f4d95deb3e12cae73d)

* [ ] [Input type auto-generation](README.md#input-type-auto-generation) reworked and may include more/fewer fields. Please check the documentation and update the schema if needed.

## `@searchBy`

* [ ] `enum SearchByTypeFlag { yes }` => `enum SearchByTypeFlag { Yes }`. 🤝
Expand Down Expand Up @@ -80,16 +88,22 @@ This section is actual only if you are extending the package. Please review and

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider`

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator` (removed `BuilderInfo`)
* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator`

* [ ] Removed `BuilderInfo`. To get `BuilderInfo` instance within Operator the `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context` should be used instead

```php
$context->get(LastDragon_ru\LaraASP\GraphQL\Builder\Context\HandlerContextBuilderInfo::class)?->value
```

* [ ] Removed `getPlaceholderTypeDefinitionNode()` => `LastDragon_ru\LaraASP\GraphQL\Utils\AstManipulator::getOriginType()`

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Directives\HandlerDirective`

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Directives\PropertyDirective`

* [ ] `LastDragon_ru\LaraASP\GraphQL\SortBy\Builders\*` => `LastDragon_ru\LaraASP\GraphQL\SortBy\Sorters\*`
* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Sources\*`

* [ ] To get `BuilderInfo` instance within Operator the `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context` should be used instead of `LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator`:
* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Types\InputObject`

```php
$context->get(\LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo::class)?->builderInfo
```
* [ ] `LastDragon_ru\LaraASP\GraphQL\SortBy\Builders\*` => `LastDragon_ru\LaraASP\GraphQL\SortBy\Sorters\*`
38 changes: 30 additions & 8 deletions packages/graphql/docs/Directives/@searchBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ Out the box directives provides following features:

Let's start:

[include:example]: ../../src/SearchBy/Directives/DirectiveTest/Example.schema.graphql
[//]: # (start: e552ccbddb2cf6a9dd4e14f9295ad974ca19c375ba683681d959d5190028ded4)
[//]: # (warning: Generated automatically. Do not edit.)

```graphql
scalar Date @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date")

Expand All @@ -58,12 +62,14 @@ type User {

input Comment {
text: String!
user: User
user: User @belongsTo
date: Date
}
```

That's all, just search 😃 (or look at [generated GraphQL schema](../../src/SearchBy/Directives/DirectiveTest~example-expected.graphql))
[//]: # (end: e552ccbddb2cf6a9dd4e14f9295ad974ca19c375ba683681d959d5190028ded4)

That's all, just search 😃 (or look at [generated GraphQL schema](../../src/SearchBy/Directives/DirectiveTest/Example.expected.graphql))

```graphql
query {
Expand Down Expand Up @@ -139,13 +145,29 @@ query {

## Input type auto-generation

As you can see in the example above you can use the special placeholder `_` instead of real `input`. In this case, `@searchBy` will generate `input` automatically by the actual `type` of the query. While converting `type` into `input` following fields will be excluded:
As you can see in the example above you can use the special placeholder `_` instead of real `input`. In this case, `@searchBy` will generate `input` automatically by the actual `type` of the query. Please check the main section of [Input type auto-generation](../../README.md#input-type-auto-generation) to learn more about general conversion rules.

The `@searchByIgnored` can be used as Ignored marker.

[include:exec]: <../../../../dev/artisan dev:directive @searchByIgnored>
[//]: # (start: 20d300e04ef04c52684a5d3db6a419825ada6f67a950a418e26dee5c9b5d218c)
[//]: # (warning: Generated automatically. Do not edit.)

```graphql
"""
Marks that field/definition should be excluded from search.
"""
directive @searchByIgnored
on
| ENUM
| FIELD_DEFINITION
| INPUT_FIELD_DEFINITION
| INPUT_OBJECT
| OBJECT
| SCALAR
```

* unions
* with `@field` directive
* with `@searchByIgnored` directive
* with any directive that implements [`Ignored`](../../src/SearchBy/Contracts/Ignored.php)
* any `Type` that implements [`Ignored`](../../src/SearchBy/Contracts/Ignored.php)
[//]: # (end: 20d300e04ef04c52684a5d3db6a419825ada6f67a950a418e26dee5c9b5d218c)

## Operators

Expand Down
59 changes: 35 additions & 24 deletions packages/graphql/docs/Directives/@sortBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ on

## Basic usage

How to use (and [generated GraphQL schema](../../src/SortBy/Directives/DirectiveTest~example-expected.graphql)):
How to use (and [generated GraphQL schema](../../src/SortBy/Directives/DirectiveTest/Example.expected.graphql)):

[include:example]: ../../src/SortBy/Directives/DirectiveTest/Example.schema.graphql
[//]: # (start: f4e6a88c853cd9b15aa5c3388c1b61148589eddbc18b410b0e846695c5765e4f)
[//]: # (warning: Generated automatically. Do not edit.)

```graphql
type Query {
Expand All @@ -37,7 +41,7 @@ input UsersSort {

type Comment {
text: String
user: User
user: User @belongsTo
}

type User {
Expand All @@ -46,6 +50,8 @@ type User {
}
```

[//]: # (end: f4e6a88c853cd9b15aa5c3388c1b61148589eddbc18b410b0e846695c5765e4f)

And:

```graphql
Expand All @@ -60,14 +66,33 @@ query {

## Input type auto-generation

As you can see in the example above you can use the special placeholder `_` instead of real `input`. In this case, `@sortBy` will generate `input` automatically by the actual `type` of the query. While converting `type` into `input` following fields will be excluded:
As you can see in the example above you can use the special placeholder `_` instead of real `input`. In this case, `@sortBy` will generate `input` automatically by the actual `type` of the query. Please check the main section of [Input type auto-generation](../../README.md#input-type-auto-generation) to learn more about general conversion rules.

Addition rules for Implicit type:

* The field is a list of `scalar`/`enum`? - exclude

* unions
* with list/array type
* with `@field` directive
* with `@sortByIgnored` directive
* with any directive that implements [`Ignored`](../../src/SortBy/Contracts/Ignored.php)
* any `Type` that implements [`Ignored`](../../src/SortBy/Contracts/Ignored.php)
The `@sortByIgnored` can be used as Ignored marker.

[include:exec]: <../../../../dev/artisan dev:directive @sortByIgnored>
[//]: # (start: 08dddca7c96cf62e6e6e632190eb16fa49d5c1652e35e29b74417dc9d52c29ff)
[//]: # (warning: Generated automatically. Do not edit.)

```graphql
"""
Marks that field/definition should be excluded from sort.
"""
directive @sortByIgnored
on
| ENUM
| FIELD_DEFINITION
| INPUT_FIELD_DEFINITION
| INPUT_OBJECT
| OBJECT
| SCALAR
```

[//]: # (end: 08dddca7c96cf62e6e6e632190eb16fa49d5c1652e35e29b74417dc9d52c29ff)

## Operators

Expand All @@ -77,20 +102,6 @@ The package defines only one's own type. To extend/replace the list of its opera

## Eloquent/Database

### Supported Relations

The main feature - the ability to sort results by relation properties, at the moment supported the following relation types:

* `HasOne` (<https://laravel.com/docs/eloquent-relationships#one-to-one>)
* `HasMany` (<https://laravel.com/docs/eloquent-relationships#one-to-many>)
* `HasManyThrough` (<https://laravel.com/docs/eloquent-relationships#has-many-through>)
* `BelongsTo` (<https://laravel.com/docs/eloquent-relationships#one-to-many-inverse>)
* `BelongsToMany` (<https://laravel.com/docs/eloquent-relationships#many-to-many>)
* `MorphOne` (<https://laravel.com/docs/eloquent-relationships#one-of-many-polymorphic-relations>)
* `MorphMany` (<https://laravel.com/docs/eloquent-relationships#one-to-many-polymorphic-relations>)
* `MorphToMany` (<https://laravel.com/docs/eloquent-relationships#many-to-many-polymorphic-relations>)
* `HasOneThrough` (<https://laravel.com/docs/eloquent-relationships#has-one-through>)

### Order by random

It is also possible to sort records in random order, but it is not enabled by default. To enable it you just need to add [`Random`](../../src/SortBy/Operators/Extra/Random.php)/`@sortByOperatorRandom` operator/directive to `Extra` type:
Expand Down Expand Up @@ -146,7 +157,7 @@ query {

### NULLs ordering

`NULL`s order different in different databases. Sometimes you may to change it. There is no default/built-it support in Laravel nor Lighthouse, but you can do it! :) Please note, not all databases have native `NULLS FIRST`/`NULLS LAST` support (eg MySQL and SQL Server doesn't). The additional `ORDER BY` clause with `CASE WHEN` will be used for these databases. It may be slow for big datasets.
`NULL`s order different in different databases. Sometimes you may want to change it. There is no default/built-it support in Laravel nor Lighthouse, but you can do it! :) Please note, not all databases have native `NULLS FIRST`/`NULLS LAST` support (eg MySQL and SQL Server doesn't). The additional `ORDER BY` clause with `CASE WHEN` will be used for these databases. It may be slow for big datasets.

Default ordering can be changed via config. You may set it for all directions if single value used, in this case NULL always be first/last:

Expand Down
Loading

0 comments on commit accd8bf

Please sign in to comment.