Skip to content

Commit

Permalink
Merge pull request #512 from liepaja/feat/making-create-directive-tra…
Browse files Browse the repository at this point in the history
…nsactional

[Feat] Make mutating directives transactional (@create and @update)
  • Loading branch information
chrissm79 authored Dec 19, 2018
2 parents 1f8725d + e3071e5 commit d6e5d8e
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 35 deletions.
14 changes: 13 additions & 1 deletion config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,20 @@
| GraphQL query batching means sending multiple queries to the server in one request,
| You may set this flag to process/deny batched queries.
|
*/
*/
'batched_queries' => true,

/*
|--------------------------------------------------------------------------
| Transactional Mutations
|--------------------------------------------------------------------------
|
| Sets default setting for transactional mutations.
| You may set this flag to have @create|@update mutations transactional or not.
|
*/
'transactional_mutations' => true,

/*
|--------------------------------------------------------------------------
| GraphQL Subscriptions
Expand Down Expand Up @@ -228,4 +239,5 @@
],
],
],

];
13 changes: 12 additions & 1 deletion docs/master/getting-started/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,18 @@ return [
| GraphQL query batching means sending multiple queries to the server in one request,
| You may set this flag to process/deny batched queries.
|
*/
*/
'batched_queries' => true,

/*
|--------------------------------------------------------------------------
| Transactional Mutations
|--------------------------------------------------------------------------
|
| Sets default setting for transactional mutations.
| You may set this flag to have @create|@update mutations transactional or not.
|
*/
'transactional_mutations' => true,
];
```
4 changes: 4 additions & 0 deletions docs/master/guides/relationships.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ class Post extends Model
Lighthouse allows you to create, update or delete your relationships in
a single mutation.

By default all mutations are wrapped in a database transaction, so if any of the nested
operations fail, the whole mutation is aborted and no changes are written to the database.
You can change this setting [in the configuration](../getting-started/configuration.md).

### Belongs To

You can allow the user to attach a `BelongsTo` relationship by defining
Expand Down
32 changes: 14 additions & 18 deletions src/Execution/MutationExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
class MutationExecutor
{
/**
* @param Model $model An empty instance of the model that should be created.
* @param Collection $args The corresponding slice of the input arguments for creating this model.
* @param HasMany|null $parentRelation If we are in a nested create, we can use this to associate the new model to its parent.
* @param Model $model an empty instance of the model that should be created
* @param Collection $args the corresponding slice of the input arguments for creating this model
* @param HasMany|null $parentRelation if we are in a nested create, we can use this to associate the new model to its parent
*
* @return Model
*/
Expand All @@ -28,23 +28,19 @@ public static function executeCreate(Model $model, Collection $args, HasMany $pa
$relation = $model->{$relationName}();

collect($nestedOperations)->each(function ($values, string $operationKey) use ($relation) {
if ($operationKey === 'create') {
if ('create' === $operationKey) {
self::handleHasManyCreate(collect($values), $relation);
}
});
});

// Make sure that values that are set through the database insert
// are immediately available for return, e.g. default values
$model->refresh();

return $model;
}

/**
* @param Model $model
* @param Model $model
* @param Collection $remaining
* @param HasMany $parentRelation
* @param HasMany $parentRelation
*
* @return Model
*/
Expand Down Expand Up @@ -86,9 +82,9 @@ protected static function handleHasManyCreate(Collection $multiValues, HasMany $
}

/**
* @param Model $model An empty instance of the model that should be updated.
* @param Collection $args The corresponding slice of the input arguments for updating this model.
* @param HasMany|null $parentRelation If we are in a nested update, we can use this to associate the new model to its parent.
* @param Model $model an empty instance of the model that should be updated
* @param Collection $args the corresponding slice of the input arguments for updating this model
* @param HasMany|null $parentRelation if we are in a nested update, we can use this to associate the new model to its parent
*
* @throws ModelNotFoundException
*
Expand All @@ -112,11 +108,11 @@ public static function executeUpdate(Model $model, Collection $args, HasMany $pa
$relation = $model->{$relationName}();

collect($nestedOperations)->each(function ($values, string $operationKey) use ($relation) {
if ($operationKey === 'create') {
if ('create' === $operationKey) {
self::handleHasManyCreate(collect($values), $relation);
}

if ($operationKey === 'update') {
if ('update' === $operationKey) {
collect($values)->each(function ($singleValues) use ($relation) {
self::executeUpdate(
$relation->getModel()->newInstance(),
Expand All @@ -126,7 +122,7 @@ public static function executeUpdate(Model $model, Collection $args, HasMany $pa
});
}

if ($operationKey === 'delete') {
if ('delete' === $operationKey) {
$relation->getModel()::destroy($values);
}
});
Expand All @@ -149,7 +145,7 @@ public static function executeUpdate(Model $model, Collection $args, HasMany $pa
* ['name' => 'Ralf']
* ]
*
* @param Model $model
* @param Model $model
* @param Collection $args
*
* @return Collection
Expand Down Expand Up @@ -185,7 +181,7 @@ protected static function extractBelongsToArgs(Model $model, Collection $args):
* ]
* ]
*
* @param Model $model
* @param Model $model
* @param Collection $args
*
* @return Collection
Expand Down
21 changes: 20 additions & 1 deletion src/Schema/Directives/Fields/CreateDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,26 @@
namespace Nuwave\Lighthouse\Schema\Directives\Fields;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\DatabaseManager;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Execution\MutationExecutor;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;

class CreateDirective extends BaseDirective implements FieldResolver
{
/**
* The policy mappings for the application.
*
* @var DatabaseManager
*/
private $db;

public function __construct(DatabaseManager $database)
{
$this->db = $database;
}

/**
* Name of the directive.
*
Expand Down Expand Up @@ -40,7 +53,13 @@ function ($root, array $args) {
? reset($args)
: $args;

return MutationExecutor::executeCreate($model, collect($args));
if (! config('lighthouse.transactional_mutations', true)) {
return MutationExecutor::executeCreate($model, collect($args))->refresh();
}

return $this->db->connection()->transaction(function () use ($model, $args) {
return MutationExecutor::executeCreate($model, collect($args))->refresh();
});
}
);
}
Expand Down
25 changes: 22 additions & 3 deletions src/Schema/Directives/Fields/UpdateDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Nuwave\Lighthouse\Schema\Directives\Fields;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\DatabaseManager;
use Nuwave\Lighthouse\Execution\Utils\GlobalId;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Execution\MutationExecutor;
Expand All @@ -11,6 +12,18 @@

class UpdateDirective extends BaseDirective implements FieldResolver
{
/**
* The policy mappings for the application.
*
* @var DatabaseManager
*/
private $db;

public function __construct(DatabaseManager $database)
{
$this->db = $database;
}

/**
* Name of the directive.
*
Expand All @@ -34,18 +47,24 @@ public function resolveField(FieldValue $fieldValue): FieldValue
function ($root, array $args) {
$modelClassName = $this->getModelClass();
/** @var Model $model */
$model = new $modelClassName;
$model = new $modelClassName();

$flatten = $this->directiveArgValue('flatten', false);
$args = $flatten
? reset($args)
: $args;

if($this->directiveArgValue('globalId', false)){
if ($this->directiveArgValue('globalId', false)) {
$args['id'] = GlobalId::decodeId($args['id']);
}

return MutationExecutor::executeUpdate($model, collect($args));
if (! config('lighthouse.transactional_mutations', true)) {
return MutationExecutor::executeUpdate($model, collect($args))->refresh();
}

return $this->db->connection()->transaction(function () use ($model, $args) {
return MutationExecutor::executeUpdate($model, collect($args))->refresh();
});
}
);
}
Expand Down
Loading

0 comments on commit d6e5d8e

Please sign in to comment.