NALU/src/Nalu.Jobs/NameRepository.cs
Ricardo Carneiro e01787ee60 Add deploy infrastructure, missing validators, and new features
- Add Docker Swarm deploy stack, CI workflow (.gitea), entrypoint script
- Fix Dockerfile to build Nalu.Web (was pointing to old Nalu.Api path)
- Add validate_name.md and other missing validators to prod
- Add Stripe endpoints, HangfireDashboardAuth, InputGuard, NameLookupService
- Add SuspiciousRateLimiter, En/ pages, Legal/ pages, Seguranca docs
- Add Nalu.Jobs and Nalu.NameImporter projects (were untracked)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 12:31:12 -03:00

72 lines
2.6 KiB
C#

using MongoDB.Driver;
namespace Nalu.Jobs;
public class NameRepository
{
private readonly IMongoCollection<NomeBr> _nomes;
private readonly IMongoCollection<JobRun> _jobRuns;
public NameRepository(IMongoDatabase db)
{
_nomes = db.GetCollection<NomeBr>("nomes_br");
_jobRuns = db.GetCollection<JobRun>("job_runs");
}
public async Task EnsureIndexesAsync(CancellationToken ct)
{
var model = new CreateIndexModel<NomeBr>(
Builders<NomeBr>.IndexKeys.Ascending(x => x.Nome),
new CreateIndexOptions { Unique = true, Name = "idx_nome_unique" });
await _nomes.Indexes.CreateOneAsync(model, cancellationToken: ct);
}
/// <summary>
/// Upserts a single name.
/// New doc: inserts all fields. Existing: increments frequencia, merges genero, updates timestamp.
/// Returns true if inserted (new), false if updated.
/// </summary>
public async Task<bool> UpsertAsync(AggregatedName name, DateTime now, CancellationToken ct)
{
var nomeDisplay = ToTitleCase(name.Nome);
var filter = Builders<NomeBr>.Filter.Eq(x => x.Nome, name.Nome);
var existing = await _nomes.Find(filter).FirstOrDefaultAsync(ct);
UpdateDefinition<NomeBr> update;
if (existing is null)
{
update = Builders<NomeBr>.Update
.SetOnInsert(x => x.Nome, name.Nome)
.SetOnInsert(x => x.NomeDisplay, nomeDisplay)
.SetOnInsert(x => x.Tipo, "primeiro_nome")
.SetOnInsert(x => x.Genero, name.Genero)
.SetOnInsert(x => x.Fonte, "ibge_censo")
.Inc(x => x.Frequencia, name.Frequencia)
.Set(x => x.UltimaAtualizacao, now);
}
else
{
var mergedGenero = existing.Genero == name.Genero ? existing.Genero : "N";
update = Builders<NomeBr>.Update
.Inc(x => x.Frequencia, name.Frequencia)
.Set(x => x.Genero, mergedGenero)
.Set(x => x.UltimaAtualizacao, now);
}
var result = await _nomes.UpdateOneAsync(filter, update,
new UpdateOptions { IsUpsert = true }, ct);
return result.UpsertedId is not null;
}
public async Task SaveJobRunAsync(JobRun run, CancellationToken ct) =>
await _jobRuns.InsertOneAsync(run, null, ct);
private static string ToTitleCase(string upper) =>
string.Join(" ", upper.Split(' ')
.Select(w => w.Length == 0 ? w :
char.ToUpperInvariant(w[0]) + w[1..].ToLowerInvariant()));
}