# Cosmos Gremlin

## Description

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

## Important concepts

* **`IFlexGraphStore` is the contract**: your code uses a shared store abstraction.
* **Gremlin vs. model operations**: generated templates typically show model-oriented operations (create node / get by id). Provider-specific traversal helpers may exist, but start with the shared operations first.
* **Partitioning matters**: Cosmos performance depends heavily on partition key selection.

## 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 Cosmos Gremlin as the IFlexGraphStore bridge.
				// Flex auto-wires generated Queries/Handlers that use IFlexGraphStore.
				services.AddFlexCosmosGremlinGraphStore(configuration);

				return services;
		}
}
```

## appsettings.json

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

```json
{
	"FlexBase": {
		"DataStores": {
			"Graph": {
				"CosmosGremlin": {
					"Hostname": "your-account.gremlin.cosmos.azure.com",
					"Port": 443,
					"Database": "your-database",
					"Container": "your-graph-container",
					"PrimaryKey": "...",
					"PartitionKey": "pk"
				}
			}
		}
	}
}
```

## 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)
		{
				var appContext = cmd.Dto.GetAppContext(); // do not remove this line
				var model = _flexHost.GetDomainModel<UserNodeModel>().Create(cmd);

				await _graphStore.CreateNodeAsync(model);
				await this.Fire(EventCondition, serviceBusContext);
		}
}

public class CreateUserNodeCommand : FlexCommandBridge<CreateUserNodeDto> { }
public class CreateUserNodeDto : DtoBridge { public string Id { get; set; } public string UserName { get; set; } }
public class UserNodeModel : FlexDomainModelBridge { public string 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 IFlexGraphStore _graphStore;
		protected GetUserNodeByIdParams _params;

		public GetUserNodeByIdQuery(ILogger<GetUserNodeByIdQuery> logger, IFlexHost flexHost, IFlexGraphStore graphStore)
				=> _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 string Id { get; set; } }
public class UserNodeDto : DtoBridge { public string Id { get; set; } public string UserName { get; set; } }
public class UserNodeModel : FlexDomainModelBridge { public string Id { get; set; } public string UserName { get; set; } }
```

## Library-specific considerations

* **Primary key**: `PrimaryKey` should be treated like a secret; store it securely.
* **Partition key**: keep `PartitionKey` stable once data is written; changing it later is typically a migration.
* **Networking**: Cosmos Gremlin is commonly locked down with firewall/VNet rules—ensure your app host can reach `Hostname:Port`.
