Skip to content

Commit

Permalink
types
Browse files Browse the repository at this point in the history
  • Loading branch information
stefano-ottolenghi committed Dec 22, 2024
1 parent 591c178 commit d576b63
Showing 1 changed file with 113 additions and 188 deletions.
301 changes: 113 additions & 188 deletions dotnet-manual/modules/ROOT/pages/data-types.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -114,255 +114,180 @@ Console.WriteLine(result.Result[0].Get<INode>("p").Get<Point>("location"));
|===


=== `NodeValue`
=== `INode`
Represents a node in a graph.

.Essential methods on node objects
.Essential members on node objects
[cols="1m,2"]
|===
|Method |Return
|Property/Method |Return

|.labels()
|.Labels
|Node labels, as a list.

|.asMap()
|.Properties
|Node properties, as a map.

|.get("<propertyName>")
|Value for the given property.
|.Get<type>("<propertyName>")
|Value for the given property, casted to `type`.

|.elementId()
|String identifier for the relationship.
|.ElementId()
|String identifier for the node.
This should be used with care, as no guarantees are given about the mapping between id values and elements outside the scope of a single transaction. In other words, using an `elementId` to `MATCH` an element across different transactions is risky.

|===

.Retrieve a node and display its details
[source, java]
[source, csharp]
----
package demo;
import java.util.Map;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.QueryConfig;
public class App {
public static void main(String... args) {
final String dbUri = "<URI for Neo4j database>";
final String dbUser = "<Username>";
final String dbPassword = "<Password>";
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
driver.verifyConnectivity();
// Get a node from the database
var result = driver.executableQuery("MERGE (p:Person:Actor {name: $name, age: 59}) RETURN p")
.withParameters(Map.of("name", "Alice"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
// Extract node from result
var nodeVal = result.records().get(0).get("p");
var node = nodeVal.asNode(); // .asNode() -> type org.neo4j.driver.types.Node
System.out.printf("Labels: %s %n", node.labels());
System.out.printf("Properties: %s %n", node.asMap());
System.out.printf("Name property: %s %n", node.get("name"));
System.out.printf("Element ID: %s %n", node.elementId());
/*
Labels: [Person, Actor]
Properties: {name=Alice, age=59}
Name property: "Alice"
Element ID: 4:549a0567-2015-4bb6-a40c-8536bf7227b0:5
*/
}
}
}
var result = await driver.ExecutableQuery("MERGE (p:Person:Actor {name: $name, age: $age}) RETURN p")
.WithParameters(new { name = "Alice", age = 59 })
.WithConfig(new QueryConfig(database: "neo4j"))
.ExecuteAsync();
var node = result.Result[0].Get<INode>("p");
Console.WriteLine("Labels: {0}", string.Join(", ", node.Labels));
Console.WriteLine("Properties: {0}", string.Join(", ", node.Properties));
Console.WriteLine("Name property: {0}", node.Get<string>("name"));
/*
Labels: Person, Actor
Properties: [name, Alice], [age, 59]
Name property: Alice
*/
----

For full documentation, see link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/internal/value/NodeValue.html[API documentation -> NodeValue].
For full documentation, see link:https://neo4j.com/docs/api/dotnet-driver/current/api/Neo4j.Driver.INode.html[API documentation -> INode].


=== `RelationshipValue`
=== `IRelationship`

Represents a relationship in a graph.

.Essential methods on relationsip objects
.Essential members on relationsip objects
[cols="1m,2"]
|===
|Method |Return
|Property/Method |Return

|.type()
|.Type
|Relationship type.

|.asMap()
|.Properties
|Relationship properties, as a map.

|.get("<propertyName>")
|Value for the given property.
|.Get<type>("<propertyName>")
|Value for the given property, casted to `type`.

|.startNodeElementId()
|.StartNodeElementId
|`elementId` of starting node.

|.endNodeElementId()
|.EndNodeElementId
| `elementId` of ending node.

|.elementId()
|.ElementId
|String identifier for the relationship.
This should be used with care, as no guarantees are given about the mapping between id values and elements outside the scope of a single transaction. In other words, using an `elementId` to `MATCH` an element across different transactions is risky.

|===

.Retrieve a relationship and display its details
[source, java]
[source, csharp]
----
package demo;
import java.util.Map;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.QueryConfig;
public class App {
public static void main(String... args) {
final String dbUri = "<URI for Neo4j database>";
final String dbUser = "<Username>";
final String dbPassword = "<Password>";
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
driver.verifyConnectivity();
// Get a relationship from the database
var result = driver.executableQuery("""
MERGE (p:Person {name: $name})
MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend:Person {name: $friendName})
RETURN r AS friendship
""")
.withParameters(Map.of("name", "Alice", "status", "BFF", "friendName", "Bob"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
// Extract relationship from result
var relationshipVal = result.records().get(0).get("friendship");
var relationship = relationshipVal.asRelationship(); // .asRelationship() -> type org.neo4j.driver.types.Relationship
System.out.printf("Type: %s %n", relationship.type());
System.out.printf("Properties: %s %n", relationship.asMap());
System.out.printf("Status property: %s %n", relationship.get("status"));
System.out.printf("Start node: %s %n", relationship.startNodeElementId());
System.out.printf("End node: %s %n", relationship.endNodeElementId());
System.out.printf("Element ID: %s %n", relationship.elementId());
/*
Type: KNOWS
Properties: {since=2024-01-12, status=BFF}
Status property: "BFF"
Start node: 4:549a0567-2015-4bb6-a40c-8536bf7227b0:0
End node: 4:549a0567-2015-4bb6-a40c-8536bf7227b0:6
Element ID: 5:549a0567-2015-4bb6-a40c-8536bf7227b0:1
*/
}
}
}
var result = await driver.ExecutableQuery(@"
MERGE (p:Person {name: $name})
MERGE (friend:Person {name: $friendName})
MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend)
RETURN r AS friendship
")
.WithParameters(new { name = "Alice", friendName = "Bob", status = "BFF" })
.WithConfig(new QueryConfig(database: "neo4j"))
.ExecuteAsync();
var relationship = result.Result[0].Get<IRelationship>("friendship");
Console.WriteLine($"Type: {relationship.Type}");
Console.WriteLine("Properties: {0}", string.Join(", ", relationship.Properties));
Console.WriteLine("Status property: {0}", relationship.Get<string>("status"));
/*
Type: KNOWS
Properties: [since, 2024-12-22], [status, BFF]
Status property: BFF
*/
----

For full documentation, see link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/internal/value/RelationshipValue.html[API documentation -> RelationshipValue].
For full documentation, see link:https://neo4j.com/docs/api/dotnet-driver/current/api/Neo4j.Driver.IRelationship.html[API documentation -> IRelationship].


=== `PathValue`
=== `IPath`

Represents a path in a graph.

The driver breaks paths into (iterable) _segments_, consisting of a start node, one relationship, and an end node.
Segments entities may be retrieved, in order, via the methods `.start()`, `.relationship()`, and `.end()`.

.Retrieve a path and _walk_ it, listing nodes and relationship
[source, java]
.Retrieve a path and _walk_ it
[source, csharp]
----
package demo;
import java.util.Map;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.types.Path;
import org.neo4j.driver.QueryConfig;
public class App {
public static void main(String... args) {
final String dbUri = "<URI for Neo4j database>";
final String dbUser = "<Username>";
final String dbPassword = "<Password>";
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
driver.verifyConnectivity();
// Create some :Person nodes linked by :KNOWS relationships
addFriend(driver, "Alice", "BFF", "Bob");
addFriend(driver, "Bob", "Fiends", "Sofia");
addFriend(driver, "Sofia", "Acquaintances", "Sofia");
// Follow :KNOWS relationships outgoing from Alice three times, return as path
var result = driver.executableQuery("""
MATCH path=(:Person {name: $name})-[:KNOWS*3]->(:Person)
RETURN path AS friendshipChain
""")
.withParameters(Map.of("name", "Alice"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
// Extract path from result
var pathVal = result.records().get(0).get("friendshipChain");
var path = pathVal.asPath(); // .asPath() -> type org.neo4j.driver.types.Path
System.out.println("-- Path breakdown --");
for (Path.Segment segment : path) {
System.out.printf(
"%s is friends with %s (%s).%n",
segment.start().get("name").asString(),
segment.end().get("name").asString(),
segment.relationship().get("status").asString());
}
/*
-- Path breakdown --
Alice is friends with Bob (BFF).
Bob is friends with Sofia (Fiends).
Sofia is friends with Sofia (Acquaintances).
*/
}
}
public static void addFriend(Driver driver, String name, String status, String friendName) {
driver.executableQuery("""
MERGE (p:Person {name: $name})
MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend:Person {name: $friendName})
""")
.withParameters(Map.of("name", name, "status", status, "friendName", friendName))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
}
using Neo4j.Driver;
const string dbUri = "<URI for Neo4j database>";
const string dbUser = "<Username>";
const string dbPassword = "<Password>";
await using var driver = GraphDatabase.Driver(dbUri, AuthTokens.Basic(dbUser, dbPassword));
await driver.VerifyConnectivityAsync();
// Create some :Person nodes linked by :KNOWS relationships
await addFriend(driver, "Alice", "BFF", "Bob");
await addFriend(driver, "Bob", "Fiends", "Sofia");
await addFriend(driver, "Sofia", "Acquaintances", "Sofia");
// Follow :KNOWS relationships outgoing from Alice three times, return as path
var result = await driver.ExecutableQuery(@"
MATCH path=(:Person {name: $name})-[:KNOWS*3]->(:Person)
RETURN path AS friendshipChain
")
.WithParameters(new { name = "Alice", friendName = "Bob", status = "BFF" })
.WithConfig(new QueryConfig(database: "neo4j"))
.ExecuteAsync();
// Extract path from result
var path = result.Result[0].Get<IPath>("friendshipChain");
Console.WriteLine("-- Path breakdown --");
for (var i=0; i<path.Relationships.Count; i++) {
Console.WriteLine("{0} is friends with {1} ({2}).",
path.Nodes[i].Get<string>("name"),
path.Nodes[i+1].Get<string>("name"),
path.Relationships[i].Get<string>("status")
);
}
/*
-- Path breakdown --
Alice is friends with Bob (BFF).
Bob is friends with Sofia (Fiends).
Sofia is friends with Sofia (Acquaintances).
*/
async Task addFriend(IDriver driver, string name, string status, string friendName) {
await driver.ExecutableQuery(@"
MERGE (p:Person {name: $name})
MERGE (friend:Person {name: $friendName})
MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend)
")
.WithParameters(new { name = name, status = status, friendName = friendName })
.WithConfig(new QueryConfig(database: "neo4j"))
.ExecuteAsync();
}
----

For full documentation, see link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/internal/value/PathValue.html[API documentation -> PathValue].
For full documentation, see link:https://neo4j.com/docs/api/dotnet-driver/current/api/Neo4j.Driver.IPath.html[API documentation -> IPath].


== Exceptions

The driver can raise a number of different exceptions, see link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/exceptions/package-summary.html[API documentation -> Exceptions].
The driver can raise a number of different exceptions, see link:https://neo4j.com/docs/api/dotnet-driver/current/api/Neo4j.Driver.Neo4jException.html[API documentation -> Neo4jException]. Exception objects are GQL-compliant.

For a list of errors the server can return, see link:{neo4j-docs-base-uri}/status-codes/{page-version}[Status codes].

Some server errors are marked as safe to retry without need to alter the original request.
Those exceptions have a `true` value for the `.IsRetriable` property.
Examples of such errors are deadlocks, memory issues, or connectivity issues.
Driver's exceptions implementing link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/exceptions/RetryableException.html[`RetryableException`] are such that a further attempt at the operation that caused it might be successful.
This is particular useful when running queries in xref:transactions#explicit-transactions[explicit transactions], to know if a failed query is worth re-running.


Expand Down

0 comments on commit d576b63

Please sign in to comment.