Skip to content

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

  1. Option Pattern: Extension configuration for any component (such as cypher.NewExecutor, api.Open) must follow the Functional Options paradigm to ensure API backward compatibility.
  2. Error Handling: GoGraph's error design is explicit (such as api.ErrDBClosed, api.ErrNoMoreRows). If the underlying layer returns pebble.ErrNotFound, please wrap it as a domain-related error in cypher/api at the upper layer.
  3. Highly Cohesive Rich Domain Model: In the recent system refactoring, all underlying KV splicing and retrieval operations have been consolidated back to the pkg/graph domain layer (such as Index and AdjacencyList).调度层 Creator, Matcher and 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 the graph.Mutator design 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.