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

Neo4J Support #320

Merged
merged 27 commits into from
Jan 15, 2020
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ WORKDIR /go/src/github.com/golang-migrate/migrate
COPY . ./

ENV GO111MODULE=on
ENV DATABASES="postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver firebird"
ENV DATABASES="postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver firebird neo4j"
ENV SOURCES="file go_bindata github github_ee aws_s3 google_cloud_storage godoc_vfs gitlab"

RUN go build -a -o build/migrate.linux-386 -ldflags="-s -w -X main.Version=${VERSION}" -tags "$DATABASES $SOURCES" ./cmd/migrate
Expand Down
11 changes: 11 additions & 0 deletions database/neo4j/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# neo4j
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add docs about installing seabolt and statically linking OpenSSL to the README


`bolt://user:password@host:port/`
dhui marked this conversation as resolved.
Show resolved Hide resolved

| URL Query | WithInstance Config | Description |
|------------|---------------------|-------------|
| `user` | Contained within `AuthConfig` | The user to sign in as |
| `password` | Contained within `AuthConfig` | The user's password |
| `host` | | The host to connect to. Values that start with / are for unix domain sockets. (default is localhost) |
| `port` | | The port to bind to. (default is 7687) |
| | `MigrationsLabel` | Name of the migrations node label |
97 changes: 97 additions & 0 deletions database/neo4j/TUTORIAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
## Create migrations
Let's create nodes called `Users`:
```
migrate create -ext cypher -dir db/migrations -seq create_user_nodes
```
If there were no errors, we should have two files available under `db/migrations` folder:
- 000001_create_user_nodes.down.cypher
- 000001_create_user_nodes.up.cypher

Note the `cypher` extension that we provided.

In the `.up.cypher` file let's create the table:
```
CREATE (u1:User {name: "Peter"})
CREATE (u2:User {name: "Paul"})
CREATE (u3:User {name: "Mary"})
```
And in the `.down.sql` let's delete it:
```
MATCH (u:User) WHERE u.name IN ["Peter", "Paul", "Mary"] DELETE u
```
Ideally your migrations should be idempotent. You can read more about idempotency in [getting started](GETTING_STARTED.md#create-migrations)

## Run migrations
```
migrate -database ${NEO4J_URL} -path db/migrations up
```
Let's check if the table was created properly by running `bin/cypher-shell -u neo4j -p password`, then `neo4j> MATCH (u:User)`
The output you are supposed to see:
```
+-----------------------------------------------------------------+
| u |
+-----------------------------------------------------------------+
| (:User {name: "Peter") |
| (:User {name: "Paul") |
| (:User {name: "Mary") |
+-----------------------------------------------------------------+
```
Great! Now let's check if running reverse migration also works:
```
migrate -database ${NEO4J_URL} -path db/migrations down
```
Make sure to check if your database changed as expected in this case as well.

## Database transactions

To show database transactions usage, let's create another set of migrations by running:
```
migrate create -ext cypher -dir db/migrations -seq add_mood_to_users
```
Again, it should create for us two migrations files:
- 000002_add_mood_to_users.down.cypher
- 000002_add_mood_to_users.up.cypher

In Neo4j, when we want our queries to be done in a transaction, we need to wrap it with `:BEGIN` and `:COMMIT` commands.
Migration up:
```
:BEGIN

MATCH (u:User)
SET u.mood = "Cheery"

:COMMIT
```
Migration down:
```
:BEGIN

MATCH (u:User)
SET u.mood = null

:COMMIT
```

## Optional: Run migrations within your Go app
Here is a very simple app running migrations for the above configuration:
```
import (
"log"

"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/neo4j"
_ "github.com/golang-migrate/migrate/v4/source/file"
)

func main() {
m, err := migrate.New(
"file://db/migrations",
"bolt://neo4j:password@localhost:7687/")
dhui marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
log.Fatal(err)
}
if err := m.Up(); err != nil {
log.Fatal(err)
}
}
```
10 changes: 6 additions & 4 deletions database/neo4j/neo4j.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build cgo

package neo4j

import (
Expand All @@ -13,7 +15,6 @@ import (

func init() {
db := Neo4j{}
database.Register("bolt", &db)
database.Register("neo4j", &db)
}

Expand All @@ -25,7 +26,7 @@ var (

type Config struct {
AuthToken neo4j.AuthToken
URL string
URL string // if using WithInstance, don't provide auth in the URL, it will be ignored
MigrationsLabel string
}

Expand Down Expand Up @@ -66,9 +67,10 @@ func (n *Neo4j) Open(url string) (database.Driver, error) {
}
password, _ := uri.User.Password()
authToken := neo4j.BasicAuth(uri.User.Username(), password, "")
uri.User = nil

dhui marked this conversation as resolved.
Show resolved Hide resolved
return WithInstance(&Config{
URL: url,
URL: uri.String(),
AuthToken: authToken,
MigrationsLabel: DefaultMigrationsLabel,
})
Expand Down Expand Up @@ -182,7 +184,7 @@ func (n *Neo4j) Drop() error {
}
defer session.Close()

_, err = session.Run("MATCH (n) DETACH DELETE n", map[string]interface{}{})
_, err = session.Run("MATCH (n) DETACH DELETE n", nil)
return err
}

Expand Down
4 changes: 3 additions & 1 deletion database/neo4j/neo4j_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build cgo

package neo4j

import (
Expand Down Expand Up @@ -101,6 +103,6 @@ func TestMigrate(t *testing.T) {
if err != nil {
t.Fatal(err)
}
dt.TestMigrate(t, m, []byte("MATCH a RETURN a"))
dt.TestMigrate(t, m)
})
}