using MongoDB.Bson;
using MongoDB.Driver;
namespace Htmx.ApiDemo.Data;
///
/// Scoped service wrapping the AppUser MongoDB collection.
/// All operations use MongoDB's native async API — no EF, no LINQ-to-SQL
/// translation, no RelationalModel, fully NativeAOT safe.
///
public sealed class MongoDbService
{
private readonly IMongoCollection _users;
public MongoDbService(IMongoClient client, IConfiguration configuration)
{
var db = client.GetDatabase(configuration["MongoDbName"] ?? "HtmxAppDb");
_users = db.GetCollection("users");
}
/// Ensures the unique index on NormalizedEmail exists (idempotent).
public async Task EnsureIndexesAsync(CancellationToken ct = default)
{
var indexKeys = Builders.IndexKeys.Ascending(u => u.NormalizedEmail);
var indexOptions = new CreateIndexOptions { Unique = true, Name = "uq_normalizedEmail" };
var model = new CreateIndexModel(indexKeys, indexOptions);
await _users.Indexes.CreateOneAsync(model, cancellationToken: ct);
}
/// Returns true if a user with the given normalised email already exists.
public async Task EmailExistsAsync(string normalizedEmail, CancellationToken ct = default)
{
var filter = Builders.Filter.Eq(u => u.NormalizedEmail, normalizedEmail);
return await _users.Find(filter).AnyAsync(ct);
}
/// Returns the user matching the normalised email, or null.
public async Task FindByNormalizedEmailAsync(string normalizedEmail, CancellationToken ct = default)
{
var filter = Builders.Filter.Eq(u => u.NormalizedEmail, normalizedEmail);
return await _users.Find(filter).FirstOrDefaultAsync(ct);
}
/// Inserts a new user document.
public Task InsertAsync(AppUser user, CancellationToken ct = default) =>
_users.InsertOneAsync(user, cancellationToken: ct);
}