Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #4263: Adds docs for apoc triggers helper functions #4311

Merged
merged 5 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
¦xref::overview/apoc.trigger/apoc.trigger.nodesByLabel.adoc[apoc.trigger.nodesByLabel icon:book[]] +

``
`apoc.trigger.nodesByLabel(labelEntries, label)` - function to filter labelEntries by label, to be used within a trigger kernelTransaction with `$assignedLabels`, `$removedLabels`, `$assigned/removedNodeProperties`.
¦label:function[]
¦label:apoc-extended[]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
¦xref::overview/apoc.trigger/apoc.trigger.propertiesByKey.adoc[apoc.trigger.propertiesByKey icon:book[]] +

``
`apoc.trigger.propertiesByKey(propertyEntries, key)` - function to filter propertyEntries by property-key, to be used within a trigger kernelTransaction with `$assignedNode/RelationshipProperties` and `$removedNode/RelationshipProperties`. Returns [`old`,`new`,`key`,`node`,`relationship`].
¦label:function[]
¦label:apoc-extended[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
¦signature
¦apoc.trigger.nodesByLabel(labelEntries :: ANY?, label :: STRING?) :: (LIST? OF ANY?)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
¦xref::overview/apoc.trigger/apoc.trigger.toNode.adoc[apoc.trigger.toNode icon:book[]] +

`apoc.trigger.toNode(node, removedLabels, removedNodeProperties)` - function to rebuild a node as a virtual, to be used in triggers with a not 'afterAsync' phase.
vga91 marked this conversation as resolved.
Show resolved Hide resolved
¦label:function[]
¦label:apoc-extended[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
¦type¦qualified name¦signature¦description
¦function¦apoc.trigger.nodesByLabel¦apoc.trigger.nodesByLabel(labelEntries :: ANY?, label :: STRING?) :: (LIST? OF ANY?)¦
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
¦signature
¦apoc.trigger.nodesByLabel(labelEntries :: ANY?, label :: STRING?) :: (LIST? OF ANY?)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
¦xref::overview/apoc.trigger/apoc.trigger.toRelationship.adoc[apoc.trigger.toRelationship icon:book[]] +

`apoc.trigger.toRelationship(rel, removedRelationshipProperties)` - function to rebuild a relationship as a virtual, to be used in triggers with a not 'afterAsync' phase.
vga91 marked this conversation as resolved.
Show resolved Hide resolved
¦label:function[]
¦label:apoc-extended[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
¦type¦qualified name¦signature¦description
¦function¦apoc.trigger.nodesByLabel¦apoc.trigger.nodesByLabel(labelEntries :: ANY?, label :: STRING?) :: (LIST? OF ANY?)¦
1 change: 1 addition & 0 deletions docs/asciidoc/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ include::partial$generated-documentation/nav.adoc[]
* xref:background-operations/index.adoc[]
** xref::background-operations/apoc-load-directory-async.adoc[]
** xref:background-operations/triggers.adoc[]
* xref:database-introspection/index.adoc[]
** xref::database-introspection/config.adoc[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@

It's possible to define listeners on one or more folders which trigger the executing of custom cypher queries if changes are observed:

* xref::background-operations/apoc-load-directory-async.adoc[]
* xref::background-operations/apoc-load-directory-async.adoc[]
* xref:background-operations/triggers.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
APOC Core provides a set of procedures for running Cypher queries that are called when data in Neo4j is changed (created, updated, deleted).

https://neo4j.com/docs/apoc/current/background-operations/triggers/[See here for more info].

In addition, APOC Extended provides some helper procedures to more easily manipulate Cypher queries and solve some transaction use cases that cannot be solved otherwise.

== Helper Functions

[separator=¦,opts=header,cols="5,1m,1m"]
|===
¦Qualified Name¦Type¦Release
include::example$generated-documentation/apoc.trigger.nodesByLabel.adoc[]
include::example$generated-documentation/apoc.trigger.propertiesByKey.adoc[]
include::example$generated-documentation/apoc.trigger.toNode.adoc[]
include::example$generated-documentation/apoc.trigger.toRelationship.adoc[]
|===
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This file is generated by DocsTest, so don't change it!
= apoc.dv.catalog.add
:description: This section contains reference documentation for the apoc.dv.catalog.add procedure.

label:procedure[] label:apoc-extended[]
label:procedure[] label:apoc-extended[] label:deprecated[]

[.emphasis]
Add a virtualized resource configuration
Expand All @@ -17,6 +17,8 @@ Add a virtualized resource configuration
apoc.dv.catalog.add(name :: STRING?, config = {} :: MAP?) :: (name :: STRING?, type :: STRING?, url :: STRING?, desc :: STRING?, labels :: LIST? OF STRING?, query :: STRING?, params :: LIST? OF STRING?)
----

include::partial$/dv/deprecated.adoc[]

[WARNING]
====
This procedure is not intended to be used in a cluster environment, and may act unpredictably.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This file is generated by DocsTest, so don't change it!
= apoc.dv.catalog.list
:description: This section contains reference documentation for the apoc.dv.catalog.list procedure.

label:procedure[] label:apoc-extended[]
label:procedure[] label:apoc-extended[] label:deprecated[]

[.emphasis]
List all virtualized resource configuration
Expand All @@ -17,6 +17,8 @@ List all virtualized resource configuration
apoc.dv.catalog.list() :: (name :: STRING?, type :: STRING?, url :: STRING?, desc :: STRING?, labels :: LIST? OF STRING?, query :: STRING?, params :: LIST? OF STRING?)
----

include::partial$/dv/deprecated.adoc[]

== Output parameters
[.procedures, opts=header]
|===
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This file is generated by DocsTest, so don't change it!
= apoc.dv.catalog.remove
:description: This section contains reference documentation for the apoc.dv.catalog.remove procedure.

label:procedure[] label:apoc-extended[]
label:procedure[] label:apoc-extended[] label:deprecated[]

[.emphasis]
Remove a virtualized resource config by name
Expand All @@ -17,6 +17,8 @@ Remove a virtualized resource config by name
apoc.dv.catalog.remove(name :: STRING?) :: (name :: STRING?, type :: STRING?, url :: STRING?, desc :: STRING?, labels :: LIST? OF STRING?, query :: STRING?, params :: LIST? OF STRING?)
----

include::partial$/dv/deprecated.adoc[]

[WARNING]
====
This procedure is not intended to be used in a cluster environment, and may act unpredictably.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

= apoc.trigger.toNode
:description: This section contains reference documentation for the apoc.trigger.toNode function.

label:function[] label:apoc-extended[]

== Signature

[source]
----
apoc.trigger.toNode(node :: NODE, removedLabels :: MAP, removedNodeProperties :: MAP) :: RELATIONSHIPH
----

== Input parameters
[.procedures, opts=header]
|===
| Name | Type | Default
|node|NODE|null
|removedLabels|MAP|null
|removedNodeProperties|MAP|null
|===

[[usage-apoc.trigger.nodesByLabel]]
== Usage Examples
include::partial$usage/apoc.trigger.toNode.adoc[]

xref::background-operations/triggers.adoc[More documentation of apoc.trigger.toNode,role=more information]

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

= apoc.trigger.toRelationship
:description: This section contains reference documentation for the apoc.trigger.toRelationship function.

label:function[] label:apoc-extended[]

== Signature

[source]
----
apoc.trigger.toRelationship(rel :: RELATIONSHIP, removedRelationshipProperties :: MAP) :: RELATIONSHIP
----

== Input parameters
[.procedures, opts=header]
|===
| Name | Type | Default
|rel|RELATIONSHIP|null
|removedRelationshipProperties|MAP|null
|===

[[usage-apoc.trigger.nodesByLabel]]
== Usage Examples
include::partial$usage/apoc.trigger.toRelationship.adoc[]

xref::background-operations/triggers.adoc[More documentation of apoc.trigger.toNode,role=more information]

17 changes: 10 additions & 7 deletions docs/asciidoc/modules/ROOT/pages/virtual-resource/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
= Virtual Resource
:description: This chapter describes how to handle external data sources as virtual resource without persisting them in the database

include::partial$systemdbonly.note.adoc[]

[NOTE]
====
There are situations where we would like to enrich/complement the results of a cypher query in a Neo4j graph with additional
Expand Down Expand Up @@ -40,10 +42,11 @@ image::apoc.dv.imported-graph-from-RDB.png[scaledwidth="100%"]
== Managing a Virtualized Resource via JDBC

=== Creating a Virtualized Resource (JDBC)
Before we can query a Virtualized Resource, we need to define it. We do this using the `apoc.dv.catalog.add` procedure.
The procedure takes two parameters:
Before we can query a Virtualized Resource, we need to define it. We do this using the `apoc.dv.catalog.install` procedure.
The procedure takes three parameters:

* a name that uniquely identifies the virtualized resource and can be used to query that resource
* the database name where we want to use the resource (default is `'neo4j'`)
* a set of parameters indicating the type of the resource (type), the access point (url), the parameterised query
that will be run on the access point (query) and the labels that will be applied to the generated virtual nodes (labels).

Expand All @@ -56,7 +59,7 @@ Here is the cypher that creates such virtualized resource:

[source,cypher]
----
CALL apoc.dv.catalog.add("fr-towns-by-dept", {
CALL apoc.dv.catalog.install("fr-towns-by-dept", "neo4j", {
type: "JDBC",
url: "jdbc:postgresql://localhost/communes?user=jb&password=jb",
labels: ["Town","PopulatedPlace"],
Expand Down Expand Up @@ -124,19 +127,19 @@ RETURN path
----

=== Listing the Virtualized Resource Catalog
The apoc.dv.catalog.list procedure returns a list with all the existing Virtualized resources and their descriptions. It takes no parameters.
The apoc.dv.catalog.list procedure returns a list with all the existing Virtualized resources and their descriptions. It accepts one parameter: i.e. the database name where we want to use the resource (default is 'neo4j').

[source,cypher]
----
CALL apoc.dv.catalog.list()
CALL apoc.dv.catalog.show()
----

=== Removing Virtualized Resources from the Catalog
When a Virtualized Resource is no longer needed it can be removed from the catalog by using the apoc.dv.catalog.remove procedure passing as parameter the unique name of the VR.

[source,cypher]
----
CALL apoc.dv.catalog.remove("vr-name")
CALL apoc.dv.catalog.drop("vr-name", <dbName>)
----

=== Export metadata
Expand Down Expand Up @@ -165,7 +168,7 @@ Here is the cypher that creates such virtualized resource:

[source,cypher]
----
CALL apoc.dv.catalog.add("prod-details-by-id", {
CALL apoc.dv.catalog.install("prod-details-by-id", "neo4j", {
type: "CSV",
url: "http://data.neo4j.com/northwind/products.csv",
labels: ["ProductDetails"],
Expand Down
19 changes: 19 additions & 0 deletions docs/asciidoc/modules/ROOT/partials/dv/deprecated.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[WARNING]
====
Please note that this procedure is deprecated.

Use the following ones instead, which allow for better support in a cluster:

[opts="header"]
|===
| deprecated procedure | new procedure
| `apoc.dv.catalog.add(<name>, $config)` | `apoc.dv.catalog.install('<name>', '<dbName>', $config)`
| `apoc.dv.catalog.remove('<name>')` | `apoc.dv.catalog.drop('<name>', '<dbName>')`
| `apoc.dv.catalog.list()` | `apoc.dv.catalog.show('<dbName>')`
|===

where `<dbName>` is the database where we want to execute the procedure

xref::virtual-resource/index.adoc[See here for more info].

====
17 changes: 0 additions & 17 deletions docs/asciidoc/modules/ROOT/partials/triggers.adoc

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ create constraint for (p:Person)
require p.id is unique;
----

This function is used inside an apoc.trigger.add Cypher statement.
This function is intended to be used inside an apoc.trigger.install Cypher statement.

We can use it to conditionally run Cypher statements when labels are added or removed or when properties are added or removed.
For example, we add an `id` property to all `Person` nodes that is the lower case value of the `name` property of that node, by defining the following trigger:

[source,cypher]
----
CALL apoc.trigger.add(
CALL apoc.trigger.install(
'neo4j',
'lowercase',
'UNWIND apoc.trigger.nodesByLabel($assignedLabels,"Person") AS n
SET n.id = toLower(n.name)',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
This function is used inside an apoc.trigger.add.adoc Cypher statement.
This function is intended to be used inside an apoc.trigger.install Cypher statement.

We can use it to conditionally run Cypher statements when properties are added or removed.
For example, we can connect nodes with a `genre` property to a `Genre` node, with the following trigger:

[source,cypher]
----
CALL apoc.trigger.add(
CALL apoc.trigger.install(
'neo4j',
'triggerTest',
'UNWIND apoc.trigger.propertiesByKey($assignedNodeProperties, "genre") as prop
WITH prop.node as n
Expand Down
46 changes: 46 additions & 0 deletions docs/asciidoc/modules/ROOT/partials/usage/apoc.trigger.toNode.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
This function is intended to be used within an `apoc.trigger.install` Cypher statement.

If we want to create a 'before' or 'after' trigger query using `$deletedNodes`, and retrieve entity information such as labels and/or properties, we cannot use the classic Cypher functions labels() and properties().
Instead, we have to leverage virtual nodes through the function `apoc.trigger.toNode(node, $removedLabels, $removedNodeProperties)`.

For example, to create a new `Report` node with a list of deleted node IDs and all the labels retrieved for each deleted node, we can execute:
[source,cypher]
----
CALL apoc.trigger.install(
'neo4j', 'myTrigger',
"UNWIND $deletedNodes as deletedNode
WITH apoc.trigger.toNode(deletedNode, $removedLabels, $removedNodeProperties) AS deletedNode
CALL apoc.merge.node(
['Report'],
{labels: apoc.node.labels(deletedNode)},
{created: datetime()},
{updated: datetime()}
) YIELD node AS report
WITH report, deletedNode
SET report.deletedIds = coalesce(report.deletedIds, [])+[id(deletedNode)]" ,
{phase:'before'}
);
----

Now, let's create and delete a `Movie` node:

[source,cypher]
----
CREATE (:Movie {title: "The White Tiger"});
MATCH (movie:Movie {title: "The White Tiger"}) DELETE movie;
----

Finally, let's check the `Report` node:

[source,cypher]
----
MATCH (report:Report {labels: ['Movie']})
RETURN report;
----

.Results
[opts="header"]
|===
| report
| (:Report {"created": "2024-12-12T08:33:27.188000000Z", "deletedIds": [12], "labels": ["Movie"]})
|===
Loading
Loading