Skip to content

Commit 4914e6f

Browse files
committed
Bump version to 10.0.1 and refactor graph store registration methods to remove MakeDefault options
1 parent 99727a6 commit 4914e6f

File tree

17 files changed

+511
-67
lines changed

17 files changed

+511
-67
lines changed

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
- Always run `dotnet test GraphRag.slnx` before finishing work, after building.
1111
- Avoid per-client connection locks (e.g., `_connectionLock` in `AgeClient`); rely on the smart connection manager for concurrency.
1212
- When initialization logic is required (initialization tasks), add a simple hosted service to perform it and register that hosted service inside the relevant extensions.
13+
- Do not expose user-facing knobs for AGE/Postgres connection pool sizing (e.g., `MaxConnections` parameters); rely on EF Core-style connection-string keywords and reasonable defaults inside the connector.
14+
- Graph store registrations (Postgres, Neo4j, Cosmos) must automatically register a default `IGraphStore`; remove `MakeDefault` toggles/options and rely on the first registration when an unkeyed graph store is requested.
1315

1416
# Conversations
1517
any resulting updates to agents.md should go under the section "## Rules to follow"

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
<RepositoryUrl>https://github.com/managedcode/graphrag</RepositoryUrl>
2626
<PackageProjectUrl>https://github.com/managedcode/graphrag</PackageProjectUrl>
2727
<Product>Managed Code GraphRag</Product>
28-
<Version>10.0.0</Version>
29-
<PackageVersion>10.0.0</PackageVersion>
28+
<Version>10.0.1</Version>
29+
<PackageVersion>10.0.1</PackageVersion>
3030

3131
</PropertyGroup>
3232
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">

README.md

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,11 @@ dotnet test tests/ManagedCode.GraphRag.Tests/ManagedCode.GraphRag.Tests.csproj \
205205

206206
---
207207

208-
## Apache AGE / PostgreSQL Setup
208+
## Graph Store Configuration
209+
210+
GraphRAG ships with adapters for Apache AGE/PostgreSQL, Neo4j, and Azure Cosmos DB. Every adapter registers keyed services so you can address a specific store via `GetRequiredKeyedService<IGraphStore>("postgres")`, while the first registered store automatically becomes the unkeyed default (`GetRequiredService<IGraphStore>()`). This mirrors EF Core’s “one default context” pattern and removes any extra `MakeDefault` toggles.
211+
212+
### Apache AGE / PostgreSQL Setup
209213

210214
GraphRAG ships with a first-class Apache AGE adapter (`ManagedCode.GraphRag.Postgres`). AGE is enabled on top of PostgreSQL, so you only need a standard Postgres instance with the AGE extension installed.
211215

@@ -226,15 +230,57 @@ GraphRAG ships with a first-class Apache AGE adapter (`ManagedCode.GraphRag.Post
226230
"GraphStores": {
227231
"postgres": {
228232
"ConnectionString": "Host=localhost;Port=5432;Username=postgres;Password=postgres;Database=graphrag",
229-
"GraphName": "graphrag",
230-
"MaxConnections": 40,
231-
"MakeDefault": true
233+
"GraphName": "graphrag"
232234
}
233235
}
234236
}
235237
}
236238
```
237-
4. **Register through DI.** `services.AddPostgresGraphStore("postgres", configure: ...)` wires up `IAgeConnectionManager`, `IAgeClientFactory`, and `IGraphStore` automatically. `MaxConnections` caps the number of concurrent AGE sessions (the default is 40 so you stay under the container’s `max_connections`).
239+
4. **Register through DI.** `services.AddPostgresGraphStore("postgres", configure: ...)` wires up `IAgeConnectionManager`, `IAgeClientFactory`, and `IGraphStore` automatically. Pool sizing behaves like EF Core—tune it via connection-string keywords such as `Maximum Pool Size` when needed, otherwise the standard Npgsql defaults apply. The first Postgres store you register becomes the default `IGraphStore`, and additional stores stay keyed-only:
240+
```csharp
241+
await using var client = ageClientFactory.CreateClient();
242+
await client.OpenConnectionAsync(cancellationToken);
243+
```
244+
245+
### Neo4j Setup
246+
247+
Neo4j support lives in `ManagedCode.GraphRag.Neo4j` and uses the official Bolt driver:
248+
249+
1. **Run Neo4j locally (optional).**
250+
```bash
251+
docker run --rm \
252+
-e NEO4J_AUTH=neo4j/test1234 \
253+
-e NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
254+
-p 7687:7687 -p 7474:7474 \
255+
neo4j:5.23.0-community
256+
```
257+
2. **Register the store.**
258+
```csharp
259+
builder.Services.AddNeo4jGraphStore("neo4j", options =>
260+
{
261+
options.Uri = "bolt://localhost:7687";
262+
options.Username = "neo4j";
263+
options.Password = "test1234";
264+
});
265+
```
266+
The first Neo4j registration will automatically satisfy `IGraphStore`; use `GetRequiredKeyedService<IGraphStore>("neo4j")` for explicit access.
267+
268+
### Azure Cosmos DB Setup
269+
270+
The Cosmos adapter (`ManagedCode.GraphRag.CosmosDb`) targets the SQL API and works with the emulator or live accounts:
271+
272+
1. **Provide a connection string.** Set `COSMOS_EMULATOR_CONNECTION_STRING` or configure options manually.
273+
2. **Register the store.**
274+
```csharp
275+
builder.Services.AddCosmosGraphStore("cosmos", options =>
276+
{
277+
options.ConnectionString = cosmosConnectionString;
278+
options.DatabaseId = "GraphRagIntegration";
279+
options.NodesContainerId = "nodes";
280+
options.EdgesContainerId = "edges";
281+
});
282+
```
283+
As with other adapters, the first Cosmos store becomes the unkeyed default.
238284

239285
> **Tip:** `IGraphStore` now exposes `GetNodesAsync` and `GetRelationshipsAsync` in addition to the targeted APIs (`InitializeAsync`, `Upsert*`, `GetOutgoingRelationshipsAsync`). These use the new AGE-powered enumerations so you can inspect or export the full graph without dropping down to concrete implementations.
240286

src/ManagedCode.GraphRag.CosmosDb/ServiceCollectionExtensions.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
using GraphRag.Graphs;
33
using Microsoft.Azure.Cosmos;
44
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
56
using Microsoft.Extensions.Logging;
67

78
namespace GraphRag.Storage.Cosmos;
89

910
public static class ServiceCollectionExtensions
1011
{
11-
public static IServiceCollection AddCosmosGraphStore(this IServiceCollection services, string key, Action<CosmosGraphStoreOptions> configure, bool makeDefault = false)
12+
public static IServiceCollection AddCosmosGraphStore(this IServiceCollection services, string key, Action<CosmosGraphStoreOptions> configure)
1213
{
1314
ArgumentNullException.ThrowIfNull(services);
1415
ArgumentException.ThrowIfNullOrWhiteSpace(key);
@@ -40,11 +41,8 @@ public static IServiceCollection AddCosmosGraphStore(this IServiceCollection ser
4041
});
4142
services.AddKeyedSingleton<IGraphStore>(key, (sp, serviceKey) => sp.GetRequiredKeyedService<CosmosGraphStore>(serviceKey));
4243

43-
if (makeDefault)
44-
{
45-
services.AddSingleton(sp => sp.GetRequiredKeyedService<CosmosGraphStore>(key));
46-
services.AddSingleton<IGraphStore>(sp => sp.GetRequiredKeyedService<CosmosGraphStore>(key));
47-
}
44+
services.TryAddSingleton<CosmosGraphStore>(sp => sp.GetRequiredKeyedService<CosmosGraphStore>(key));
45+
services.TryAddSingleton<IGraphStore>(sp => sp.GetRequiredKeyedService<CosmosGraphStore>(key));
4846

4947
return services;
5048
}

src/ManagedCode.GraphRag.Neo4j/ServiceCollectionExtensions.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using GraphRag.Graphs;
22
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.DependencyInjection.Extensions;
34
using Microsoft.Extensions.Logging;
45

56
namespace GraphRag.Storage.Neo4j;
67

78
public static class ServiceCollectionExtensions
89
{
9-
public static IServiceCollection AddNeo4jGraphStore(this IServiceCollection services, string key, Action<Neo4jGraphStoreOptions> configure, bool makeDefault = false)
10+
public static IServiceCollection AddNeo4jGraphStore(this IServiceCollection services, string key, Action<Neo4jGraphStoreOptions> configure)
1011
{
1112
ArgumentNullException.ThrowIfNull(services);
1213
ArgumentException.ThrowIfNullOrWhiteSpace(key);
@@ -24,11 +25,8 @@ public static IServiceCollection AddNeo4jGraphStore(this IServiceCollection serv
2425
});
2526
services.AddKeyedSingleton<IGraphStore>(key, (sp, serviceKey) => sp.GetRequiredKeyedService<Neo4jGraphStore>(serviceKey));
2627

27-
if (makeDefault)
28-
{
29-
services.AddSingleton(sp => sp.GetRequiredKeyedService<Neo4jGraphStore>(key));
30-
services.AddSingleton<IGraphStore>(sp => sp.GetRequiredKeyedService<Neo4jGraphStore>(key));
31-
}
28+
services.TryAddSingleton<Neo4jGraphStore>(sp => sp.GetRequiredKeyedService<Neo4jGraphStore>(key));
29+
services.TryAddSingleton<IGraphStore>(sp => sp.GetRequiredKeyedService<Neo4jGraphStore>(key));
3230

3331
return services;
3432
}

src/ManagedCode.GraphRag.Postgres/ApacheAge/AgeClientFactory.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Microsoft.Extensions.DependencyInjection;
12
using Microsoft.Extensions.Logging;
23

34
namespace GraphRag.Storage.Postgres.ApacheAge;
@@ -7,7 +8,7 @@ public interface IAgeClientFactory
78
AgeClient CreateClient();
89
}
910

10-
internal sealed class AgeClientFactory(IAgeConnectionManager connectionManager, ILoggerFactory loggerFactory) : IAgeClientFactory
11+
internal sealed class AgeClientFactory([FromKeyedServices] IAgeConnectionManager connectionManager, ILoggerFactory loggerFactory) : IAgeClientFactory
1112
{
1213
private readonly IAgeConnectionManager _connectionManager = connectionManager ?? throw new ArgumentNullException(nameof(connectionManager));
1314
private readonly ILoggerFactory _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));

src/ManagedCode.GraphRag.Postgres/ApacheAge/AgeConnectionManager.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Microsoft.Extensions.DependencyInjection;
12
using Microsoft.Extensions.Logging;
23
using Microsoft.Extensions.Logging.Abstractions;
34
using Npgsql;
@@ -18,19 +19,24 @@ public sealed class AgeConnectionManager : IAgeConnectionManager
1819
private volatile bool _extensionEnsured;
1920
private bool _disposed;
2021

21-
public AgeConnectionManager(string connectionString, ILogger<AgeConnectionManager>? logger = null, int maxPoolSize = 100)
22+
[ActivatorUtilitiesConstructor]
23+
public AgeConnectionManager(
24+
[FromKeyedServices] PostgresGraphStoreOptions options,
25+
ILogger<AgeConnectionManager>? logger = null)
26+
: this(options?.ConnectionString ?? throw new ArgumentNullException(nameof(options)), logger)
27+
{
28+
}
29+
30+
public AgeConnectionManager(string connectionString, ILogger<AgeConnectionManager>? logger = null)
2231
{
2332
ArgumentException.ThrowIfNullOrWhiteSpace(connectionString);
24-
if (maxPoolSize <= 0)
25-
{
26-
throw new ArgumentOutOfRangeException(nameof(maxPoolSize), "Max pool size must be greater than zero.");
27-
}
2833

29-
var connectionBuilder = new NpgsqlConnectionStringBuilder(connectionString)
34+
var connectionBuilder = new NpgsqlConnectionStringBuilder(connectionString);
35+
if (connectionBuilder.MaxPoolSize <= 0)
3036
{
31-
MaxPoolSize = maxPoolSize,
32-
MinPoolSize = Math.Min(10, maxPoolSize)
33-
};
37+
throw new ArgumentOutOfRangeException(nameof(connectionString), "Maximum Pool Size must be greater than zero.");
38+
}
39+
connectionBuilder.MinPoolSize = Math.Min(10, connectionBuilder.MaxPoolSize);
3440

3541
ConnectionString = connectionBuilder.ConnectionString;
3642
_dataSource = NpgsqlDataSource.Create(connectionBuilder.ConnectionString);

src/ManagedCode.GraphRag.Postgres/ApacheAge/Resolvers/AgtypeResolverFactory.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ private class Resolver : IPgTypeInfoResolver
2424
{
2525
protected static DataTypeName AgtypeDataTypeName => new("ag_catalog.agtype");
2626

27-
private TypeInfoMappingCollection? _mappings;
28-
protected TypeInfoMappingCollection Mappings => _mappings ??= AddMappings(new());
27+
private static readonly Lazy<TypeInfoMappingCollection> ResolverMappings = new(static () => AddMappings(new()));
28+
29+
protected static TypeInfoMappingCollection BaseMappings => ResolverMappings.Value;
30+
31+
protected static TypeInfoMappingCollection Mappings => BaseMappings;
2932

3033
public PgTypeInfo? GetTypeInfo(Type? type, DataTypeName? dataTypeName, PgSerializerOptions options)
3134
=> Mappings.Find(type, dataTypeName, options);
@@ -41,8 +44,9 @@ private static TypeInfoMappingCollection AddMappings(TypeInfoMappingCollection m
4144

4245
private sealed class ArrayResolver : Resolver, IPgTypeInfoResolver
4346
{
44-
private TypeInfoMappingCollection? _mappings;
45-
private new TypeInfoMappingCollection Mappings => _mappings ??= AddMappings(new(base.Mappings));
47+
private static readonly Lazy<TypeInfoMappingCollection> ArrayMappings = new(static () => AddMappings(new(BaseMappings)));
48+
49+
private static new TypeInfoMappingCollection Mappings => ArrayMappings.Value;
4650

4751
public new PgTypeInfo? GetTypeInfo(Type? type, DataTypeName? dataTypeName, PgSerializerOptions options)
4852
=> Mappings.Find(type, dataTypeName, options);
@@ -56,4 +60,3 @@ private static TypeInfoMappingCollection AddMappings(TypeInfoMappingCollection m
5660
}
5761
}
5862
#pragma warning restore NPG9001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
59-

src/ManagedCode.GraphRag.Postgres/PostgresGraphStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public PostgresGraphStore(PostgresGraphStoreOptions options, ILogger<PostgresGra
6666
{
6767
var factory = loggerFactory ?? NullLoggerFactory.Instance;
6868
var connectionManagerLogger = factory.CreateLogger<AgeConnectionManager>();
69-
var connectionManager = new AgeConnectionManager(connectionString, connectionManagerLogger, options.MaxConnections);
69+
var connectionManager = new AgeConnectionManager(connectionString, connectionManagerLogger);
7070
_ownedConnectionManager = connectionManager;
7171
_ageClientFactory = new AgeClientFactory(connectionManager, factory);
7272
}

src/ManagedCode.GraphRag.Postgres/PostgresGraphStoreConfig.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,4 @@ public sealed class PostgresGraphStoreConfig
1212

1313
public Dictionary<string, string[]> EdgePropertyIndexes { get; set; } = new(StringComparer.OrdinalIgnoreCase);
1414

15-
public bool MakeDefault { get; set; }
16-
1715
}

0 commit comments

Comments
 (0)