Files
Mantas VidutisandDale Hui 7989e23e22 Neo4J Support (#320)
* initial pass

* new cli build file

* add ready function for docker start

* lowercase j

* explicit return

* test migration

* undo dockerfile change

* neo4j in dockerfile

* remove auth from url once transferred to auth token

* assorted review notes

* initial docs attempt

* unlock behavior more in line with lock behavior

* consistent naming

* linting

* seabolt in travis ci

* stdlib logger

* install seabolt as sudo

* enabled cgo

* correct version #

* remove neo4j todo

* named return values for errors

* review notes

* add libssl for alpine

* updates for review
2020-01-14 21:59:22 -08:00

2.7 KiB

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

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",
		"neo4j://neo4j:password@localhost:7687/")
	if err != nil {
		log.Fatal(err)
	}
	if err := m.Up(); err != nil {
		log.Fatal(err)
	}
}