diff --git a/.gitignore b/.gitignore index acb4088f2..1fd5860f8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ cli/migrate .godoc.pid vendor/ .vscode/ +.idea/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index c2367b3e1..ec44d4a02 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,11 @@ before_install: # Install golangci-lint - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.22.2 - echo "TRAVIS_GO_VERSION=${TRAVIS_GO_VERSION}" + # Install seabolt for Neo4j + - sudo apt-get install -y libssl1.0.0 + - wget https://github.com/neo4j-drivers/seabolt/releases/download/v1.7.4/seabolt-1.7.4-Linux-ubuntu-$(lsb_release -rs).deb + - sudo dpkg -i seabolt-1.7.4-Linux-ubuntu-$(lsb_release -rs).deb + - rm seabolt-1.7.4-Linux-ubuntu-$(lsb_release -rs).deb install: - go get github.com/mattn/goveralls diff --git a/Dockerfile b/Dockerfile index bd37e5f14..029c4c9d3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,12 +3,20 @@ ARG VERSION RUN apk add --no-cache git gcc musl-dev +# dependencies for neo4j +RUN apk add --update --no-cache ca-certificates cmake make g++ openssl-libs-static openssl-dev git curl pkgconfig + +# build seabolt for neo4j driver +RUN git clone -b 1.7 https://github.com/neo4j-drivers/seabolt.git /seabolt +WORKDIR /seabolt/build +RUN cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_LIBDIR=lib .. && cmake --build . --target install + 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 diff --git a/Makefile b/Makefile index 426f27a5a..19c8e386d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ SOURCE ?= file go_bindata github github_ee aws_s3 google_cloud_storage godoc_vfs gitlab DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver firebird +DATABASE_TEST ?= $(DATABASE) sqlite neo4j VERSION ?= $(shell git describe --tags 2>/dev/null | cut -c 2-) TEST_FLAGS ?= REPO_OWNER ?= $(shell cd .. && basename "$$(pwd)") @@ -34,7 +35,7 @@ test: test-with-flags: @echo SOURCE: $(SOURCE) - @echo DATABASE: $(DATABASE) + @echo DATABASE_TEST: $(DATABASE_TEST) @go test $(TEST_FLAGS) ./... diff --git a/README.md b/README.md index c9076cb3e..4f3da48a6 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Database drivers run migrations. [Add a new database?](database/driver.go) * [Cassandra](database/cassandra) * [SQLite](database/sqlite3) ([todo #165](https://github.com/mattes/migrate/issues/165)) * [MySQL/ MariaDB](database/mysql) -* [Neo4j](database/neo4j) ([todo #167](https://github.com/mattes/migrate/issues/167)) +* [Neo4j](database/neo4j) * [MongoDB](database/mongodb) * [CrateDB](database/crate) ([todo #170](https://github.com/mattes/migrate/issues/170)) * [Shell](database/shell) ([todo #171](https://github.com/mattes/migrate/issues/171)) diff --git a/database/driver.go b/database/driver.go index 2c673caaf..fa80f455c 100644 --- a/database/driver.go +++ b/database/driver.go @@ -13,7 +13,8 @@ import ( ) var ( - ErrLocked = fmt.Errorf("can't acquire lock") + ErrLocked = fmt.Errorf("can't acquire lock") + ErrNotLocked = fmt.Errorf("can't unlock, as not currently locked") ) const NilVersion int = -1 @@ -33,7 +34,7 @@ var drivers = make(map[string]Driver) // All other functions are tested by tests in database/testing. // Saves you some time and makes sure all database drivers behave the same way. // 5. Call Register in init(). -// 6. Create a migrate/cli/build_.go file +// 6. Create a internal/cli/build_.go file // 7. Add driver name in 'DATABASE' variable in Makefile // // Guidelines: @@ -61,7 +62,7 @@ type Driver interface { // all migrations have been run. Unlock() error - // Run applies a migration to the database. migration is garantueed to be not nil. + // Run applies a migration to the database. migration is guaranteed to be not nil. Run(migration io.Reader) error // SetVersion saves version and dirty state. diff --git a/database/neo4j/README.md b/database/neo4j/README.md index e69de29bb..4b93cb040 100644 --- a/database/neo4j/README.md +++ b/database/neo4j/README.md @@ -0,0 +1,11 @@ +# neo4j + +`neo4j://user:password@host:port/` + +| 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 | diff --git a/database/neo4j/TUTORIAL.md b/database/neo4j/TUTORIAL.md new file mode 100644 index 000000000..14bb1986c --- /dev/null +++ b/database/neo4j/TUTORIAL.md @@ -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", + "neo4j://neo4j:password@localhost:7687/") + if err != nil { + log.Fatal(err) + } + if err := m.Up(); err != nil { + log.Fatal(err) + } +} +``` \ No newline at end of file diff --git a/database/neo4j/examples/migrations/1578421040_create_movies_constraint.down.cypher b/database/neo4j/examples/migrations/1578421040_create_movies_constraint.down.cypher new file mode 100644 index 000000000..8e65d5aef --- /dev/null +++ b/database/neo4j/examples/migrations/1578421040_create_movies_constraint.down.cypher @@ -0,0 +1 @@ +DROP CONSTRAINT ON (m:Movie) ASSERT m.Name IS UNIQUE \ No newline at end of file diff --git a/database/neo4j/examples/migrations/1578421040_create_movies_constraint.up.cypher b/database/neo4j/examples/migrations/1578421040_create_movies_constraint.up.cypher new file mode 100644 index 000000000..4ca81fed1 --- /dev/null +++ b/database/neo4j/examples/migrations/1578421040_create_movies_constraint.up.cypher @@ -0,0 +1 @@ +CREATE CONSTRAINT ON (m:Movie) ASSERT m.Name IS UNIQUE \ No newline at end of file diff --git a/database/neo4j/examples/migrations/1578421725_create_movies.down.cypher b/database/neo4j/examples/migrations/1578421725_create_movies.down.cypher new file mode 100644 index 000000000..110dd68de --- /dev/null +++ b/database/neo4j/examples/migrations/1578421725_create_movies.down.cypher @@ -0,0 +1,2 @@ +MATCH (m:Movie) +DELETE m \ No newline at end of file diff --git a/database/neo4j/examples/migrations/1578421725_create_movies.up.cypher b/database/neo4j/examples/migrations/1578421725_create_movies.up.cypher new file mode 100644 index 000000000..5283d85ac --- /dev/null +++ b/database/neo4j/examples/migrations/1578421725_create_movies.up.cypher @@ -0,0 +1,2 @@ +CREATE (:Movie {name: "Footloose"}) +CREATE (:Movie {name: "Ghost"}) \ No newline at end of file diff --git a/database/neo4j/neo4j.go b/database/neo4j/neo4j.go new file mode 100644 index 000000000..f89338239 --- /dev/null +++ b/database/neo4j/neo4j.go @@ -0,0 +1,236 @@ +package neo4j + +import ( + "C" // import C so that we can't compile with CGO_ENABLED=0 + "fmt" + "github.com/hashicorp/go-multierror" + "io" + "io/ioutil" + neturl "net/url" + "sync/atomic" + + "github.com/golang-migrate/migrate/v4/database" + "github.com/neo4j/neo4j-go-driver/neo4j" +) + +func init() { + db := Neo4j{} + database.Register("neo4j", &db) +} + +var DefaultMigrationsLabel = "SchemaMigration" + +var ( + ErrNilConfig = fmt.Errorf("no config") +) + +type Config struct { + AuthToken neo4j.AuthToken + URL string // if using WithInstance, don't provide auth in the URL, it will be ignored + MigrationsLabel string +} + +type Neo4j struct { + driver neo4j.Driver + lock uint32 + + // Open and WithInstance need to guarantee that config is never nil + config *Config +} + +func WithInstance(config *Config) (database.Driver, error) { + if config == nil { + return nil, ErrNilConfig + } + + neoDriver, err := neo4j.NewDriver(config.URL, config.AuthToken) + if err != nil { + return nil, err + } + + driver := &Neo4j{ + driver: neoDriver, + config: config, + } + + if err := driver.ensureVersionConstraint(); err != nil { + return nil, err + } + + return driver, nil +} + +func (n *Neo4j) Open(url string) (database.Driver, error) { + uri, err := neturl.Parse(url) + if err != nil { + return nil, err + } + password, _ := uri.User.Password() + authToken := neo4j.BasicAuth(uri.User.Username(), password, "") + uri.User = nil + uri.Scheme = "bolt" + + return WithInstance(&Config{ + URL: uri.String(), + AuthToken: authToken, + MigrationsLabel: DefaultMigrationsLabel, + }) +} + +func (n *Neo4j) Close() error { + return n.driver.Close() +} + +// local locking in order to pass tests, Neo doesn't support database locking +func (n *Neo4j) Lock() error { + if !atomic.CompareAndSwapUint32(&n.lock, 0, 1) { + return database.ErrLocked + } + + return nil +} + +func (n *Neo4j) Unlock() error { + if !atomic.CompareAndSwapUint32(&n.lock, 1, 0) { + return database.ErrNotLocked + } + return nil +} + +func (n *Neo4j) Run(migration io.Reader) (err error) { + body, err := ioutil.ReadAll(migration) + if err != nil { + return err + } + + session, err := n.driver.Session(neo4j.AccessModeWrite) + if err != nil { + return err + } + defer func() { + if cerr := session.Close(); cerr != nil { + err = multierror.Append(err, cerr) + } + }() + + result, err := session.Run(string(body[:]), nil) + if err != nil { + return err + } + if err = result.Err(); err != nil { + return err + } + return nil +} + +func (n *Neo4j) SetVersion(version int, dirty bool) (err error) { + session, err := n.driver.Session(neo4j.AccessModeRead) + if err != nil { + return err + } + defer func() { + if cerr := session.Close(); cerr != nil { + err = multierror.Append(err, cerr) + } + }() + + query := fmt.Sprintf("MERGE (sm:%s {version: $version, dirty: $dirty})", + n.config.MigrationsLabel) + result, err := session.Run(query, map[string]interface{}{"version": version, "dirty": dirty}) + if err != nil { + return err + } + if err = result.Err(); err != nil { + return err + } + return nil +} + +type MigrationRecord struct { + Version int + Dirty bool +} + +func (n *Neo4j) Version() (version int, dirty bool, err error) { + session, err := n.driver.Session(neo4j.AccessModeRead) + if err != nil { + return -1, false, err + } + defer func() { + if cerr := session.Close(); cerr != nil { + err = multierror.Append(err, cerr) + } + }() + + query := fmt.Sprintf("MATCH (sm:%s) RETURN sm.version AS version, sm.dirty AS dirty ORDER BY sm.version DESC LIMIT 1", + n.config.MigrationsLabel) + result, err := session.ReadTransaction(func(transaction neo4j.Transaction) (interface{}, error) { + result, err := transaction.Run(query, nil) + if err != nil { + return nil, err + } + if result.Next() { + record := result.Record() + mr := MigrationRecord{} + versionResult, ok := record.Get("version") + if !ok { + mr.Version = -1 + } else { + mr.Version = int(versionResult.(int64)) + } + + dirtyResult, ok := record.Get("dirty") + if ok { + mr.Dirty = dirtyResult.(bool) + } + + return mr, nil + } + return nil, result.Err() + }) + if err != nil { + return -1, false, err + } + if result == nil { + return -1, false, err + } + mr := result.(MigrationRecord) + return mr.Version, mr.Dirty, err +} + +func (n *Neo4j) Drop() (err error) { + session, err := n.driver.Session(neo4j.AccessModeWrite) + if err != nil { + return err + } + defer func() { + if cerr := session.Close(); cerr != nil { + err = multierror.Append(err, cerr) + } + }() + + _, err = session.Run("MATCH (n) DETACH DELETE n", nil) + return err +} + +func (n *Neo4j) ensureVersionConstraint() (err error) { + session, err := n.driver.Session(neo4j.AccessModeWrite) + if err != nil { + return err + } + defer func() { + if cerr := session.Close(); cerr != nil { + err = multierror.Append(err, cerr) + } + }() + + query := fmt.Sprintf("CREATE CONSTRAINT ON (a:%s) ASSERT a.version IS UNIQUE", n.config.MigrationsLabel) + result, err := session.Run(query, nil) + if err != nil { + return err + } + if err = result.Err(); err != nil { + return err + } + return nil +} diff --git a/database/neo4j/neo4j_test.go b/database/neo4j/neo4j_test.go new file mode 100644 index 000000000..5e1ebe554 --- /dev/null +++ b/database/neo4j/neo4j_test.go @@ -0,0 +1,106 @@ +package neo4j + +import ( + "context" + "fmt" + "log" + "testing" + + "github.com/dhui/dktest" + "github.com/neo4j/neo4j-go-driver/neo4j" + + "github.com/golang-migrate/migrate/v4" + dt "github.com/golang-migrate/migrate/v4/database/testing" + "github.com/golang-migrate/migrate/v4/dktesting" + _ "github.com/golang-migrate/migrate/v4/source/file" +) + +var ( + opts = dktest.Options{PortRequired: true, ReadyFunc: isReady, + Env: map[string]string{"NEO4J_AUTH": "neo4j/migratetest", "NEO4J_ACCEPT_LICENSE_AGREEMENT": "yes"}} + specs = []dktesting.ContainerSpec{ + {ImageName: "neo4j:3.5", Options: opts}, + {ImageName: "neo4j:3.5-enterprise", Options: opts}, + {ImageName: "neo4j:3.4", Options: opts}, + {ImageName: "neo4j:3.4-enterprise", Options: opts}, + } +) + +func neoConnectionString(host, port string) string { + return fmt.Sprintf("bolt://neo4j:migratetest@%s:%s", host, port) +} + +func isReady(ctx context.Context, c dktest.ContainerInfo) bool { + ip, port, err := c.Port(7687) + if err != nil { + return false + } + + driver, err := neo4j.NewDriver(neoConnectionString(ip, port), neo4j.BasicAuth("neo4j", "migratetest", "")) + if err != nil { + return false + } + defer func() { + if err := driver.Close(); err != nil { + log.Println("close error:", err) + } + }() + session, err := driver.Session(neo4j.AccessModeRead) + if err != nil { + return false + } + result, err := session.Run("RETURN 1", nil) + if err != nil { + return false + } else if result.Err() != nil { + return false + } + + return true +} + +func Test(t *testing.T) { + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.Port(7687) + if err != nil { + t.Fatal(err) + } + + n := &Neo4j{} + d, err := n.Open(neoConnectionString(ip, port)) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := d.Close(); err != nil { + t.Error(err) + } + }() + dt.Test(t, d, []byte("MATCH a RETURN a")) + }) +} + +func TestMigrate(t *testing.T) { + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.Port(7687) + if err != nil { + t.Fatal(err) + } + + n := &Neo4j{} + d, err := n.Open(neoConnectionString(ip, port)) + if err != nil { + t.Fatal(err) + } + defer func() { + if err := d.Close(); err != nil { + t.Error(err) + } + }() + m, err := migrate.NewWithDatabaseInstance("file://./examples/migrations", "neo4j", d) + if err != nil { + t.Fatal(err) + } + dt.TestMigrate(t, m) + }) +} diff --git a/go.mod b/go.mod index 2cdf910c2..d9f199857 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,10 @@ require ( github.com/mattn/go-sqlite3 v1.10.0 github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 + github.com/neo4j-drivers/gobolt v1.7.4 // indirect + github.com/neo4j/neo4j-go-driver v1.7.4 github.com/pkg/errors v0.8.1 // indirect + github.com/prometheus/common v0.2.0 github.com/satori/go.uuid v1.2.0 // indirect github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect github.com/sirupsen/logrus v1.4.1 // indirect diff --git a/go.sum b/go.sum index 1823019d1..6e70bfefd 100644 --- a/go.sum +++ b/go.sum @@ -13,7 +13,9 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/aws/aws-sdk-go v1.17.7 h1:/4+rDPe0W95KBmNGYCG+NUvdL8ssPYBMxL+aSCg6nIA= @@ -57,6 +59,7 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/fake-gcs-server v1.7.0 h1:Un0BXUXrRWYSmYyC1Rqm2e2WJfTPyDy/HGMz31emTi8= github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= @@ -76,6 +79,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= @@ -109,6 +113,7 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= @@ -143,8 +148,14 @@ github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 h1:P48LjvUQpTReR3TQRbxSeSBsMXzfK0uol7eRcr7VBYQ= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= +github.com/neo4j-drivers/gobolt v1.7.4 h1:80c7W+vtw39ES9Q85q9GZh4tJo+1MpQGpFTuo28CP+Y= +github.com/neo4j-drivers/gobolt v1.7.4/go.mod h1:O9AUbip4Dgre+CD3p40dnMD4a4r52QBIfblg5k7CTbE= +github.com/neo4j/neo4j-go-driver v1.7.4 h1:BgVVwYkG3DWcZGiOPUOkwkd54sSg+UHDaLYz3aiNCek= +github.com/neo4j/neo4j-go-driver v1.7.4/go.mod h1:aPO0vVr+WnhEJne+FgFjfsjzAnssPFLucHgGZ76Zb/U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -162,6 +173,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -176,6 +188,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= @@ -283,15 +296,19 @@ google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/internal/cli/build_neo4j.go b/internal/cli/build_neo4j.go new file mode 100644 index 000000000..1f6b83a70 --- /dev/null +++ b/internal/cli/build_neo4j.go @@ -0,0 +1,7 @@ +// +build neo4j + +package cli + +import ( + _ "github.com/golang-migrate/migrate/v4/database/neo4j" +) \ No newline at end of file