Skip to content

Commit

Permalink
Merge pull request #219 from neo4j/backport/7.x/pr-218
Browse files Browse the repository at this point in the history
[Cherry-pick][7.x] Merge pull request #218 from neo4j/apply-unify-directives-to-6.x
  • Loading branch information
rsill-neo4j authored Nov 11, 2024
2 parents caca276 + 37f1aad commit d09439d
Show file tree
Hide file tree
Showing 14 changed files with 274 additions and 149 deletions.
2 changes: 1 addition & 1 deletion modules/ROOT/pages/directives/autogeneration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This enables autogeneration of IDs for the field.
The format of each generated ID is a UUID generated by the link:https://neo4j.com/docs/cypher-manual/current/functions/scalar/#functions-randomuuid[`randomUUID()` function].
The field will not be present in input types for mutations.

It is recommended to use xref::/directives/indexes-and-constraints.adoc#_unique_node_property_constraints[`@unique`] in conjunction with this to add a unique node property constraint.
It is recommended to use xref::/directives/indexes-and-constraints.adoc#_unique[`@unique`] in conjunction with this to add a unique node property constraint.

=== Definition

Expand Down
18 changes: 10 additions & 8 deletions modules/ROOT/pages/directives/custom-logic.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
The `@cypher` directive binds a GraphQL field to the results of a Cypher query.
This directive can be used both for properties in a type or as top level queries.

=== Global variables
=== Definition

==== Global variables

Global variables are available for use within the Cypher statement, and can be applied to the `@cypher` directive.

Expand Down Expand Up @@ -90,14 +92,14 @@ type Query {
|===


=== Return values
==== Return values

The return value of Cypher statements must always be of the same type to which the directive is applied.

The variable must also be aliased with a name that is the same as the one passed to `columnName`.
This can be the name of a node, relationship query, or an alias in the `RETURN` statement of the Cypher statement.

==== Scalar values
===== Scalar values

Cypher statements must return a value which matches the scalar type to which the directive was applied.
For example:
Expand All @@ -109,7 +111,7 @@ type Query {
}
----

==== Object types
===== Object types

When returning an object type, all fields of the type must be available in the Cypher return value.
This can be achieved by either returning the entire object from the Cypher query, or returning a map of the fields which are required for the object type.
Expand Down Expand Up @@ -152,7 +154,7 @@ type Query {
The downside of the latter approach is that you need to adjust the return object as you change your object type definition.


=== Input arguments
==== Input arguments

The `@cypher` statement can access the query parameters by prepending `$` to the parameter name.
For example:
Expand All @@ -174,7 +176,7 @@ query {
----


=== Usage examples
=== Usage

The `@cypher` directive can be used in different contexts, such as the ones described in this section.

Expand Down Expand Up @@ -383,7 +385,7 @@ directive @customResolver(
) on FIELD_DEFINITION
----

=== The `requires` argument
=== Usage

The `requires` argument can be used:

Expand Down Expand Up @@ -552,7 +554,7 @@ new Neo4jGraphQL({
})
----

=== Context values
==== Context values

The GraphQL context for the request is available as the third argument in a callback.
This maps to the argument pattern for GraphQL resolvers.
Expand Down
123 changes: 100 additions & 23 deletions modules/ROOT/pages/directives/database-mapping.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@ This page describes how to use directives for database mapping.
Each type in your GraphQL type definitions can be mapped to an entity in your Neo4j database, such as nodes, relationships, and relationship properties.


[[type-definitions-node]]
== `@node`

=== Definition

[source, graphql, indent=0]
----
"""Informs @neo4j/graphql of node metadata"""
directive @node(
"""The labels to map this GraphQL type to in the Neo4j database"""
labels: [String!]
) on OBJECT
----

=== Usage

Adding the `@node` directive to your GraphQL type specifies that it represents a Neo4j node.
For example, to represent a Neo4j node with the label "Movie" and a single property "title" of type string:

Expand All @@ -27,12 +39,16 @@ In version 6.x, it's not required to specify every GraphQL type representing a N
In the future, types without the `@node` directive will no longer be treated as Neo4j nodes.
====

When not differently specified, the GraphQL type name is used as a label for the represented Neo4j node. It's possible to explicitly define the Neo4j node labels by using the argument `labels`:
When not differently specified, the GraphQL type name is used as a label for the represented Neo4j node. It's possible to explicitly define the Neo4j node labels by using the parameter `labels`.

[discrete]
=== `labels`
==== The `labels` parameter

This parameter defines the list of label to be used in Neo4j instead of the GraphQL type name:
You can append the optional parameters `labels` to a GraphQL object with the `@node` directive.
This parameter lists the labels to be used in Neo4j instead of the GraphQL type name.

.Querying a field with the `labels` parameter
====
Consider the following type definition:
[source, graphql, indent=0]
----
Expand All @@ -41,7 +57,7 @@ type Dog @node(labels: ["K9"]) {
}
----
This way, the following query:
Here is a query against the `Dog` node:
[source, graphql, indent=0]
----
Expand All @@ -52,15 +68,20 @@ This way, the following query:
}
----
Generates the Cypher query:
The following Cypher is generated:
[source, cypher, indent=0]
----
MATCH (this: K9)
RETURN this { .name } as name
----
====

If the GraphQL type name should still be used as a label, it needs to be specified as well:
If you want to use the GraphQL type name as a label, specifiy both.

.Querying a field with two entries for the `labels` parameter
====
Consider the following type definition:
[source, graphql, indent=0]
----
Expand All @@ -69,7 +90,8 @@ type Dog @node(labels: ["Dog", "K9"]) {
}
----
This way, the following query:
Here is an example for a query against the `Dog` node
[source, graphql, indent=0]
----
Expand All @@ -80,13 +102,14 @@ This way, the following query:
}
----
Generates the Cypher query:
The following Cypher is generated:
[source, cypher, indent=0]
----
MATCH (this:Dog:K9)
RETURN this { .name } as this
----
====

[NOTE]
====
Expand All @@ -103,12 +126,18 @@ type Dog @node(labels: ["K9", "Dog"]) {
}
----

See xref::/directives/indexes-and-constraints.adoc#_unique[`@unique`] to learn more about the `@unique` directive.


[discrete]
=== Using `$jwt` and `$context`
==== Using `$jwt` and `$context`

In some cases, you may want to generate dynamic labels depending on the user requesting.
For that, you can use the variable `$jwt` to define a custom label in the JWT:
You can use the variable `$jwt` to define a custom label in the JWT.


.Querying a field with a `$jwt` variable in the `labels` parameter
====
Consider the following type definition:
[source, graphql, indent=0]
----
Expand All @@ -128,13 +157,14 @@ The following query yields a different Cypher query depending on the user JWT:
}
----
Assuming there is a user with the value `"username": "arthur"` in JWT, the Cypher query looks like:
Assuming there is a user with the value `"username": "arthur"` in JWT, the Cypher query looks like this:
[source, cypher, indent=0]
----
MATCH (this:arthur)
RETURN this { .name } as this
----
====

Similarly, context values can be passed directly:

Expand All @@ -145,7 +175,7 @@ type User @node(label: ["$context.appId"]) {
}
----

When running the server with Apollo:
For example, if you are running the server with Apollo:

[source, js, indent=0]
----
Expand All @@ -160,26 +190,59 @@ await startStandaloneServer(server, {

== `@relationship`

=== Definition

[source, graphql, indent=0]
----
"""
Instructs @neo4j/graphql to treat this field as a relationship. Opens up the ability to create and connect on this field.
"""
directive @relationship(
type: String!
"""Valid and default directions for this relationship."""
queryDirection: RelationshipQueryDirection = DEFAULT_DIRECTED
direction: RelationshipDirection!
"""
The name of the interface containing the properties for this relationship.
"""
properties: String
"""
Prevent all but these operations from being generated for this relationship
"""
nestedOperations: [RelationshipNestedOperations!]! = [CREATE, UPDATE, DELETE, CONNECT, DISCONNECT, CONNECT_OR_CREATE]
"""Prevent aggregation for this relationship"""
aggregate: Boolean = true
) on FIELD_DEFINITION
----

=== Usage

Relationships are represented by marking particular fields with a directive -- in this case, `@relationship`.
It defines the relationship type in the database, as well as its direction.
It defines the relationship type in the database, as well as which direction that relationship goes in.

The following type definitions add a second node type, `Actor`, and connect `Movie` and `Actor` via the `ACTED_IN` relationship:
To add two node types, "Movie" and "Actor", and connect the two:

[source, graphql, indent=0]
----
type Movie @node {
type Movie {
title: String
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
}
type Actor @node {
type Actor {
name: String
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}
----

Note that, in this case, there is a directive on each "end" of the relationship, but it is not essential.
[NOTE]
====
The `@relationship` directive is used twice, once on each end of the relationship.
This is the standard way of modeling a relationship with the GraphQL Library.
However, it is not a requirement of the type definitions themselves as relationships can deliberately be underspecified, for example to limit access through the API layer.
====

See also: xref::/directives/schema-configuration/field-configuration#_relationship[`@relationship` field configuration].

== `@relationshipProperties`

Expand All @@ -201,12 +264,12 @@ For example, for the "ACTED_IN" relationship, add a property "roles":

[source, graphql, indent=0]
----
type Movie @node {
type Movie {
title: String
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn")
}
type Actor @node {
type Actor {
name: String
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn")
}
Expand All @@ -220,9 +283,23 @@ Note that in addition to this type, there is an added key `properties` in the ex
For more information, see xref::/types/relationships.adoc[Type definitions -> Relationships].


[[type-definitions-alias]]
== `@alias`

=== Definition

[source, graphql, indent=0]
----
"""
Instructs @neo4j/graphql to map a GraphQL field to a Neo4j node or relationship property.
"""
directive @alias(
"""The name of the Neo4j property"""
property: String!
) on FIELD_DEFINITION
----

=== Usage

This directive maps a GraphQL field to a Neo4j property on a node or relationship.
It can be used on any fields that are not `@cypher` or `@relationship` fields.

Expand Down
Loading

0 comments on commit d09439d

Please sign in to comment.