diff --git a/README.md b/README.md index b13c9fb..06fe754 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A collection of Datastore related Flogo contributions. This repository consists ### Activities * [couchbase](activity/couchbase): Couchbase * [mongodb](activity/mongodb): MongoDB +* [neo4j](activity/neo4j): Neo4j ## Contributing and support diff --git a/neo4j/activity/executeCypherQuery/README.md b/neo4j/activity/executeCypherQuery/README.md new file mode 100644 index 0000000..df21f65 --- /dev/null +++ b/neo4j/activity/executeCypherQuery/README.md @@ -0,0 +1,70 @@ + +# Neo4j Execute Cypher Query +This activity allows you to query Neo4j Graph DB using Cypher Query Language + +## Installation + +### Flogo CLI +```bash +flogo install github.com/project-flogo/datastore-contrib/neo4j/activity/executeCypherQuery +``` + +## Configuration + +### Settings: +| Name | Type | Description +| :--- | :--- | :--- +| connection | connection | Choose a Neo4j connection from the drop down - ***REQUIRED*** + +### Input: + +| Name | Type | Description +| :--- | :--- | :--- +| cypherQuery | string | The Cypher Query to execute + + +### Output: + +| Name | Type | Description +| :--- | :--- | :--- +| output | any | Returns cypher query execution response + +## Example + + +```json +{ + "id": "executeCypherQuery_2", + "name": "Neo4j Execute Cypher Query", + "description": "Neo4j Execute Cypher Query activity", + "activity": { + "ref": "#executeCypherQuery", + "input": { + "cypherQuery": "MATCH (n) RETURN n LIMIT 25" + }, + "settings": { + "accessMode": "Read", + "databaseName": "neo4j", + "connection": "conn://neo4jcon" + } + } +} + +"connections": { + "neo4jcon": { + "ref": "github.com/project-flogo/datastore-contrib/neo4j/connection", + "settings": { + "name": "neo4jcon", + "description": "", + "connectionURI": "bolt://localhost:7687", + "credType": "None", + "username": "", + "password": "" + } + } +} + +``` \ No newline at end of file diff --git a/neo4j/activity/executeCypherQuery/activity.go b/neo4j/activity/executeCypherQuery/activity.go new file mode 100644 index 0000000..e39a819 --- /dev/null +++ b/neo4j/activity/executeCypherQuery/activity.go @@ -0,0 +1,122 @@ +package executeCypherQuery + +import ( + "github.com/neo4j/neo4j-go-driver/neo4j" + "github.com/project-flogo/core/activity" + "github.com/project-flogo/core/data/coerce" + "github.com/project-flogo/core/data/metadata" + "github.com/project-flogo/core/support/log" +) + +var logquery = log.ChildLogger(log.RootLogger(), "neo4j-executecyppherquery") + +func init() { + err := activity.Register(&Activity{}, New) + if err != nil { + logquery.Errorf("Neo4j Execute Query Activity init error : %s ", err.Error()) + } +} + +// New functioncommon +func New(ctx activity.InitContext) (activity.Activity, error) { + settings := &Settings{} + err := metadata.MapToStruct(ctx.Settings(), settings, true) + if err != nil { + return nil, err + } + if settings.Connection != "" { + + neo4jcon, toConnerr := coerce.ToConnection(settings.Connection) + if toConnerr != nil { + return nil, toConnerr + } + driver := neo4jcon.GetConnection().(neo4j.Driver) + accessMode := neo4j.AccessModeRead + if settings.AccessMode != "Read" { + accessMode = neo4j.AccessModeWrite + } + act := &Activity{driver: driver, accessMode: accessMode, databaseName: settings.DatabaseName} + return act, nil + } + return nil, nil +} + +// Activity is a stub for your Activity implementation +type Activity struct { + driver neo4j.Driver + accessMode neo4j.AccessMode + databaseName string +} + +var activityMd = activity.ToMetadata(&Input{}, &Output{}) + +// Metadata implements activity.Activity.Metadata +func (a *Activity) Metadata() *activity.Metadata { + return activityMd +} + +//Cleanup method +func (a *Activity) Cleanup() error { + logquery.Debugf("cleaning up Neo4j activity") + return nil +} + +type NodeOutput struct { + Id int64 + Labels []string + Props map[string]interface{} +} + +// Eval implements activity.Activity.Eval +func (a *Activity) Eval(context activity.Context) (done bool, err error) { + logquery.Debugf("Executing neo4j cypher query Activity") + + input := &Input{} + err = context.GetInputObject(input) + if err != nil { + return true, nil + } + + sessionConfig := neo4j.SessionConfig{AccessMode: a.accessMode, DatabaseName: a.databaseName} + session, err := a.driver.NewSession(sessionConfig) + if err != nil { + logquery.Errorf("===session error==", err) + return false, err + } + + result, err := session.Run(input.CypherQuery, input.QueryParams) + if err != nil { + return false, err + } + + //nodeList := []NodeOutput{} + nodeList := []interface{}{} + for result.Next() { + keys := result.Record().Keys() + for i, _ := range keys { + record := result.Record().GetByIndex(i) + switch record.(type) { + case neo4j.Node: + node := record.(neo4j.Node) + nodeOutput := NodeOutput{Id: node.Id(), + Labels: node.Labels(), + Props: node.Props(), + } + nodeList = append(nodeList, nodeOutput) + case string: + node := record.(string) + nodeList = append(nodeList, node) + case int64: + node := record.(int64) + nodeList = append(nodeList, node) + case float64: + node := record.(float64) + nodeList = append(nodeList, node) + } + } + } + context.SetOutput("response", nodeList) + session.Close() + + return true, nil +} diff --git a/neo4j/activity/executeCypherQuery/activity_test.go b/neo4j/activity/executeCypherQuery/activity_test.go new file mode 100644 index 0000000..ecc77d6 --- /dev/null +++ b/neo4j/activity/executeCypherQuery/activity_test.go @@ -0,0 +1,172 @@ +package executeCypherQuery + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "testing" + + "github.com/project-flogo/core/activity" + "github.com/project-flogo/core/data/mapper" + "github.com/project-flogo/core/data/resolve" + "github.com/project-flogo/core/support" + "github.com/project-flogo/core/support/log" + "github.com/project-flogo/core/support/test" + _ "github.com/project-flogo/datastore-contrib/neo4j/connection" + "github.com/stretchr/testify/assert" +) + +var activityMetadata *activity.Metadata + +var settingsRead = `{ + "settings": { + "connection": { + "id": "e1e890d0-de91-11e9-aef0-13201957902e", + "name": "neo4jcon", + "ref": "github.com/project-flogo/datastore-contrib/neo4j/connection", + "settings": { + "name": "neo4jcon", + "description": "", + "connectionURI": "bolt://localhost:7687", + "credType": "None", + "username": "", + "password": "" + } + }, + "databaseName": "neo4j", + "accessMode": "Read" + } +}` + +var settingsWrite = `{ + "settings": { + "connection": { + "id": "e1e890d0-de91-11e9-aef0-13201957902e", + "name": "neo4jcon", + "ref": "github.com/project-flogo/datastore-contrib/neo4j/connection", + "settings": { + "name": "neo4jcon", + "description": "", + "connectionURI": "bolt://localhost:7687", + "credType": "None", + "username": "", + "password": "" + } + }, + "databaseName": "neo4j", + "accessMode": "Write" + } +}` + +func getActivityMetadata() *activity.Metadata { + + if activityMetadata == nil { + jsonMetadataBytes, err := ioutil.ReadFile("activity.json") + if err != nil { + panic("No Json Metadata found for activity.json path") + } + + activityMetadata = activity.ToMetadata(string(jsonMetadataBytes)) + } + + return activityMetadata +} +func TestMatchQuery(t *testing.T) { + log.RootLogger().Info("****TEST : Executing start****") + m := make(map[string]interface{}) + err1 := json.Unmarshal([]byte(settingsRead), &m) + assert.Nil(t, err1) + mf := mapper.NewFactory(resolve.GetBasicResolver()) + + support.RegisterAlias("connection", "connection", "github.com/project-flogo/datastore-contrib/neo4j/connection") + fmt.Println("=======Settings========", m["settings"]) + iCtx := test.NewActivityInitContext(m["settings"], mf) + act, err := New(iCtx) + assert.Nil(t, err) + tc := test.NewActivityContext(act.Metadata()) + //tc.SetInput("cypherQuery", "MATCH (n:Movie) RETURN n LIMIT 25") + tc.SetInput("cypherQuery", "MATCH (n) RETURN n LIMIT 25") + //tc.SetInput("cypherQuery", "MATCH (p:Person)-[:ACTED_IN]->(n:Movie) RETURN p LIMIT 25") + _, err = act.Eval(tc) + // Getting outputs + testOutput := tc.GetOutput("response") + jsonOutput, _ := json.Marshal(testOutput) + log.RootLogger().Infof("jsonOutput is : %s", string(jsonOutput)) + log.RootLogger().Info("****TEST : Executing ends****") + assert.Nil(t, err) +} + +func TestCreateQuery(t *testing.T) { + log.RootLogger().Info("****TEST : Executing start****") + m := make(map[string]interface{}) + err1 := json.Unmarshal([]byte(settingsWrite), &m) + assert.Nil(t, err1) + mf := mapper.NewFactory(resolve.GetBasicResolver()) + + support.RegisterAlias("connection", "connection", "github.com/project-flogo/datastore-contrib/neo4j/connection") + fmt.Println("=======Settings========", m["settings"]) + iCtx := test.NewActivityInitContext(m["settings"], mf) + act, err := New(iCtx) + assert.Nil(t, err) + tc := test.NewActivityContext(act.Metadata()) + //tc.SetInput("cypherQuery", "MATCH (n:Movie) RETURN n LIMIT 25") + tc.SetInput("cypherQuery", "CREATE (n:Item { id: $id, name: $name }) RETURN n.id, n.name") + tc.SetInput("queryParams", map[string]interface{}{"id": 11, "name": "Neel"}) + _, err = act.Eval(tc) + // Getting outputs + testOutput := tc.GetOutput("response") + jsonOutput, _ := json.Marshal(testOutput) + log.RootLogger().Infof("jsonOutput is : %s", string(jsonOutput)) + log.RootLogger().Info("****TEST : Executing ends****") + assert.Nil(t, err) +} + +func TestUpdateQuery(t *testing.T) { + log.RootLogger().Info("****TEST : Executing start****") + m := make(map[string]interface{}) + err1 := json.Unmarshal([]byte(settingsWrite), &m) + assert.Nil(t, err1) + mf := mapper.NewFactory(resolve.GetBasicResolver()) + + support.RegisterAlias("connection", "connection", "github.com/project-flogo/datastore-contrib/neo4j/connection") + fmt.Println("=======Settings========", m["settings"]) + iCtx := test.NewActivityInitContext(m["settings"], mf) + act, err := New(iCtx) + assert.Nil(t, err) + tc := test.NewActivityContext(act.Metadata()) + //tc.SetInput("cypherQuery", "MATCH (n:Movie) RETURN n LIMIT 25") + tc.SetInput("cypherQuery", "MATCH (p:Person {name: 'Tom Cruise'}) SET p.born = 2020 RETURN p") + //tc.SetInput("queryParams", map[string]interface{}{"id": 11, "name": "Neel"}) + _, err = act.Eval(tc) + // Getting outputs + testOutput := tc.GetOutput("response") + jsonOutput, _ := json.Marshal(testOutput) + log.RootLogger().Infof("jsonOutput is : %s", string(jsonOutput)) + log.RootLogger().Info("****TEST : Executing ends****") + assert.Nil(t, err) +} + +func TestDeleteQuery(t *testing.T) { + log.RootLogger().Info("****TEST : Executing start****") + m := make(map[string]interface{}) + err1 := json.Unmarshal([]byte(settingsWrite), &m) + assert.Nil(t, err1) + mf := mapper.NewFactory(resolve.GetBasicResolver()) + + support.RegisterAlias("connection", "connection", "github.com/project-flogo/datastore-contrib/neo4j/connection") + fmt.Println("=======Settings========", m["settings"]) + iCtx := test.NewActivityInitContext(m["settings"], mf) + act, err := New(iCtx) + assert.Nil(t, err) + tc := test.NewActivityContext(act.Metadata()) + //tc.SetInput("cypherQuery", "MATCH (n:Movie) RETURN n LIMIT 25") + tc.SetInput("cypherQuery", "MATCH (p:Person {name: 'Jack Nicholson'}) DETACH DELETE p") + //tc.SetInput("queryParams", map[string]interface{}{"id": 11, "name": "Neel"}) + _, err = act.Eval(tc) + // Getting outputs + testOutput := tc.GetOutput("response") + jsonOutput, _ := json.Marshal(testOutput) + log.RootLogger().Infof("jsonOutput is : %s", string(jsonOutput)) + log.RootLogger().Info("****TEST : Executing ends****") + assert.Nil(t, err) +} diff --git a/neo4j/activity/executeCypherQuery/descriptor.json b/neo4j/activity/executeCypherQuery/descriptor.json new file mode 100644 index 0000000..c9b7d6d --- /dev/null +++ b/neo4j/activity/executeCypherQuery/descriptor.json @@ -0,0 +1,46 @@ +{ + "name": "neo4j-executeCypherQuery", + "title": "Neo4j Execute Cypher Query", + "version": "0.1.0", + "author": "TIBCO Software Inc.", + "type": "flogo:activity", + "description": "Neo4j Execute Cypher Query activity", + "settings": [ + { + "name": "connection", + "type": "connection", + "required": true + }, + { + "name": "databaseName", + "type": "string", + "required": true + }, + { + "name": "accessMode", + "type": "string", + "required": true, + "allowed": [ + "Read", + "Write" + ] + } + ], + "input":[ + { + "name": "cypherQuery", + "type": "string", + "required": true + }, + { + "name": "queryParams", + "type": "object" + } + ], + "output": [ + { + "name": "response", + "type": "object" + } + ] +} \ No newline at end of file diff --git a/neo4j/activity/executeCypherQuery/metadata.go b/neo4j/activity/executeCypherQuery/metadata.go new file mode 100644 index 0000000..1971d12 --- /dev/null +++ b/neo4j/activity/executeCypherQuery/metadata.go @@ -0,0 +1,60 @@ +package executeCypherQuery + +import ( + "github.com/project-flogo/core/data/coerce" +) + +// Settings structure +type Settings struct { + Connection string `md:"connection,required"` // The Neo4j connection + DatabaseName string `md:"databaseName,required"` + AccessMode string `md:"accessMode,required"` +} + +//Input structure +type Input struct { + CypherQuery string `md:"cypherQuery,required"` // The cypher query + QueryParams map[string]interface{} `md:"queryParams"` +} + +//Output structure +type Output struct { + Output interface{} `md:"response"` // The JSON Response of the query +} + +//FromMap method +func (i *Input) FromMap(values map[string]interface{}) error { + var err error + i.CypherQuery, err = coerce.ToString(values["cypherQuery"]) + if err != nil { + return err + } + i.QueryParams, err = coerce.ToObject(values["queryParams"]) + return err +} + +//ToMap method +func (i *Input) ToMap() map[string]interface{} { + return map[string]interface{}{ + "cypherQuery": i.CypherQuery, + "queryParams": i.QueryParams, + } +} + +//ToMap Output +func (o *Output) ToMap() map[string]interface{} { + return map[string]interface{}{ + "response": o.Output, + } +} + +//FromMap Output +func (o *Output) FromMap(values map[string]interface{}) error { + var err error + o.Output, err = (values["response"]) + if err != nil { + return err + } + + return nil +} diff --git a/neo4j/connection/README.md b/neo4j/connection/README.md new file mode 100644 index 0000000..3ffde06 --- /dev/null +++ b/neo4j/connection/README.md @@ -0,0 +1,53 @@ + +# Neo4j Connection +This connection allows you to configure properties necessary to establish a connection with a Neo4j Graph DB. A Neo4j Connection is necessary to work with the activities and trigger under neo4j contribution. + +## Installation + +### Flogo CLI +```bash +flogo install github.com/project-flogo/datastore-contrib/neo4j/connection +``` + +## Configuration + +### Settings: +| Name | Type | Description +| :--- | :--- | :--- +| name | string | A name for the connection - ***REQUIRED*** +| description | string | A short description for the connection +| connectionURI | string | Neo4j instance connection URI - ***REQUIRED*** +| credType | string | Credential Type e.g None, BasicAuth +| username | string | Username of the Neo4j instance +| password | string | Password of the Neo4j instance + +## Example +A sample Neo4j connection + +```json +"connections": { + "neo4jcon": { + "ref": "github.com/project-flogo/datastore-contrib/neo4j/connection", + "settings": { + "name": "neo4jcon", + "description": "", + "connectionURI": "bolt://localhost:7687", + "credType": "None", + "username": "", + "password": "" + } + } +} +``` + +## Testing + +Launch Neo4j docker container using below command +```bash +docker run --publish=7474:7474 --publish=7687:7687 --volume=$HOME/neo4j/data:/data neo4j +``` +Open "http://localhost:7474/browser" and verify connectivity. You can optionally load sample data by running ":play movie-graph" command and follow the steps. + diff --git a/neo4j/connection/connection.go b/neo4j/connection/connection.go new file mode 100644 index 0000000..4e18d08 --- /dev/null +++ b/neo4j/connection/connection.go @@ -0,0 +1,124 @@ +package neo4jconnection + +import ( + "github.com/neo4j/neo4j-go-driver/neo4j" + "github.com/project-flogo/core/data/coerce" + "github.com/project-flogo/core/data/metadata" + "github.com/project-flogo/core/support/connection" + "github.com/project-flogo/core/support/log" +) + +var logneo4jconn = log.ChildLogger(log.RootLogger(), "neo4j-connection") +var factory = &neo4jFactory{} + +// Settings struct +type Settings struct { + Name string `md:"name,required"` + Description string `md:"description"` + ConnectionURI string `md:"connectionURI,required"` + CredType string `md:"credType,required"` + UserName string `md:"username"` + Password string `md:"password"` +} + +func init() { + err := connection.RegisterManagerFactory(factory) + if err != nil { + panic(err) + } +} + +type neo4jFactory struct { +} + +func (*neo4jFactory) Type() string { + return "neo4j" +} + +func (*neo4jFactory) NewManager(settings map[string]interface{}) (connection.Manager, error) { + sharedConn := &Neo4jSharedConfigManager{} + var err error + sharedConn.config, err = getNeo4jClientConfig(settings) + if err != nil { + return nil, err + } + if sharedConn.driver != nil { + return sharedConn, nil + } + + url := sharedConn.config.ConnectionURI + credType := sharedConn.config.CredType + username := sharedConn.config.UserName + password := sharedConn.config.Password + + configForNeo4j40 := func(conf *neo4j.Config) { conf.Encrypted = false } + + auth := neo4j.NoAuth() + if credType != "None" { + auth = neo4j.BasicAuth(username, password, "") + } + + driver, err := neo4j.NewDriver(url, auth, configForNeo4j40) + if err != nil { + logneo4jconn.Errorf("===driver error==", err) + return nil, err + } + + sharedConn.driver = driver + logneo4jconn.Debugf("Returning neo4j connection") + return sharedConn, nil +} + +// Neo4jSharedConfigManager Structure +type Neo4jSharedConfigManager struct { + config *Settings + name string + driver neo4j.Driver +} + +// Type of SharedConfigManager +func (k *Neo4jSharedConfigManager) Type() string { + return "neo4j" +} + +// GetConnection ss +func (k *Neo4jSharedConfigManager) GetConnection() interface{} { + return k.driver +} + +// ReleaseConnection ss +func (k *Neo4jSharedConfigManager) ReleaseConnection(connection interface{}) { + +} + +// Start connection manager +func (k *Neo4jSharedConfigManager) Start() error { + return nil +} + +// Stop connection manager +func (k *Neo4jSharedConfigManager) Stop() error { + logneo4jconn.Debug("Cleaning up client connection cache") + k.driver.Close() + return nil +} + +// GetSharedConfiguration function to return Neo4j connection manager +func GetSharedConfiguration(conn interface{}) (connection.Manager, error) { + var cManager connection.Manager + var err error + cManager, err = coerce.ToConnection(conn) + if err != nil { + return nil, err + } + return cManager, nil +} + +func getNeo4jClientConfig(settings map[string]interface{}) (*Settings, error) { + connectionConfig := &Settings{} + err := metadata.MapToStruct(settings, connectionConfig, false) + if err != nil { + return nil, err + } + return connectionConfig, nil +} diff --git a/neo4j/connection/descriptor.json b/neo4j/connection/descriptor.json new file mode 100644 index 0000000..5ab746a --- /dev/null +++ b/neo4j/connection/descriptor.json @@ -0,0 +1,44 @@ +{ + "name": "neo4j-connector", + "title": "Neo4j Connector", + "author": "TIBCO Software Inc.", + "type": "flogo:connector", + "version": "0.1.0", + "settings": [ + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "description", + "type": "string" + }, + { + "name": "connectionURI", + "type": "string", + "required": true, + "value": "bolt://localhost:7687" + }, + { + "name": "credType", + "type": "string", + "required": true, + "allowed": [ + "None", + "BasicAuth" + ], + "value": "None" + }, + { + "name": "username", + "type": "string", + "required": false + }, + { + "name": "password", + "type": "password", + "required": false + } + ] +} \ No newline at end of file diff --git a/neo4j/go.mod b/neo4j/go.mod new file mode 100644 index 0000000..3fc5ad1 --- /dev/null +++ b/neo4j/go.mod @@ -0,0 +1,9 @@ +module github.com/project-flogo/datastore-contrib/neo4j + +go 1.13 + +require ( + github.com/neo4j/neo4j-go-driver v1.8.0 + github.com/project-flogo/core v1.0.0 + github.com/stretchr/testify v1.6.1 +) diff --git a/neo4j/go.sum b/neo4j/go.sum new file mode 100644 index 0000000..978d081 --- /dev/null +++ b/neo4j/go.sum @@ -0,0 +1,101 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195 h1:c4mLfegoDw6OhSJXTd2jUEQgZUQuJWtocudb97Qn9EM= +github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/neo4j/neo4j-go-driver v1.8.0 h1:YRp9jsFcF9k/AnvbcqFCN9OMeIT2XTJgxOpp2Puq7OE= +github.com/neo4j/neo4j-go-driver v1.8.0/go.mod h1:0A49wIv0oP3uQdnbceK7Kc+snlY5B0F6dmtYArM0ltk= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/project-flogo/core v1.0.0 h1:OdJWU89NZcM+YTNWcAQ+yN5/fGN7qCxfTrI0rQ3FrRI= +github.com/project-flogo/core v1.0.0/go.mod h1:dt3AJeC/QzrgGSoPoZBEdyqR6UAqSMRppz4E47FWmYU= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=