UNPKG

graphql-genie

Version:
609 lines (528 loc) 13.4 kB
- [Mutations](#mutations) - [Create](#create) - [Example](#example) - [Update](#update) - [Examples](#examples) - [Update the city name and push onto neighborhoods](#update-the-city-name-and-push-onto-neighborhoods) - [Update the user nested with city with passing conditions](#update-the-user-nested-with-city-with-passing-conditions) - [Update the city with failing conditions](#update-the-city-with-failing-conditions) - [Upsert](#upsert) - [Examples](#examples-1) - [Upsert a user resulting in a create](#upsert-a-user-resulting-in-a-create) - [Upsert a user resulting in an update](#upsert-a-user-resulting-in-an-update) - [Delete](#delete) - [Examples](#examples-2) - [Delete a user](#delete-a-user) - [UpdateMany and DeleteMany](#updatemany-and-deletemany) - [Examples](#examples-3) - [UpdateManyUsers](#updatemanyusers) - [Delete Every User](#delete-every-user) - [Import Data](#import-data) # Mutations If you would rather learn by playing with a demo checkout the [client demo](https://genie-team.github.io/graphql-genie-client/). GraphQL Genie follows [Relay GraphQL Server Specifications](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#mutations). > Uses a common pattern for mutations, where they are root fields on the mutation type with a single argument, input, and where the input and output both contain a client mutation identifier used to reconcile requests and responses. For each type in your model genie can generate [create](#create), [update](#update), [delete](#delete) and [upsert](#upsert) mutations. For the below schema definition these mutations will be created: * createCity * createUser * updateCity * updateManyCities * updateUser * updateManyUsers * upsertCity * upsertUser * deleteCity * deleteManyCities * deleteUser * deleteManyUsers Also Genie allows nested mutations, so when creating a city you can create a related user, or connect your relation to an existing user. When updating a city you can create, connect, disconnect, delete, update or upsert a related user. ```typescript const typeDefs = ` type City { id: ID! @unique name: String! neighborhoods: [String] user: [User] founded: Date population: Int } type User { id: ID! @unique displayname: String @unique email: String! @unique address: City } ` const genie = new GraphQLGenie({ typeDefs, generatorOptions: { generateCreate: true, generateUpdate: true, generateDelete: true, generateUpsert: true } }); ``` ## Create We will take a look at the createCity mutation ```graphql createCity(input: CreateCityMutationInput!): CityPayload input CreateCityMutationInput { data: CityCreateInput! # clientMutationID is optional, but if provided the same clientMutationId will be returned clientMutationId: String } input CityCreateInput { name: String! neighborhoods: [String] # nested create, create or connect User objects. # Relation will be built automatically to the newly created City user: UserCreateManyWithoutAddressInput founded: Date population: Int } input UserCreateManyWithoutAddressInput { # create one or more new User objects create: [UserCreateWithoutAddressInput!] # setup a relation to one or more existing User options, you can connect based on any unique field connect: [UserWhereUniqueInput!] } input UserWhereUniqueInput { id: ID displayname: String email: String } ``` ### Example Create a city and a related user ```graphql mutation { createCity(input:{ data: { name: "NY", neighborhoods: ["queens", "manhattan"] user: { create: { email: "steve@example.com", displayname: "steve" } } }, clientMutationId: "createNY" }) { data { id name neighborhoods user { displayname } } clientMutationId } } ``` will return ```json { "data": { "createCity": { "data": { "id": "ID1", "name": "NY", "neighborhoods": [ "queens", "manhattan" ], "user": [ { "displayname": "steve" } ] }, "clientMutationId": "createNY" } } } ``` ## Update Updates also have a single argument, input. input has data and clientMutationId arguments like create. They also have a where field. The where field type is the where unique input, same that we saw in the create if we were connecting a User (UserWhereUniqueInput). You can update based on id or any other field that has the @unique directive. Updates also have a conditions field, if the condition isn't met the update won't happen. This could of course always be done with multiple server calls and some client side logic but this can help minimize round trips. The payload will have the `unalteredData` field with the current store data (normal updates that succeed fill the `data` field). ```graphql updateCity(input: UpdateCityMutationInput!): CityPayload input UpdateCityMutationInput { data: CityUpdateInput! # In the case of city this will just be id, but any field with @unique would be allowed where: CityWhereUniqueInput! clientMutationId: String # Update will only be performed if these conditions are met conditions: CityWhereInput } # The update input is similar to the unique input. # Note that updating a scalar field is an input object which has fields for push, pull and set ``` A major difference between the UpdateInput and the CreateInput is on related types. While creating a City you can only create/connect a user. But while updating a City you can create, connect, disconnect, delete, update and upsert. ```graphql type CityUpdateInput { name: String # neighborhoods is a list field, so we have the option of push, pull or set when updating neighborhoods: StringScalarListInput user: UserUpdateManyWithoutAddressInput founded: Date population: Int } type UserUpdateManyWithoutAddressInput { # create a new user that is related to this city create: [UserCreateWithoutAddressInput!] # relate an existing user to this city connect: [UserWhereUniqueInput!] # un-relate a user matching the where unique input disconnect: [UserWhereUniqueInput!] # delete a user matching the where unique input delete: [UserWhereUniqueInput!] # update a user matching the where unique input with the supplied data update: [UserUpdateWithWhereUniqueWithoutAddressInput!] # upsert a user matching the where unique input with the supplied data upsert: [UserUpsertWithWhereUniqueWithoutAddressInput!] } ``` ### Examples #### Update the city name and push onto neighborhoods Say we wanted to update the created city above, we could use the update resolver. ```graphql mutation { updateCity(input:{ where: {id: "ID1"} data: { name: "New York", # neighborhoods is a list field, so we have the option of push, pull or set when updating neighborhoods: { push: ["east side"] } }, clientMutationId: "updateNY" }) { data { id name neighborhoods user { displayname } } clientMutationId } } ``` will return ```json { "data": { "updateCity": { "data": { "id": "ID1", "name": "New York", "neighborhoods": [ "queens", "manhattan", "east side" ], "user": [ { "displayname": "steve" } ] }, "clientMutationId": "updateNY" } } } ``` #### Update the user nested with city with passing conditions ```graphql mutation { updateCity(input:{ where: {id: "ID1"} data: { name: "New York", user: { update: { where: { displayname: "steve" } data: { email: "steven@example.com" } } } }, conditions: { match: { neighborhoods: "east side" } } }) { data { name user { displayname email } } unalteredData { neighborhoods } } } ``` will return ```json { "data": { "updateCity": { "data": { "name": "New York", "user": [ { "displayname": "steve", "email": "steven@example.com" } ] }, "unalteredData": null } } } ``` #### Update the city with failing conditions ```graphql mutation { updateCity(input:{ where: {id: "ID1"} data: { name: "NYC", }, conditions: { match: { neighborhoods: "bronx" } } }) { data { name } unalteredData { name neighborhoods } } } ``` will return (note data is null instead of unalteredData and the name is not changed) ```json { "data": { "updateCity": { "data": null, "unalteredData": { "name": New York "neighborhoods": [ "queens", "manhattan", "east side" ], } } } } ``` ## Upsert Upserts also have a single argument, input. input has where and clientMutationId arguments like update. But instead of a data field it has a create and an update field. If the where argument finds something the update data will be used and the record will be updated, otherwise a new record will be created with the create data Upsert also have a conditions field, in case of an update the condition isn't met the update won't happen. On create conditions are ignored. ```graphql type UpsertUserMutationInput { create: UserCreateInput! update: UserUpdateInput! where: UserWhereUniqueInput! clientMutationId: String conditions: UserWhereInput } ``` ### Examples #### Upsert a user resulting in a create ```graphql mutation { upsertUser(input:{ where: {email: "zeus@example.com"}, create: { email: "zeus@example.com" }, update: { displayname: "zeus" } }) { data { displayname email } } } ``` will return ```json { "data": { "upsertUser": { "data": { "displayname": null, "email": "zeus@example.com" } } } } ``` #### Upsert a user resulting in an update ```graphql mutation { upsertUser(input:{ where: {email: "zeus@example.com"}, create: { email: "zeus@example.com" }, update: { displayname: "zeus" } }) { data { displayname email } } } ``` will return ```json { "data": { "upsertUser": { "data": { "displayname": "zeus", "email": "zeus@example.com" } } } } ``` ## Delete Deletes also have a single argument, input. input has where and clientMutationId arguments. The data returned will be of the record that used to exist Deletes also have a conditions argument, if the conditions don't pass the delete won't be performed. ### Examples #### Delete a user ```graphql mutation { deleteUser(input:{ where: {email: "zeus@example.com"}, clientMutationId: "deleteUser" }) { data { displayname email } clientMutationId } } ``` will return ```json { "data": { "deleteUser": { "data": { "displayname": "zeus", "email": "zeus@example.com" }, "clientMutationId": "deleteUser" } } } ``` ## UpdateMany and DeleteMany UpdateMany and DeleteMany have a single argument input. input has the same arguments (where, clientMutationId and data if an update). The difference is the where argument contains all the arguments used in [queries](https://github.com/genie-team/graphql-genie/blob/master/docs/queries.md), not just the unique fields. Many mutations return a BatchPayload which has the number of fields updated ```graphql input UpdateManyCitiesMutationInput { data: CityUpdateInput! where: CityWhereInput! clientMutationId: String }: BatchPayload # see type queries documentation for more info on these arguments input CityWhereInput { user: UserWhereInput exists: CityExistsInput match: CityMatchInput range: CityRangeInput and: [CityWhereInput!] or: [CityWhereInput!] not: CityWhereInput } type BatchPayload { # The number of nodes that have been affected by the Batch operation. count: Int! clientMutationId: String } ``` ### Examples #### UpdateManyUsers ```graphql mutation { updateManyCities(input: { where: { exists: { name: true } }, data: { name: "Everywhere is Earth" } }) { count } } ``` will return ```json { "data": { "updateManyCities": { "count": 2 } } } ``` #### Delete Every User ```graphql mutation { deleteManyUsers ( input: { where: { exists: { id: true } } } ) { count } } ``` will return ```json { "data": { "deleteManyUsers": { "count": 200 } } } ``` ## Import Data If `generateMigrations` is true in the generatorOptions (defaults to true) a mutation will be created called `importData`. This is used to import/merge data into the database. See the [importRawData function](https://github.com/genie-team/graphql-genie/blob/master/docs/GraphQLGenieAPI.md#importrawdata) function of GraphQL Genie for more details as this mutation calls that function