Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 171 additions & 92 deletions src/Microsoft.OData.Core/Json/ODataJsonResourceDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,49 +137,22 @@ internal ODataDeletedResource ReadDeletedResource()
this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);

ODataDeletedResource deletedResource = null;
DeltaDeletedEntryReason reason = DeltaDeletedEntryReason.Changed;
Uri id = null;

// If the current node is the deleted property - read it.
if (this.JsonReader.NodeType == JsonNodeType.Property)
{
string propertyName = this.JsonReader.GetPropertyName();

// Case 1: removed property first
if (string.Equals(ODataJsonConstants.PrefixedODataRemovedPropertyName, propertyName, StringComparison.Ordinal)
|| this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataRemovedPropertyName, propertyName))
{
DeltaDeletedEntryReason reason = DeltaDeletedEntryReason.Changed;
Uri id = null;

// Read over the property to move to its value.
this.JsonReader.Read();

// Read the removed object and extract the reason, if present
this.AssertJsonCondition(JsonNodeType.StartObject, JsonNodeType.PrimitiveValue /*null*/);
if (this.JsonReader.NodeType != JsonNodeType.PrimitiveValue)
{
while (this.JsonReader.NodeType != JsonNodeType.EndObject && this.JsonReader.Read())
{
// If the current node is the reason property - read it.
if (this.JsonReader.NodeType == JsonNodeType.Property &&
string.Equals(ODataJsonConstants.ODataReasonPropertyName, this.JsonReader.GetPropertyName(), StringComparison.Ordinal))
{
// Read over the property to move to its value.
this.JsonReader.Read();

// Read the reason value.
if (string.Equals(ODataJsonConstants.ODataReasonDeletedValue, this.JsonReader.ReadStringValue(), StringComparison.Ordinal))
{
reason = DeltaDeletedEntryReason.Deleted;
}
}
}
}
else
{
object value = this.JsonReader.GetValue();
if (value != null)
{
throw new ODataException(Error.Format(SRResources.ODataJsonResourceDeserializer_DeltaRemovedAnnotationMustBeObject, value));
}
}
reason = ReadDeletedReason();

// read over end object or null value
this.JsonReader.Read();
Expand All @@ -204,6 +177,31 @@ internal ODataDeletedResource ReadDeletedResource()

deletedResource = ReaderUtils.CreateDeletedResource(id, reason);
}
//// Case 2: id property first
//else if (this.JsonReader.NodeType == JsonNodeType.Property && !propertyName.EndsWith(ODataJsonConstants.SimplifiedODataDeltaPropertyName) && !propertyName.Contains(ODataJsonConstants.ODataPropertyAnnotationSeparatorChar))
//{
// // read over end object or null value
// this.JsonReader.Read();

// ReadOnlyMemory<char> idPropertyName = propertyName.AsMemory();
// object value = this.JsonReader.ReadPrimitiveValue();

// // If the next property is the removed property - read it.
// propertyName = this.JsonReader.GetPropertyName();
// if (string.Equals(ODataJsonConstants.PrefixedODataRemovedPropertyName, propertyName, StringComparison.Ordinal)
// || this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataRemovedPropertyName, propertyName))
// {
// // Read over the property to move to its value.
// this.JsonReader.Read();

// reason = ReadDeletedReason();

// // Read over end object or null value
// this.JsonReader.Read();

// deletedResource = ReaderUtils.CreateDeletedResource(id, reason, KeyValuePair.Create<string, object>(idPropertyName.Span.ToString(), value));
// }
//}
}

this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);
Expand Down Expand Up @@ -2431,79 +2429,75 @@ internal async Task<ODataDeletedResource> ReadDeletedResourceAsync()
{
this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);

if (this.JsonReader.NodeType != JsonNodeType.Property)
{
this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);
return null;
}

ODataDeletedResource deletedResource = null;
DeltaDeletedEntryReason reason = DeltaDeletedEntryReason.Changed;
Uri id = null;

// If the current node is the deleted property - read it.
if (this.JsonReader.NodeType == JsonNodeType.Property)
string propertyName = await this.JsonReader.GetPropertyNameAsync().ConfigureAwait(false);

// Case 1: removed property first
if (string.Equals(ODataJsonConstants.PrefixedODataRemovedPropertyName, propertyName, StringComparison.Ordinal)
|| this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataRemovedPropertyName, propertyName))
{
string propertyName = await this.JsonReader.GetPropertyNameAsync()
.ConfigureAwait(false);
if (string.Equals(ODataJsonConstants.PrefixedODataRemovedPropertyName, propertyName, StringComparison.Ordinal)
|| this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataRemovedPropertyName, propertyName))
// Read over the property to move to its value.
await this.JsonReader.ReadAsync().ConfigureAwait(false);

reason = await ReadDeletedReasonAsync();

// Read over end object or null value
await this.JsonReader.ReadAsync().ConfigureAwait(false);

// A deleted object must have at least either the odata id annotation or the key values
if (this.JsonReader.NodeType != JsonNodeType.Property)
{
DeltaDeletedEntryReason reason = DeltaDeletedEntryReason.Changed;
Uri id = null;
throw new ODataException(SRResources.ODataWriterCore_DeltaResourceWithoutIdOrKeyProperties);
}

// If the next property is the id property - read it.
propertyName = await this.JsonReader.GetPropertyNameAsync().ConfigureAwait(false);
if (string.Equals(ODataJsonConstants.PrefixedODataIdPropertyName, propertyName, StringComparison.Ordinal)
|| this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataIdPropertyName, propertyName))
{
// Read over the property to move to its value.
await this.JsonReader.ReadAsync()
.ConfigureAwait(false);
await this.JsonReader.ReadAsync().ConfigureAwait(false);

// Read the removed object and extract the reason, if present
this.AssertJsonCondition(JsonNodeType.StartObject, JsonNodeType.PrimitiveValue /*null*/);
object removedValue;
if (this.JsonReader.NodeType != JsonNodeType.PrimitiveValue)
{
while (this.JsonReader.NodeType != JsonNodeType.EndObject && await this.JsonReader.ReadAsync().ConfigureAwait(false))
{
// If the current node is the reason property - read it.
if (this.JsonReader.NodeType == JsonNodeType.Property
&& string.Equals(ODataJsonConstants.ODataReasonPropertyName, await this.JsonReader.GetPropertyNameAsync().ConfigureAwait(false), StringComparison.Ordinal))
{
// Read over the property to move to its value.
await this.JsonReader.ReadAsync()
.ConfigureAwait(false);
// Read the id value.
id = UriUtils.StringToUri(await this.JsonReader.ReadStringValueAsync().ConfigureAwait(false));
}

// Read the reason value.
if (string.Equals(ODataJsonConstants.ODataReasonDeletedValue, await this.JsonReader.ReadStringValueAsync().ConfigureAwait(false), StringComparison.Ordinal))
{
reason = DeltaDeletedEntryReason.Deleted;
}
}
}
}
else if ((removedValue = await this.JsonReader.GetValueAsync().ConfigureAwait(false)) != null)
{
throw new ODataException(
Error.Format(SRResources.ODataJsonResourceDeserializer_DeltaRemovedAnnotationMustBeObject, removedValue));
}
deletedResource = ReaderUtils.CreateDeletedResource(id, reason);
}
//else if (string.Equals(ODataJsonConstants.ODataIdPropertyName, propertyName, StringComparison.OrdinalIgnoreCase)
// || this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataRemovedPropertyName, propertyName))
//{
// // read over end object or null value
// this.JsonReader.Read();

// Read over end object or null value
await this.JsonReader.ReadAsync()
.ConfigureAwait(false);
// ReadOnlyMemory<char> idPropertyName = propertyName.AsMemory();
// object value = this.JsonReader.ReadPrimitiveValue();

// A deleted object must have at least either the odata id annotation or the key values
if (this.JsonReader.NodeType != JsonNodeType.Property)
{
throw new ODataException(SRResources.ODataWriterCore_DeltaResourceWithoutIdOrKeyProperties);
}
// // If the next property is the removed property - read it.
// propertyName = this.JsonReader.GetPropertyName();
// if (string.Equals(ODataJsonConstants.PrefixedODataRemovedPropertyName, propertyName, StringComparison.Ordinal)
// || this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataRemovedPropertyName, propertyName))
// {
// // Read over the property to move to its value.
// this.JsonReader.Read();

// If the next property is the id property - read it.
propertyName = await this.JsonReader.GetPropertyNameAsync()
.ConfigureAwait(false);
if (string.Equals(ODataJsonConstants.PrefixedODataIdPropertyName, propertyName, StringComparison.Ordinal)
|| this.CompareSimplifiedODataAnnotation(ODataJsonConstants.SimplifiedODataIdPropertyName, propertyName))
{
// Read over the property to move to its value.
await this.JsonReader.ReadAsync()
.ConfigureAwait(false);
// reason = ReadDeletedReason();

// Read the id value.
id = UriUtils.StringToUri(await this.JsonReader.ReadStringValueAsync().ConfigureAwait(false));
}
// // Read over end object or null value
// this.JsonReader.Read();

deletedResource = ReaderUtils.CreateDeletedResource(id, reason);
}
}
// deletedResource = ReaderUtils.CreateDeletedResource(id, reason, KeyValuePair.Create<string, object>(idPropertyName.Span.ToString(), value));
// }
//}

this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);

Expand Down Expand Up @@ -4332,5 +4326,90 @@ await this.JsonReader.ReadEndArrayAsync()
this.JsonReader.AssertNotBuffering();
this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);
}

/// <summary>
/// Reads the reason for a deleted entry.
/// </summary>
/// <returns>The reason for the deleted entry.</returns>
/// <exception cref="ODataException"></exception>
private DeltaDeletedEntryReason ReadDeletedReason()
{
DeltaDeletedEntryReason reason = DeltaDeletedEntryReason.Changed;

// Read the removed object and extract the reason, if present
this.AssertJsonCondition(JsonNodeType.StartObject, JsonNodeType.PrimitiveValue /*null*/);

if (this.JsonReader.NodeType != JsonNodeType.PrimitiveValue)
{
while (this.JsonReader.NodeType != JsonNodeType.EndObject && this.JsonReader.Read())
{
// If the current node is the reason property - read it.
if (this.JsonReader.NodeType == JsonNodeType.Property &&
string.Equals(ODataJsonConstants.ODataReasonPropertyName, this.JsonReader.GetPropertyName(), StringComparison.Ordinal))
{
// Read over the property to move to its value.
this.JsonReader.Read();

// Read the reason value.
if (string.Equals(ODataJsonConstants.ODataReasonDeletedValue, this.JsonReader.ReadStringValue(), StringComparison.Ordinal))
{
reason = DeltaDeletedEntryReason.Deleted;
}
}
}
}
else
{
object value = this.JsonReader.GetValue();
if (value != null)
{
throw new ODataException(Error.Format(SRResources.ODataJsonResourceDeserializer_DeltaRemovedAnnotationMustBeObject, value));
}
}

return reason;
}

/// <summary>
/// Asynchronously reads the reason for a deleted entry.
/// </summary>
/// <returns>The reason for the deleted entry.</returns>
/// <exception cref="ODataException"></exception>
private async Task<DeltaDeletedEntryReason> ReadDeletedReasonAsync()
{
DeltaDeletedEntryReason reason = DeltaDeletedEntryReason.Changed;

// Read the removed object and extract the reason, if present
this.AssertJsonCondition(JsonNodeType.StartObject, JsonNodeType.PrimitiveValue /*null*/);

object removedValue;
if (this.JsonReader.NodeType != JsonNodeType.PrimitiveValue)
{
while (this.JsonReader.NodeType != JsonNodeType.EndObject && await this.JsonReader.ReadAsync().ConfigureAwait(false))
{
// If the current node is the reason property - read it.
if (this.JsonReader.NodeType == JsonNodeType.Property
&& string.Equals(ODataJsonConstants.ODataReasonPropertyName, await this.JsonReader.GetPropertyNameAsync().ConfigureAwait(false), StringComparison.Ordinal))
{
// Read over the property to move to its value.
await this.JsonReader.ReadAsync()
.ConfigureAwait(false);

// Read the reason value.
if (string.Equals(ODataJsonConstants.ODataReasonDeletedValue, await this.JsonReader.ReadStringValueAsync().ConfigureAwait(false), StringComparison.Ordinal))
{
reason = DeltaDeletedEntryReason.Deleted;
}
}
}
}
else if ((removedValue = await this.JsonReader.GetValueAsync().ConfigureAwait(false)) != null)
{
throw new ODataException(
Error.Format(SRResources.ODataJsonResourceDeserializer_DeltaRemovedAnnotationMustBeObject, removedValue));
}

return reason;
}
}
}
23 changes: 20 additions & 3 deletions src/Microsoft.OData.Core/ReaderUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ namespace Microsoft.OData
{
#region Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Microsoft.OData.Metadata;
using Microsoft.OData.Edm;
using Microsoft.OData.Metadata;
#endregion Namespaces

/// <summary>
Expand Down Expand Up @@ -66,13 +67,29 @@ internal static ODataResource CreateNewResource()
/// </summary>
/// <param name="id">The id of the deleted resource, or null if not yet known.</param>
/// <param name="reason">The <see cref="DeltaDeletedEntryReason"/> for the deleted resource.</param>
/// <param name="keyValue">The key of the deleted resource, or null if not yet known.</param>
/// <returns>The newly created deleted resource.</returns>
/// <remarks>The method populates the Properties property with an empty read only enumeration.</remarks>
internal static ODataDeletedResource CreateDeletedResource(Uri id, DeltaDeletedEntryReason reason)
internal static ODataDeletedResource CreateDeletedResource(Uri id, DeltaDeletedEntryReason reason, KeyValuePair<string, object>? keyValue = null)
{
if (keyValue == null)
{
return new ODataDeletedResource(id, reason)
{
Properties = new ReadOnlyEnumerable<ODataPropertyInfo>()
};
}

return new ODataDeletedResource(id, reason)
{
Properties = new ReadOnlyEnumerable<ODataPropertyInfo>()
Properties = new ReadOnlyEnumerable<ODataPropertyInfo>(new ODataPropertyInfo[]
{
new ODataProperty()
{
Name = keyValue.Value.Key,
Value = keyValue.Value.Value,
}
})
};
}

Expand Down
Loading