- 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>
72 lines
2.6 KiB
C#
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()));
|
|
}
|