Skip to content

Commit

Permalink
Implement @forceDelete and @restore directives (#941)
Browse files Browse the repository at this point in the history
Add possibility to use `forceDelete()` and `restore()` on soft deletable models with ease
  • Loading branch information
lorado authored Sep 3, 2019
1 parent eaf4556 commit b30ef88
Show file tree
Hide file tree
Showing 20 changed files with 930 additions and 169 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add `@restore` and `@forceDelete` directives, similar to `@delete` https://github.com/nuwave/lighthouse/pull/941
- Add `@softDeletes` and `@trashed` directives to enable
filtering soft deleted models https://github.com/nuwave/lighthouse/pull/937

### Fixed

- Prevent throwing in `lighthouse:ide-helper` when no custom directives are defined https://github.com/nuwave/lighthouse/pull/948

## Changed

- Validate requirements for argument definitions of `@delete`, `@forceDelete` and `@restore`
during schema build time https://github.com/nuwave/lighthouse/pull/941

## [4.2.1](https://github.com/nuwave/lighthouse/compare/v4.2.0...v4.2.1)

### Fixed
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@
"extra": {
"laravel": {
"providers": [
"Nuwave\\Lighthouse\\LighthouseServiceProvider"
"Nuwave\\Lighthouse\\LighthouseServiceProvider",
"Nuwave\\Lighthouse\\SoftDeletes\\SoftDeletesServiceProvider"
],
"aliases": {
"graphql": "Nuwave\\Lighthouse\\GraphQL"
Expand Down
92 changes: 81 additions & 11 deletions docs/master/api-reference/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -630,30 +630,34 @@ type Mutation {

## @delete

Delete one or more models by their ID.

```graphql
type Mutation {
deletePost(id: ID!): Post @delete
}
```

### Definition

```graphql
"""
Delete one or more models by their ID.
The field must have an single non-null argument that may be a list.
The field must have a single non-null argument that may be a list.
"""
directive @delete(
"""
Set to `true` to use global ids for finding the model.
If set to `false`, regular non-global ids are used.
"""
globalId: Boolean = false

"""
Specify the class name of the model to use.
This is only needed when the default model resolution does not work.
"""
model: String
) on FIELD_DEFINITION
```

Use it on a root mutation field that returns an instance of the Model.

```graphql
type Mutation {
deletePost(id: ID!): Post @delete
}
```

### Examples

If you use global ids, you can set the `globalId` argument to `true`.
Expand All @@ -669,6 +673,8 @@ You can also delete multiple models at once.
Define a field that takes a list of IDs and returns a Collection of the
deleted models.

_In contrast to Laravel mass updates, this does trigger model events._

```graphql
type Mutation {
deletePosts(id: [ID!]!): [Post!]! @delete
Expand Down Expand Up @@ -856,6 +862,38 @@ type Query {
}
```

## @forceDelete

```graphql
"""
Permanently remove one or more soft deleted models by their ID.
The field must have a single non-null argument that may be a list.
"""
directive @forceDelete(
"""
Set to `true` to use global ids for finding the model.
If set to `false`, regular non-global ids are used.
"""
globalId: Boolean = false

"""
Specify the class name of the model to use.
This is only needed when the default model resolution does not work.
"""
model: String
) on FIELD_DEFINITION
```

Use it on a root mutation field that returns an instance of the Model.

```graphql
type Mutation {
forceDeletePost(id: ID!): Post @forceDelete
}
```

Works very similar to the [`@delete`](#delete) directive.

## @enum

Assign an internal value to an enum key. When dealing with the Enum type in your code,
Expand Down Expand Up @@ -1918,6 +1956,38 @@ directive @rename(
) on FIELD_DEFINITION
```

## @restore

```graphql
"""
Un-delete one or more soft deleted models by their ID.
The field must have a single non-null argument that may be a list.
"""
directive @restore(
"""
Set to `true` to use global ids for finding the model.
If set to `false`, regular non-global ids are used.
"""
globalId: Boolean = false

"""
Specify the class name of the model to use.
This is only needed when the default model resolution does not work.
"""
model: String
) on FIELD_DEFINITION
```

Use it on a root mutation field that returns an instance of the Model.

```graphql
type Mutation {
restorePost(id: ID!): Post @restore
}
```

Works very similar to the [`@delete`](#delete) directive.

## @rules

Validate an argument using [Laravel built-in validation](https://laravel.com/docs/validation).
Expand Down
63 changes: 60 additions & 3 deletions docs/master/eloquent/soft-deleting.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Lighthouse offers convenient helpers to work with models that utilize
## Filter Soft Deleted Models

If your model uses the `Illuminate\Database\Eloquent\SoftDeletes` trait,
you can add the [`@softDeletes`](../api-reference/directives.md) directive to a field
you can add the [`@softDeletes`](../api-reference/directives.md#softdeletes) directive to a field
to be able to query `onlyTrashed`, `withTrashed` or `withoutTrashed` elements.

```graphql
Expand All @@ -15,8 +15,8 @@ type Query {
}
```

Lighthouse will add an argument `trashed` to the field definition
and automatically include the enum `Trashed`.
Lighthouse will automatically add an argument `trashed` to the field definition
and include the enum `Trashed`.

```graphql
type Query {
Expand All @@ -42,3 +42,60 @@ You can include soft deleted models in your result with a query like this:
}
}
```

## Restoring Soft Deleted Models

If your model uses the `Illuminate\Database\Eloquent\SoftDeletes` trait,
you can restore your model using the [`@restore`](../api-reference/directives.md#restore) directive.

```graphql
type Mutation {
restoreFlight(id: ID!): Flight @restore
}
```

Simply call the field with the ID of the flight you want to restore.

```graphql
mutation {
restoreFlight(id: 1) {
id
}
}
```

This mutation will return the restored object.

## Permanently Deleting Models

To truly remove model from database,
use the [@forceDelete](../api-reference/directives.md#forcedelete) directive.
Your model must use the `Illuminate\Database\Eloquent\SoftDeletes` trait.

```graphql
type Mutation {
forceDeleteFlight(id: ID!): Flight @forceDelete
}
```

Simply call it with the ID of the Flight you want to permanently remove.

```graphql
mutation {
forceDeleteFlight(id: 5){
id
}
}
```

This mutation will return the deleted object, so you will have a last chance to look at the data.

```json
{
"data": {
"forceDeleteFlight": {
"id": 5
}
}
}
```
6 changes: 3 additions & 3 deletions src/Console/IdeHelperCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Illuminate\Console\Command;
use HaydenPierce\ClassFinder\ClassFinder;
use Nuwave\Lighthouse\Schema\AST\PartialParser;
use Nuwave\Lighthouse\Schema\DirectiveNamespaces;
use Nuwave\Lighthouse\Schema\DirectiveNamespacer;
use Nuwave\Lighthouse\Support\Contracts\Directive;
use Nuwave\Lighthouse\Support\Contracts\DefinedDirective;
use HaydenPierce\ClassFinder\Exception\ClassFinderException;
Expand Down Expand Up @@ -36,10 +36,10 @@ class IdeHelperCommand extends Command
/**
* Execute the console command.
*
* @param \Nuwave\Lighthouse\Schema\DirectiveNamespaces $directiveNamespaces
* @param \Nuwave\Lighthouse\Schema\DirectiveNamespacer $directiveNamespaces
* @return int
*/
public function handle(DirectiveNamespaces $directiveNamespaces): int
public function handle(DirectiveNamespacer $directiveNamespaces): int
{
if (! class_exists('HaydenPierce\ClassFinder\ClassFinder')) {
$this->error(
Expand Down
21 changes: 0 additions & 21 deletions src/Schema/AST/ASTBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ public function build(): DocumentAST
$this->addPaginationInfoTypes();
$this->addNodeSupport();
$this->addOrderByTypes();
$this->addTrashedEnum();

// Listeners may manipulate the DocumentAST that is passed by reference
// into the ManipulateAST event. This can be useful for extensions
Expand Down Expand Up @@ -362,24 +361,4 @@ enum SortOrder {
')
);
}

/**
* Add Trashed enum to filter soft deleted models.
*
* @see \Nuwave\Lighthouse\Schema\Directives\TrashedDirective
*
* @return void
*/
protected function addTrashedEnum(): void
{
$this->documentAST->setTypeDefinition(
PartialParser::enumTypeDefinition('
enum Trashed {
ONLY @enum(value: "only")
WITH @enum(value: "with")
WITHOUT @enum(value: "without")
}
')
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Illuminate\Contracts\Events\Dispatcher;
use Nuwave\Lighthouse\Events\RegisterDirectiveNamespaces;

class DirectiveNamespaces
class DirectiveNamespacer
{
/**
* @var \Illuminate\Contracts\Events\Dispatcher
Expand Down
Loading

0 comments on commit b30ef88

Please sign in to comment.