cvoya

CVOYA Graph v1.0 is out

Last week, I wrote about the evolution of the CVOYA Graph. After a lot of progress this week, I am graduating the library to v1.0.

CVOYA Graph is a type-safe .NET library for modeling and querying graphs with LINQ. It offers three graph providers: in-memory, Neo4j, and Apache AGE. Version 1.0 establishes a stable, provider-tested foundation with explicit capabilities and a reusable compatibility test kit.

This is intentionally a breaking release from GraphModel and the prerelease line. If you are upgrading an existing application, please read the migration guide.

The packages are now available on NuGet, with documentation and source on GitHub.

An important note: Since last week, I fixed many bugs and completed the support for AGE 1.7 as a provider. Along the way, I made a big change to CVOYA Graph’s .NET data model. The foundational IEntity interface no longer defines a mandatory Id property. That has major consequences to the API. A CVOYA Graph-defined ID can no longer be used to identify nodes and relationships in Get, Update, and Delete operations. You have to use LINQ expressions to identify a node or relationship. However, creating a relationship is easier now through the introduction of an atomic CreateAsync<TSource, TRelationship, TTarget>() operation. You can still model your domain types to have an ID property and even identify it as a primary key. It’s just that CVOYA Graph doesn’t dictate such an identifier any more.

using Cvoya.Graph;
using Cvoya.Graph.Neo4j;

// Instantiate your provider
await using var store = new Neo4jGraphStore(
    "bolt://localhost:7687",
    "neo4j",
    "password",
    databaseName: "myapp");

// Get the graph abstraction
var graph = store.Graph;

// All subsequent operations are against the IGraph interface, not the provider

// Create two nodes
var alice = new Person
{
    Tenant = "northwest",
    Email = "alice@example.com",
    Name = "Alice",
    Age = 30,
};

var bob = new Person
{
    Tenant = "northwest",
    Email = "bob@example.com",
    Name = "Bob",
    Age = 28,
};

// Create a relationship
await graph.CreateAsync(
    alice,
    new Knows { Since = DateTime.UtcNow },
    bob);

// Query the nodes
var aliceSelection = graph.Nodes<Person>()
    .Where(person => person.Tenant == "northwest" &&
                     person.Email == "alice@example.com");

// Update
await aliceSelection.UpdateAsync(setters => setters
    .SetProperty(person => person.Age, person => person.Age + 1)
    .SetProperty(person => person.Name, "Alice Smith"));

// Get relationsihps
var connections = await aliceSelection
    .PathSegments<Person, Knows, Person>()
    .ToListAsync();

foreach (var segment in connections)
{
    Console.WriteLine(
        $"{segment.StartNode.Name} --{segment.Relationship.Type}--> " +
        $"{segment.EndNode.Name} ({segment.Direction})");
}

The docs contain many more examples.

Here is the capability matrix for the three providers included in v1.0:

CapabilityNeo4jin-memoryAGE
FullTextSearchpasspasspass
Transactionspasspasspass
ComplexPropertyCascadepasspasspass
CallSubqueriespasspasspass
PatternSizeProjectionpasspasspass
MultiLabelMatchpasspasspass
LabelFilteringpasspasspass
OrderByEntitypassskipskip
OptionalTraversalpasspasspass
GroupByAggregationpasspasspass
NestedTransactions
RelationshipPredicatespasspasspass
ShortestPathpasspassskip (issue 355)
SetOperationspasspasspass
NullElementsInSimpleCollectionspasspasspass

I chose not to implement shortest path for AGE at this stage since the 1.8.0 release is just around the corner and comes with native support for the feature.

Enjoy!

Savas Parastatidis

Savas Parastatidis works at Amazon as a Sr. Principal Engineer in Alexa AI'. Previously, he worked at Microsoft where he co-founded Cortana and led the effort as the team's architect. While at Microsoft, Savas also worked on distributed data storage and high-performance data processing technologies. He was involved in various e-Science projects while at Microsoft Research where he also investigated technologies related to knowledge representation & reasoning. Savas also worked on language understanding technologies at Facebook. Prior to joining Microsoft, Savas was a Principal Research Associate at Newcastle University where he undertook research in the areas of distributed, service-oriented computing and e-Science. He was also the Chief Software Architect at the North-East Regional e-Science Centre where he oversaw the architecture and the application of Web Services technologies for a number of large research projects. Savas worked as a Senior Software Engineer for Hewlett Packard where he co-lead the R&D effort for the industry's Web Service transactions service and protocol. You can find out more about Savas at https://savas.me/about

Share
Published by
Savas Parastatidis

Recent Posts

CVOYA Graph – Evolution

Last year, I released the "Graph Model" library for .NET as an open source project. It…

6 days ago

The boat is in the water: Spring Voyage is open source

Today I'm pushing Spring Voyage out of the harbor. You can track its journey on…

2 months ago

My Coding Agent Needed Its Own GitHub Identity

In my last post, I wrote that "the typing of code was parallelized and delegated.…

3 months ago

Rebuilding My AI Team in Twelve Days — And Why

In February, I wrote about the small team I'd stood up instead of hiring humans:…

3 months ago

How I Built My Own Team of AI Developers

Assembling a dream team without a single hire I've been making great progress on CVOYA's…

5 months ago

Reflecting on 2025: Building CVOYA’s Future with AI Coding Agents

As 2025 is now behind us, I wanted to share a few reflections from my…

6 months ago