using System.Text.Json; using Api.Data; using Api.Data.Entities; using Api.Data.Repositories.Contracts; using Api.Models.Responses; using Microsoft.EntityFrameworkCore; namespace Api.Data.Repositories; public sealed class EfMatcherRepository : IMatcherRepository { private readonly CvMatcherDbContext _db; private readonly ILogger _logger; public EfMatcherRepository(CvMatcherDbContext db, ILogger logger) { _db = db; _logger = logger; } public async Task InitializeAsync(CancellationToken ct) { _logger.LogInformation("Ensuring CV matcher database schema exists using EF Core"); await _db.Database.EnsureCreatedAsync(ct); } public async Task GetMatchAsync(string cvDocumentId, string jobDocumentId, CancellationToken ct) { var json = await _db.CvMatchResults .AsNoTracking() .Where(x => x.CvDocumentId == cvDocumentId && x.JobDocumentId == jobDocumentId) .Select(x => x.ResultJson) .FirstOrDefaultAsync(ct); if (string.IsNullOrWhiteSpace(json)) return null; var result = JsonSerializer.Deserialize(json, new JsonSerializerOptions(JsonSerializerDefaults.Web)); if (result is not null) result.Cached = true; return result; } public async Task SaveMatchAsync(string cvDocumentId, string jobDocumentId, JobMatchResponse response, CancellationToken ct) { var exists = await _db.CvMatchResults.AnyAsync( x => x.CvDocumentId == cvDocumentId && x.JobDocumentId == jobDocumentId, ct); if (exists) return; _db.CvMatchResults.Add(new CvMatchResultEntity { Id = Guid.NewGuid().ToString("N"), CvDocumentId = cvDocumentId, JobDocumentId = jobDocumentId, ResultJson = JsonSerializer.Serialize(response, new JsonSerializerOptions(JsonSerializerDefaults.Web)), Score = response.Score, CreatedAt = DateTime.UtcNow }); await _db.SaveChangesAsync(ct); } public async Task GetChatCompletionAsync(string cacheKey, CancellationToken ct) { return await _db.CvMatcherChatCache .AsNoTracking() .Where(x => x.CacheKey == cacheKey) .Select(x => x.ResponseText) .FirstOrDefaultAsync(ct); } public async Task SaveChatCompletionAsync(string cacheKey, string model, decimal temperature, string responseText, CancellationToken ct) { var exists = await _db.CvMatcherChatCache.AnyAsync(x => x.CacheKey == cacheKey, ct); if (exists) return; _db.CvMatcherChatCache.Add(new CvMatcherChatCacheEntity { CacheKey = cacheKey, Model = model, Temperature = temperature, ResponseText = responseText, CreatedAt = DateTime.UtcNow }); await _db.SaveChangesAsync(ct); } }