Skip to content
This repository has been archived by the owner on Sep 3, 2021. It is now read-only.

Relation type API #108

Merged
merged 8 commits into from
Sep 19, 2018
Merged

Relation type API #108

merged 8 commits into from
Sep 19, 2018

Conversation

michaeldgraham
Copy link
Collaborator

@michaeldgraham michaeldgraham commented Sep 19, 2018

This contains initial support for using relation types with managed directional fields from and to, along with an optional @relation type directive (should resolve #26 and #97).

Input types are now generated in the schema augmentation process and used for from and to node selection arguments in a new relation mutation API (should resolve #102).

On a related note, relation mutations are now generated for @relation fields with the IN direction (#98).

A relation type is a type with both a from field and a to field. Any type with either but not the other will throw an error in the schema augmentation process.

Example types:

type Person {
  name: String
  rated: [Rated]
}
type Rated @relation(name: "RATED") {
  from: Person
  rating: Int
  to: Movie
}
type Movie {
  title: String
  ratings: [Rated]
}

If a type has both a from field and a to field but no @relation directive is provided, then one is generated. In that case, or if you write a @relation type directive but provide no name argument, then a default relation name is created for you, equal to a transformation of the relation type name (rated into RATED, FriendOf into FRIEND_OF, etc.).

If you choose to use such a default name, then you can omit the @relation directive:

type Rated {
  from: Person
  rating: Int
  to: Movie
}

Relation Query API

During the schema augmentation process, the from and to fields on relation
types are transformed to be equal to their type values. This is done in the hopes of making nested queries more semantic.

query {
  Person(name: "Michael") {
    name
    rated {
      rating 
      Movie {
        title
      }
    }
  }
}
query {
  Movie(title: "The Matrix") {
    title
    ratings {
      rating
      Person {
        name
      }
    }
  }
}

Relation Mutation API

While the use of relation types is optional, the relation mutation API has changed generally to include input types for from and to arguments. Add and remove relation mutations are still generated for @relation fields, but they use the from and to argument format in order to keep the relation mutation API consistent and provide a bit more structure.

Relation mutation payload types are also generated in order to make the return selection format consistent with the from and to arguments.

Relation mutations generated for the rated field of the Person type:

AddPersonRated

mutation {
  AddPersonRated(
    from: {
      name: "Michael"
    },
    to: {
      title: "The Matrix"
    },
    data: {
      rating: 5
    }
  ) {
    from {
      name
    }
    to {
      title
    }
    rating
  }
}

If there are no fields other than from and to on a relation type (see below), the add relation mutation will not have a data argument, making it identical to the add relation mutation normally generated for a @relation field.

type Rated {
  from: Person
  to: Movie
}

RemovePersonRated

mutation {
  RemovePersonRated(
    from: {
      name: "Michael"
    },
    to: {
      title: "The Matrix"
    }
  ) {
    from {
      name
    }
    to {
      title
    }
  }
}

Similar relation mutations would be generated for the ratings field of the Movie type.

@johnymontana johnymontana merged commit d2dca74 into neo4j-graphql:master Sep 19, 2018
@YizYah
Copy link

YizYah commented Sep 20, 2018

@michaeldgraham nice. A clean and semantically clear implementation. (Disclaimer: I haven't tried it yet...)

But I do have two thoughts. First, why complicate things with the@relation directive when it would be sensible to expect a from and to field anyway, which would remove the need?

Second, it's confusing to use the same name as the field directive @relation. I really hope you haven't done away with that. It makes the schema fast and much more intuitive. When my team discusses changes to the back end we literally work with the SDL. Even the front end guys understand everything 100% and we can make the changes as we speak. If you don't have any field requirements for a relationship, I think think it's better to keep it simple with a field directive. Perhaps a different name could be used to prevent confusion? It seems to me that in the rare case where we would need a type directive at all we could use a @complex-relationship directive, or something to that effect.

@michaeldgraham
Copy link
Collaborator Author

michaeldgraham commented Sep 20, 2018

Thanks! I’m still working on some tests and trying to put together some more information on this PR’s post :)


A lot of the SDL inspiration comes from @jexp's comment on this post: neo4j-graphql/neo4j-graphql#51 :)

Nothing was done away with, the @relation field directives still work normally. You can progressively add types for relationships, if you want them. The @relation type directive is still necessary in order to keep it possible for the user to provide a relationship name if they do not want to use the generated default name.

I have worried about directives maintaining consistency of metadata representation. So for now, because the metadata is the same as the existing ‘relation’ field directive (at least, the name argument remains), I kept the type directive named ‘relation’. That way, representation of Neo4j relationship metadata by directives is semantically consistent. It seems the ambiguity here is that the 'relation' directive can now be on both fields and types, but I think the structural difference built into fields vs types is enough there — I’ve gotten used to that, though. This is just the way I feel about it. Maybe in the future we could make directive names configurable.

Also, if we introduce a @model (or maybe @node / configurable) directive to be used to distinguish types representing node labels from types used for other purposes, such as custom mutation payloads, then it may turn out to be useful to use a @relation directive to distinguish relationship types from such node types.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Same label add relationship mutation only includes one ID param for auto-gen mutation Edge Properties
3 participants