# Mongo Db

## Description

MongoDB is used as a **Document DB provider** through the shared Flex document-store abstraction (`IFlexDocumentStore`). Generated code keeps your application code provider-agnostic: your queries/handlers talk to `IFlexDocumentStore`, and the provider wiring decides whether that’s MongoDB, Cosmos DB, Dynamo DB, etc.

## Important Concepts

* **Query/Handler pattern**: reads happen in `.../Queries`, writes happen in `.../Handlers`.
* **AppContext is mandatory**: always call `dto.GetAppContext()` in queries/handlers (the templates mark it as “do not remove”).
* **Provider is hidden behind interfaces**: your code depends on `IFlexDocumentStore`, not Mongo SDK types.

## Configuration in DI (where to add)

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

If you are wiring Mongo manually, add the **document-store provider** registration where you configure infrastructure services (often in `Program.cs` or an Infrastructure DI module):

```csharp
// Infrastructure (example)
services.AddFlexMongoDocumentStore<InvoiceDocument>(
    configuration,
    collectionName: "Invoices");
```

> Where to put business registrations? Use your EndPoints “common configs” area (like `OtherApplicationServicesConfig`) for registering *your own* application services. The MongoDB provider itself is registered in Infrastructure.

## appsettings.json

```json
{
	"FlexBase": {
		"DataStores": {
			"Document": {
				"MongoDb": {
					"ConnectionString": "mongodb://...",
					"DatabaseName": "{YourApplication}",
					"EnableSSL": true,
					"ConnectionTimeout": "00:00:30",
					"MaxConnectionPoolSize": 100
				}
			}
		}
  }
}
```

## Examples (from the generated templates)

The generator uses the same shape for all Document DB providers; only the provider wiring changes.

### Handler example (Create)

This follows the template in `PostBusHandler/DocumentDataStore/DocumentStoreHandlerTemplate_Create.cs`.

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

public interface ICreateInvoiceHandler : IAmFlexCommandHandler<CreateInvoiceCommand> { }

public partial class CreateInvoiceHandler : ICreateInvoiceHandler
{
	protected string EventCondition = "";

	protected readonly ILogger<CreateInvoiceHandler> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected readonly IInvoiceMapper _mapper;

	protected InvoiceDocument? _model;
	protected FlexAppContextBridge? _flexAppContext;

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

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

		_model = _mapper.MapToDocument(cmd.Dto);
		var created = await _documentStore.CreateAsync<InvoiceDocument>(_model);

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

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

This follows the template in `Query/DocumentDataStore/DocumentStoreQueryGetByIdTemplate.cs`.

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

public class GetInvoiceById : FlexiQueryBridgeAsync<InvoiceDto>
{
	protected readonly ILogger<GetInvoiceById> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected GetInvoiceByIdParams _params;
	protected FlexAppContextBridge _flexAppContext;

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

	public virtual GetInvoiceById AssignParameters(GetInvoiceByIdParams @params)
	{
		_params = @params;
		return this;
	}

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

		var doc = await _documentStore.GetByIdAsync<InvoiceDocument>(_params.Id);
		return doc == null ? null : new InvoiceDto { Id = doc.Id, Status = doc.Status };
	}
}

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

### Query example (Simple list)

This follows the template in `Query/DocumentDataStore/DocumentStoreQueryGetEnumerableTemplate.cs`.

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;

public class ListInvoices : FlexiQueryEnumerableBridgeAsync<InvoiceDto>
{
	protected readonly ILogger<ListInvoices> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected ListInvoicesParams _params;
	protected FlexAppContextBridge _flexAppContext;

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

	public virtual ListInvoices AssignParameters(ListInvoicesParams @params)
	{
		_params = @params;
		return this;
	}

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

		Expression<Func<InvoiceDocument, bool>> filter = x => x.CustomerId == _params.CustomerId;
		var docs = await _documentStore.GetManyAsync<InvoiceDocument>(filter);

		// TODO: map documents to DTOs
		return docs == null
			? Array.Empty<InvoiceDto>()
			: docs.Select(d => new InvoiceDto { Id = d.Id, Status = d.Status });
	}
}

public class ListInvoicesParams : DtoBridge
{
	public string CustomerId { get; set; } = "";
}
```

## Provider-specific considerations

* **Replica sets**: prefer replica-set aware connection strings for failover.
* **Indexing**: define the “must have” indexes for your hot queries in configuration so deployments stay consistent.
* **Read preferences**: align read preference with your consistency needs (primary vs preferred).
