• Stars
    star
    494
  • Rank 89,130 (Top 2 %)
  • Language
    Go
  • License
    Apache License 2.0
  • Created over 6 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Neo4j Bolt Driver for Go

neo4j-go-driver

This is the official Neo4j Go Driver.

Getting the Driver

Go version prerequisites

The Go driver only works with actively maintained Go versions.

Read Go official release policy to learn more.

Module version

Make sure your application has been set up to use go modules (there should be a go.mod file in your application root).

5.x

Add the driver with:

go get github.com/neo4j/neo4j-go-driver/v5

4.x

Add the driver with:

go get github.com/neo4j/neo4j-go-driver/v4

1.x

For versions 1.x of the driver (notice the absence of /v4 or /v5), run instead the following:

go get github.com/neo4j/neo4j-go-driver

Documentation

Drivers manual that describes general driver concepts in depth here. Go package API documentation here.

Preview Features

The preview feature is a new feature that is a candidate for a future GA status.

It enables users to try the feature out and maintainers to refine and update it.

The preview features are not considered to be experimental, temporary or unstable.

However, they may change more rapidly, without following the usual deprecation cycle.

Most preview features are expected to be granted the GA status unless some unexpected conditions arise.

Due to the increased flexibility of the preview status, user feedback is encouraged so that it can be considered before the GA status.

Every preview feature gets a dedicated GitHub Discussion where users can share their initial impressions and thoughts.

Migrating from previous versions

See migration guide for information on how to migrate from previous versions of the driver to the current one.

Minimum Viable Snippet

Connect, execute a statement and handle results

Make sure to use the configuration in the code that matches the version of Neo4j server that you run.

package main

import (
    "context"
    "fmt"
    "github.com/neo4j/neo4j-go-driver/v5/neo4j"
)

func main() {
    dbUri := "neo4j://localhost" // scheme://host(:port) (default port is 7687)
    driver, err := neo4j.NewDriverWithContext(dbUri, neo4j.BasicAuth("neo4j", "letmein!", ""))
    if err != nil {
        panic(err)
    }
    // Starting with 5.0, you can control the execution of most driver APIs
    // To keep things simple, we create here a never-cancelling context
    // Read https://pkg.go.dev/context to learn more about contexts
    ctx := context.Background()
    // Handle driver lifetime based on your application lifetime requirements.
    // driver's lifetime is usually bound by the application lifetime, which usually implies one driver instance per
    // application

    defer driver.Close(ctx) // Make sure to handle errors during deferred calls
    item, err := insertItem(ctx, driver)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v\n", item)
}

func insertItem(ctx context.Context, driver neo4j.DriverWithContext) (*Item, error) {
    result, err := neo4j.ExecuteQuery(ctx, driver,
        "CREATE (n:Item { id: $id, name: $name }) RETURN n",
        map[string]any{
            "id":   1,
            "name": "Item 1",
        }, neo4j.EagerResultTransformer)
    if err != nil {
        return nil, err
    }
    itemNode, _, err := neo4j.GetRecordValue[neo4j.Node](result.Records[0], "n")
    if err != nil {
        return nil, fmt.Errorf("could not find node n")
    }
    id, err := neo4j.GetProperty[int64](itemNode, "id")
    if err != nil {
        return nil, err
    }
    name, err := neo4j.GetProperty[string](itemNode, "name")
    if err != nil {
        return nil, err
    }
    return &Item{Id: id, Name: name}, nil
}

type Item struct {
    Id   int64
    Name string
}

func (i *Item) String() string {
    return fmt.Sprintf("Item (id: %d, name: %q)", i.Id, i.Name)
}

Server/Driver compatibility

Starting with 5.0, the Neo4j Drivers will be moving to a monthly release cadence. A minor version will be released on the last Friday of each month so as to maintain versioning consistency with the core product (Neo4j DBMS) which has also moved to a monthly cadence.

As a policy, patch versions will not be released except on rare occasions. Bug fixes and updates will go into the latest minor version and users should upgrade to that. Driver upgrades within a major version will never contain breaking API changes.

See also: https://neo4j.com/developer/kb/neo4j-supported-versions/

Connecting to a causal cluster

You just need to use neo4j as the URL scheme and set host of the URL to one of your core members of the cluster.

if driver, err = neo4j.NewDriver("neo4j://localhost:7687", neo4j.BasicAuth("username", "password", "")); err != nil {
	return err // handle error
}

There are a few points that need to be highlighted:

  • Each Driver instance maintains a pool of connections inside, as a result, it is recommended to only use one driver per application.
  • It is considerably cheap to create new sessions and transactions, as sessions and transactions do not create new connections as long as there are free connections available in the connection pool.
  • The driver is thread-safe, while the session or the transaction is not thread-safe.

Parsing Result Values

Record Stream

A cypher execution result is comprised of a stream of records followed by a result summary. The records inside the result can be accessed via Next()/Record() functions defined on Result. It is important to check Err() after Next() returning false to find out whether it is the end of the result stream or an error that caused the end of result consumption.

	// Next returns false upon error
	for result.Next(ctx) {
		record := result.Record()
		handleRecord(record)
	}
	// Err returns the error that caused Next to return false
	if err = result.Err(); err != nil {
		handleError(err)
	}

Accessing Values in a Record

Values in a Record can be accessed either by index or by alias. The return value is an any which means you need to convert the interface to the expected type

value := record.Values[0]
if value, ok := record.Get('field_name'); ok {
	// a value with alias field_name was found
	// process value
}

Value Types

The driver exposes values in the record as an any type. The underlying types of the returned values depend on the corresponding Cypher types.

The mapping between Cypher types and the types used by this driver (to represent the Cypher type):

Cypher Type Driver Type
null nil
List []any
Map map[string]any
Boolean bool
Integer int64
Float float
String string
ByteArray []byte
Node neo4j.Node
Relationship neo4j.Relationship
Path neo4j.Path

Spatial Types - Point

Cypher Type Driver Type
Point neo4j.Point2D
Point neo4j.Point3D

The temporal types are introduced in Neo4j 3.4 series.

You can create a 2-dimensional Point value using;

point := neo4j.Point2D {X: 1.0, Y: 2.0, SpatialRefId: srId }

or a 3-dimensional point value using;

point := neo4j.Point3D {X: 1.0, Y: 2.0, Z: 3.0, SpatialRefId: srId }

NOTE:

  • For a list of supported srId values, please refer to the docs here.

Temporal Types - Date and Time

The temporal types are introduced in Neo4j 3.4 series. Given the fact that database supports a range of different temporal types, most of them are backed by custom types defined at the driver level.

The mapping among the Cypher temporal types and actual exposed types are as follows:

Cypher Type Driver Type
Date neo4j.Date
Time neo4j.OffsetTime
LocalTime neo4j.LocalTime
DateTime time.Time
LocalDateTime neo4j.LocalDateTime
Duration neo4j.Duration

Receiving a temporal value as driver type:

dateValue := record.Values[0].(neo4j.Date)

All custom temporal types can be constructed from a time.Time value using <Type>Of() (DateOf, OffsetTimeOf, ...) functions.

dateValue := DateOf(time.Date(2005, time.December, 16, 0, 0, 0, 0, time.Local)

Converting a custom temporal value into time.Time (all neo4j temporal types expose Time() function to gets its corresponding time.Time value):

dateValueAsTime := dateValue.Time()

Note:

  • When neo4j.OffsetTime is converted into time.Time or constructed through OffsetTimeOf(time.Time), its Location is given a fixed name of Offset (i.e. assigned time.FixedZone("Offset", offsetTime.offset)).
  • When time.Time values are sent/received through the driver, if its Zone() returns a name of Offset the value is stored with its offset value and with its zone name otherwise.

Logging

Logging at the driver level can be configured by setting Log field of neo4j.Config through configuration functions that can be passed to neo4j.NewDriver function.

Console Logger

For simplicity, we provide a predefined console logger which can be constructed by neo4j.ConsoleLogger function. To enable console logger, you need to specify which level you need to enable (neo4j.ERROR, neo4j.WARNING, neo4j.INFO and neo4j.DEBUG which are ordered by the level of detail).

A simple code snippet that will enable console logging is as follows;

useConsoleLogger := func(level neo4j.LogLevel) func(config *neo4j.Config) {
	return func(config *neo4j.Config) {
		config.Log = neo4j.ConsoleLogger(level)
	}
}

// Construct a new driver
if driver, err = neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""), useConsoleLogger(neo4j.ERROR)); err != nil {
	return err
}
defer driver.Close()

Custom Logger

The Log field of the neo4j.Config struct is defined to be of interface neo4j/log.Logger which has the following definition:

type Logger interface {
	Error(name string, id string, err error)
	Warnf(name string, id string, msg string, args ...any)
	Infof(name string, id string, msg string, args ...any)
	Debugf(name string, id string, msg string, args ...any)
}

For a customised logging target, you can implement the above interface and pass an instance of that implementation to the Log field.

Bolt tracing

Logging Bolt messages is done at the session level and is configured independently of the logging configuration described above. This is disabled by default.

Console Bolt logger

For simplicity, we provide a predefined console logger which can be constructed by neo4j.ConsoleBoltLogger.

boltLogger := neo4j.ConsoleBoltLogger()

# for ExecuteQuery
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, transformer, neo4j.ExecuteQueryWithBoltLogger(boltLogger))

# for the regular session APIs (session.Run, session.BeginTransaction, session.ExecuteRead, session.ExecuteWrite)
session := driver.NewSession(neo4j.SessionConfig{BoltLogger: boltLogger})

Custom Bolt Logger

The BoltLogger field of the neo4j.SessionConfig struct is defined to be of interface neo4j/log.BoltLogger which has the following definition:

type BoltLogger interface {
	LogClientMessage(context string, msg string, args ...any)
	LogServerMessage(context string, msg string, args ...any)
}

For a customised logging target, you can implement the above interface and pass an instance of that implementation to the BoltLogger field.

Development

This section describes instructions to use during the development phase of the driver.

Prerequisites

The Go driver on this branch requires at least Go 1.18 and relies on Go modules for dependency resolution.

Unit Testing

You can run unit tests as follows:

go test -tags internal_testkit,internal_time_mock -short ./...

Integration and Benchmark Testing

For these tests, you'll need to start a Neo4j server. This can be done with Neo4j Desktop or with the official Docker image:

docker run --rm \
  --env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
  --env NEO4J_AUTH=neo4j/password \
  --publish=7687:7687 \
  --health-cmd 'cypher-shell -u neo4j -p password "RETURN 1"' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 5 \
  neo4j:4.4-enterprise

Once the server is running, you run integration tests like this:

TEST_NEO4J_HOST="localhost" TEST_NEO4J_VERSION=4.4 \
  go test ./neo4j/test-integration/...

Likewise, benchmark tests are run like this:

cd benchmark
go run . neo4j://localhost neo4j password

All-In-One / Acceptance Testing

Tests require the latest Testkit, Python3 and Docker.

Testkit needs to be cloned and configured to run against the Go Driver. Use the following steps to configure it.

  1. Clone the Testkit repository
git clone https://github.com/neo4j-drivers/testkit.git
  1. Under the Testkit folder, install the requirements.
pip3 install -r requirements.txt
  1. Define the following required environment variables
export TEST_DRIVER_NAME=go
export TEST_DRIVER_REPO=<path for the root folder of driver repository>

To run test against some Neo4j version:

python3 main.py

More details about how to use Testkit can be found on its repository

More Repositories

1

neo4j

Graphs for Everyone
Java
13,266
star
2

NaLLM

Repository for the NaLLM project
TypeScript
1,253
star
3

neo4j-python-driver

Neo4j Bolt driver for Python
Python
898
star
4

neo4j-javascript-driver

Neo4j Bolt driver for JavaScript
JavaScript
853
star
5

neo4j-browser

Neo4j Browser is the general purpose user interface for working with Neo4j. Query, visualize, administrate and monitor the database.
TypeScript
690
star
6

graph-data-science

Source code for the Neo4j Graph Data Science library of graph algorithms.
Java
629
star
7

graphql

A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations.
TypeScript
504
star
8

docker-neo4j

Docker Images for the Neo4j Graph Database
Shell
333
star
9

neo4j-ogm

Java Object-Graph Mapping Library for Neo4j
Java
332
star
10

neo4j-java-driver

Neo4j Bolt driver for Java
Java
329
star
11

neo4j-spark-connector

Neo4j Connector for Apache Spark, which provides bi-directional read/write access to Neo4j from Spark, using the Spark DataSource APIs
Scala
313
star
12

neo4j-dotnet-driver

Neo4j Bolt driver for .NET
C#
231
star
13

cypher-dsl

A Java DSL (Builder) for the Cypher Query Language
Java
194
star
14

graph-data-science-client

A Python client for the Neo4j Graph Data Science (GDS) library
Python
191
star
15

neo4j-graphrag-python

Neo4j GraphRAG for Python
Python
172
star
16

neo4j-jdbc

Official Neo4j JDBC Driver
Java
135
star
17

neo4j-documentation

Scala
103
star
18

apoc

Java
94
star
19

cypher-shell

Cypher Shell has moved to https://github.com/neo4j/neo4j
Java
89
star
20

trillion-graph

A scale demo of Neo4j Fabric spanning up to 1129 machines/shards running a 100TB (LDBC) dataset with 1.2tn nodes and relationships.
Java
89
star
21

docker-neo4j-publish

Shell
83
star
22

sdn-rx

Nextgen Spring Data module for Neo4j supporting (not only) reactive data access and immutable support
Java
65
star
23

helm-charts

Go
59
star
24

cypher-builder

A library for building Cypher queries for Neo4j programmatically.
TypeScript
50
star
25

cypher-editor

Codemirror editor for Cypher, with syntax awareness and auto-completion
JavaScript
42
star
26

neo4j-java-driver-spring-boot-starter

Automatic configuration of Neo4j's Java Driver for Spring Boot applications
Java
33
star
27

cypher-language-support

Neo4j's Cypher Language support
TypeScript
31
star
28

neo4j-example-auth-plugins

Example authentication and authorization plugins for Neo4j
Java
17
star
29

neo4j-ogm-quarkus

Quarkus extension to that allows proper usage of Neo4j-OGM inside Quarkus.
Java
13
star
30

neo4j-python-driver-rust-ext

Optional Rust Extensions to Speed Up the Python Driver
Python
13
star
31

graphql-tracker-temp

This is a temporary repository for documentation and tracking issues for the @neo4j/graphql package until that repo is made public
12
star
32

docs-cypher

Neo4j Cypher Documentation
JavaScript
12
star
33

graph-schema-introspector

This is a Proof of concept (PoC) for a Neo4j schema introspector that produces output in JSON format validating against graph-schema-json-js-utils.
Java
11
star
34

docs-drivers

Neo4j Drivers Documentation
Python
10
star
35

windows-wrapper

A service wrapper for windows
Java
9
star
36

docs-bolt

Neo4j Bolt Protocol Documentation
JavaScript
7
star
37

neo4j.github.com

Web published resources
HTML
7
star
38

dappr

Distributed Approximate Personalised PageRank
Jupyter Notebook
6
star
39

docs-operations

Neo4j Operations documentation
JavaScript
6
star
40

docs-getting-started

JavaScript
6
star
41

jsr311-api

Forked from revision 612
Java
6
star
42

docs-graphql

GraphQL docs
JavaScript
5
star
43

doctools

Perl
5
star
44

graph-schema-json-js-utils

Utility library to work with the Graph Schema JSON representation
TypeScript
5
star
45

docs-aura

Jupyter Notebook
5
star
46

kafka-connector-workshop

TypeScript
4
star
47

neo4j-kafka-connector

Neo4j Kafka Connector
Kotlin
4
star
48

graphql-toolbox

TypeScript
4
star
49

github-action-traceability

TypeScript
4
star
50

docs-status-codes

Documentation for Neo4j status codes
JavaScript
4
star
51

parents

Neo4j Build Configuration
4
star
52

neo4j-aws-terraform

HCL
3
star
53

docs-http-api

Documentation for Neo4j HTTP API
JavaScript
3
star
54

jbang-catalog

JBang catalog
Java
2
star
55

import-spec

Java
2
star
56

docs-maven-plugin

Java
2
star
57

ease-maven-plugin

Java
2
star
58

license-maven-plugin

Fork of http://code.google.com/p/maven-license-plugin/
Java
2
star
59

maven-skin

Neo4j Maven Skin
Java
2
star
60

docs-bloom

JavaScript
1
star
61

docs-data-importer

JavaScript
1
star
62

azure-neo4j

Azure topology files
Shell
1
star
63

clirr-maven-plugin

Java
1
star
64

neo4jtester

neo4j tester
Go
1
star
65

docs-genai-tutorials

Python
1
star
66

docs-ops-manager

JavaScript
1
star