public static DeviceTwinModel Patch()

in src/Azure.IIoT.OpcUa.Publisher.Service/src/Services/Extensions/ApplicationRegistrationEx.cs [42:228]


        public static DeviceTwinModel Patch(this ApplicationRegistration? existing,
            ApplicationRegistration update, IJsonSerializer serializer, TimeProvider timeProvider)
        {
            var tags = new Dictionary<string, VariantValue>();
            var desired = new Dictionary<string, VariantValue>();

            // Tags

            if (update?.ApplicationId != null &&
                update.ApplicationId != existing?.ApplicationId)
            {
                tags.Add(nameof(ApplicationId), update.ApplicationId);
            }

            if (update?.IsDisabled != null &&
                update.IsDisabled != existing?.IsDisabled)
            {
                tags.Add(nameof(EntityRegistration.IsDisabled), (update?.IsDisabled ?? false) ?
                    true : (bool?)null);
                tags.Add(nameof(EntityRegistration.NotSeenSince), (update?.IsDisabled ?? false) ?
                    timeProvider.GetUtcNow().UtcDateTime : (DateTime?)null);
            }

            if (update?.SiteOrGatewayId != existing?.SiteOrGatewayId)
            {
                tags.Add(nameof(EntityRegistration.SiteOrGatewayId), update?.SiteOrGatewayId);
            }

            if (update?.DiscovererId != existing?.DiscovererId)
            {
                tags.Add(nameof(ApplicationRegistration.DiscovererId), update?.DiscovererId);
            }

            if (update?.SiteId != existing?.SiteId)
            {
                tags.Add(nameof(EntityRegistration.SiteId), update?.SiteId);
            }

            tags.Add(nameof(EntityRegistration.DeviceType), update?.DeviceType);

            if (update?.ApplicationType != null &&
                update.ApplicationType != existing?.ApplicationType)
            {
                tags.Add(nameof(ApplicationRegistration.ApplicationType),
                    serializer.FromObject(update.ApplicationType.ToString()));
                tags.Add(nameof(ApplicationType.Server),
                    update.ApplicationType != ApplicationType.Client);
                tags.Add(nameof(ApplicationType.Client),
                    update.ApplicationType != ApplicationType.Server &&
                    update.ApplicationType != ApplicationType.DiscoveryServer);
                tags.Add(nameof(ApplicationType.DiscoveryServer),
                    update.ApplicationType == ApplicationType.DiscoveryServer);
            }

            if (update?.ApplicationUri != existing?.ApplicationUri)
            {
                tags.Add(nameof(ApplicationRegistration.ApplicationUri),
                    update?.ApplicationUri);
                tags.Add(nameof(ApplicationRegistration.ApplicationUriLC),
                    update?.ApplicationUriLC);
            }

            if (update?.RecordId != existing?.RecordId)
            {
                tags.Add(nameof(ApplicationRegistration.RecordId),
                    update?.RecordId);
            }

            if (update?.ApplicationName != existing?.ApplicationName)
            {
                tags.Add(nameof(ApplicationRegistration.ApplicationName),
                    update?.ApplicationName);
            }

            if (update?.Locale != existing?.Locale)
            {
                tags.Add(nameof(ApplicationRegistration.Locale),
                    update?.Locale);
            }

            if (update?.DiscoveryProfileUri != existing?.DiscoveryProfileUri)
            {
                tags.Add(nameof(ApplicationRegistration.DiscoveryProfileUri),
                    update?.DiscoveryProfileUri);
            }

            if (update?.GatewayServerUri != existing?.GatewayServerUri)
            {
                tags.Add(nameof(ApplicationRegistration.GatewayServerUri),
                    update?.GatewayServerUri);
            }

            if (update?.ProductUri != existing?.ProductUri)
            {
                tags.Add(nameof(ApplicationRegistration.ProductUri), update?.ProductUri);
            }

            var urlUpdate = update?.DiscoveryUrls.DecodeAsList().SequenceEqualsSafe(
                existing?.DiscoveryUrls?.DecodeAsList());
            if (!(urlUpdate ?? true))
            {
                tags.Add(nameof(ApplicationRegistration.DiscoveryUrls),
                    update?.DiscoveryUrls == null ?
                    VariantValue.Null : serializer.FromObject(update.DiscoveryUrls));
            }

            var capsUpdate = update?.Capabilities.DecodeAsSet().SetEqualsSafe(
                existing?.Capabilities?.DecodeAsSet());
            if (!(capsUpdate ?? true))
            {
                tags.Add(nameof(ApplicationRegistration.Capabilities),
                    update?.Capabilities == null ?
                    VariantValue.Null : serializer.FromObject(update.Capabilities));
            }

            var namesUpdate = update?.LocalizedNames.DictionaryEqualsSafe(
                existing?.LocalizedNames);
            if (!(namesUpdate ?? true))
            {
                tags.Add(nameof(ApplicationRegistration.LocalizedNames),
                    update?.LocalizedNames == null ?
                    VariantValue.Null : serializer.FromObject(update.LocalizedNames));
            }

            var hostsUpdate = update?.HostAddresses.DecodeAsList().SequenceEqualsSafe(
                existing?.HostAddresses?.DecodeAsList());
            if (!(hostsUpdate ?? true))
            {
                tags.Add(nameof(ApplicationRegistration.HostAddresses),
                    update?.HostAddresses == null ?
                    VariantValue.Null : serializer.FromObject(update.HostAddresses));
            }

            if (update?.CreateAuthorityId != existing?.CreateAuthorityId)
            {
                tags.Add(nameof(ApplicationRegistration.CreateAuthorityId),
                    update?.CreateAuthorityId);
            }
            if (update?.CreateTime != existing?.CreateTime)
            {
                tags.Add(nameof(ApplicationRegistration.CreateTime),
                    update?.CreateTime);
            }

            if (update?.UpdateAuthorityId != existing?.UpdateAuthorityId)
            {
                tags.Add(nameof(ApplicationRegistration.UpdateAuthorityId),
                    update?.UpdateAuthorityId);
            }
            if (update?.UpdateTime != existing?.UpdateTime)
            {
                tags.Add(nameof(ApplicationRegistration.UpdateTime),
                    update?.UpdateTime);
            }

            // Recalculate identity

            var applicationUri = existing?.ApplicationUri;
            if (update?.ApplicationUri != null)
            {
                applicationUri = update?.ApplicationUri;
            }
            if (applicationUri == null)
            {
                throw new ArgumentException(nameof(ApplicationRegistration.ApplicationUri));
            }

            var siteOrGatewayId = (existing?.SiteOrGatewayId) ??
                (update?.SiteOrGatewayId) ?? EntityRegistration.UnknownGatewayOrSiteId;

            var applicationType = existing?.ApplicationType;
            if (update?.ApplicationType != null)
            {
                applicationType = update?.ApplicationType ?? ApplicationType.Server;
            }

            var id = ApplicationInfoModelEx.CreateApplicationId(
                siteOrGatewayId, applicationUri, applicationType);
            return new DeviceTwinModel
            {
                Id = id ?? string.Empty,
                // Force creation of new identity
                Etag = existing?.DeviceId != id ? string.Empty : existing?.Etag ?? string.Empty,
                Tags = tags,
                Desired = desired
            };
        }