Documentation
¶
Index ¶
- func ExtractNodeLabels(i any) []string
- func ExtractRelationshipType(relationship any) string
- func NewMock() mockDriver
- func NewNode[N any, PN interface{ ... }]() PN
- func NodeWithID[N any, PN interface{ ... }](id string) PN
- func WithSessionConfig(configurers ...func(*neo4j.SessionConfig)) func(ec *execConfig)
- func WithTxConfig(configurers ...func(*neo4j.TransactionConfig)) func(ec *execConfig)
- func WithTypes(types ...any) func(*driver)
- type Abstract
- type Config
- type Driver
- type Expression
- type IAbstract
- type INode
- type IRelationship
- type Label
- type Node
- type Query
- type Relationship
- type Transaction
- type Valuer
- type Work
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtractNodeLabels ¶
func ExtractRelationshipType ¶
func NewNode ¶
NewNode creates a new node with a random ID.
Example ¶
package main import ( "fmt" "github.com/rlch/neogo" ) func main() { n := neogo.NewNode[neogo.Node]() fmt.Printf("generated: %v", n.ID != "") }
Output: generated: true
func NodeWithID ¶
NodeWithID creates a new node with the given ID.
Example ¶
package main import ( "fmt" "github.com/rlch/neogo" ) func main() { n := neogo.NodeWithID[neogo.Node]("test") fmt.Printf("id: %v", n.ID) }
Output: id: test
func WithSessionConfig ¶
func WithSessionConfig(configurers ...func(*neo4j.SessionConfig)) func(ec *execConfig)
WithSessionConfig configures the session used by Exec().
func WithTxConfig ¶
func WithTxConfig(configurers ...func(*neo4j.TransactionConfig)) func(ec *execConfig)
WithTxConfig configures the transaction used by Exec().
Types ¶
type Abstract ¶
Abstract is a base type for all abstract nodes. An abstract node can have multiple concrete implementers, where each implementer must have a distinct label. This means that each node will have at least 2 labels.
A useful design pattern for constructing abstract nodes is to create a base type which provides an implementation for IAbstract and embed Abstract + Node, then embed that type in all concrete implementers:
type Organism interface { internal.IAbstract } type BaseOrganism struct { internal.Abstract `neo4j:"Organism"` internal.Node Alive bool `json:"alive"` } func (b BaseOrganism) Implementers() []internal.IAbstract { return []internal.IAbstract{ &Human{}, &Dog{}, } } type Human struct { BaseOrganism `neo4j:"Human"` Name string `json:"name"` } type Dog struct { BaseOrganism `neo4j:"Dog"` Borfs bool `json:"borfs"` }
type Driver ¶
type Driver interface { // DB returns the underlying neo4j driver. DB() neo4j.DriverWithContext // ReadSession creates a new read-access session based on the specified session configuration. ReadSession(ctx context.Context, configurers ...func(*neo4j.SessionConfig)) readSession // WriteSession creates a new write-access session based on the specified session configuration. WriteSession(ctx context.Context, configurers ...func(*neo4j.SessionConfig)) writeSession // Exec creates a new transaction + session and executes the given Cypher // query. // // The access mode is inferred from the clauses used in the query. If using // Cypher() to inject a write query, one should use [WithSessionConfig] to // override the access mode. // // The session is closed after the query is executed. Exec(configurers ...func(*execConfig)) Query }
Driver represents a pool of connections to a neo4j server or cluster. It provides an entrypoint to a neogo query.Client, which can be used to build cypher queries.
It's safe for concurrent use.
Example ¶
ctx := context.Background() var d Driver if testing.Short() { m := NewMock() m.Bind(map[string]any{ "person": Person{ Node: internal.Node{ID: "some-unique-id"}, Name: "Spongebob", Surname: "Squarepants", Age: 20, }, }) d = m } else { neo4j, cancel := startNeo4J(ctx) d = New(neo4j) defer func() { if err := cancel(ctx); err != nil { panic(err) } }() } person := Person{ Name: "Spongebob", Surname: "Squarepants", } person.ID = "some-unique-id" err := d.Exec(). Create(db.Node(&person)). Set(db.SetPropValue(&person.Age, 20)). Return(&person). Print(). Run(ctx) fmt.Printf("err: %v\n", err) fmt.Printf("person: %v\n", person)
Output: CREATE (person:Person {id: $person_id, name: $person_name, surname: $person_surname}) SET person.age = $v1 RETURN person err: <nil> person: {{some-unique-id} Spongebob Squarepants 20}
Example (ReadSession) ¶
ctx := context.Background() var d Driver if testing.Short() { m := NewMock() records := make([]map[string]any, 11) for i := range records { records[i] = map[string]any{"i": i} } m.BindRecords(records) records2x := make([]map[string]any, 11) for i := range records2x { records2x[i] = map[string]any{"i * 2": i * 2} } m.BindRecords(records2x) d = m } else { neo4j, cancel := startNeo4J(ctx) d = New(neo4j) defer func() { if err := cancel(ctx); err != nil { panic(err) } }() } var ns, nsTimes2 []int session := d.ReadSession(ctx) defer func() { if err := session.Close(ctx); err != nil { panic(err) } }() err := session.ReadTransaction(ctx, func(begin func() Query) error { if err := begin(). Unwind("range(0, 10)", "i"). Return(db.Qual(&ns, "i")).Run(ctx); err != nil { return err } if err := begin(). Unwind(&ns, "i"). Return(db.Qual(&nsTimes2, "i * 2")).Run(ctx); err != nil { return err } return nil }) fmt.Printf("err: %v\n", err) fmt.Printf("ns: %v\n", ns) fmt.Printf("nsTimes2: %v\n", nsTimes2)
Output: err: <nil> ns: [0 1 2 3 4 5 6 7 8 9 10] nsTimes2: [0 2 4 6 8 10 12 14 16 18 20]
Example (RunWithParams) ¶
ctx := context.Background() var d Driver if testing.Short() { m := NewMock() m.Bind(map[string]any{ "$ns": []int{1, 2, 3}, }) d = m } else { neo4j, cancel := startNeo4J(ctx) d = New(neo4j) defer func() { if err := cancel(ctx); err != nil { panic(err) } }() } var ns []int err := d.Exec(). Return(db.Qual(&ns, "$ns")). RunWithParams(ctx, map[string]interface{}{ "ns": []int{1, 2, 3}, }) fmt.Printf("err: %v\n", err) fmt.Printf("ns: %v\n", ns)
Output: err: <nil> ns: [1 2 3]
Example (StreamWithParams) ¶
ctx := context.Background() var d Driver n := 3 if testing.Short() { m := NewMock() records := make([]map[string]any, n+1) for i := range records { records[i] = map[string]any{"i": i} } m.BindRecords(records) d = m } else { neo4j, cancel := startNeo4J(ctx) d = New(neo4j) defer func() { if err := cancel(ctx); err != nil { panic(err) } }() } ns := []int{} session := d.ReadSession(ctx) defer func() { if err := session.Close(ctx); err != nil { panic(err) } }() err := session.ReadTransaction(ctx, func(begin func() Query) error { var num int params := map[string]interface{}{ "total": n, } return begin(). Unwind("range(0, $total)", "i"). Return(db.Qual(&num, "i")). StreamWithParams(ctx, params, func(r query.Result) error { for i := 0; r.Next(ctx); i++ { if err := r.Read(); err != nil { return err } ns = append(ns, num) } return nil }) }) fmt.Printf("err: %v\n", err) fmt.Printf("ns: %v\n", ns)
Output: err: <nil> ns: [0 1 2 3]
Example (WriteSession) ¶
ctx := context.Background() var d Driver if testing.Short() { m := NewMock() m.Bind(nil) records := make([]map[string]any, 10) for i := range records { records[i] = map[string]any{"p": &Person{ Node: internal.Node{ ID: strconv.Itoa(i + 1), }, }} } m.BindRecords(records) d = m } else { neo4j, cancel := startNeo4J(ctx) d = New(neo4j) defer func() { if err := cancel(ctx); err != nil { panic(err) } }() } var people []*Person session := d.WriteSession(ctx) defer func() { if err := session.Close(ctx); err != nil { panic(err) } }() err := session.WriteTransaction(ctx, func(begin func() Query) error { if err := begin(). Unwind("range(1, 10)", "i"). Merge(db.Node( db.Qual( Person{}, "p", db.Props{"id": "toString(i)"}, ), )). Run(ctx); err != nil { return err } if err := begin(). Unwind("range(1, 10)", "i"). Match(db.Node(db.Qual(&people, "p"))). Where(db.And( db.Cond("p.id", "=", "toString(i)"), )). Return(&people). Run(ctx); err != nil { return err } return nil }) ids := make([]string, len(people)) for i, p := range people { ids[i] = p.ID } fmt.Printf("err: %v\n", err) fmt.Printf("ids: %v\n", ids)
Output: err: <nil> ids: [1 2 3 4 5 6 7 8 9 10]
func New ¶
func New(neo4j neo4j.DriverWithContext, configurers ...Config) Driver
New creates a new neogo Driver from a neo4j.DriverWithContext.
type Expression ¶
type Expression = query.Expression
Expression is an interface for compiling a Cypher expression outside the context of a query.
type IAbstract ¶
IAbstract is an interface for abstract nodes. See Abstract for the default implementation.
type IRelationship ¶
type IRelationship = internal.IRelationship
IRelationship is an interface for relationships. See Relationship for the default implementation.
type Label ¶ added in v1.0.2
Label is a used to specify a label for a node. This allows for multiple labels to be specified idiomatically.
type Robot struct { neogo.Label `neo4j:"Robot"` }
type Node ¶
Node is a base type for all nodes.
The neo4j tag is used to specify the label for the node. Multiple labels may be specified idiomatically by nested Node types. See internal/tests for examples.
type Person struct { neogo.Node `neo4j:"Person"` Name string `json:"name"` Age int `json:"age"` }
type Relationship ¶
type Relationship = internal.Relationship
Relationship is a base type for all relationships.
The neo4j tag is used to specify the type for the relationship.
type ActedIn struct { neogo.Relationship `neo4j:"ACTED_IN"` Role string `json:"role"` }
type Transaction ¶
type Transaction interface { // Run executes a statement on this transaction and returns a result // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. Run(work Work) error // Commit commits the transaction // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. Commit(ctx context.Context) error // Rollback rolls back the transaction // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. Rollback(ctx context.Context) error // Close rolls back the actual transaction if it's not already committed/rolled back // and closes all resources associated with this transaction // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. Close(ctx context.Context, joinedErrors ...error) error }
Transaction represents an explicit transaction that can be committed or rolled back.
type Valuer ¶
type Valuer[V neo4j.RecordValue] interface { Marshal() (*V, error) Unmarshal(*V) error }
Valuer allows arbitrary types to be marshalled into and unmarshalled from Neo4J data types. This allows any type (as oppposed to stdlib types, INode, IAbstract, IRelationship, and structs with json tags) to be used with neogo. The valid Neo4J data types are defined by neo4j.RecordValue.
For example, here we define a custom type MyString that marshals to and from a string, one of the types in the neo4j.RecordValue union:
type MyString string var _ Valuer[string] = (*MyString)(nil) func (s MyString) Marshal() (*string, error) { return func(s string) *string { return &s }(string(s)), nil } func (s *MyString) Unmarshal(v *string) error { *s = MyString(*v) return nil }
Directories
¶
Path | Synopsis |
---|---|
Package db provides building blocks for constructing Cypher clauses.
|
Package db provides building blocks for constructing Cypher clauses. |
Package query provides client interfaces for constructing and executing Cypher queries.
|
Package query provides client interfaces for constructing and executing Cypher queries. |