diff --git a/database/neo4j/README.md b/database/neo4j/README.md index 60b6ab507..f4a67e612 100644 --- a/database/neo4j/README.md +++ b/database/neo4j/README.md @@ -1,20 +1,33 @@ # neo4j -The Neo4j driver (bolt) does not natively support executing multiple statements in a single query. To allow for multiple statements in a single migration, you can use the `x-multi-statement` param. -This mode splits the migration text into separately-executed statements by a semi-colon `;`. Thus `x-multi-statement` cannot be used when a statement in the migration contains a string with a semi-colon. -The queries **should** run in a single transaction, so partial migrations should not be a concern, but this is untested. +The Neo4j driver (bolt) does not natively support executing multiple statements +in a single query. To allow for multiple statements in a single migration, you +can use the `x-multi-statement` param. This mode splits the migration text into +separately-executed statements by a semicolon `;`. Thus `x-multi-statement` +cannot be used when a statement in the migration contains a string with a +semicolon. The queries **should** run in a single transaction, so partial +migrations should not be a concern, but this is untested. +Here are possible connection URLs: -`neo4j://user:password@host:port/` +- `neo4j://user:password@host:port/` +- `neo4j+s://user:password@host:port/` +- `neo4j+ssc://user:password@host:port/` +- `bolt://user:password@host:port/` +- `bolt+s://user:password@host:port/` +- `bolt+ssc://user:password@host:port/` + +| URL Query | WithInstance Config | Description | +|---------------------|-------------------------------|------------------------------------------------------------------------------------------------------| +| `x-multi-statement` | `MultiStatement` | Enable multiple statements to be ran in a single migration (See note above) | +| `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 | -| URL Query | WithInstance Config | Description | -|------------|---------------------|-------------| -| `x-multi-statement` | `MultiStatement` | Enable multiple statements to be ran in a single migration (See note above) | -| `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 | ## Supported versions -Only Neo4j v3.5+ is [supported](https://github.com/neo4j/neo4j-go-driver/issues/64#issuecomment-625133600) +Neo4j v4.4 LTS and v5+ is supported. + +Make sure to check [End Of Life dates](https://neo4j.com/developer/kb/neo4j-supported-versions/) of Neo4j versions. \ 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 index 8e65d5aef..03d0fa6b2 100644 --- a/database/neo4j/examples/migrations/1578421040_create_movies_constraint.down.cypher +++ b/database/neo4j/examples/migrations/1578421040_create_movies_constraint.down.cypher @@ -1 +1 @@ -DROP CONSTRAINT ON (m:Movie) ASSERT m.Name IS UNIQUE \ No newline at end of file +DROP CONSTRAINT FOR (m:Movie) REQUIRE 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 index 4ca81fed1..06a46c17f 100644 --- a/database/neo4j/examples/migrations/1578421040_create_movies_constraint.up.cypher +++ b/database/neo4j/examples/migrations/1578421040_create_movies_constraint.up.cypher @@ -1 +1 @@ -CREATE CONSTRAINT ON (m:Movie) ASSERT m.Name IS UNIQUE \ No newline at end of file +CREATE CONSTRAINT FOR (m:Movie) REQUIRE m.Name IS UNIQUE \ No newline at end of file diff --git a/database/neo4j/neo4j.go b/database/neo4j/neo4j.go index 179e0da60..6ee59bda1 100644 --- a/database/neo4j/neo4j.go +++ b/database/neo4j/neo4j.go @@ -2,16 +2,19 @@ package neo4j import ( "bytes" + "context" "fmt" "io" neturl "net/url" "strconv" "sync/atomic" + "golang.org/x/mod/semver" + "github.com/golang-migrate/migrate/v4/database" "github.com/golang-migrate/migrate/v4/database/multistmt" "github.com/hashicorp/go-multierror" - "github.com/neo4j/neo4j-go-driver/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" ) func init() { @@ -37,14 +40,14 @@ type Config struct { } type Neo4j struct { - driver neo4j.Driver + driver neo4j.DriverWithContext lock uint32 // Open and WithInstance need to guarantee that config is never nil config *Config } -func WithInstance(driver neo4j.Driver, config *Config) (database.Driver, error) { +func WithInstance(driver neo4j.DriverWithContext, config *Config) (database.Driver, error) { if config == nil { return nil, ErrNilConfig } @@ -69,13 +72,9 @@ func (n *Neo4j) Open(url string) (database.Driver, error) { password, _ := uri.User.Password() authToken := neo4j.BasicAuth(uri.User.Username(), password, "") uri.User = nil - uri.Scheme = "bolt" msQuery := uri.Query().Get("x-multi-statement") - // Whether to turn on/off TLS encryption. - tlsEncrypted := uri.Query().Get("x-tls-encrypted") multi := false - encrypted := false if msQuery != "" { multi, err = strconv.ParseBool(uri.Query().Get("x-multi-statement")) if err != nil { @@ -83,13 +82,6 @@ func (n *Neo4j) Open(url string) (database.Driver, error) { } } - if tlsEncrypted != "" { - encrypted, err = strconv.ParseBool(tlsEncrypted) - if err != nil { - return nil, err - } - } - multiStatementMaxSize := DefaultMultiStatementMaxSize if s := uri.Query().Get("x-multi-statement-max-size"); s != "" { multiStatementMaxSize, err = strconv.Atoi(s) @@ -100,13 +92,15 @@ func (n *Neo4j) Open(url string) (database.Driver, error) { uri.RawQuery = "" - driver, err := neo4j.NewDriver(uri.String(), authToken, func(config *neo4j.Config) { - config.Encrypted = encrypted - }) + driver, err := neo4j.NewDriverWithContext(uri.String(), authToken) if err != nil { return nil, err } + if err = driver.VerifyConnectivity(context.Background()); err != nil { + return nil, err + } + return WithInstance(driver, &Config{ MigrationsLabel: DefaultMigrationsLabel, MultiStatement: multi, @@ -115,7 +109,7 @@ func (n *Neo4j) Open(url string) (database.Driver, error) { } func (n *Neo4j) Close() error { - return n.driver.Close() + return n.driver.Close(context.Background()) } // local locking in order to pass tests, Neo doesn't support database locking @@ -135,41 +129,46 @@ func (n *Neo4j) Unlock() error { } func (n *Neo4j) Run(migration io.Reader) (err error) { - session, err := n.driver.Session(neo4j.AccessModeWrite) - if err != nil { - return err - } + ctx := context.Background() + session := n.driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) defer func() { - if cerr := session.Close(); cerr != nil { + if cerr := session.Close(ctx); cerr != nil { err = multierror.Append(err, cerr) } }() if n.config.MultiStatement { - _, err = session.WriteTransaction(func(transaction neo4j.Transaction) (interface{}, error) { - var stmtRunErr error - if err := multistmt.Parse(migration, StatementSeparator, n.config.MultiStatementMaxSize, func(stmt []byte) bool { - trimStmt := bytes.TrimSpace(stmt) - if len(trimStmt) == 0 { - return true - } - trimStmt = bytes.TrimSuffix(trimStmt, StatementSeparator) - if len(trimStmt) == 0 { - return true - } - - result, err := transaction.Run(string(trimStmt), nil) - if _, err := neo4j.Collect(result, err); err != nil { - stmtRunErr = err - return false - } + tx, err := session.BeginTransaction(ctx) + if err != nil { + return err + } + defer func() { + if cerr := tx.Close(ctx); cerr != nil { + err = multierror.Append(err, cerr) + } + }() + + var stmtRunErr error + if err := multistmt.Parse(migration, StatementSeparator, n.config.MultiStatementMaxSize, func(stmt []byte) bool { + trimStmt := bytes.TrimSpace(stmt) + if len(trimStmt) == 0 { return true - }); err != nil { - return nil, err } - return nil, stmtRunErr - }) - return err + trimStmt = bytes.TrimSuffix(trimStmt, StatementSeparator) + if len(trimStmt) == 0 { + return true + } + + result, err := tx.Run(ctx, string(trimStmt), nil) + if _, err := neo4j.CollectWithContext(ctx, result, err); err != nil { + stmtRunErr = err + return false + } + return true + }); err != nil { + return err + } + return stmtRunErr } body, err := io.ReadAll(migration) @@ -177,24 +176,24 @@ func (n *Neo4j) Run(migration io.Reader) (err error) { return err } - _, err = neo4j.Collect(session.Run(string(body[:]), nil)) + res, err := session.Run(ctx, string(body[:]), nil) + _, err = neo4j.CollectWithContext(ctx, res, err) return err } func (n *Neo4j) SetVersion(version int, dirty bool) (err error) { - session, err := n.driver.Session(neo4j.AccessModeWrite) - if err != nil { - return err - } + ctx := context.Background() + session := n.driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) defer func() { - if cerr := session.Close(); cerr != nil { + if cerr := session.Close(ctx); cerr != nil { err = multierror.Append(err, cerr) } }() query := fmt.Sprintf("MERGE (sm:%s {version: $version}) SET sm.dirty = $dirty, sm.ts = datetime()", n.config.MigrationsLabel) - _, err = neo4j.Collect(session.Run(query, map[string]interface{}{"version": version, "dirty": dirty})) + res, err := session.Run(ctx, query, map[string]interface{}{"version": version, "dirty": dirty}) + _, err = neo4j.CollectWithContext(ctx, res, err) if err != nil { return err } @@ -207,12 +206,10 @@ type MigrationRecord struct { } func (n *Neo4j) Version() (version int, dirty bool, err error) { - session, err := n.driver.Session(neo4j.AccessModeRead) - if err != nil { - return database.NilVersion, false, err - } + ctx := context.Background() + session := n.driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) defer func() { - if cerr := session.Close(); cerr != nil { + if cerr := session.Close(ctx); cerr != nil { err = multierror.Append(err, cerr) } }() @@ -220,74 +217,78 @@ func (n *Neo4j) Version() (version int, dirty bool, err error) { query := fmt.Sprintf(`MATCH (sm:%s) RETURN sm.version AS version, sm.dirty AS dirty ORDER BY COALESCE(sm.ts, datetime({year: 0})) DESC, 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 = database.NilVersion - } else { - mr.Version = int(versionResult.(int64)) - } - dirtyResult, ok := record.Get("dirty") - if ok { - mr.Dirty = dirtyResult.(bool) - } + tx, err := session.BeginTransaction(ctx) - return mr, nil - } - return nil, result.Err() - }) + result, err := tx.Run(ctx, query, nil) if err != nil { return database.NilVersion, false, err } - if result == nil { - return database.NilVersion, false, err + if result.Next(ctx) { + record := result.Record() + mr := MigrationRecord{} + versionResult, ok := record.Get("version") + if !ok { + mr.Version = database.NilVersion + } else { + mr.Version = int(versionResult.(int64)) + } + + dirtyResult, ok := record.Get("dirty") + if ok { + mr.Dirty = dirtyResult.(bool) + } + + return mr.Version, mr.Dirty, nil } - mr := result.(MigrationRecord) - return mr.Version, mr.Dirty, err + + return database.NilVersion, false, err } func (n *Neo4j) Drop() (err error) { - session, err := n.driver.Session(neo4j.AccessModeWrite) - if err != nil { - return err - } + ctx := context.Background() + session := n.driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) defer func() { - if cerr := session.Close(); cerr != nil { + if cerr := session.Close(ctx); cerr != nil { err = multierror.Append(err, cerr) } }() - if _, err := neo4j.Collect(session.Run("MATCH (n) DETACH DELETE n", nil)); err != nil { + res, err := session.Run(ctx, "MATCH (n) DETACH DELETE n", nil) + if _, err := neo4j.CollectWithContext(ctx, res, err); err != nil { return err } return nil } func (n *Neo4j) ensureVersionConstraint() (err error) { - session, err := n.driver.Session(neo4j.AccessModeWrite) - if err != nil { - return err - } + ctx := context.Background() + session := n.driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) defer func() { - if cerr := session.Close(); cerr != nil { + if cerr := session.Close(ctx); cerr != nil { err = multierror.Append(err, cerr) } }() + var neo4jVersion string + result, err := session.Run(ctx, "call dbms.components() yield versions unwind versions as version return version", nil) + res, err := neo4j.CollectWithContext(ctx, result, err) + if err != nil { + return err + } + if len(res) > 0 && len(res[0].Values) > 0 { + if v, ok := res[0].Values[0].(string); ok { + neo4jVersion = semver.Major("v" + v) + } + } + /** Get constraint and check to avoid error duplicate using db.labels() to support Neo4j 3 and 4. Neo4J 3 doesn't support db.constraints() YIELD name */ - res, err := neo4j.Collect(session.Run(fmt.Sprintf("CALL db.labels() YIELD label WHERE label=\"%s\" RETURN label", n.config.MigrationsLabel), nil)) + result, err = session.Run(ctx, fmt.Sprintf("CALL db.labels() YIELD label WHERE label=\"%s\" RETURN label", n.config.MigrationsLabel), nil) + res, err = neo4j.CollectWithContext(ctx, result, err) if err != nil { return err } @@ -295,8 +296,18 @@ func (n *Neo4j) ensureVersionConstraint() (err error) { return nil } - query := fmt.Sprintf("CREATE CONSTRAINT ON (a:%s) ASSERT a.version IS UNIQUE", n.config.MigrationsLabel) - if _, err := neo4j.Collect(session.Run(query, nil)); err != nil { + var query string + switch neo4jVersion { + case "v5": + query = fmt.Sprintf("CREATE CONSTRAINT FOR (a:%s) REQUIRE a.version IS UNIQUE", n.config.MigrationsLabel) + case "v4": + query = fmt.Sprintf("CREATE CONSTRAINT ON (a:%s) ASSERT a.version IS UNIQUE", n.config.MigrationsLabel) + default: + return fmt.Errorf("unsupported neo4j version %v", neo4jVersion) + } + + result, err = session.Run(ctx, query, nil) + if _, err := neo4j.CollectWithContext(ctx, result, err); err != nil { return err } return nil diff --git a/database/neo4j/neo4j_test.go b/database/neo4j/neo4j_test.go index c8e914525..c17c236c2 100644 --- a/database/neo4j/neo4j_test.go +++ b/database/neo4j/neo4j_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/dhui/dktest" - "github.com/neo4j/neo4j-go-driver/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" "github.com/golang-migrate/migrate/v4" dt "github.com/golang-migrate/migrate/v4/database/testing" @@ -20,10 +20,10 @@ 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:4.0", Options: opts}, - {ImageName: "neo4j:4.0-enterprise", Options: opts}, - {ImageName: "neo4j:3.5", Options: opts}, - {ImageName: "neo4j:3.5-enterprise", Options: opts}, + {ImageName: "neo4j:5-community", Options: opts}, + //{ImageName: "neo4j:5-enterprise", Options: opts}, + {ImageName: "neo4j:4.4-community", Options: opts}, + //{ImageName: "neo4j:4.4-enterprise", Options: opts}, } ) @@ -37,32 +37,19 @@ func isReady(ctx context.Context, c dktest.ContainerInfo) bool { return false } - driver, err := neo4j.NewDriver( + driver, err := neo4j.NewDriverWithContext( neoConnectionString(ip, port), - neo4j.BasicAuth("neo4j", "migratetest", ""), - func(config *neo4j.Config) { - config.Encrypted = false - }) + neo4j.BasicAuth("neo4j", "migratetest", "")) if err != nil { return false } defer func() { - if err := driver.Close(); err != nil { + if err := driver.Close(ctx); 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 + err = driver.VerifyConnectivity(ctx) + return err == nil } func Test(t *testing.T) { diff --git a/go.mod b/go.mod index 851054ffd..0ff7beca3 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/microsoft/go-mssqldb v1.0.0 github.com/mutecomm/go-sqlcipher/v4 v4.4.0 github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 - github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba + github.com/neo4j/neo4j-go-driver/v5 v5.25.0 github.com/snowflakedb/gosnowflake v1.6.19 github.com/stretchr/testify v1.9.0 github.com/xanzy/go-gitlab v0.15.0 @@ -157,8 +157,6 @@ require ( github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/onsi/ginkgo v1.16.4 // indirect - github.com/onsi/gomega v1.15.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.16 // indirect @@ -178,7 +176,7 @@ require ( go.opencensus.io v0.24.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect - golang.org/x/mod v0.21.0 // indirect + golang.org/x/mod v0.21.0 golang.org/x/net v0.29.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect diff --git a/go.sum b/go.sum index 846e435b8..a9d671e03 100644 --- a/go.sum +++ b/go.sum @@ -184,9 +184,6 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsouza/fake-gcs-server v1.17.0 h1:OeH75kBZcZa3ZE+zz/mFdJ2btt9FgqfjI7gIh9+5fvk= github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q= @@ -205,7 +202,6 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= @@ -235,7 +231,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -247,7 +242,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -320,7 +314,6 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -493,22 +486,9 @@ github.com/mutecomm/go-sqlcipher/v4 v4.4.0 h1:sV1tWCWGAVlPhNGT95Q+z/txFxuhAYWwHD github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= 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/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba h1:fhFP5RliM2HW/8XdcO5QngSfFli9GcRIpMXvypTQt6E= -github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= +github.com/neo4j/neo4j-go-driver/v5 v5.25.0 h1:esvltei4tilM6hpG8m3THbbCN2872P39fzzCDaHOQkk= +github.com/neo4j/neo4j-go-driver/v5 v5.25.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= -github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -682,7 +662,6 @@ golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -698,12 +677,10 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -731,7 +708,6 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -745,17 +721,12 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -776,7 +747,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -821,7 +791,6 @@ golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= @@ -903,20 +872,15 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -991,5 +955,3 @@ modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= modernc.org/zappy v1.0.0 h1:dPVaP+3ueIUv4guk8PuZ2wiUGcJ1WUVvIheeSSTD0yk= modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=