# Neo4j

## Description

Neo4j can be used as the backing implementation for Flex graph operations. Your application code should depend on `IFlexGraphStore`, while Flex provides the Neo4j implementation and wiring.

## Important concepts

* **`IFlexGraphStore` is the contract**: your app uses a shared graph abstraction rather than Neo4j driver APIs.
* **Nodes are models**: graph operations typically read/write node models (domain models) through the store.
* **Generated flow**: generated handlers/queries use `cmd.Dto.GetAppContext()` / `params.GetAppContext()` and then call `IFlexGraphStore`.

## Configuration in DI

Add the provider in your DI composition root (commonly in `EndPoints/...CommonConfigs/OtherApplicationServicesConfig.cs`).

```csharp
public static class OtherApplicationServicesConfig
{
	public static IServiceCollection AddOtherApplicationServices(
		this IServiceCollection services,
		IConfiguration configuration)
	{
		// Registers Neo4j as the IFlexGraphStore bridge.
		// Flex auto-wires generated Queries/Handlers that use IFlexGraphStore.
		services.AddFlexNeo4jGraphStore(configuration);

		return services;
	}
}
```

## appsettings.json

Configuration is read from `FlexBase:DataStores:Graph:Neo4j`.

```json
{
  "FlexBase": {
	"DataStores": {
	  "Graph": {
		"Neo4j": {
		  "Uri": "bolt://localhost:7687",
		  "Username": "neo4j",
		  "Password": "...",
		  "Database": "neo4j"
		}
	  }
	}
  }
}
```

## Examples (template-based)

These examples mirror the generated Query and PostBusHandler templates. You do **not** register these types manually—Flex discovers and wires generated Queries/Handlers automatically.

### Create node (PostBusHandler)

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System;
using System.Threading.Tasks;

namespace {YourApplication}.Handlers.Graph;

public partial class CreateUserNodeHandler : IAmFlexCommandHandler<CreateUserNodeCommand>
{
	protected string EventCondition = "";

	protected readonly ILogger<CreateUserNodeHandler> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexGraphStore _graphStore;

	public CreateUserNodeHandler(ILogger<CreateUserNodeHandler> logger, IFlexHost flexHost, IFlexGraphStore graphStore)
	{
		_logger = logger;
		_flexHost = flexHost;
		_graphStore = graphStore;
	}

	public virtual async Task Execute(CreateUserNodeCommand cmd, IFlexServiceBusContext serviceBusContext)
	{
		_logger.LogDebug("Starting Create Node for {EntityType}", nameof(UserNodeModel));

		var appContext = cmd.Dto.GetAppContext(); // do not remove this line

		var model = _flexHost.GetDomainModel<UserNodeModel>().Create(cmd);
		await _graphStore.CreateNodeAsync(model);

		// Example:
		// EventCondition = CreateUserNodeEvents.CONDITION_ONSUCCESS;
		await this.Fire(EventCondition, serviceBusContext);
	}
}

public class CreateUserNodeCommand : FlexCommandBridge<CreateUserNodeDto> { }

public class CreateUserNodeDto : DtoBridge
{
	public Guid Id { get; set; }
	public string UserName { get; set; }
}

public class UserNodeModel : FlexDomainModelBridge
{
	public Guid Id { get; set; }
	public string UserName { get; set; }
}
```

### Get node by ID (Query)

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System;
using System.Threading.Tasks;

namespace {YourApplication}.Queries.Graph;

public class GetUserNodeByIdQuery : FlexiQueryBridgeAsync<UserNodeDto>
{
	protected readonly ILogger<GetUserNodeByIdQuery> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexGraphStore _graphStore;
	protected GetUserNodeByIdParams _params;

	public GetUserNodeByIdQuery(ILogger<GetUserNodeByIdQuery> logger, IFlexHost flexHost, IFlexGraphStore graphStore)
	{
		_logger = logger;
		_flexHost = flexHost;
		_graphStore = graphStore;
	}

	public virtual GetUserNodeByIdQuery AssignParameters(GetUserNodeByIdParams @params)
	{
		_params = @params;
		return this;
	}

	public virtual async Task<UserNodeDto?> Fetch()
	{
		var appContext = _params.GetAppContext();

		var node = await _graphStore.GetNodeByIdAsync<UserNodeModel>(_params.Id);
		if (node == null) return default;

		return new UserNodeDto { Id = node.Id, UserName = node.UserName };
	}
}

public class GetUserNodeByIdParams : DtoBridge
{
	public Guid Id { get; set; }
}

public class UserNodeDto : DtoBridge
{
	public Guid Id { get; set; }
	public string UserName { get; set; }
}
```

## Library-specific considerations

* **Secrets**: store Neo4j passwords in a secret manager and inject via configuration.
* **Connection URI**: use `bolt+s://` (or your cluster’s required scheme) when connecting over TLS.
