diff --git a/src/Particular.LicensingComponent.Contracts/LicensedEndpointDetails.cs b/src/Particular.LicensingComponent.Contracts/LicensedEndpointDetails.cs index d61bd4abcf..57fa350fbf 100644 --- a/src/Particular.LicensingComponent.Contracts/LicensedEndpointDetails.cs +++ b/src/Particular.LicensingComponent.Contracts/LicensedEndpointDetails.cs @@ -41,6 +41,7 @@ public record LicensedEndpoint public string ClientId { get; set; } = Guid.NewGuid().ToString(); public required string Name { get; set; } public required int Classification { get; set; } + public bool Amended { get; set; } = false; public string? EndpointSize { get; set; } public QueueIdentity[] Queues { get; set; } = []; diff --git a/src/Particular.LicensingComponent.Persistence.InMemory/InMemoryLicensingDataStore.cs b/src/Particular.LicensingComponent.Persistence.InMemory/InMemoryLicensingDataStore.cs index 11669f9cd4..9567b97bce 100644 --- a/src/Particular.LicensingComponent.Persistence.InMemory/InMemoryLicensingDataStore.cs +++ b/src/Particular.LicensingComponent.Persistence.InMemory/InMemoryLicensingDataStore.cs @@ -200,7 +200,7 @@ public Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, Cancella public Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment? result, CancellationToken cancellationToken = default) { - result?.UnmappedQueues = [.. endpointDetailsAmendment?.UnmappedQueues ?? [], .. result.UnmappedQueues]; + result.MergeWithExisting(endpointDetailsAmendment); endpointDetailsAmendment = result; return Task.CompletedTask; } diff --git a/src/Particular.LicensingComponent.Persistence/LicenseMetadata.cs b/src/Particular.LicensingComponent.Persistence/LicenseMetadata.cs index 60079668bb..3bde1d3c72 100644 --- a/src/Particular.LicensingComponent.Persistence/LicenseMetadata.cs +++ b/src/Particular.LicensingComponent.Persistence/LicenseMetadata.cs @@ -41,6 +41,7 @@ .. baseDetails.Endpoints.Where(endpoint => !amendments.RemovedEndpointIds.Contai { Name = amendment?.Name ?? endpoint.Name, Classification = amendment?.Classification ?? endpoint.Classification, + Amended = amendment is not null, Queues = [.. endpoint.Queues.Except( [ .. amendments.UnassignedQueues, @@ -64,5 +65,19 @@ .. amendments.Endpoints.Where(endpoint => !baseDetails.Endpoints.Any(baseEndpoin return baseDetails; } } + + extension(LicensedEndpointDetailsAmendment? amendment) + { + public void MergeWithExisting(LicensedEndpointDetailsAmendment? existing) + { + if (amendment is null || existing is null) + { + return; + } + + // these do not round-trip the full collections, so reapply what we already have + amendment.UnmappedQueues = [.. existing.UnmappedQueues, .. amendment.UnmappedQueues]; + } + } } } diff --git a/src/ServiceControl.Persistence.EFCore/Implementation/LicensingDataStore.cs b/src/ServiceControl.Persistence.EFCore/Implementation/LicensingDataStore.cs index 5a359a7a9a..806869607d 100644 --- a/src/ServiceControl.Persistence.EFCore/Implementation/LicensingDataStore.cs +++ b/src/ServiceControl.Persistence.EFCore/Implementation/LicensingDataStore.cs @@ -348,8 +348,7 @@ public Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendmen await context.SaveChangesAsync(cancellationToken); return; } - // these do not round-trip - result.UnmappedQueues = [.. existing.UnmappedQueues, .. result.UnmappedQueues]; + result.MergeWithExisting(existing); } await context.StoreSetting(SettingKeys.LicensedEndpointDetailsAmendment, result, token); }, cancellationToken); diff --git a/src/ServiceControl.Persistence.RavenDB/Throughput/LicensingDataStore.cs b/src/ServiceControl.Persistence.RavenDB/Throughput/LicensingDataStore.cs index 61c50a1cec..1641d4856b 100644 --- a/src/ServiceControl.Persistence.RavenDB/Throughput/LicensingDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/Throughput/LicensingDataStore.cs @@ -402,8 +402,7 @@ public async Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAm var existing = await session.LoadAsync(LicencedEndpointDetailsAmendmentDocumentId, cancellationToken); if (existing is not null) { - // these do not round-trip - result.UnmappedQueues = [.. existing.UnmappedQueues, .. result.UnmappedQueues]; + result.MergeWithExisting(existing); session.Advanced.Evict(existing); }