Go Embedded
Run Traverse as an embedded graph database in Go applications.
Install
Download the Go SDK and add it as a local module:
# Download the SDK
curl -LO https://api.truespar.com/api/versions/traverse-sdk-go/latest/download
tar xzf traverse-sdk-go-*.tar.gz
# Add to your project
go mod edit -require truespar.com/traverse-go@v0.0.0
go mod edit -replace truespar.com/traverse-go=./traverse-sdk-go-0.6.7
Note: No CGo required. The native library is loaded at runtime. Set TRAVERSE_FFI_LIB to specify the library path, or place it alongside your executable.
Open a Database
package main
import (
"fmt"
"log"
"truespar.com/traverse-go"
)
func main() {
// Open or create a database
db, err := traverse.Open("mydb.tvdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
Run Queries
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
result, err := tx.Execute("MATCH (n:Person) RETURN n.name, n.age")
if err != nil {
tx.Abort()
log.Fatal(err)
}
for _, row := range result.Rows {
fmt.Println(row["n.name"], row["n.age"])
}
tx.Abort() // read-only, no changes to commit
Write Data
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
_, err = tx.Execute("CREATE (p:Person {name: 'Alice', age: 30})")
if err != nil {
tx.Abort()
log.Fatal(err)
}
_, err = tx.Execute("CREATE (p:Person {name: 'Bob', age: 25})")
if err != nil {
tx.Abort()
log.Fatal(err)
}
if err := tx.Commit(); err != nil {
log.Fatal(err)
}
Note: You must call Commit() to persist changes. Call Abort() to discard them. Once committed or aborted, the transaction cannot be reused.
QueryResult
tx, _ := db.Begin()
result, _ := tx.Execute("MATCH (n:Person) RETURN n.name, n.age")
fmt.Println(result.Columns) // [n.name n.age]
fmt.Println(result.RowCount) // number of rows
// Rows are []map[string]interface{}
for _, row := range result.Rows {
name := row["n.name"].(string)
age := row["n.age"].(int64)
fmt.Printf("%s is %d years old\n", name, age)
}
// Node values
result, _ = tx.Execute("MATCH (n:Person) RETURN n LIMIT 1")
node := result.Rows[0]["n"].(traverse.Node)
fmt.Println(node.ID, node.Labels, node.Properties)
// Edge values
result, _ = tx.Execute("MATCH ()-[r:KNOWS]->() RETURN r LIMIT 1")
edge := result.Rows[0]["r"].(traverse.Edge)
fmt.Println(edge.Type, edge.Source, edge.Target)
tx.Abort()
Bulk Writer
The BulkWriter bypasses MVCC for high-throughput imports (2–5M rows/s).
writer, err := db.BulkWriter()
if err != nil {
log.Fatal(err)
}
nid1, err := writer.CreateNode(
[]string{"Person"},
map[string]string{"name": "Alice", "age": "30"},
)
if err != nil {
writer.Abort()
log.Fatal(err)
}
nid2, err := writer.CreateNode(
[]string{"Person"},
map[string]string{"name": "Bob", "age": "25"},
)
if err != nil {
writer.Abort()
log.Fatal(err)
}
_, err = writer.CreateEdge(nid1, nid2, "KNOWS", map[string]string{"since": "2024"})
if err != nil {
writer.Abort()
log.Fatal(err)
}
if err := writer.Commit(); err != nil {
log.Fatal(err)
}
Note: The Go bulk writer takes properties as map[string]string; values are auto-type-inferred (numbers, booleans, strings).
Indexes
Create indexes via the bulk writer or Cypher:
// Via BulkWriter
writer, _ := db.BulkWriter()
writer.CreateIndex("idx_person_name", "Person", "name")
writer.CreateEdgeIndex("idx_knows_since", "KNOWS", "since")
writer.CreateEdgeIndex("idx_knows", "KNOWS", "") // type-only index (empty property)
writer.Commit()
// Via Cypher
tx, _ := db.Begin()
tx.Execute("CREATE INDEX idx_person_age FOR (n:Person) ON (n.age)")
tx.Commit()
Flush and Close
// Flush dirty pages to disk
if err := db.Flush(); err != nil {
log.Fatal(err)
}
// Close the database
if err := db.Close(); err != nil {
log.Fatal(err)
}
Note: Traverse is an in-memory database. Call Flush() to persist data to the .tvdb file. Data written since the last flush is lost if the process crashes.
Error Handling
db, err := traverse.Open("mydb.tvdb")
if err != nil {
// Check error type
if tvErr, ok := err.(*traverse.TraverseError); ok {
fmt.Println("Error code:", tvErr.Code)
fmt.Println("Message:", tvErr.Message)
}
}
Error codes include:
traverse.ErrIO // I/O error
traverse.ErrSyntax // Cypher syntax error
traverse.ErrType // Type mismatch
traverse.ErrSemantic // Semantic error
traverse.ErrGraph // Graph constraint violation
traverse.ErrTransaction // Transaction error
traverse.ErrInvalidArg // Invalid argument