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

Input object argument format for mutation API #531

Merged
merged 19 commits into from
Nov 6, 2020
Merged

Input object argument format for mutation API #531

merged 19 commits into from
Nov 6, 2020

Conversation

michaeldgraham
Copy link
Collaborator

@michaeldgraham michaeldgraham commented Oct 31, 2020

Experimental Mutation API

This PR adds initial support for generating input object arguments for node and relationship mutations. A documentation update preview is available at: https://deploy-preview-59--distracted-golick-08ed24.netlify.app/docs/graphql-schema-generation-augmentation#experimental-api.

To prevent breaking changes moving forward, the new API is available under this configuration flag:

config: {
  experimental: true
}

Example schema

In the below schema, we have a User type and a Movie type. Each has an @id field along with at least one other @unique or @index field:

  type User {
    idField: ID! @id
    name: String
    birthday: DateTime
    uniqueString: String! @unique
    indexedInt: Int @index
    rated: [Rating]
  }

  extend type User {
    extensionString: String!
  }

  type Rating @relation(from: "user", to: "movie") {
    user: User
    rating: Int!
    movie: Movie
  }
    
  type Movie {
    id: ID! @id
    title: String! @unique
    genre: MovieGenre @index
    ratedBy: [Rating]
  }

  enum MovieGenre {
    Action
    Mystery
    Scary
  }

Node mutations

In the new mutation API design, the following node mutations are generated for the User type:

type Mutation {
  CreateUser(data: _UserData!): User
  UpdateUser(where: _UserWhere!, data: _UserData!): User
  DeleteUser(where: _UserWhere!): User
  MergeUser(where: _UserKeys!, data: _UserData!): User
}

The _UserWhere input object is generated for node selection, containing the same arguments geneated for filter in the query API, for all @id, @unique, and @index fields on the User type:

  input _UserWhere {
    AND: [_UserWhere!]
    OR: [_UserWhere!]
    idField: ID
    idField_not: ID
    idField_in: [ID!]
    idField_not_in: [ID!]
    idField_contains: ID
    idField_not_contains: ID
    idField_starts_with: ID
    idField_not_starts_with: ID
    idField_ends_with: ID
    idField_not_ends_with: ID
    uniqueString: String
    uniqueString_not: String
    uniqueString_in: [String!]
    uniqueString_not_in: [String!]
    uniqueString_contains: String
    uniqueString_not_contains: String
    uniqueString_starts_with: String
    uniqueString_not_starts_with: String
    uniqueString_ends_with: String
    uniqueString_not_ends_with: String
    indexedInt: Int
    indexedInt_not: Int
    indexedInt_in: [Int!]
    indexedInt_not_in: [Int!]
    indexedInt_lt: Int
    indexedInt_lte: Int
    indexedInt_gt: Int
    indexedInt_gte: Int
  }

The _UserData input object is generated for providing property values when creating, updating, or merging a User type node:

  input _UserData {
    idField: ID
    name: String
    birthday: _Neo4jDateTimeInput
    uniqueString: String
    indexedInt: Int
    extensionString: String
  }

Relationship mutations

These Where input objects with complex filtering arguments are also used by relationship mutations to select source and target nodes. The following relationship field mutations are generated for the User type:

  type Mutation {
    AddUserRated(
      user: _UserWhere!
      movie: _MovieWhere!
      data: _RatingInput!
    ): _AddUserRatedPayload
    RemoveUserRated(
      user: _UserWhere!
      movie: _MovieWhere!
    ): _RemoveUserRatedPayload
    UpdateUserRated(
      user: _UserWhere!
      movie: _MovieWhere!
      data: _RatingInput!
    ): _UpdateUserRatedPayload
    MergeUserRated(
      user: _UserWhere!
      movie: _MovieWhere!
      data: _RatingInput!
    ): _MergeUserRatedPayload
  }

Using multiple keys

In alignment with the "Input object arguments" sub-section of the "Future design considerations" section in PR #499, initial behavior is to use all @id, @unique, and @index fields on a node type when generating its corresponding where argument input object. When using assertSchema to set property indexes and uniqueness constraints, this should provide a way to ensure that available complex node selection arguments are performant.

Merge node mutations

Because the Cypher MERGE clause cannot be combined with WHERE, complex filtering arguments (_not, _in, etc.) are not generated for the where input objects used by merge node mutations. But multiple keys can still be used. So, merge mutation where input objects contain arguments for any @id, @unique, and @index fields, with no additional custom filters added.

For the below MergeUser mutation:

type Mutation {
  MergeUser(where: _UserKeys!, data: _UserData!): User
}

The _UserKeys input objects is generated specifically for it:

  input _UserKeys {
    idField: ID
    uniqueString: String
    indexedInt: Int
  }

Tests

Tests for experimental API have been added to test/unit/experimental:

Augmentation

Translation

This should resolve #516.

This PR also fixes #495 and fixes #524.

@michaeldgraham michaeldgraham added the Needs docs Document the features added in this PR better label Oct 31, 2020
@michaeldgraham michaeldgraham removed the Needs docs Document the features added in this PR better label Nov 1, 2020
@codecov-io
Copy link

Codecov Report

❗ No coverage uploaded for pull request base (master@ea2f5c5). Click here to learn what that means.
The diff coverage is n/a.

#524: unified the translation of nested orderBy arguments for relationship fields into translateNestedOrderingArgument, fixed schemaType argument to be innerSchemaType, for call in relationFieldOnNodeType

#495: uses parentIsListArgument to buildNeo4jTypeTranslation, to appropriately translate temporal filters used within OR / AND list filters
this results in letting the cypher error pass through, caused by datetime(""), if an empty string is provided for a .formatted argument
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
3 participants