Skip to content

Commit

Permalink
Public properties : Fixes public types to be upgrade safe so new cont…
Browse files Browse the repository at this point in the history
…ent is not lost on deserialize and serialize paths. (#2712)

The current public types like ContainerProperties lose any new fields added by the service currently. If the property is not a know field is lost on the deserialize/serialize logic. This can possibly break older SDKs if new contract elements are added by the service and an update is attempted. The service might throw an exception thinking the user attempted to remove the new field when it was lost in the serialization logic.

To fix this issue a new internal dictionary is added to all the public service contract types to hold any additional properties the c# poco type is not aware of. So that in case of service contract evolution if metadata information changes, we won't loose any information.
  • Loading branch information
sourabh1007 committed Sep 15, 2021
1 parent f5e1ae6 commit 3c6d747
Show file tree
Hide file tree
Showing 34 changed files with 765 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos
using System.Linq;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Details of an encryption key for use with the Azure Cosmos DB service.
Expand Down Expand Up @@ -61,6 +62,7 @@ internal ClientEncryptionKeyProperties(ClientEncryptionKeyProperties source)
this.WrappedDataEncryptionKey = new byte[source.WrappedDataEncryptionKey.Length];
source.WrappedDataEncryptionKey.CopyTo(this.WrappedDataEncryptionKey, index: 0);
}
this.AdditionalProperties = source.AdditionalProperties;
}

/// <summary>
Expand Down Expand Up @@ -148,6 +150,13 @@ internal ClientEncryptionKeyProperties(ClientEncryptionKeyProperties source)
[JsonProperty(PropertyName = Constants.Properties.RId, NullValueHandling = NullValueHandling.Ignore)]
internal string ResourceId { get; set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

/// <summary>
/// Compares this instance of client encryption key properties to another object.
/// </summary>
Expand All @@ -170,6 +179,7 @@ public bool Equals(ClientEncryptionKeyProperties other)
this.EncryptionAlgorithm == other.EncryptionAlgorithm &&
ClientEncryptionKeyProperties.Equals(this.WrappedDataEncryptionKey, other.WrappedDataEncryptionKey) &&
EqualityComparer<EncryptionKeyWrapMetadata>.Default.Equals(this.EncryptionKeyWrapMetadata, other.EncryptionKeyWrapMetadata) &&
this.AdditionalProperties.EqualsTo(other.AdditionalProperties) &&
this.CreatedTime == other.CreatedTime &&
this.ETag == other.ETag &&
this.LastModified == other.LastModified &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Metadata that a key wrapping provider can use to wrap/unwrap data encryption keys.
Expand Down Expand Up @@ -69,6 +70,13 @@ public EncryptionKeyWrapMetadata(EncryptionKeyWrapMetadata source)
[JsonProperty(PropertyName = "value", NullValueHandling = NullValueHandling.Ignore)]
public string Value { get; private set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

/// <inheritdoc/>
public override bool Equals(object obj)
{
Expand Down Expand Up @@ -98,7 +106,8 @@ public bool Equals(EncryptionKeyWrapMetadata other)
return other != null &&
this.Type == other.Type &&
this.Name == other.Name &&
this.Value == other.Value;
this.Value == other.Value &&
this.AdditionalProperties.EqualsTo(other.AdditionalProperties);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

namespace Microsoft.Azure.Cosmos
{
using System.Collections.Generic;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

internal sealed class OfferAutoscaleAutoUpgradeProperties
{
Expand All @@ -25,6 +27,13 @@ internal OfferAutoscaleAutoUpgradeProperties(int incrementPercent)
[JsonProperty(PropertyName = Constants.Properties.AutopilotThroughputPolicy, NullValueHandling = NullValueHandling.Ignore)]
public AutoscaleThroughputProperties ThroughputProperties { get; private set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

internal string GetJsonString()
{
return JsonConvert.SerializeObject(this, Formatting.None);
Expand All @@ -39,6 +48,14 @@ public AutoscaleThroughputProperties(int incrementPercent)

[JsonProperty(PropertyName = Constants.Properties.AutopilotThroughputPolicyIncrementPercent, NullValueHandling = NullValueHandling.Ignore)]
public int IncrementPercent { get; private set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

namespace Microsoft.Azure.Cosmos
{
using System.Collections.Generic;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

internal sealed class OfferAutoscaleProperties
{
Expand Down Expand Up @@ -39,6 +41,13 @@ internal OfferAutoscaleProperties(
[JsonProperty(PropertyName = Constants.Properties.AutopilotAutoUpgradePolicy, NullValueHandling = NullValueHandling.Ignore)]
public OfferAutoscaleAutoUpgradeProperties AutoscaleAutoUpgradeProperties { get; private set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

internal string GetJsonString()
{
return JsonConvert.SerializeObject(this, Formatting.None);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace Microsoft.Azure.Cosmos
{
using System;
using System.Collections.Generic;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

internal sealed class OfferContentProperties
{
Expand Down Expand Up @@ -54,6 +56,13 @@ private OfferContentProperties(OfferAutoscaleProperties autoscaleProperties)
[JsonProperty(PropertyName = Constants.Properties.OfferLastReplaceTimestamp, DefaultValueHandling = DefaultValueHandling.Ignore)]
internal long? OfferLastReplaceTimestamp { get; private set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

public static OfferContentProperties CreateManualOfferConent(int throughput)
{
return new OfferContentProperties(manualThroughput: throughput);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos
{
using System.Collections.Generic;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

/// <summary>
/// Represents the consistency policy of a database account of the Azure Cosmos DB service.
Expand Down Expand Up @@ -44,6 +46,13 @@ public class AccountConsistency
[JsonProperty(PropertyName = Constants.Properties.MaxStalenessIntervalInSeconds)]
public int MaxStalenessIntervalInSeconds { get; internal set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

internal Documents.ConsistencyLevel ToDirectConsistencyLevel()
{
return (Documents.ConsistencyLevel)this.DefaultConsistencyLevel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos
using System.Collections.ObjectModel;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Represents a <see cref="AccountProperties"/>. A AccountProperties is the container for databases in the Azure Cosmos DB service.
Expand Down Expand Up @@ -233,5 +234,12 @@ private IDictionary<string, object> QueryStringToDictConverter()
return new Dictionary<string, object>();
}
}

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }
}
}
9 changes: 9 additions & 0 deletions Microsoft.Azure.Cosmos/src/Resource/Settings/AccountRegion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos
{
using System.Collections.Generic;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// The AccountLocation class represents an Azure Cosmos DB database account in a specific region.
Expand All @@ -25,5 +27,12 @@ public class AccountRegion
/// </summary>
[JsonProperty(PropertyName = Constants.Properties.DatabaseAccountEndpoint)]
public string Endpoint { get; internal set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos
{
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Represents bounding box for geometry spatial path in the Azure Cosmos DB service
Expand Down Expand Up @@ -70,5 +72,12 @@ public double Ymax
{
get; set;
}

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }
}
}
10 changes: 10 additions & 0 deletions Microsoft.Azure.Cosmos/src/Resource/Settings/ChangeFeedPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace Microsoft.Azure.Cosmos
{
using System;
using System.Collections.Generic;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Represents the change feed policy configuration for a container in the Azure Cosmos DB service.
Expand Down Expand Up @@ -73,5 +75,13 @@ public TimeSpan FullFidelityRetention
/// Disables the retention log.
/// </summary>
public static TimeSpan FullFidelityNoRetention => TimeSpan.Zero;

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Microsoft.Azure.Cosmos
{
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Path that needs encryption and the associated settings within <see cref="ClientEncryptionPolicy"/>.
Expand Down Expand Up @@ -39,5 +41,12 @@ sealed class ClientEncryptionIncludedPath
/// </summary>
[JsonProperty(PropertyName = "encryptionAlgorithm")]
public string EncryptionAlgorithm { get; set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos
using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Client encryption policy.
Expand Down Expand Up @@ -51,6 +52,13 @@ public IEnumerable<ClientEncryptionIncludedPath> IncludedPaths
[JsonProperty(PropertyName = "policyFormatVersion")]
public int PolicyFormatVersion { get; private set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }

/// <summary>
/// Ensures that partition key paths are not specified in the client encryption policy for encryption.
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions Microsoft.Azure.Cosmos/src/Resource/Settings/CompositePath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos
{
using System.Collections.Generic;
using System.Runtime.Serialization;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

/// <summary>
/// Defines the target data type of an index path specification in the Azure Cosmos DB service.
Expand Down Expand Up @@ -49,5 +51,12 @@ public sealed class CompositePath
[JsonProperty(PropertyName = Constants.Properties.Order)]
[JsonConverter(typeof(StringEnumConverter))]
public CompositePathSortOrder Order { get; set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace Microsoft.Azure.Cosmos
{
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

/// <summary>
/// Represents a conflict in the Azure Cosmos DB service.
Expand Down Expand Up @@ -65,5 +67,12 @@ public class ConflictProperties

[JsonProperty(PropertyName = Documents.Constants.Properties.ConflictLSN)]
internal long ConflictLSN { get; set; }

/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }
}
}
Loading

0 comments on commit 3c6d747

Please sign in to comment.