Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions databases/neo4j/neo4j.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,21 +191,24 @@ func (t *Transaction) Rollback(ctx context.Context) error {
}

// splitStatements splits a multi-statement query into individual statements.
// Statements are split when we see a new "starter" keyword (MATCH, CREATE, MERGE, etc.)
// at the beginning of a line, AND the previous accumulated statement looks complete
// (contains RETURN, or is a write-only statement like CREATE/DELETE).
// Statements are split when we see a new "starter" keyword (MATCH, MERGE, etc.)
// at the beginning of a line, AND the previous accumulated statement looks complete.
//
// A statement is complete if it has a RETURN clause. Write-only statements (CREATE, DELETE, etc.)
// are NOT considered complete on their own - they may be followed by more CREATE clauses
// that are part of the same logical statement.
func splitStatements(query string) []string {
lines := strings.Split(strings.TrimSpace(query), "\n")

var statements []string

var current strings.Builder

// These keywords can start a new statement. Split only happens if previous has RETURN.
starterKeywords := []string{"MATCH", "CREATE", "MERGE", "DETACH", "OPTIONAL", "CALL", "UNWIND", "FOREACH"}
writeKeywords := []string{"CREATE", "MERGE", "DELETE", "DETACH DELETE", "SET", "REMOVE"}

isStarter := func(s string) bool {
upper := strings.ToUpper(s)
upper := strings.ToUpper(strings.TrimSpace(s))
for _, kw := range starterKeywords {
if strings.HasPrefix(upper, kw) {
return true
Expand All @@ -217,18 +220,8 @@ func splitStatements(query string) []string {

isComplete := func(s string) bool {
upper := strings.ToUpper(s)
// Has RETURN clause
if strings.Contains(upper, "RETURN ") || strings.HasSuffix(upper, "RETURN") {
return true
}
// Is a write-only statement (CREATE, DELETE, etc. without needing RETURN)
for _, kw := range writeKeywords {
if strings.Contains(upper, kw) {
return true
}
}

return false
// Only complete if it has RETURN clause
return strings.Contains(upper, "RETURN ") || strings.HasSuffix(upper, "RETURN")
}

for _, line := range lines {
Expand Down