using Guestbooky.Domain.Abstractions.Repositories;
using Guestbooky.Domain.Entities.Message;
using Guestbooky.Infrastructure.Persistence.DTOs;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;
namespace Guestbooky.Infrastructure.Persistence.Repositories
{
///
/// First time ever using NoSQL here. I'm still not sure if I fell into any big anti-patterns.
/// As someone much more used to SQL lingo, this feels a bit weird but it is enjoyable.
/// Could use more robust error handling but I've yet to see it not working.
///
public class MongoGuestbookMessageRepository : IGuestbookMessageRepository
{
private const string COLLECTION_NAME = "GuestbookMessages";
private readonly IMongoCollection _messages;
private readonly ILogger _logger;
public MongoGuestbookMessageRepository(IMongoDatabase database, ILogger logger)
{
_messages = database.GetCollection(COLLECTION_NAME);
_logger = logger;
}
public async Task AddAsync(GuestbookMessage message, CancellationToken cancellationToken)
{
_logger.LogDebug("Adding guestbook entry.");
var messageDto = MapToDto(message);
await _messages.InsertOneAsync(messageDto, cancellationToken: cancellationToken);
}
public async Task DeleteAsync(string id, CancellationToken cancellationToken)
{
_logger.LogDebug($"Removing guestbook entry. Id: {id}");
var result = await _messages.DeleteOneAsync(m => m.Id == id, cancellationToken: cancellationToken);
if (result.DeletedCount != 1)
_logger.LogError($"Deleted count is different from 1. Value: {result.DeletedCount}");
if (!result.IsAcknowledged)
_logger.LogError("Deletion was not acknowledged.");
return result.IsAcknowledged && result.DeletedCount == 1;
}
public async Task> GetAsync(long offset, CancellationToken cancellationToken)
{
if (offset < 0) offset = 0;
_logger.LogDebug("Acquiring guestbook entries.");
var messageDtos = await _messages.Find(_ => true)
.SortBy(x => x.Timestamp)
.Skip((int?)offset)
.Limit(10)
.ToCursorAsync(cancellationToken);
return messageDtos.ToEnumerable().Select(MapToDomainModel).ToArray();
}
public async Task CountAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Getting amount of messages stored.");
return await _messages.CountDocumentsAsync(_ => true, cancellationToken: cancellationToken);
}
private static GuestbookMessage MapToDomainModel(GuestbookMessageDto dto)
{
return GuestbookMessage.CreateExisting(
Guid.Parse(dto.Id),
dto.Author,
dto.Message,
new DateTimeOffset(dto.Timestamp, TimeSpan.Zero)
);
}
private static GuestbookMessageDto MapToDto(GuestbookMessage message)
{
return new GuestbookMessageDto
{
Id = message.Id.ToString(),
Author = message.Author,
Message = message.Message,
Timestamp = message.Timestamp.UtcDateTime
};
}
}
}