Developer Guide¶
Welcome to participating in GoGraph-related extensions and usage. This document summarizes practical development tips, best practices, and solutions to common problems.
1. Best Practices¶
Secure Parameterized Queries¶
To prevent Cypher injection risks and because pre-compiled parameters can improve executor performance, always use parameterized queries:
// Wrong example (prone to injection and poor performance):
// cypher := fmt.Sprintf("MATCH (n:User {name: '%s'}) RETURN n", userName)
// Recommended approach:
ctx := context.Background()
cypherQuery := "MATCH (n:User {name: $name}) RETURN n"
args := map[string]interface{}{
"name": "Alice",
}
rows, err := db.Query(ctx, cypherQuery, args)
Resource Release Habits¶
Cursor and transaction leaks can lead to system resource exhaustion and write deadlocks. Always use defer:
rows, err := db.Query(ctx, "MATCH (n) RETURN n")
if err != nil {
return err
}
defer rows.Close() // Key: release iterator internal resources
tx, _ := db.BeginTx(ctx, nil)
defer tx.Rollback() // Key: even if panic occurs, MVCC will be rolled back
// ...
tx.Commit() // Explicit commit
Observability Injection¶
GoGraph natively supports dependency injection for logging (Logger), distributed tracing (Tracer), and metrics collection (Meter), which greatly facilitates monitoring in microservice environments:
import "github.com/DotNetAge/gograph/pkg/cypher"
// Inject your custom Logger (must implement cypher.Logger interface)
obs := cypher.NewObservability(
cypher.WithLogger(myCustomLogger),
cypher.WithTracer(myOpenTelemetryTracer),
)
// Register with DB instance via Option pattern
db, err := api.Open("./data.db", api.WithObservability(obs))
2. Frequently Asked Questions (FAQ)¶
Why choose Pebble as the storage engine?¶
Pebble is a pure Go KV library developed by the CockroachDB team to replace RocksDB and LevelDB. It avoids CGO cross-platform compilation challenges while supporting WAL write-ahead logging, excellent write performance, and native MVCC (multi-version concurrency control) support. It is very suitable as an embedded database engine.
What is the MVCC locking mechanism?¶
GoGraph adopts a "read-write separation" design, relying on the underlying Pebble DB's NewBatch implementation:
- Read-write transactions can read in parallel, but when a write operation is submitted, if contention occurs (although currently guaranteed by application-level sync.RWMutex or the underlying layer), uncommitted data is invisible to other sessions.
- Dirty reads are completely avoided; read operations are never blocked by write operations.
What types of property values are supported?¶
In GoGraph, node and relationship properties PropertyValue core supports four types:
- string
- int64 (compatible with int, internally stored as int64)
- float64
- bool
If other typed objects are passed in, the internal implementation calls fmt.Sprintf("%v", v) to automatically convert them to strings, which may cause inconsistent side effects for data structure analysis. Please try to pass only supported primitive types.
3. Code and Coding Standards¶
- Option Pattern: Extension configuration for any component (such as
cypher.NewExecutor,api.Open) must follow the Functional Options paradigm to ensure API backward compatibility. - Error Handling: GoGraph's error design is explicit (such as
api.ErrDBClosed,api.ErrNoMoreRows). If the underlying layer returnspebble.ErrNotFound, please wrap it as a domain-related error incypher/apiat the upper layer. - Highly Cohesive Rich Domain Model: In the recent system refactoring, all underlying KV splicing and retrieval operations have been consolidated back to the
pkg/graphdomain layer (such asIndexandAdjacencyList).调度层Creator,Matcherand other scheduler layers should no longer bypass their authority to directly manipulate raw storage bytes. When adding new indexes and relationship features in the future, please follow thegraph.Mutatordesign pattern to delegate modifications back to the corresponding entity layer.
4. Performance Optimization¶
Utilizing Index Scan and Graph Traversal¶
For ultimate data retrieval performance, fully utilize the new engine's features when writing your Cypher queries:
- Specify Label to avoid full table scan: For MATCH (n:User), the engine will use Index Scan; if you directly MATCH (n) without a Label, the system can only degrade to executing full-database Node Key sequential scans, which can cause significant delays with massive data.
- Following the vine to utilize adjacency lists: GoGraph's relationship AdjacencyList perfectly supports O(1) pointer jumping. Once the starting node's ID is located, querying MATCH (n)-[r]->(m) will only pull m along the associated edges, without executing full-database joins (JOIN), keeping complex deep traversals at extremely low latency.