|
- using System.Collections.Concurrent;
-
- namespace Campaign_Tracker.Server.Municipalities;
-
- public sealed class InMemoryMunicipalityAddressRepository : IMunicipalityAddressRepository
- {
- private readonly ConcurrentDictionary<string, MunicipalityAddress> _addresses =
- new(StringComparer.OrdinalIgnoreCase);
- private readonly object _lock = new();
- private readonly TimeProvider _timeProvider;
-
- public InMemoryMunicipalityAddressRepository(TimeProvider timeProvider)
- {
- _timeProvider = timeProvider;
- }
-
- public Task<IReadOnlyList<MunicipalityAddress>> GetByProfileIdAsync(
- string profileId,
- CancellationToken cancellationToken = default)
- {
- var result = _addresses.Values
- .Where(a => a.ProfileId == profileId && !a.IsDeleted)
- .OrderByDescending(a => a.EffectiveDate)
- .ToArray();
- return Task.FromResult<IReadOnlyList<MunicipalityAddress>>(result);
- }
-
- public Task<MunicipalityAddress?> GetByIdAsync(
- string addressId,
- CancellationToken cancellationToken = default)
- {
- _addresses.TryGetValue(addressId, out var address);
- return Task.FromResult(address is { IsDeleted: false } ? address : null);
- }
-
- public Task<MunicipalityAddressSaveResult> AddAsync(
- string profileId,
- string addressType,
- string street,
- string city,
- string state,
- string zipCode,
- DateTimeOffset effectiveDate,
- string actorIdentity,
- CancellationToken cancellationToken = default)
- {
- var now = _timeProvider.GetUtcNow();
-
- lock (_lock)
- {
- // Per-type history: mark existing current address of same type as not-current
- foreach (var existing in _addresses.Values
- .Where(a => a.ProfileId == profileId && a.AddressType == addressType
- && a.IsCurrent && !a.IsDeleted))
- {
- _addresses[existing.AddressId] = existing with
- {
- IsCurrent = false,
- UpdatedAt = now,
- UpdatedBy = actorIdentity
- };
- }
-
- var address = new MunicipalityAddress(
- AddressId: Guid.NewGuid().ToString("N"),
- ProfileId: profileId,
- AddressType: addressType,
- Street: street,
- City: city,
- State: state,
- ZipCode: zipCode,
- EffectiveDate: effectiveDate,
- IsCurrent: true,
- IsDeleted: false,
- CreatedAt: now,
- CreatedBy: actorIdentity,
- UpdatedAt: now,
- UpdatedBy: actorIdentity);
-
- _addresses[address.AddressId] = address;
- return Task.FromResult(MunicipalityAddressSaveResult.Success(address));
- }
- }
-
- public Task<MunicipalityAddressSaveResult> UpdateAsync(
- string addressId,
- string addressType,
- string street,
- string city,
- string state,
- string zipCode,
- DateTimeOffset effectiveDate,
- string actorIdentity,
- CancellationToken cancellationToken = default)
- {
- var now = _timeProvider.GetUtcNow();
-
- lock (_lock)
- {
- if (!_addresses.TryGetValue(addressId, out var existing) || existing.IsDeleted)
- return Task.FromResult(MunicipalityAddressSaveResult.NotFound(addressId));
-
- // Preserve the old record in history by marking it not-current
- _addresses[addressId] = existing with
- {
- IsCurrent = false,
- UpdatedAt = now,
- UpdatedBy = actorIdentity
- };
-
- // Mark any other current addresses of the same type as not-current
- foreach (var other in _addresses.Values
- .Where(a => a.ProfileId == existing.ProfileId && a.AddressType == addressType
- && a.IsCurrent && a.AddressId != addressId && !a.IsDeleted))
- {
- _addresses[other.AddressId] = other with
- {
- IsCurrent = false,
- UpdatedAt = now,
- UpdatedBy = actorIdentity
- };
- }
-
- // Insert a new current record (history-preserving update)
- var updated = new MunicipalityAddress(
- AddressId: Guid.NewGuid().ToString("N"),
- ProfileId: existing.ProfileId,
- AddressType: addressType,
- Street: street,
- City: city,
- State: state,
- ZipCode: zipCode,
- EffectiveDate: effectiveDate,
- IsCurrent: true,
- IsDeleted: false,
- CreatedAt: now,
- CreatedBy: actorIdentity,
- UpdatedAt: now,
- UpdatedBy: actorIdentity);
-
- _addresses[updated.AddressId] = updated;
- return Task.FromResult(MunicipalityAddressSaveResult.Success(updated));
- }
- }
-
- public Task<MunicipalityAddressSaveResult> SoftDeleteAsync(
- string addressId,
- string actorIdentity,
- CancellationToken cancellationToken = default)
- {
- var now = _timeProvider.GetUtcNow();
-
- lock (_lock)
- {
- if (!_addresses.TryGetValue(addressId, out var existing) || existing.IsDeleted)
- return Task.FromResult(MunicipalityAddressSaveResult.NotFound(addressId));
-
- _addresses[addressId] = existing with
- {
- IsDeleted = true,
- IsCurrent = false,
- UpdatedAt = now,
- UpdatedBy = actorIdentity
- };
-
- return Task.FromResult(MunicipalityAddressSaveResult.Success(_addresses[addressId]));
- }
- }
- }
|