Skip to content

Commit

Permalink
implement the filter for additional properties property
Browse files Browse the repository at this point in the history
  • Loading branch information
ArcturusZhang committed Apr 2, 2024
1 parent 03dc014 commit 78c93af
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 26 deletions.
21 changes: 19 additions & 2 deletions src/AutoRest.CSharp/Common/Output/Builders/BuilderHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Security;
using System.Text;
using AutoRest.CSharp.Common.Input;
using AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions;
using AutoRest.CSharp.Generation.Types;
using AutoRest.CSharp.Input;
using AutoRest.CSharp.Output.Models;
Expand All @@ -18,6 +18,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using SerializationFormat = AutoRest.CSharp.Output.Models.Serialization.SerializationFormat;
using static AutoRest.CSharp.Common.Output.Models.Snippets;

namespace AutoRest.CSharp.Output.Builders
{
Expand Down Expand Up @@ -358,5 +359,21 @@ public static MethodSignatureModifiers MapModifiers(ISymbol symbol)
}
return modifiers;
}

private static readonly HashSet<Type> _verifiableTypes = new HashSet<Type>
{
// The following types are constructed by the `TryGetXXX` methods on `JsonElement`.
typeof(byte), typeof(byte[]), typeof(sbyte),
typeof(DateTime), typeof(DateTimeOffset),
typeof(decimal), typeof(double), typeof(short), typeof(int), typeof(long), typeof(float),
typeof(ushort), typeof(uint), typeof(ulong),
typeof(Guid),
// The following types have a firm JsonValueKind to verify
typeof(string), typeof(bool)
};

public static bool IsVerifiableType(Type type) => _verifiableTypes.Contains(type);

public static bool IsVerifiableType(CSharpType type) => type is { IsFrameworkType: true, FrameworkType: { } frameworkType } && IsVerifiableType(frameworkType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
Expand All @@ -23,6 +24,7 @@
using AutoRest.CSharp.Input.Source;
using AutoRest.CSharp.Mgmt.Decorator;
using AutoRest.CSharp.Mgmt.Output;
using AutoRest.CSharp.Output.Builders;
using AutoRest.CSharp.Output.Models;
using AutoRest.CSharp.Output.Models.Serialization;
using AutoRest.CSharp.Output.Models.Serialization.Json;
Expand Down Expand Up @@ -582,19 +584,35 @@ private static IEnumerable<MethodBodyStatement> WriteObjectInitialization(JsonOb

if (additionalProperties != null && additionalPropertiesDictionary != null)
{
// TODO -- add value filter here
yield return DeserializeValue(additionalProperties.ValueSerialization!, jsonProperty.Value, options, out var value);
var additionalPropertiesStatement = additionalPropertiesDictionary.Add(jsonProperty.Name, value);
var valueSerialization = additionalProperties.ValueSerialization ?? throw new InvalidOperationException("ValueSerialization of AdditionalProperties property should never be null");
var deserializationStatement = TryDeserializeValue(valueSerialization, jsonProperty.Value, options, out var value);

yield return Serializations.WrapInCheckNotWire(
var additionalPropertiesStatement = additionalPropertiesDictionary.Add(jsonProperty.Name, value);
additionalPropertiesStatement = Serializations.WrapInCheckNotWire(
additionalProperties,
options?.Format,
additionalPropertiesStatement);

if (deserializationStatement is IfStatement tryDeserializationStatement)
{
// when we have a verifier, the statement is a if statement, the following value processing statements should be wrapped by this if statement
tryDeserializationStatement.Add(additionalPropertiesStatement);
// we also need to add "continue" to let the raw data field be skipped
tryDeserializationStatement.Add(Continue);
yield return tryDeserializationStatement;
}
else
{
// when we do not have a verifier, the statement is not a if statement
yield return deserializationStatement;
yield return additionalPropertiesStatement;
}
}

if (rawDataField != null && rawDataFieldDictionary != null)
{
yield return DeserializeValue(rawDataField.ValueSerialization!, jsonProperty.Value, options, out var value);
var valueSerialization = rawDataField.ValueSerialization ?? throw new InvalidOperationException("ValueSerialization of raw data field should never be null");
yield return DeserializeValue(valueSerialization, jsonProperty.Value, options, out var value);
var rawDataFieldStatement = rawDataFieldDictionary.Add(jsonProperty.Name, value);

yield return Serializations.WrapInCheckNotWire(
Expand Down Expand Up @@ -802,6 +820,36 @@ public static MethodBodyStatement BuildDeserializationForMethods(JsonSerializati
};
}

public static MethodBodyStatement TryDeserializeValue(JsonSerialization serialization, JsonElementExpression element, ModelReaderWriterOptionsExpression? options, out ValueExpression value)
{
var valueType = serialization.Type;
if (BuilderHelpers.IsVerifiableType(valueType))
{
var frameworkType = valueType.FrameworkType;
if (frameworkType == typeof(string))
{
DeserializeValue(serialization, element, options, out value);
return new IfStatement(Or(element.ValueKindEqualsString(), element.ValueKindEqualsNull()));
}
else if (frameworkType == typeof(bool))
{
DeserializeValue(serialization, element, options, out value);
var valueKind = element.ValueKind;
return new IfStatement(Or(Equal(valueKind, JsonValueKindExpression.True), Equal(valueKind, JsonValueKindExpression.False)));
}
else
{
var declarationExpression = new DeclarationExpression(valueType, "value", out var variable, isOut: true);
value = variable;
return new IfStatement(new BoolExpression(element.Invoke($"TryGet{frameworkType.Name}", declarationExpression)));
}
}
else
{
return DeserializeValue(serialization, element, options, out value);
}
}

// TODO -- make options parameter non-nullable again when we remove the `use-model-reader-writer` flag
public static MethodBodyStatement DeserializeValue(JsonSerialization serialization, JsonElementExpression element, ModelReaderWriterOptionsExpression? options, out ValueExpression value)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ protected override FormattableString CreateDescription()

private ModelTypeProviderFields EnsureFields()
{
return new ModelTypeProviderFields(_inputModelProperties, Declaration.Name, _inputModelUsage, _typeFactory, ModelTypeMapping, GetBaseObjectType(), _inputModel.InheritedDictionaryType, IsStruct, _inputModel.IsPropertyBag);
return new ModelTypeProviderFields(_inputModelProperties, Declaration.Name, _inputModelUsage, _typeFactory, ModelTypeMapping, _inputModel.InheritedDictionaryType, IsStruct, _inputModel.IsPropertyBag);
}

private ConstructorSignature EnsurePublicConstructorSignature()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal sealed class ModelTypeProviderFields : IReadOnlyCollection<FieldDeclara
public int Count => _fields.Count;
public FieldDeclaration? AdditionalProperties { get; }

public ModelTypeProviderFields(IReadOnlyList<InputModelProperty> properties, string modelName, InputModelTypeUsage inputModelUsage, TypeFactory typeFactory, ModelTypeMapping? modelTypeMapping, ObjectType? baseModel, InputDictionaryType? additionalPropertiesType, bool isStruct, bool isPropertyBag)
public ModelTypeProviderFields(IReadOnlyList<InputModelProperty> properties, string modelName, InputModelTypeUsage inputModelUsage, TypeFactory typeFactory, ModelTypeMapping? modelTypeMapping, InputDictionaryType? additionalPropertiesType, bool isStruct, bool isPropertyBag)
{
var fields = new List<FieldDeclaration>();
var fieldsToInputs = new Dictionary<FieldDeclaration, InputModelProperty>();
Expand Down Expand Up @@ -169,7 +169,7 @@ private static CSharpType CreateAdditionalPropertiesPropertyType(TypeFactory typ
private static CSharpType ReplaceUnverifiableType(CSharpType type)
{
// when the type is a verifiable type
if (type is { IsFrameworkType: true, FrameworkType: { } frameworkType } && _verifiableTypes.Contains(frameworkType))
if (BuilderHelpers.IsVerifiableType(type))
{
return type;
}
Expand All @@ -195,18 +195,6 @@ private static CSharpType ReplaceUnverifiableType(CSharpType type)
return CSharpType.FromUnion(new[] { type }, type.IsNullable);
}

private static readonly HashSet<Type> _verifiableTypes = new HashSet<Type>
{
// The following types are constructed by the `TryGetXXX` methods on `JsonElement`.
typeof(byte), typeof(byte[]), typeof(sbyte),
typeof(DateTime), typeof(DateTimeOffset),
typeof(decimal), typeof(double), typeof(short), typeof(int), typeof(long), typeof(float),
typeof(ushort), typeof(uint), typeof(ulong),
typeof(Guid),
// The following types have a firm JsonValueKind to verify
typeof(string), typeof(bool)
};

private static ValidationType GetParameterValidation(FieldDeclaration field, InputModelProperty inputModelProperty)
{
// we do not validate a parameter when it is a value type (struct or int, etc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ internal static ExtendsFloatAdditionalProperties DeserializeExtendsFloatAddition
id = property.Value.GetSingle();
continue;
}
additionalPropertiesDictionary.Add(property.Name, property.Value.GetSingle());
if (property.Value.TryGetSingle(out float value))
{
additionalPropertiesDictionary.Add(property.Name, value);
continue;
}
if (options.Format != "W")
{
rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ internal static ExtendsStringAdditionalProperties DeserializeExtendsStringAdditi
name = property.Value.GetString();
continue;
}
additionalPropertiesDictionary.Add(property.Name, property.Value.GetString());
if (property.Value.ValueKind == JsonValueKind.String || property.Value.ValueKind == JsonValueKind.Null)
{
additionalPropertiesDictionary.Add(property.Name, property.Value.GetString());
continue;
}
if (options.Format != "W")
{
rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ internal static IsFloatAdditionalProperties DeserializeIsFloatAdditionalProperti
id = property.Value.GetSingle();
continue;
}
additionalPropertiesDictionary.Add(property.Name, property.Value.GetSingle());
if (property.Value.TryGetSingle(out float value))
{
additionalPropertiesDictionary.Add(property.Name, value);
continue;
}
if (options.Format != "W")
{
rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ internal static IsStringAdditionalProperties DeserializeIsStringAdditionalProper
name = property.Value.GetString();
continue;
}
additionalPropertiesDictionary.Add(property.Name, property.Value.GetString());
if (property.Value.ValueKind == JsonValueKind.String || property.Value.ValueKind == JsonValueKind.Null)
{
additionalPropertiesDictionary.Add(property.Name, property.Value.GetString());
continue;
}
if (options.Format != "W")
{
rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText()));
Expand Down

0 comments on commit 78c93af

Please sign in to comment.