# Triggers

**Database triggers** are an integral part of most database systems. A trigger
is a procedural code that is automatically executed in response to specific
events. Events are related to some change in data, such as created, updated and
deleted data records. The trigger is often used for maintaining the integrity of
the information in the database. 

Memgraph supports running openCypher clauses after a certain event happens
during database transaction execution, i.e. triggers. For example, when a new
`Employee` node is added, all relevant relationships should be created. Triggers
can also be used to log historical data, for example, to keep track of
employees' previous salaries.

You can **create**, **delete** and **print** triggers. All the triggers are
persisted on the disk, so no information is lost on database reruns.

## Create a trigger

To create a new trigger, use a query of the following format:

```plaintext
CREATE TRIGGER trigger_name [ SECURITY ( DEFINER | INVOKER ) ] [ ON [ () | --> ] CREATE | UPDATE | DELETE ]
[ BEFORE | AFTER ] COMMIT
EXECUTE openCypherStatements
```

The first line creates a trigger with a certain name and defines event type.
Event type determines what event will trigger the execution of Cypher
statements. The event type can be the creation, updated or deletion of nodes ( `()` )
or relationships ( `-->` ) before or after the commitment of that transaction.

Let's break down each element of the query.

### Trigger privilege context

The `SECURITY` clause determines which user's permissions are used when executing the trigger's Cypher statements. This is also known as the **trigger privilege context**.

- **`SECURITY DEFINER`** (default): The trigger executes with the permissions of the user who created the trigger (the definer). This means any user can invoke the trigger, but it will run with the definer's privileges. This is useful when you want to ensure consistent behavior regardless of who triggers the execution.

- **`SECURITY INVOKER`**: The trigger executes with the permissions of the user who invoked the trigger (the invoker). This means the trigger will only succeed if the invoking user has the necessary privileges. This provides more granular control over who can successfully execute trigger operations.

If the `SECURITY` clause is not specified, the default behavior is `SECURITY DEFINER`.

### Trigger name

Each created trigger must have a globally unique name. Two triggers can't have
the same name even if they apply to different events.

### Event type

The event type defines what will trigger the execution of certain Cypher
statements.

There are three main event types:
  - CREATE
  - UPDATE
  - DELETE

Each event type can be fined tuned to trigger the execution only when nodes were
modified by adding `()`, when relationships were modified by adding `-->` or when
any object was modified by not defining `()` or `-->` in the trigger creation.

For example:
* `ON CREATE` - Execute certain Cypher statements if an object (node or a
  relationship) was created by a transaction.
* `ON () UPDATE` - Execute certain Cypher statements if a node was updated by a
  transaction, perhaps a new property was added, or an existing property
  changed.
* `ON --> DELETE` - Execute certain Cypher statements if a relationship was
  deleted by a transaction.

Event type produces information about created, updated or deleted objects within
predefined variables, which can be used to write the Cypher queries trigger was
set to execute.

If no event type is specified, the trigger executes its statements every time,
and all the predefined variables can be used.

#### Predefined variables

When an event that triggers execution of certain Cypher queries is identified,
information about the event, that is the information about the created, updated,
or deleted objects (nodes, relationships or both) in a single transaction are
saved within a predefined variables. 

Each event type creates different predefined variables: 

| Event type              | Predefined variables |
| ----------------------- | -------------------- |
| ON CREATE               | `createdVertices`, `createdEdges`, `createdObjects`|
| ON () CREATE            | `createdVertices` |
| ON --> CREATE           | `createdEdges` |
| ON UPDATE               | `setVertexProperties`, `setEdgeProperties`, `removedVertexProperties`, `removedEdgeProperties`, `setVertexLabels`, `removedVertexLabels`, `updatedVertices`, `updatedEdges`, `updatedObjects` |
| ON () UPDATE            | `setVertexProperties`, `removedVertexProperties`, `setVertexLabels`, `removedVertexLabels`, `updatedVertices` |
| ON --> UPDATE           | `setEdgeProperties`, `removedEdgeProperties`, `updatedEdges` |
| ON DELETE               | `deletedVertices`, `deletedEdges`, `deletedObjects` |
| ON () DELETE            | `deletedVertices` |
| ON --> DELETE           | `deletedEdges` |
| no event type specified | All predefined variables can be used. |

##### `ON CREATE`

###### createdVertices

List of all created nodes (vertices).

###### createdEdges

List of all created relationships (edges).

###### createdObjects

List of all created objects where each element is a map. 

If the element contains a created node (vertex), it will be in the following format:

```json
{
  "event_type": "created_vertex",
  "vertex": created_vertex_object
}
```

If the element contains a created relationship (edge), it will be in the following format:

```json
{
  "event_type": "created_edge",
  "edge": created_edge_object
}
```

##### `ON UPDATE`

Setting an element to `NULL` is counted as a removal. 

The changes are looked at on the transaction level only. That means if the value
of a property on the same object was changed multiple times, only one update
will be generated. The same applies for changes to node labels.

###### setVertexProperties

List of all set node (vertex) properties. 

Each element is in the following format:

```json
{
  "vertex": updated_vertex_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property,
  "new": new_value_of_that_property
}
```

###### setEdgeProperties

List of all set relationship (edge) properties.

 Each element is in the following format:

```json
{
  "edge": updated_vertex_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property,
  "new": new_value_of_that_property
}
```

###### removedVertexProperties

List of all removed node (vertex) properties. 

Each element is in the following format:

```json
{
  "vertex": updated_vertex_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property
}
```

###### removedEdgeProperties

List of all removed relationship (edge) properties. 

Each element is in the following format:

```json
{
  "vertex": updated_vertex_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property
}
```

###### setVertexLabels

List of all set node (vertex) labels. 

Each element is in the following format:

```json
{
  "label": label,
  "vertices": list_of_updated_vertices
}
```

###### removedVertexLabels

List of all removed node (vertex) labels. 

Each element is in the following format:

```json
{
  "label": label,
  "vertices": list_of_updated_vertices
}
```

###### updatedVertices

List of updates consisting of set and removed properties, and set and removed
labels on nodes (vertices).

###### updatedEdges

List of updates consisting of set and removed properties on relationships (edges).

###### updatedObjects

List of updates consisting of set and removed properties on relationships
(edges) and nodes (vertices), and set and removed labels on nodes (vertices).

###### Elements of update predefined variables

If the element contains information about a set node (vertex) property, it's in
the following format:

```json
{
  "event_type": "set_vertex_property",
  "vertex": updated_vertex_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property,
  "new": new_value_of_that_property
}
```

If the element contains information about a removed node (vertex) property, it's
in the following format:

```json
{
  "event_type": "removed_vertex_property",
  "vertex": updated_vertex_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property
}
```

If the element contains information about a set relationship (edge) property,
it's in the following format:

```json
{
  "event_type": "set_edge_property",
  "edge": updated_edge_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property,
  "new": new_value_of_that_property
}
```

If the element contains information about a removed relationship (edge)
property, it's in the following format:

```json
{
  "event_type": "removed_edge_property",
  "edge": updated_edge_object,
  "key": property_that_was_updated,
  "old": old_value_of_that_property
}
```

If the element contains information about a set node (vertex) label, it's in the
following format:

```json
{
  "event_type": "set_vertex_label",
  "vertex": updated_vertex_object,
  "label": label
}
```

If the element contains information about a removed node (vertex) label, it's in
the following format:

```json
{
  "event_type": "removed_vertex_label",
  "vertex": updated_vertex_object,
  "label": label
}
```

##### `ON DELETE`

###### deletedVertices

List of all deleted (nodes) vertices.

###### deletedEdges

List of all deleted (relationships) edges.

###### deletedObjects

List of all deleted objects where each element is a map.

If the element contains a created node (vertex), it will be in the following format:

```json
{
  "event_type": "deleted_vertex",
  "vertex": deleted_vertex_object
}
```

If the element contains a created relationship (edge), it will be in the following format:

```json
{
  "event_type": "deleted_edge",
  "edge": deleted_edge_object
}
```

### Statement execution phase

A trigger can execute its statements at a specified phase, before or after
Memgraph commits the transaction that triggered it. If the `BEFORE COMMIT` option is
used, the trigger will execute its statements as part of that transaction before
it's committed. If the `AFTER COMMIT` option is used, the trigger will execute
its statements asynchronously after that transaction is committed.

### Execute statements

A trigger can execute any valid openCypher query. No specific constraints are
imposed on the queries. The only way trigger queries (i.e. statements) differ
from standard queries is that a trigger query may use predefined variables,
which are based on the event type specified for the trigger.

### Example triggers

An example of a trigger would be:

```
CREATE TRIGGER exampleTrigger1 
ON () CREATE AFTER COMMIT EXECUTE
UNWIND createdVertices AS newNodes
SET newNodes.created = timestamp();
```

When a new node is created and the transaction is committed, the `exampleTrigger1`
will take the list of newly created nodes and for each new node set the property
`created` to a timestamp value indicating the time of its creation. Since no `SECURITY`
clause is specified, it defaults to `SECURITY DEFINER`, meaning it executes with the
permissions of the user who created the trigger.

A more complex example would be:

```cypher
CREATE TRIGGER exampleTrigger2
ON UPDATE AFTER COMMIT EXECUTE
UNWIND updatedObjects AS updatedObject
WITH CASE
        WHEN updatedObject.vertex IS NOT null THEN updatedObject.vertex
        WHEN updatedObject.edge IS NOT null THEN updatedObject.edge
    END AS object
SET object.updated_at = timestamp();
```

The query is more complex, so let's break it down:

* `CREATE TRIGGER exampleTrigger`: Creates the trigger and gives it a unique name `exampleTrigger`.
* `ON UPDATE AFTER COMMIT EXECUTE`: Specifies what event will trigger the
  execution of Cypher statements. In `exampleTrigger2` any update of any graph
  object will trigger the execution once the update event has been committed. 
* `UNWIND updatedObjects AS updatedObject`: If multiple objects were updated,
  unwind the list inside the predefined variable and go over each one.
* `WITH CASE...`: The `CASE` expression checks what type of object was updated,
  a node (vertex) or a relationship (edge).
* `SET object.updated_at = timestamp();`: Add an `updated_at` property to the
  object indicating when the action happened.

### Create a trigger for Python query module

If you want a trigger to be activated by executing code from a Python query
module, you can call the query module from the trigger. In the example below,
the trigger will call `query_module.new_edge(edge)` each time a new relationship
(edge) is created:

```cypher
CREATE TRIGGER newEdge
ON CREATE BEFORE COMMIT EXECUTE
UNWIND createdEdges AS edge
CALL query_module.new_edge(edge) YIELD *;
```

Make sure your function accepts the proper Memgraph type, `mgp.Edge` in this
case. 

```python
def new_edge(
    context: mgp.ProcCtx,
    edge: mgp.Edge
)
```
Memgraph Python API is defined by `mgp.py` script, and in it, you can find all
supported types such as `mgp.Edge`, `mgp.Vertex` etc. If you want to explore the
API further, feel free to check the reference guide on [Python
API](https://memgraph.com/docs/custom-query-modules/python/python-api).

### Create a trigger for dynamic algorithms

[Dynamic
algorithms](https://memgraph.com/docs/advanced-algorithms/available-algorithms#dynamic-graph-algorithms-enterprise)
are often designed for dataset updates. With a trigger, you can ensure that any
dataset is up to date and consistent. In the sample code below, a trigger is set
to use MAGE `pagerank_online` algorithm. 

```cypher
CREATE TRIGGER pagerank_trigger 
BEFORE COMMIT 
EXECUTE CALL pagerank_online.update(createdVertices, createdEdges, deletedVertices, deletedEdges) 
YIELD node, rank
SET node.rank = rank;
```

In this case, all created or deleted objects are passed from the database
transaction to the trigger. After each transaction that has created or deleted
objects, the trigger will automatically execute the PageRank algorithm and
update the rank property. This will ensure data consistency and lead to
performance benefits. 

## Dropping a trigger

A trigger can be deleted by running the following query:

```plaintext
DROP TRIGGER trigger_name;
```

## Trigger owner and privilege context

The user who executes the `CREATE TRIGGER` query is the owner (definer) of the trigger.
Authentication and authorization are not supported in Memgraph Community, thus
the owner is always `Null`, and the privileges are not checked.

In Memgraph Enterprise, the trigger's privilege context determines which user's permissions are used when executing the trigger's Cypher statements:

- **`SECURITY DEFINER`** (default): The trigger executes with the privileges of the owner (definer). The execution of the statements will fail if the owner doesn't have the required [privileges](https://memgraph.com/docs/configuration/security#role-based-access-control-enterprise). Any user can invoke the trigger, but it will run with the definer's permissions.

- **`SECURITY INVOKER`**: The trigger executes with the privileges of the user who invokes the trigger. The execution of the statements will fail if the invoking user doesn't have the required [privileges](https://memgraph.com/docs/configuration/security#role-based-access-control-enterprise).

The privilege context affects both standard privileges and fine-grained privileges (label-based and edge-type-based permissions). For `SECURITY DEFINER` triggers, the definer must have all necessary privileges at the time of trigger creation, and these privileges are checked during trigger execution.

## Trigger info

The following query will return information about all triggers:

```cypher
SHOW TRIGGERS;
```

users can also use the following query to obtain the same information:

```cypher
SHOW TRIGGER INFO;
```

Information:

| trigger name | statement                       | privilege context                | event type                                        | phase                         | owner                          |
|--------------|-------------------------------- | ---------------------------------| --------------------------------------------------| ------------------------------|--------------------------------|
| Trigger name | Statement the trigger executes. | Which user's permissions are used | Event type that triggers the statement execution. | When is the trigger executed. | The trigger owner or `Null`.   |
