Reindex mutations allow you to perform basic create, update, delete operations on nodes and also add and remove nodes in the many-to-many relationships.
All Reindex mutations share several common traits - they all have one argument
called input
, that holds one optional field clientMutationId
. Mutations
return a payload object, which also always contains a clientMutationId
.
If clientMutationId
is passed to input it will always be returned as-is in
the payload. This way client libraries, like Relay, can tell results of
different mutations apart.
Those basic operations share payloads and have similar input
formats. They
accept all fields that can be modified in the node. The difference is that
update
and replace
also require id
of the node being modified in the
input, while create
doesn’t allow it. delete
just accepts the id
of the
type in the input.
Payload types are generated from the types being modified by the mutation. Their structure is the same for all the mutations of that type.
type _XPayload {
clientMutationId: String
id: ID
changedX: X
changedXEdge: _XEdge
viewer: ReindexViewer
# Fields with Nodes to which Node fields of the type point
y: Y,
# for example
user: User,
}
As payloads need to support various mutation types of Relay, there are multiple
fields included in them. In addition to clientMutationId
, there is:
id
- the ID of the mutated node
changedX
- the mutated node
changedXEdge
- a connection edge containg the mutated node. Can be used to
add a newly created node to a connection in Relay.
viewer
- The global viewer object. Can be used on the client to add
a newly created node to the connection of all nodes of the type.
E.g. when creating a Todo object, you can add it
to viewer.allTodos
using the following Relay
mutation config:
{
type: 'RANGE_ADD',
parentID: this.props.viewer.id,
connectionName: 'allTodos',
edgeName: 'changedTodoEdge',
rangeBehaviors: {
'': 'prepend',
},
}
All the node reference fields in this type. These can be used to
refer to the parent node for RANGE_ADD
mutations in Relay.
See this guide for more information about Relay mutations.
mutation createX(input: _CreateXInput): _XPayload
Create a node of some type. input
is a flat object with all the fields
of the type alongside clientMutationId
. All nonNull
fields are required.
mutation {
createUser(input: {
username: "freiksenet",
email: "freiksenet@example.com"
}) {
changedUser {
id
username
email
}
}
}
mutation updateX(input: _UpdateXInput): _XPayload
Update the given node. Given fields are merged into existing object. input
is a flat object with all the fields of the type alongside clientMutationId
and id
. id
is an id of the node being updated and it is required.
mutation {
updateUser(input: {
id: "some-user-id"
username: "freiksenets-new-name",
}) {
changedUser {
id
username
}
}
}
mutation replaceX(input: _ReplaceXInput): _XPayload
Replaces the given node with a new one. input
is a flat object with all the
fields of the type alongside clientMutationId
and id
. id
is an id of
the node being replaced and it is required. All nonNull
fields are required.
mutation {
replaceUser(input: {
id: "some-user-id"
username: "freiksenets-new-name",
email: "freiksenet-new@example.com"
}) {
changedUser {
id
username
email
}
}
}
mutation deleteX(input: _DeleteXInput): _XPayload
Delete the given node. input
is an object with fields clientMutationId
and
id
. id
is an id of the node being deleted and it is required.
mutation {
deleteUser(input: {
id: "some-user-id"
}) {
# Will contain deleted object
changedUser {
id
username
email
}
}
}
Many-to-many relationships can not be updated using the create/replace
mutations. Instead, every many-to-many relationship has mutations to add or
remove items from them. The name takes the form of
add<Type1>From<Type2><ConnectionName>
, e.g. addMicropostToUserFavorites
or
removeUserFromUserFriends
. Note that relationships have mutations for both of
the connection fields, so there will be both AddMicropostToUserFavorites
and
AddUserToMicropostFavoritedBy
. They are equivalent, they always add or remove
items from both connections and are provided for convenience.
Adding item to a relationship that already has it doesn’t produce an error, as won’t removing item from a relationship that doesn’t include it.
Inputs for both operations have the following format:
type _Type1Type2ConnectionNameConnectionInput {
clientMutationId: String
type1Id: ID!
type2Id: ID!
}
# For example
type _MicropostUserFavoritesConnectionInput {
clientMutationId: String
micropostId: ID!,
userId: ID!
}
# If connecting the same type
type _UserFriendsConnectionInput {
clientMutationId: String
user1Id: ID!,
user2Id: ID!
}
Payload for both operations has the following format:
type _Type1Type2ConnectionNamePayload {
clientMutationId: String
changedType1: Type1
changedType1Edge: _Type1Edge
changedType2: Type2
changedType2Edge: _Type2Edge
}
# For example
type _MicropostUserFavoritesPayload {
clientMutationId: String
changedMicropost: Micropost
changedMicropostEdge: _MicropostEdge
changedUser: User
changedUserEdge: _UserEdge,
}
# If connecting the same type
type _UserFriendsPayload {
clientMutationId: String
changedUser1: User
changedUser1Edge: _UserEdge
changedUser2: User
changedUser2Edge: _UserEdge
}
mutation addTypeToType2ConnectionName(input: _Type1Type2ConnectionNameConnectionInput): _Type1Type2ConnectionNamePayload
For example:
mutation addMicropostToUserFavorites(input: _MicropostUserFavoritesConnectionInput): _MicropostUserFavoritesPayload
mutation addUserToUserFriends(input: _UserFriendsConnectionInput): _UserFriendsPayload
Add node defined by type1Id
to connection connectionName
of node defined
by type2Id
.
mutation {
addMicropostToUserFavorites(input: {
micropostId: "some-micropost-id",
userId: "some-user-id"
}) {
changedMicropost {
favoritedBy {
count
}
}
changedUser {
favorites {
count
}
}
}
}
mutation removeTypeFromType2ConnectionName(input: _Type1Type2ConnectionNameConnectionInput): _Type1Type2ConnectionNamePayload
For example:
mutation removeMicropostFromUserFavorites(input: _MicropostUserFavoritesConnectionInput): _MicropostUserFavoritesPayload
mutation removeUserFromUserFriends(input: _UserFriendsConnectionInput): _UserFriendsPayload
Remove node defined by type1Id
from connection connectionName
of node
defined by type2Id
.
mutation {
removeMicropostFromUserFavorites(input: {
micropostId: "some-micropost-id",
userId: "some-user-id"
}) {
changedMicropost {
favoritedBy {
count
}
}
changedUser {
favorites {
count
}
}
}
}
While most of the time, one would use reindex-cli schema-push
to perform
migration, you could also use the low-level GraphQL mutation API directly.
mutation migrate(input: ReindexMigrationInput!): ReindexMigrationPayload
input ReindexMigrationInput {
types: [ReindexTypeInput]
force: Boolean
dryRun: Boolean
clientMutationId: String
}
type ReindexMigrationPayload {
clientMutationId: String
commands: [ReindexMigrationCommand]
isExecuted: Boolean
}
type ReindexMigrationCommand {
commandType: String
isDestructive: Boolean
description: String
}
Performs a schema migration.
types
is the list of types in the desired
Reindex schema.force
- must be true
to run the migration, if it includes destructive
commands.dryRun
- if true
, we only validate the schema and return the migration
commands without running them.Output is a list of commands and whether they have been performed.