Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 3 additions & 21 deletions src/Execution/Arguments/ArgPartitioner.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,15 @@ class ArgPartitioner
/**
* Partition the arguments into nested and regular.
*
* @return array{
* 0: \Nuwave\Lighthouse\Execution\Arguments\ArgumentSet,
* 1: \Nuwave\Lighthouse\Execution\Arguments\ArgumentSet,
* }
*/
public static function nestedArgResolvers(ArgumentSet $argumentSet, mixed $root): array
{
static::prepareArgResolvers($argumentSet, $root);

return static::partition(
$argumentSet,
static fn (string $name, Argument $argument): bool => isset($argument->resolver),
);
}

/**
* Like nestedArgResolvers(), but excludes SaveAwareArgResolvers that run before save.
*
* Used by SaveModel's ResolveNested wrapper so pre-save resolvers stay in the
* regular set and reach SaveModel for execution before $model->save().
* SaveAwareArgResolvers where runBeforeSave() returns true stay in the regular set
* so they reach SaveModel for execution before $model->save().
*
* @return array{
* 0: \Nuwave\Lighthouse\Execution\Arguments\ArgumentSet,
* 1: \Nuwave\Lighthouse\Execution\Arguments\ArgumentSet,
* }
*/
public static function nestedArgResolversWithoutPreSave(ArgumentSet $argumentSet, mixed $root): array
public static function nestedArgResolvers(ArgumentSet $argumentSet, mixed $root): array
{
$model = static::prepareArgResolvers($argumentSet, $root);

Expand Down
1 change: 0 additions & 1 deletion src/Schema/Directives/ModelMutationDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ protected function executeMutation(Model $model, ArgumentSet|array $args, ?Relat
{
$update = new ResolveNested(
$this->makeExecutionFunction($parentRelation),
[ArgPartitioner::class, 'nestedArgResolversWithoutPreSave'],
);

return Utils::mapEach(
Expand Down
273 changes: 273 additions & 0 deletions tests/Integration/Schema/Directives/CreateDirectiveTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -876,4 +876,277 @@ public function testCustomDirectiveSetsModelAttributesBeforeSaveInsideNest(): vo
],
]);
}

public function testCustomDirectiveSetsModelAttributesBeforeSaveInsideNestedHasMany(): void
{
$this->schema .= /** @lang GraphQL */ <<<'GRAPHQL'
type Task {
id: ID!
name: String!
latitude: Float
longitude: Float
}

type User {
id: ID!
name: String!
tasks: [Task!]! @hasMany
}

type Mutation {
createUser(input: CreateUserInput! @spread): User @create
}

input CreateUserInput {
name: String!
tasks: CreateTaskRelation
}

input CreateTaskRelation {
create: [CreateTaskInput!]
}

input CreateTaskInput {
name: String!
location: LocationInput @geocode
}

input LocationInput {
lat: Float!
lng: Float!
}
GRAPHQL;

$this->graphQL(/** @lang GraphQL */ <<<'GRAPHQL'
mutation {
createUser(input: {
name: "Geo Parent"
tasks: {
create: [{
name: "Geo Task"
location: {
lat: 48.1351
lng: 11.5820
}
}]
}
}) {
id
name
tasks {
id
name
latitude
longitude
}
}
}
GRAPHQL)->assertJson([
'data' => [
'createUser' => [
'name' => 'Geo Parent',
'tasks' => [
[
'name' => 'Geo Task',
'latitude' => 48.1351,
'longitude' => 11.582,
],
],
],
],
]);
}

public function testCustomDirectiveSetsModelAttributesBeforeSaveInsideNestInsideNestedHasMany(): void
{
$this->schema .= /** @lang GraphQL */ <<<'GRAPHQL'
type Task {
id: ID!
name: String!
latitude: Float
longitude: Float
}

type User {
id: ID!
name: String!
tasks: [Task!]! @hasMany
}

type Mutation {
createUser(input: CreateUserInput! @spread): User @create
}

input CreateUserInput {
name: String!
tasks: CreateTaskRelation
}

input CreateTaskRelation {
create: [CreateTaskInput!]
}

input CreateTaskInput {
name: String!
nested: TaskNestedInput @nest
}

input TaskNestedInput {
location: LocationInput @geocode
}

input LocationInput {
lat: Float!
lng: Float!
}
GRAPHQL;

$this->graphQL(/** @lang GraphQL */ <<<'GRAPHQL'
mutation {
createUser(input: {
name: "Geo Nest Parent"
tasks: {
create: [{
name: "Geo Nest Task"
nested: {
location: {
lat: 48.1351
lng: 11.5820
}
}
}]
}
}) {
id
name
tasks {
id
name
latitude
longitude
}
}
}
GRAPHQL)->assertJson([
'data' => [
'createUser' => [
'name' => 'Geo Nest Parent',
'tasks' => [
[
'name' => 'Geo Nest Task',
'latitude' => 48.1351,
'longitude' => 11.582,
],
],
],
],
]);
}

public function testCustomDirectiveSetsModelAttributesBeforeSaveInsideDeeplyNestedRelation(): void
{
$this->schema .= /** @lang GraphQL */ <<<'GRAPHQL'
type Post {
id: ID!
title: String!
latitude: Float
longitude: Float
}

type Task {
id: ID!
name: String!
post: Post @hasOne
}

type User {
id: ID!
name: String!
tasks: [Task!]! @hasMany
}

type Mutation {
createUser(input: CreateUserInput! @spread): User @create
}

input CreateUserInput {
name: String!
tasks: CreateTaskRelation
}

input CreateTaskRelation {
create: [CreateTaskInput!]
}

input CreateTaskInput {
name: String!
post: CreatePostRelation
}

input CreatePostRelation {
create: CreatePostInput
}

input CreatePostInput {
title: String!
location: LocationInput @geocode
}

input LocationInput {
lat: Float!
lng: Float!
}
GRAPHQL;

$this->graphQL(/** @lang GraphQL */ <<<'GRAPHQL'
mutation {
createUser(input: {
name: "Geo Deep Parent"
tasks: {
create: [{
name: "Geo Deep Task"
post: {
create: {
title: "Geo Deep Post"
location: {
lat: 48.1351
lng: 11.5820
}
}
}
}]
}
}) {
id
name
tasks {
id
name
post {
id
title
latitude
longitude
}
}
}
}
GRAPHQL)->assertJson([
'data' => [
'createUser' => [
'name' => 'Geo Deep Parent',
'tasks' => [
[
'name' => 'Geo Deep Task',
'post' => [
'title' => 'Geo Deep Post',
'latitude' => 48.1351,
'longitude' => 11.582,
],
],
],
],
],
]);
}
}
27 changes: 1 addition & 26 deletions tests/Unit/Execution/Arguments/ArgPartitionerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,31 +138,6 @@ public function testSaveAwareArgResolverWithNonModelRoot(): void
);
}

public function testSaveAwareArgResolverWithNonModelRootInWithoutPreSave(): void
{
$argumentSet = new ArgumentSet();

$regular = new Argument();
$argumentSet->arguments['regular'] = $regular;

$saveAware = new Argument();
$saveAware->directives->push(new SaveAwareNested());
$argumentSet->arguments['saveAware'] = $saveAware;

[$nestedArgs, $regularArgs] = ArgPartitioner::nestedArgResolversWithoutPreSave($argumentSet, null);

$this->assertSame(
['regular' => $regular],
$regularArgs->arguments,
);

$this->assertSame(
['saveAware' => $saveAware],
$nestedArgs->arguments,
'SaveAwareArgResolver should be in nested set when root is not a Model',
);
}

public function testSaveAwareArgResolverWithModelRoot(): void
{
$argumentSet = new ArgumentSet();
Expand All @@ -174,7 +149,7 @@ public function testSaveAwareArgResolverWithModelRoot(): void
$saveAware->directives->push(new SaveAwareNested());
$argumentSet->arguments['saveAware'] = $saveAware;

[$nestedArgs, $regularArgs] = ArgPartitioner::nestedArgResolversWithoutPreSave($argumentSet, new User());
[$nestedArgs, $regularArgs] = ArgPartitioner::nestedArgResolvers($argumentSet, new User());

$this->assertSame(
['regular' => $regular, 'saveAware' => $saveAware],
Expand Down
2 changes: 2 additions & 0 deletions tests/Utils/Models/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
* Attributes
* @property string $title
* @property string|null $body
* @property float|null $latitude
* @property float|null $longitude
*
* Timestamps
* @property \Illuminate\Support\Carbon $created_at
Expand Down
2 changes: 2 additions & 0 deletions tests/Utils/Models/Task.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
* @property string $name
* @property int|null $difficulty
* @property string|null $guard
* @property float|null $latitude
* @property float|null $longitude
* @property \Illuminate\Support\Carbon $completed_at
*
* Timestamps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public function up(): void
->comment('The purpose of this property is to collide with a native model method name');
$table->unsignedBigInteger('difficulty')->nullable();
$table->unsignedBigInteger('user_id')->nullable();
$table->double('latitude')->nullable();
$table->double('longitude')->nullable();
$table->timestamp('completed_at')->nullable();
$table->timestamps();
$table->softDeletes();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public function up(): void
$table->unsignedBigInteger('task_id');
$table->unsignedBigInteger('user_id')->nullable();
$table->unsignedBigInteger('parent_id')->nullable();
$table->double('latitude')->nullable();
$table->double('longitude')->nullable();
$table->timestamps();
$table->softDeletes();
});
Expand Down
Loading