Mutation Conventions
In this document we go over general patterns the GraphQL API exposes as "mutations," which are calls that fall in the grouping of Create/Update/Delete.
Outside of specialized mutations, we generally expose a handful of concepts, which are enumerated below.
Create
Creates represent the starting point for our top level types, like Parties, Venues, and EventSeries, as well as our Category Nodes
Format:
create<ObjectType>(<ObjectType>CreateInput)
Examples:
createVenue(venueCreateInput)createClient(clientCreateInput)createLanguage(languageCreateInput)
What they do:
- expose top-level type creation
- expose category node creation
- allow owned-node creation (think Name, Phone Number)
- allow hyper edge creation (think Representation, ParticipantGroups)
- allow connection through all-but-one allowed relationships
- Party creates support supply an optional fromDate and thruDate
- expose an ID override for the top-level item being created, like Venue
What they don't do:
- DO NOT support nested creates of other Top Level Types
- DO NOT support nested creates of Category Nodes
- DO NOT allow to immediately draw an IS_DUPLICATE_OF relationship to another object
Adds
Adds exist to create AND connect a Node to another Node. They are separated from regular create to signify that these objects should all generally be created only in conjunction with a connection to a significant other Object like a top level type. For example, addPartyName() being called for a Party.
Format:
add<OriginObjectType><ObjectType>({originId, <ObjectType>CreateInput})
Examples:
addPartyName({partyId, nameCreateInput})addClientRepresentation({clientId, representationCreateInput})
What they do:
- Create a new Node and attach it via a specific Relationship to a starting Node (via ID)
- Include owned-nodes and hyper edges
What they don't do:
- DO NOT support additional sub-tiers of nested creates
- DO NOT include top-level creates (no
addPartyToParty) - DO NOT include category node creates (no
addLanguageToParty)
Connects
Connects exist to connect two existing Nodes, by an abstracted Relationship. They exist for virtually all relationships connecting non-owned Nodes. The connect ID arg convention is directional, but that is for developer consistency and the client shouldn't care because the function naming is explicit enough that they have enough context.
Format:
connect<ObjectType>To<ObjectType>({fromId, toId, optionalArgs})
Examples:
connectPartyToLanguage({partyId, languageId})connectEventSeriesToMusicGenre({eventSeriesId, musicGenreId})connectPartyToRole({partyId, roleId, subType})connectPartyToParticipantGroup({partyId, participantGroupId})
What they do:
- Draw relationships from one existing Node to another existing Node
What they don't do:
- DO NOT create any Nodes
- DO NOT Over-expose the actual relationship details if possible
- DO NOT allow connecting to owned nodes
Deactivates
Deactivates will update relationships to set a thruDate on them, effectively inactivating them. This may also propagate downwards as a series of additional deactivations through all Owned Nodes and Hyper Edges. Naming should be close to a mirror of the create, add, and connect mutations.
Format:
deactivate<ObjectType>({<ObjectType>Id, thruDate=now()})deactivate<ObjectType>From<ObjectType>({<ObjectTypeId>Id, thruDate=now()})
Examples:
deactivateClientRole({clientId, thruDate=now()})deactivateClientRepresentation({representationId, thruDate=now()})deactivateAssignment({assignmentId, thruDate=now()})deactivateName({nameId, thruDate=now()})deactivatePartyFromParticipantGroup({partyId, participantGroupId})
What they do:
- Mark relationships with a thruDate
- Cascade to propagate deactivations, with custom logic per deactivation
What they don't do:
- DO NOT actually delete anything
Corrections - Edits
Edits exist to modify Node and Relationship properties in a CORRECTIVE CAPACITY ONLY. The relationship function over-exposes the underlying relationships but is considered acceptable only in this corrective capacity.
A relationship ID is required here because it is possible for two Nodes to be connected by the same Relationship Type multiple times (think active vs inactive, over time).
NOTE: This will require that the API eventually exposes relationship IDs consistently, which is not currently the case
Format:
_edit<ObjectType>({objectId, <ObjectType>EditInput})_editRelationship({relationshipId, relationshipLabel, relationshipProperties})(singular)
Examples:
_editName({nameId, nameEditInput})_editVenueConfiguration({configurationId, configurationEditInput})_editRelationship({relationshipId, relationshipLabel, relationshipProperties})
What they do:
- Edit Node and Relationship properties
What they don't do:
- DO NOT create or delete nodes or relationships
Corrections - Disconnects
Disconnects exist exclusively to DELETE relationships. This is a CORRECTIVE ACTION ONLY. Associated history is not preserved. They cover ALL relationships.
A relationship ID is required here because it is possible for two Nodes to be connected by the same Relationship Type multiple times (think active vs inactive, over time).
The functions are split apart per relationship, because _disconnect must run the full suite of validations that any deactivate has, to ensure that the delete that is being requested is compliant.
NOTE: This will require that the API eventually exposes relationship IDs consistently, which is not currently the case
Format:
_disconnect<PrimaryObject>From<SecondaryObject>({relationshipId})(singular)
Examples:
_disconnectPartyFromName({relationshipId})_disconnectPartyFromSpokenLanguage({relationshipId})
What they do:
- Delete relationships
What they don't do:
- DO NOT impact connected Nodes.
Note: These will have downstream impacts similar to Deactivate
Corrections - Deletes
Deletes exist exclusively to DELETE nodes. This is a CORRECTIVE ACTION ONLY. Per Neo4j conventions, they must happen after no more relationships exist. They are not DETACH DELETE operations.
Format:
_delete<ObjectType>({<ObjectTypeId>})
Examples:
_deleteParty({partyId})_deleteName({nameId})
What they do:
- Delete a node, completely.
- If any relationships still exist, the API will throw an error reflecting the existing connections which must be
disconnectedfirst.
What they don't do:
- DO NOT disconnect existing relationships