func (s *boltStmt) QueryPipeline(params ...map[string]interface{}) (PipelineRows, error) { if s.closed { return nil, errors.New("Neo4j Bolt statement already closed") } if s.rows != nil { return nil, errors.New("Another query is already open") } if len(params) != len(s.queries) { return nil, errors.New("Must pass same number of params as there are queries") } for i, query := range s.queries { err := s.conn.sendRunPullAll(query, params[i]) if err != nil { return nil, errors.Wrap(err, "Error running query:\n\n%s\n\nWith Params:\n%#v", query, params[i]) } } log.Info("Successfully ran all pipeline queries") resp, err := s.conn.consume() if err != nil { return nil, errors.Wrap(err, "An error occurred consuming initial pipeline command") } success, ok := resp.(messages.SuccessMessage) if !ok { return nil, errors.New("Got unexpected return message when consuming initial pipeline command: %#v", resp) } s.rows = newPipelineRows(s, success.Metadata, 0) return s.rows, nil }
func (s *boltStmt) ExecPipeline(params ...map[string]interface{}) ([]Result, error) { if s.closed { return nil, errors.New("Neo4j Bolt statement already closed") } if s.rows != nil { return nil, errors.New("Another query is already open") } if len(params) != len(s.queries) { return nil, errors.New("Must pass same number of params as there are queries") } for i, query := range s.queries { err := s.conn.sendRunPullAll(query, params[i]) if err != nil { return nil, errors.Wrap(err, "Error running exec query:\n\n%s\n\nWith Params:\n%#v", query, params[i]) } } log.Info("Successfully ran all pipeline queries") results := make([]Result, len(s.queries)) for i := range s.queries { runResp, err := s.conn.consume() if err != nil { return nil, errors.Wrap(err, "An error occurred getting result of exec command: %#v", runResp) } success, ok := runResp.(messages.SuccessMessage) if !ok { return nil, errors.New("Unexpected response when getting exec query result: %#v", runResp) } _, pullResp, err := s.conn.consumeAll() if err != nil { return nil, errors.Wrap(err, "An error occurred getting result of exec discard command: %#v", pullResp) } success, ok = pullResp.(messages.SuccessMessage) if !ok { return nil, errors.New("Unexpected response when getting exec query discard result: %#v", pullResp) } results[i] = newResult(success.Metadata) } return results, nil }
func (c *boltConn) consumeAllMultiple(mult int) ([][]interface{}, []interface{}, error) { log.Info("Consuming all responses %d times until success/failure", mult) responses := make([][]interface{}, mult) successes := make([]interface{}, mult) for i := 0; i < mult; i++ { resp, success, err := c.consumeAll() if err != nil { return responses, successes, err } responses[i] = resp successes[i] = success } return responses, successes, nil }
func (c *boltConn) consumeAll() ([]interface{}, interface{}, error) { log.Info("Consuming all responses until success/failure") responses := []interface{}{} for { respInt, err := c.consume() if err != nil { return nil, respInt, err } if success, isSuccess := respInt.(messages.SuccessMessage); isSuccess { log.Infof("Got success message: %#v", success) return responses, success, nil } responses = append(responses, respInt) } }
func TestMain(m *testing.M) { log.SetLevel(os.Getenv("BOLT_DRIVER_LOG")) neo4jConnStr = os.Getenv("NEO4J_BOLT") if neo4jConnStr != "" { log.Info("Using NEO4J for tests:", neo4jConnStr) } else if os.Getenv("ENSURE_NEO4J_BOLT") != "" { log.Fatal("Must give NEO4J_BOLT environment variable") } output := m.Run() if neo4jConnStr != "" { // If we're using a DB for testing neo, clear it out after all the test runs clearNeo() } os.Exit(output) }
func (c *boltConn) reset() error { log.Info("Resetting session") reset := messages.NewResetMessage() err := encoding.NewEncoder(c, c.chunkSize).Encode(reset) if err != nil { return errors.Wrap(err, "An error occurred encoding reset message") } for { respInt, err := encoding.NewDecoder(c).Decode() if err != nil { return errors.Wrap(err, "An error occurred decoding reset message response") } switch resp := respInt.(type) { case messages.IgnoredMessage: log.Infof("Got ignored message when resetting session: %#v", resp) continue case messages.SuccessMessage: log.Infof("Got success message when resetting session: %#v", resp) return nil case messages.FailureMessage: log.Errorf("Got failure message when resetting session: %#v", resp) err = c.Close() if err != nil { log.Errorf("An error occurred closing the session: %s", err) } return errors.New("Error resetting session: %#v. CLOSING SESSION!", resp) default: log.Errorf("Got unrecognized response from resetting session: %#v", resp) err = c.Close() if err != nil { log.Errorf("An error occurred closing the session: %s", err) } return errors.New("Got unrecognized response from resetting session: %#v. CLOSING SESSION!", resp) } } }
func (c *boltConn) consume() (interface{}, error) { log.Info("Consuming response from bolt stream") respInt, err := encoding.NewDecoder(c).Decode() if err != nil { return respInt, err } if log.GetLevel() >= log.TraceLevel { log.Tracef("Consumed Response: %#v", respInt) } if failure, isFail := respInt.(messages.FailureMessage); isFail { log.Errorf("Got failure message: %#v", failure) err := c.ackFailure(failure) if err != nil { return nil, err } return failure, errors.New("Got failure message: %#v", failure) } return respInt, err }
func TestBoltDriverPool_Concurrent(t *testing.T) { if neo4jConnStr == "" { t.Skip("Cannot run this test when in recording mode") } var wg sync.WaitGroup wg.Add(2) driver, err := NewDriverPool(neo4jConnStr, 2) if err != nil { t.Fatalf("An error occurred opening driver pool: %#v", err) } one := make(chan bool) two := make(chan bool) three := make(chan bool) four := make(chan bool) five := make(chan bool) six := make(chan bool) seven := make(chan bool) go func() { defer wg.Done() conn, err := driver.OpenPool() if err != nil { t.Fatalf("An error occurred opening conn: %s", err) } defer conn.Close() data, _, _, err := conn.QueryNeoAll(`MATCH (n) RETURN n`, nil) if err != nil { t.Fatalf("An error occurred querying neo: %s", err) } log.Info("1") one <- true <-two if len(data) != 0 { t.Fatalf("Expected no data: %#v", data) } data, _, _, err = conn.QueryNeoAll(`MATCH (n) RETURN n`, nil) if err != nil { t.Fatalf("An error occurred querying neo: %s", err) } log.Infof("data: %#v", data) if len(data) != 1 { t.Fatalf("Expected no data: %#v", data) } log.Info("3") three <- true <-four data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil) if err != nil { t.Fatalf("An error occurred querying neo: %s", err) } if len(data) != 1 { t.Fatalf("Expected no data: %#v", data) } log.Info("5") five <- true <-six data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil) if err != nil { t.Fatalf("An error occurred querying neo: %s", err) } if len(data) != 0 { t.Fatalf("Expected no data: %#v", data) } log.Info("7") seven <- true }() go func() { <-one defer wg.Done() conn, err := driver.OpenPool() if err != nil { t.Fatalf("An error occurred opening conn: %s", err) } defer conn.Close() _, err = conn.ExecNeo(`CREATE (f:FOO)`, nil) if err != nil { t.Fatalf("An error occurred creating f neo: %s", err) } log.Info("2") two <- true <-three _, err = conn.ExecNeo(`MATCH (f:FOO) CREATE UNIQUE (f)-[b:BAR]->(c:BAZ)`, nil) if err != nil { t.Fatalf("An error occurred creating f neo: %s", err) } log.Info("4") four <- true <-five _, err = conn.ExecNeo(`MATCH (:FOO)-[b:BAR]->(:BAZ) DELETE b`, nil) if err != nil { t.Fatalf("An error occurred creating f neo: %s", err) } _, err = conn.ExecNeo(`MATCH (n) DETACH DELETE n`, nil) if err != nil { t.Fatalf("An error occurred creating f neo: %s", err) } log.Info("6") six <- true <-seven }() wg.Wait() }