C API¶
C-compatible FFI layer for embedding Grafeo in any language. Used by the Go bindings via CGO, the C# bindings via P/Invoke, and the Dart bindings via dart:ffi.
Building¶
Output:
target/release/libgrafeo_c.so(Linux)target/release/libgrafeo_c.dylib(macOS)target/release/grafeo_c.dll(Windows)
Header: crates/bindings/c/grafeo.h
Quick Start¶
#include "grafeo.h"
#include <stdio.h>
int main(void) {
/* Open an in-memory database (returns NULL on error) */
GrafeoDatabase *db = grafeo_open_memory();
if (!db) {
fprintf(stderr, "Error: %s\n", grafeo_last_error());
return 1;
}
/* Create nodes with labels (JSON array) and properties (JSON object) */
uint64_t alix = grafeo_create_node(db, "[\"Person\"]", "{\"name\":\"Alix\",\"age\":30}");
uint64_t gus = grafeo_create_node(db, "[\"Person\"]", "{\"name\":\"Gus\",\"age\":25}");
/* Create an edge between them */
grafeo_create_edge(db, alix, gus, "KNOWS", "{\"since\":2020}");
/* Execute a GQL query */
GrafeoResult *r = grafeo_execute(db, "MATCH (p:Person) RETURN p.name, p.age");
if (r) {
printf("Rows: %zu\n", grafeo_result_row_count(r));
printf("JSON: %s\n", grafeo_result_json(r));
grafeo_free_result(r);
} else {
fprintf(stderr, "Query error: %s\n", grafeo_last_error());
}
grafeo_close(db);
grafeo_free_database(db);
return 0;
}
Compile:
Error Handling¶
Functions that return pointers (GrafeoDatabase*, GrafeoResult*, GrafeoTransaction*) return NULL on error. Functions that return GrafeoStatus return GRAFEO_OK (0) on success. In both cases, call grafeo_last_error() on failure for a human-readable message:
GrafeoResult *r = grafeo_execute(db, query);
if (!r) {
fprintf(stderr, "Error: %s\n", grafeo_last_error());
}
Status Codes¶
typedef enum {
GRAFEO_OK = 0,
GRAFEO_ERROR_DATABASE = 1,
GRAFEO_ERROR_QUERY = 2,
GRAFEO_ERROR_TRANSACTION = 3,
GRAFEO_ERROR_STORAGE = 4,
GRAFEO_ERROR_IO = 5,
GRAFEO_ERROR_SERIALIZATION = 6,
GRAFEO_ERROR_INTERNAL = 7,
GRAFEO_ERROR_NULL_POINTER = 8,
GRAFEO_ERROR_INVALID_UTF8 = 9
} GrafeoStatus;
Error Functions¶
const char* grafeo_last_error(void); /* thread-local error message, or NULL */
void grafeo_clear_error(void); /* clear the last error */
The pointer from grafeo_last_error() is valid until the next FFI call on the same thread. Do NOT free it.
Lifecycle¶
GrafeoDatabase* grafeo_open_memory(void); /* in-memory */
GrafeoDatabase* grafeo_open(const char* path); /* persistent (directory) */
GrafeoDatabase* grafeo_open_read_only(const char* path); /* read-only (shared lock) */
GrafeoDatabase* grafeo_open_single_file(const char* path); /* single .grafeo file */
GrafeoStatus grafeo_close(GrafeoDatabase* db); /* flush and close */
void grafeo_free_database(GrafeoDatabase* db); /* free handle */
const char* grafeo_version(void); /* library version (static) */
All grafeo_open* functions return NULL on error. Always call grafeo_close before grafeo_free_database to flush pending writes.
Query Execution¶
All query functions return a GrafeoResult* pointer, or NULL on error.
GQL (default)¶
GrafeoResult* grafeo_execute(GrafeoDatabase* db, const char* query);
GrafeoResult* grafeo_execute_with_params(GrafeoDatabase* db, const char* query, const char* params_json);
Other Languages¶
Each language has a base function and a _with_params variant. Parameters are passed as a JSON object string.
/* Cypher (requires cypher feature) */
GrafeoResult* grafeo_execute_cypher(GrafeoDatabase* db, const char* query);
GrafeoResult* grafeo_execute_cypher_with_params(GrafeoDatabase* db, const char* query, const char* params_json);
/* Gremlin (requires gremlin feature) */
GrafeoResult* grafeo_execute_gremlin(GrafeoDatabase* db, const char* query);
GrafeoResult* grafeo_execute_gremlin_with_params(GrafeoDatabase* db, const char* query, const char* params_json);
/* GraphQL (requires graphql feature) */
GrafeoResult* grafeo_execute_graphql(GrafeoDatabase* db, const char* query);
GrafeoResult* grafeo_execute_graphql_with_params(GrafeoDatabase* db, const char* query, const char* params_json);
/* SPARQL (requires sparql feature) */
GrafeoResult* grafeo_execute_sparql(GrafeoDatabase* db, const char* query);
GrafeoResult* grafeo_execute_sparql_with_params(GrafeoDatabase* db, const char* query, const char* params_json);
/* SQL/PGQ (requires sql-pgq feature) */
GrafeoResult* grafeo_execute_sql(GrafeoDatabase* db, const char* query);
GrafeoResult* grafeo_execute_sql_with_params(GrafeoDatabase* db, const char* query, const char* params_json);
Unified Language Dispatcher¶
Execute a query in any supported language. params_json may be NULL.
GrafeoResult* grafeo_execute_language(GrafeoDatabase* db, const char* language, const char* query, const char* params_json);
The language parameter accepts: "gql", "cypher", "gremlin", "graphql", "sparql", or "sql".
Result Access¶
const char* grafeo_result_json(const GrafeoResult* r); /* JSON array of row objects */
size_t grafeo_result_row_count(const GrafeoResult* r); /* number of rows */
double grafeo_result_execution_time_ms(const GrafeoResult* r); /* execution time in ms */
uint64_t grafeo_result_rows_scanned(const GrafeoResult* r); /* estimated rows scanned */
const char* grafeo_result_nodes_json(const GrafeoResult* r); /* JSON array of node objects */
const char* grafeo_result_edges_json(const GrafeoResult* r); /* JSON array of edge objects */
void grafeo_free_result(GrafeoResult* r); /* free the result */
All const char* pointers from result accessors are valid until grafeo_free_result is called. Do NOT free them separately.
The grafeo_result_nodes_json and grafeo_result_edges_json functions return deduplicated, typed entities extracted from the result. Node objects have the shape {"element_type": "node", "id": ..., "labels": [...], "properties": {...}}. Edge objects have the shape {"element_type": "edge", "id": ..., "type": "...", "source_id": ..., "target_id": ..., "properties": {...}}.
Node CRUD¶
Create and Delete Nodes¶
/* Returns new node ID, or UINT64_MAX on error */
uint64_t grafeo_create_node(GrafeoDatabase* db, const char* labels_json, const char* properties_json);
/* Returns 1 if deleted, 0 if not found, -1 on null pointer */
int32_t grafeo_delete_node(GrafeoDatabase* db, uint64_t id);
labels_json is a JSON array of strings (e.g. "[\"Person\",\"Employee\"]"). properties_json is a JSON object (e.g. "{\"name\":\"Alix\"}"), or NULL for no properties.
Get Node¶
On success, *out must be freed with grafeo_free_node. Access fields with:
uint64_t grafeo_node_id(const GrafeoNode* node);
const char* grafeo_node_labels_json(const GrafeoNode* node);
const char* grafeo_node_properties_json(const GrafeoNode* node);
void grafeo_free_node(GrafeoNode* node);
Node Properties and Labels¶
GrafeoStatus grafeo_set_node_property(GrafeoDatabase* db, uint64_t id, const char* key, const char* value_json);
int32_t grafeo_remove_node_property(GrafeoDatabase* db, uint64_t id, const char* key);
int32_t grafeo_add_node_label(GrafeoDatabase* db, uint64_t id, const char* label);
int32_t grafeo_remove_node_label(GrafeoDatabase* db, uint64_t id, const char* label);
char* grafeo_get_node_labels(GrafeoDatabase* db, uint64_t id); /* free with grafeo_free_string */
Edge CRUD¶
Create and Delete Edges¶
/* Returns new edge ID, or UINT64_MAX on error */
uint64_t grafeo_create_edge(GrafeoDatabase* db, uint64_t source_id, uint64_t target_id, const char* edge_type, const char* properties_json);
/* Returns 1 if deleted, 0 if not found, -1 on null pointer */
int32_t grafeo_delete_edge(GrafeoDatabase* db, uint64_t id);
Get Edge¶
On success, *out must be freed with grafeo_free_edge. Access fields with:
uint64_t grafeo_edge_id(const GrafeoEdge* edge);
uint64_t grafeo_edge_source_id(const GrafeoEdge* edge);
uint64_t grafeo_edge_target_id(const GrafeoEdge* edge);
const char* grafeo_edge_type(const GrafeoEdge* edge);
const char* grafeo_edge_properties_json(const GrafeoEdge* edge);
void grafeo_free_edge(GrafeoEdge* edge);
Edge Properties¶
GrafeoStatus grafeo_set_edge_property(GrafeoDatabase* db, uint64_t id, const char* key, const char* value_json);
int32_t grafeo_remove_edge_property(GrafeoDatabase* db, uint64_t id, const char* key);
Transactions¶
Transactions use snapshot isolation by default. A transaction that is neither committed nor rolled back is automatically rolled back when freed.
GrafeoTransaction* grafeo_begin_transaction(GrafeoDatabase* db);
GrafeoTransaction* grafeo_begin_transaction_with_isolation(GrafeoDatabase* db, GrafeoIsolationLevel isolation);
Isolation levels: GRAFEO_ISOLATION_READ_COMMITTED (0), GRAFEO_ISOLATION_SNAPSHOT (1), GRAFEO_ISOLATION_SERIALIZABLE (2).
Execute Within a Transaction¶
GrafeoResult* grafeo_transaction_execute(GrafeoTransaction* tx, const char* query);
GrafeoResult* grafeo_transaction_execute_with_params(GrafeoTransaction* tx, const char* query, const char* params_json);
GrafeoResult* grafeo_transaction_execute_language(GrafeoTransaction* tx, const char* language, const char* query, const char* params_json);
Commit, Rollback, and Free¶
GrafeoStatus grafeo_commit(GrafeoTransaction* tx);
GrafeoStatus grafeo_rollback(GrafeoTransaction* tx);
void grafeo_free_transaction(GrafeoTransaction* tx);
Transaction Example¶
GrafeoTransaction *tx = grafeo_begin_transaction(db);
if (!tx) {
fprintf(stderr, "Error: %s\n", grafeo_last_error());
return;
}
GrafeoResult *r = grafeo_transaction_execute(tx, "INSERT (:Person {name: 'Alix'})");
if (r) grafeo_free_result(r);
if (grafeo_commit(tx) != GRAFEO_OK) {
fprintf(stderr, "Commit failed: %s\n", grafeo_last_error());
}
grafeo_free_transaction(tx);
Schema Context¶
GrafeoStatus grafeo_set_schema(GrafeoDatabase* db, const char* name);
GrafeoStatus grafeo_reset_schema(GrafeoDatabase* db);
const char* grafeo_current_schema(const GrafeoDatabase* db); /* NULL if no schema set */
The pointer from grafeo_current_schema is valid until the next call to grafeo_current_schema, grafeo_set_schema, or grafeo_reset_schema on the same thread.
Property Indexes¶
GrafeoStatus grafeo_create_property_index(GrafeoDatabase* db, const char* property);
int32_t grafeo_drop_property_index(GrafeoDatabase* db, const char* property);
int32_t grafeo_has_property_index(GrafeoDatabase* db, const char* property);
Find Nodes by Property¶
GrafeoStatus grafeo_find_nodes_by_property(GrafeoDatabase* db, const char* property, const char* value_json, uint64_t** out_ids, size_t* out_count);
void grafeo_free_node_ids(uint64_t* ids, size_t count);
Example:
uint64_t *ids = NULL;
size_t count = 0;
if (grafeo_find_nodes_by_property(db, "name", "\"Alix\"", &ids, &count) == GRAFEO_OK) {
for (size_t i = 0; i < count; i++) {
printf("Node ID: %llu\n", (unsigned long long)ids[i]);
}
grafeo_free_node_ids(ids, count);
}
Vector Search¶
Requires the vector-index feature.
Index Management¶
GrafeoStatus grafeo_create_vector_index(GrafeoDatabase* db, const char* label, const char* property, int32_t dimensions, const char* metric, int32_t m, int32_t ef_construction);
int32_t grafeo_drop_vector_index(GrafeoDatabase* db, const char* label, const char* property);
GrafeoStatus grafeo_rebuild_vector_index(GrafeoDatabase* db, const char* label, const char* property);
Pass -1 for dimensions, m, or ef_construction to use defaults. Pass NULL for metric to default to cosine similarity.
Nearest Neighbor Search¶
GrafeoStatus grafeo_vector_search(GrafeoDatabase* db, const char* label, const char* property, const float* query, size_t query_len, size_t k, int32_t ef, uint64_t** out_ids, float** out_distances, size_t* out_count);
MMR Search (Maximal Marginal Relevance)¶
GrafeoStatus grafeo_mmr_search(GrafeoDatabase* db, const char* label, const char* property, const float* query, size_t query_len, size_t k, int32_t fetch_k, float lambda, int32_t ef, uint64_t** out_ids, float** out_distances, size_t* out_count);
Batch Node Creation¶
GrafeoStatus grafeo_batch_create_nodes(GrafeoDatabase* db, const char* label, const char* property, const float* vectors, size_t vector_count, size_t dimensions, uint64_t** out_ids, size_t* out_count);
Freeing Vector Results¶
void grafeo_free_vector_results(uint64_t* ids, float* distances, size_t count);
void grafeo_free_node_ids(uint64_t* ids, size_t count); /* for batch_create_nodes */
Vector Search Example¶
/* Create a vector index */
grafeo_create_vector_index(db, "Document", "embedding", 384, "cosine", 16, 200);
/* Search for 5 nearest neighbors */
float query_vec[384] = { /* ... */ };
uint64_t *ids = NULL;
float *distances = NULL;
size_t count = 0;
if (grafeo_vector_search(db, "Document", "embedding", query_vec, 384, 5, -1, &ids, &distances, &count) == GRAFEO_OK) {
for (size_t i = 0; i < count; i++) {
printf("Node %llu, distance: %f\n", (unsigned long long)ids[i], distances[i]);
}
grafeo_free_vector_results(ids, distances, count);
}
CDC (Change Data Capture)¶
Requires the cdc feature.
void grafeo_set_cdc_enabled(GrafeoDatabase* db, bool enabled);
bool grafeo_is_cdc_enabled(GrafeoDatabase* db);
Statistics¶
Admin¶
char* grafeo_info(GrafeoDatabase* db); /* JSON string, free with grafeo_free_string */
GrafeoStatus grafeo_save(GrafeoDatabase* db, const char* path);
GrafeoStatus grafeo_wal_checkpoint(GrafeoDatabase* db);
Compact Store¶
Convert to a read-only columnar store for faster queries. Requires the compact-store feature.
After this call, all write operations return an error. Queries continue to work with lower memory usage and faster traversal.
Memory Management¶
- Opaque pointers (
GrafeoDatabase*,GrafeoResult*,GrafeoTransaction*,GrafeoNode*,GrafeoEdge*) must be freed with theirgrafeo_free_*function const char*pointers from accessor functions (e.g.grafeo_result_json,grafeo_node_labels_json) are valid until the parent object is freed: do NOT free themchar*pointers from functions likegrafeo_infoandgrafeo_get_node_labelsare caller-owned: free withgrafeo_free_string- Array results from vector search and property lookups must be freed with
grafeo_free_vector_resultsorgrafeo_free_node_ids
void grafeo_free_database(GrafeoDatabase* db);
void grafeo_free_result(GrafeoResult* r);
void grafeo_free_transaction(GrafeoTransaction* tx);
void grafeo_free_node(GrafeoNode* node);
void grafeo_free_edge(GrafeoEdge* edge);
void grafeo_free_string(char* s);
void grafeo_free_node_ids(uint64_t* ids, size_t count);
void grafeo_free_vector_results(uint64_t* ids, float* distances, size_t count);
Links¶
- GitHub
- Go bindings (built on this library)
- C# bindings (uses this library via P/Invoke)
- Dart bindings (uses this library via dart:ffi)