# Cosmos Db

## Description

Cosmos DB is used as a **Document DB provider** behind `IFlexDocumentStore`. Generated apps keep document reads/writes in the standard Query/Handler pattern while Cosmos-specific concerns (partition keys, throughput, retry/backoff) are handled in the provider wiring.

## Important Concepts

* **Container mapping is config-driven**: logical store/container names and partition keys live in configuration.
* **AppContext is mandatory**: always call `dto.GetAppContext()` in generated queries/handlers.
* **Provider-agnostic code**: your business logic depends on `IFlexDocumentStore`, not the Cosmos SDK.

## Configuration in DI (where to add)

Provider wiring is generated in your Infrastructure project (under a `...DataStoreProviders/Document/CosmosDb` folder). You typically do **not** register individual queries/handlers here — Flex generates and wires those.

If you are wiring Cosmos manually, add the **document-store provider** registration where you configure infrastructure services:

```csharp
// Infrastructure (example)
services.AddFlexCosmosDocumentStore<CustomerProfileDocument>(configuration);
```

## appsettings.json

```json
{
	"FlexBase": {
		"DataStores": {
			"Document": {
				"CosmosDb": {
					"Endpoint": "https://...documents.azure.com:443/",
					"AccountKey": "<from-secrets>",
					"DatabaseName": "{YourApplication}",
					"ContainerName": "CustomerProfiles",
					"PartitionKeyPath": "/id",
					"ThroughputRUs": 400
				}
			}
	}
  }
}
```

## Examples (from the generated templates)

Cosmos uses the same generated shapes as other Document DB providers.

### Handler example (Create)

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

public interface ICreateCustomerProfileHandler : IAmFlexCommandHandler<CreateCustomerProfileCommand> { }

public partial class CreateCustomerProfileHandler : ICreateCustomerProfileHandler
{
	protected string EventCondition = "";

	protected readonly ILogger<CreateCustomerProfileHandler> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected readonly ICustomerProfileMapper _mapper;

	protected CustomerProfileDocument? _model;
	protected FlexAppContextBridge? _flexAppContext;

	public CreateCustomerProfileHandler(
		ILogger<CreateCustomerProfileHandler> logger,
		IFlexHost flexHost,
		IFlexDocumentStore documentStore,
		ICustomerProfileMapper mapper)
	{
		_logger = logger;
		_flexHost = flexHost;
		_documentStore = documentStore;
		_mapper = mapper;
	}

	public virtual async Task Execute(CreateCustomerProfileCommand cmd, IFlexServiceBusContext serviceBusContext)
	{
		_flexAppContext = cmd.Dto.GetAppContext(); // do not remove

		_model = _mapper.MapToDocument(cmd.Dto);
		await _documentStore.CreateAsync<CustomerProfileDocument>(_model);

		// TODO: set EventCondition (example: CONDITION_ONSUCCESS)
		await this.Fire(EventCondition, serviceBusContext);
	}
}
```

### Query example (Get-by-id)

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

public class GetCustomerProfileById : FlexiQueryBridgeAsync<CustomerProfileDto>
{
	protected readonly ILogger<GetCustomerProfileById> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected GetCustomerProfileByIdParams _params;
	protected FlexAppContextBridge _flexAppContext;

	public GetCustomerProfileById(ILogger<GetCustomerProfileById> logger, IFlexHost flexHost, IFlexDocumentStore documentStore)
	{
		_logger = logger;
		_flexHost = flexHost;
		_documentStore = documentStore;
	}

	public virtual GetCustomerProfileById AssignParameters(GetCustomerProfileByIdParams @params)
	{
		_params = @params;
		return this;
	}

	public virtual async Task<CustomerProfileDto?> Fetch()
	{
		_flexAppContext = _params.GetAppContext();

		var doc = await _documentStore.GetByIdAsync<CustomerProfileDocument>(_params.Id);
		return doc == null ? null : new CustomerProfileDto { Id = doc.Id };
	}
}

public class GetCustomerProfileByIdParams : DtoBridge
{
	public Guid Id { get; set; }
}
```

## Provider-specific considerations

* **Partition keys**: model your access patterns around the partition key to avoid cross-partition scans.
* **Throughput**: keep RU/autoscale settings in config so environments can tune independently.
* **Retries/backoff**: rely on the provider’s retry policies for throttling (429) behavior.
