Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for nested relationship CRUD #75

Open
chillu opened this issue Feb 13, 2017 · 6 comments
Open

Support for nested relationship CRUD #75

chillu opened this issue Feb 13, 2017 · 6 comments

Comments

@chillu
Copy link
Member

chillu commented Feb 13, 2017

Allow editing of has_one, has_many and many_many relationships (create, update, delete). Either through inlining into the mutation for the "parent" object, or through separate mutations (e.g. updatePageAddComment, 'updatePageDeleteComment`).

Some drafts from @unclecheese (for a has_one)

types:
  BlogPost:
    fields: [Title, Content, Author] # AuthorID is now implicitly exposed
createPost($Input) { ... }

{
  "Input": {
    "Title": "Some post title",
    "AuthorID": 5 <-- Use an existing author
  }
}
createPost($Input) { ... }

{
  "Input": {
    "Title": "Some post title",
    "Author": { "FirstName": "Uncle", "Surname": "Cheese" } <--- Creates a new author
  }
}
createPost($Input) { ... }

{
  "Input": {
    "Title": "Some post title",
    "Author": { "ID": 5, "FirstName": "Aunty", "Surname": "Crackers" } <--- Throws. ID is never mutable
  }
}
createPost($Input) { ... }

{
  "Input": {
    "Title": "Some post title",
    "AuthorID": 5,
    "Author": { "FirstName": "Aunty", "Surname": "Crackers" } <--- Creates post, updates Author.
  }
}

See prior discussion at #67

@PapaBearNZ
Copy link
Contributor

This looks to be a very workable example to me. Perhaps with the minor modification that the RelationID becomes a Map to allow for multiple affected relations eg:

## Single Author
createPost($Input) { ... }

{
  "Input": {
    "Title": "Some post title",
    "Author": { "ID": 5 } <-- Use an existing author
  }
}

## Multiple Authors
createPost($Input) { ... }

{
  "Input": {
    "Title": "Some post title",
    "Author": [
      { "ID": 5 }
      { "ID": 14 } <-- Use existing authors
    ]
  }
}

With this variant it will be easier to scaffold has_many and many_many relations (although it might make for a complex resolver, especially for complex classes. The resolvers may need to be split out and created in subclasses or something - I'm just brainstorming here)

I don't think we would want to go more than one level deep or the scaffolding will become more complex that useful. Any deeper nested relations than one level I think could be more easily handled by a shallow nested mutation on the child records.

However it is done, for real world situations we need mutations to be able to handle relationship connections, preferably scaffolded, in order to make the most use out of the interface.

I think that 1-1 and 1-many relationships should be relatively easy to implement (grin) but many-many might be a lot more complex.

I would be happy with an interim solution providing me with the ability to attach or remove a relationship in the first phase, whilst the ability to Create or amend the parent or child record coming in a later phase (if at all). It's no real issue to use a second mutation to CRUD a parent or child record, but the ability to attach or remove said relation is mandatory I think. Especially in the situation where one is using SS as a detached COPE repository.

@chillu
Copy link
Member Author

chillu commented Feb 16, 2017

Note that we need to use database transactions when writing more than one record here.

@michalkleiner
Copy link
Contributor

Perhaps a relevant article with a different backend service, but the idea there looks nice to me and Apollo could be used with React apps.

https://hackernoon.com/graphql-nested-mutations-with-apollo-small-fatigue-max-gain-1020f627ea2e

@altwohill
Copy link

in order to handle many-many I'm currently using setByIDList

I'd love to be able to properly set the type for Relations but haven't been able to figure out how to do that. I expected to be able to specify GraphQL\Type\Definition\Type::listOf('Int').

        $scaffolder->mutation('setRelations', MyObject::class)
            ->addArgs([
                'ID' => 'Int!',
                'Relations' => 'String!' //TODO: this is json_encoded as needs to be list. yuck!
            ])
            ->setResolver(function($obj, $args, $context) {
                $myObject = MyObject::get()->byID($args['ID']);
                if ($myObject->canEdit($context['currentUser'])) {
                    $myObject->Relations()->setByIDList(json_decode($args['Relations'])); //TODO: get rid of json_decode
                    $myObject->write();
                    return $myObject;
                }
            });

        return $scaffolder;

    }```

@guywatson
Copy link

fyi I've had a go at inlining the mutations on the "parent" object. I'm still pretty new to graphql so I'm not sure if it's the best way to do it or not. But anyway it seems to be working pretty well for me and hopefully it might help some other people :)

https://github.com/Internetrix/silverstripe-graphql-nested-mutations

@ec8or
Copy link
Contributor

ec8or commented Apr 4, 2019

Just adding to the critical mass.

unclecheese pushed a commit to unclecheese/silverstripe-graphql that referenced this issue Jan 27, 2021
…here-be-protocols

Fix open up external link to protocols outside http(s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants