- Fragment model with validation, DTOs (immutable records), repository, service - Sidecar stdin/stdout JSON protocol for Tauri integration - DI wiring via ServiceCollectionExtensions - Scaffolded Journal.Api (not yet wired) Co-Authored-By: Warp <agent@warp.dev>
80 lines
2.5 KiB
C#
80 lines
2.5 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using Journal.Core.Dtos;
|
|
using Journal.Core.Models;
|
|
using Journal.Core.Repositories;
|
|
|
|
namespace Journal.Core.Services;
|
|
|
|
public class FragmentService : IFragmentService
|
|
{
|
|
private readonly IFragmentRepository _repo;
|
|
|
|
public FragmentService(IFragmentRepository repo) => _repo = repo ?? throw new ArgumentNullException(nameof(repo));
|
|
|
|
private static FragmentDto Map(Fragment f) => new(
|
|
f.Id,
|
|
f.Type,
|
|
f.Description,
|
|
f.Time,
|
|
f.Tags != null ? [.. f.Tags] : []
|
|
);
|
|
|
|
public async Task<FragmentDto> CreateAsync(CreateFragmentDto dto)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(dto);
|
|
|
|
var ctx = new ValidationContext(dto);
|
|
Validator.ValidateObject(dto, ctx, validateAllProperties: true);
|
|
|
|
var f = new Fragment(dto.Type, dto.Description);
|
|
if (dto.Tags != null)
|
|
f.Tags = [.. dto.Tags.Where(t => !string.IsNullOrWhiteSpace(t)).Select(t => t!.Trim())];
|
|
|
|
await _repo.AddAsync(f);
|
|
return Map(f);
|
|
}
|
|
|
|
public async Task<bool> UpdateAsync(Guid id, UpdateFragmentDto dto)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(dto);
|
|
if (dto.Type != null)
|
|
throw new ValidationException("Type cannot be empty");
|
|
if (dto.Description != null && string.IsNullOrWhiteSpace(dto.Description))
|
|
throw new ValidationException("Description cannot be empty");
|
|
|
|
return await _repo.UpdateAsync(id, dto.Type, dto.Description, dto.Tags, dto.Time);
|
|
}
|
|
|
|
public Task<bool> RemoveAsync(Guid id) => _repo.RemoveAsync(id);
|
|
|
|
public async Task<List<FragmentDto>> SearchAsync(string? type = null, string? tag = null, DateTimeOffset? timeAfter = null)
|
|
{
|
|
var items = await _repo.SearchAsync(type, tag, timeAfter);
|
|
return [.. items.Select(Map)];
|
|
}
|
|
|
|
public async Task<List<FragmentDto>> GetByTagAsync(string tag)
|
|
{
|
|
var items = await _repo.GetByTagAsync(tag);
|
|
return [.. items.Select(Map)];
|
|
}
|
|
|
|
public async Task<List<FragmentDto>> GetByTypeAsync(string type)
|
|
{
|
|
var items = await _repo.GetByTypeAsync(type);
|
|
return [.. items.Select(Map)];
|
|
}
|
|
|
|
public async Task<List<FragmentDto>> GetAllAsync()
|
|
{
|
|
var items = await _repo.GetAllAsync();
|
|
return [.. items.Select(Map)];
|
|
}
|
|
|
|
public async Task<FragmentDto?> GetByIdAsync(Guid id)
|
|
{
|
|
var f = await _repo.GetByIdAsync(id);
|
|
return f is null ? null : Map(f);
|
|
}
|
|
}
|