Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
09f77ab
feat(cadl): support literal type model property
archerzz Jan 28, 2023
e39b60c
add initial support to differentiate integer from float
archerzz Jan 31, 2023
f43f3df
add e2e test
archerzz Jan 31, 2023
28b97ad
do not generate deserialization codes for literal model properties
archerzz Jan 31, 2023
aebde91
fix test
archerzz Jan 31, 2023
f2c8345
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Jan 31, 2023
f6f82ec
move skip deserialization check into ModelTypeProvider
archerzz Feb 1, 2023
d8a3d1b
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 1, 2023
5bdc0db
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 1, 2023
c0b82f9
treat literal operation parameters as constant parameters
archerzz Feb 2, 2023
841c1c7
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 2, 2023
714a335
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 3, 2023
b45756b
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 3, 2023
d649af8
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 7, 2023
a3633ca
set the parameter type to constant for literal type in emitter
archerzz Feb 7, 2023
7c472e6
fix typescript format
archerzz Feb 7, 2023
6ca9a26
add back optional literal model properties
archerzz Feb 7, 2023
d3331e1
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 7, 2023
4fe8338
Merge branch 'feature/v3' into cadl/literal-model-property
archerzz Feb 8, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ private static void ToSerializeCall(this CodeWriter writer, FormattableString wr

private static void DeserializeIntoObjectProperties(this CodeWriter writer, IEnumerable<JsonPropertySerialization> propertySerializations, FormattableString itemVariable, Dictionary<JsonPropertySerialization, ObjectPropertyVariable> propertyVariables)
{
foreach (JsonPropertySerialization property in propertySerializations)
foreach (JsonPropertySerialization property in propertySerializations.Where(p => !p.ShouldSkipDeserialization))
{
writer.Append($"if({itemVariable}.NameEquals({property.SerializedName:L}u8))");
using (writer.Scope())
Expand Down Expand Up @@ -379,9 +379,9 @@ private static FormattableString GetOptionalFormattable(JsonPropertySerializatio
}

/// Collects a list of properties being read from all level of object hierarchy
private static void CollectProperties(Dictionary<JsonPropertySerialization, ObjectPropertyVariable> propertyVariables, IEnumerable<JsonPropertySerialization> jsonProperties)
private static void CollectPropertiesForDeserialization(Dictionary<JsonPropertySerialization, ObjectPropertyVariable> propertyVariables, IEnumerable<JsonPropertySerialization> jsonProperties)
{
foreach (JsonPropertySerialization jsonProperty in jsonProperties)
foreach (JsonPropertySerialization jsonProperty in jsonProperties.Where(p => !p.ShouldSkipDeserialization))
{
if (jsonProperty.ValueType != null)
{
Expand All @@ -399,7 +399,7 @@ private static void CollectProperties(Dictionary<JsonPropertySerialization, Obje
}
else if (jsonProperty.PropertySerializations != null)
{
CollectProperties(propertyVariables, jsonProperty.PropertySerializations);
CollectPropertiesForDeserialization(propertyVariables, jsonProperty.PropertySerializations);
}
}
}
Expand Down Expand Up @@ -492,7 +492,7 @@ public static void WriteObjectInitialization(this CodeWriter writer, JsonObjectS
// collect all properties and initialize the dictionary
var propertyVariables = new Dictionary<JsonPropertySerialization, ObjectPropertyVariable>();

CollectProperties(propertyVariables, serialization.Properties);
CollectPropertiesForDeserialization(propertyVariables, serialization.Properties);

var additionalProperties = serialization.AdditionalProperties;
if (additionalProperties != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ protected virtual void AddCtorAttribute(CodeWriter writer, ObjectType schema, Ob
{
}

public void WriteConstructor(CodeWriter writer, ObjectType schema)
private void WriteConstructor(CodeWriter writer, ObjectType schema)
{
foreach (var constructor in schema.Constructors)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,28 @@ public static object ReadLiteralValue(ref Utf8JsonReader reader, string property
Object? value = null;
switch (type)
{
case InputPrimitiveType primitype:
switch (primitype.Kind)
case InputPrimitiveType primitiveType:
switch (primitiveType.Kind)
{
case InputTypeKind.String:
value = reader.GetString() ?? throw new JsonException();
break;
case InputTypeKind.Int32:
value = reader.GetInt32();
break;
case InputTypeKind.Int64:
value = reader.GetInt64();
case InputTypeKind.Float64:
value = reader.GetDouble();
break;
case InputTypeKind.Boolean:
value = reader.GetBoolean();
break;
default:
throw new JsonException($"Not supported litreal type {primitype.Kind}.");
throw new JsonException($"Not supported literal type {primitiveType.Kind}.");

}
break;
default:
throw new JsonException($"Not supported litreal type {type.Name}.");
throw new JsonException($"Not supported literal type {type.Name}.");
}
reader.Read();
return value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,35 @@ private static InputModelProperty ReadInputModelProperty(ref Utf8JsonReader read
description = BuilderHelpers.EscapeXmlDocDescription(description);
propertyType = propertyType ?? throw new JsonException($"{nameof(InputModelProperty)} must have a property type.");

var property = new InputModelProperty(name, serializedName ?? name, description, propertyType, isRequired, isReadOnly, isDiscriminator);
var property = new InputModelProperty(name, serializedName ?? name, description, propertyType, isRequired, isReadOnly, isDiscriminator, GetDefaultValue(propertyType));
if (id != null)
{
resolver.AddReference(id, property);
}

return property;
}

private static FormattableString? GetDefaultValue(InputType propertyType)
{
if (propertyType is not InputLiteralType literalType)
{
return null;
}

return literalType.LiteralValueType switch
{
InputPrimitiveType primitiveType => primitiveType.Kind switch
{
InputTypeKind.Boolean => $"{literalType.Value.ToString()!.ToLower()}",
InputTypeKind.Float32 or InputTypeKind.Float64 or InputTypeKind.Float128
or InputTypeKind.Int32 or InputTypeKind.Int64 => $"{literalType.Value.ToString()}",
InputTypeKind.String => $"\"{(literalType.Value).ToString()}\"",
_ => throw new Exception($"Unsupported literal value type: {primitiveType}"),

},
_ => throw new Exception($"Unsupported literal value type: {literalType.LiteralValueType}"),
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ private IEnumerable<JsonPropertySerialization> GetPropertySerializationsFromBag(
BuildSerialization(property.Schema, objectProperty.ValueType),
property.IsRequired,
property.IsReadOnly,
false,
objectProperty.OptionalViaNullability);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ private ReferenceOrConstant CreateReference(InputParameter operationParameter, P
return (ReferenceOrConstant)_parameters[operationParameter.Name];
}

if (operationParameter.Kind == InputOperationParameterKind.Constant && parameter.DefaultValue != null)
if (operationParameter is { Kind:InputOperationParameterKind.Constant } && parameter.DefaultValue is not null)
{
return (ReferenceOrConstant)parameter.DefaultValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class JsonAdditionalPropertiesSerialization : JsonPropertySerialization
public CSharpType Type { get; }

public JsonAdditionalPropertiesSerialization(ObjectTypeProperty property, JsonSerialization valueSerialization, CSharpType type)
: base(property.Declaration.Name.ToVariableName(), property.Declaration.Name, property.Declaration.Name, property.Declaration.Type, property.ValueType, valueSerialization, true, property.IsReadOnly, property.OptionalViaNullability)
: base(property.Declaration.Name.ToVariableName(), property.Declaration.Name, property.Declaration.Name, property.Declaration.Type, property.ValueType, valueSerialization, true, property.IsReadOnly, false, property.OptionalViaNullability)
{
Type = type;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace AutoRest.CSharp.Output.Models.Serialization.Json
{
internal class JsonPropertySerialization : PropertySerialization
{
public JsonPropertySerialization(string parameterName, string propertyName, string serializedName, CSharpType propertyType, CSharpType? valueType, JsonSerialization valueSerialization, bool isRequired, bool shouldSkipSerialization, bool optionalViaNullability)
: base(propertyName, serializedName, propertyType, valueType, isRequired, shouldSkipSerialization)
public JsonPropertySerialization(string parameterName, string propertyName, string serializedName, CSharpType propertyType, CSharpType? valueType, JsonSerialization valueSerialization, bool isRequired, bool shouldSkipSerialization, bool shouldSkipDeserialization, bool optionalViaNullability)
: base(propertyName, serializedName, propertyType, valueType, isRequired, shouldSkipSerialization, shouldSkipDeserialization)
{
ParameterName = parameterName;
OptionalViaNullability = optionalViaNullability;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,22 @@ internal abstract class PropertySerialization
public CSharpType? ValueType { get; }
public bool IsRequired { get; }
public bool ShouldSkipSerialization { get; }
public bool ShouldSkipDeserialization { get; }

protected PropertySerialization(string propertyName, string serializedName, CSharpType propertyType, CSharpType? valueType, bool isRequired, bool shouldSkipSerialization)
protected PropertySerialization(string propertyName, string serializedName, CSharpType propertyType, CSharpType? valueType, bool isRequired, bool shouldSkipSerialization) :
this(propertyName, serializedName, propertyType, valueType, isRequired, shouldSkipSerialization, false)
{
}

protected PropertySerialization(string propertyName, string serializedName, CSharpType propertyType, CSharpType? valueType, bool isRequired, bool shouldSkipSerialization, bool shouldSkipDeserialization)
{
PropertyName = propertyName;
SerializedName = serializedName;
PropertyType = propertyType;
ValueType = valueType;
IsRequired = isRequired;
ShouldSkipSerialization = shouldSkipSerialization;
ShouldSkipDeserialization = shouldSkipDeserialization;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ private IEnumerable<JsonPropertySerialization> CreatePropertySerializations()
valueSerialization,
property.IsRequired,
shouldSkipSerialization,
ShouldSkipDeserialization(property),
optionalViaNullability));
}
}
Expand All @@ -160,6 +161,11 @@ private bool ShouldSkipSerialization(ObjectTypeProperty property)
return false;
}

if (property.InputModelProperty.Type is InputLiteralType)
{
return false;
}

if (property.InputModelProperty!.IsReadOnly)
{
return true;
Expand All @@ -173,6 +179,8 @@ private bool ShouldSkipSerialization(ObjectTypeProperty property)
return property.IsReadOnly && _inputModel.Usage is not InputModelTypeUsage.Input;
}

private bool ShouldSkipDeserialization(ObjectTypeProperty property) => property.InputModelProperty?.Type is InputLiteralType;

private ConstructorSignature? CreateSerializationConstructorSignature(string name, IReadOnlyList<Parameter> publicParameters, IReadOnlyList<Parameter> serializationParameters)
{
if (!serializationParameters.Any(p => TypeFactory.IsList(p.Type)) && publicParameters.SequenceEqual(serializationParameters))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ public ModelTypeProviderFields(InputModelType inputModel, TypeFactory typeFactor
fields.Add(field);
fieldsToInputs[field] = inputModelProperty;

if (inputModelProperty.Type is InputLiteralType)
{
continue; // literal property does not show up in the constructor parameter list
}
var parameter = Parameter.FromModelProperty(inputModelProperty, existingMember is IFieldSymbol ? inputModelProperty.Name.ToVariableName() : field.Name.FirstCharToLowerCase(), field.Type);
parametersToFields[parameter.Name] = field;
serializationParameters.Add(parameter);
Expand Down Expand Up @@ -95,9 +99,10 @@ private static FieldDeclaration CreateField(string fieldName, CSharpType fieldTy
inputModelProperty.Type is CodeModelType type && (type.Schema is ArraySchema or DictionarySchema);
var propertyIsRequiredInNonRoundTripModel = inputModel.Usage is InputModelTypeUsage.Input or InputModelTypeUsage.Output && inputModelProperty.IsRequired;
var propertyIsOptionalInOutputModel = inputModel.Usage is InputModelTypeUsage.Output && !inputModelProperty.IsRequired;
var propertyIsReadOnly = inputModelProperty.IsReadOnly || propertyIsCollection || propertyIsRequiredInNonRoundTripModel || propertyIsOptionalInOutputModel;
var propertyIsLiteralType = inputModelProperty.Type is InputLiteralType;
var propertyIsReadOnly = inputModelProperty.IsReadOnly || propertyIsLiteralType || propertyIsCollection || propertyIsRequiredInNonRoundTripModel || propertyIsOptionalInOutputModel;

var fieldModifiers = propertyIsReadOnly ? Public | ReadOnly : Public;
var fieldModifiers = propertyIsReadOnly ? (propertyIsLiteralType ? Internal : Public ) | ReadOnly : Public;

CodeWriterDeclaration declaration = new CodeWriterDeclaration(fieldName);
declaration.SetActualName(fieldName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public ObjectTypeProperty(FieldDeclaration field, InputModelProperty inputModelP
: this(new MemberDeclarationOptions(field.Accessibility, field.Name, field.Type), field.Description?.ToString() ?? String.Empty, field.Modifiers.HasFlag(FieldModifiers.ReadOnly), null, field.IsRequired, inputModelProperty: inputModelProperty)
{
// now the default value will be set only when the model is generated from property bag
if (enclosingType is ModelTypeProvider model && model.IsPropertyBag)
if ((enclosingType is ModelTypeProvider model && model.IsPropertyBag) ||
(inputModelProperty.Type is InputLiteralType)) // or the property is a literal type
{
DefaultValue = field.DefaultValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,9 @@ private void AddReference(string nameInRequest, InputParameter? operationParamet
_requestParts.Add(new RequestPartSource(nameInRequest, operationParameter, reference, serializationFormat));
}

private ReferenceOrConstant CreateReference(InputParameter? operationParameter, Parameter parameter)
private ReferenceOrConstant CreateReference(InputParameter operationParameter, Parameter parameter)
{
if (operationParameter?.Kind == InputOperationParameterKind.Client)
if (operationParameter.Kind == InputOperationParameterKind.Client)
{
var field = operationParameter.IsEndpoint ? _fields.EndpointField : _fields.GetFieldByParameter(parameter);
if (field == null)
Expand All @@ -449,7 +449,7 @@ private ReferenceOrConstant CreateReference(InputParameter? operationParameter,
return new Reference(field.Name, field.Type);
}

if (operationParameter?.Kind == InputOperationParameterKind.Constant && parameter.DefaultValue != null)
if (operationParameter.Kind is InputOperationParameterKind.Constant && parameter.DefaultValue is not null)
{
return (ReferenceOrConstant)parameter.DefaultValue;
}
Expand Down
13 changes: 7 additions & 6 deletions src/CADL.Extension/Emitter.Csharp/src/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -846,13 +846,14 @@ function loadOperation(
const isContentType: boolean =
requestLocation === RequestLocation.Header &&
name.toLowerCase() === "content-type";
const kind: InputOperationParameterKind = isContentType
? InputOperationParameterKind.Constant
: isApiVer
? defaultValue
const kind: InputOperationParameterKind =
isContentType || inputType.Name === "Literal"
? InputOperationParameterKind.Constant
: InputOperationParameterKind.Client
: InputOperationParameterKind.Method;
: isApiVer
? defaultValue
? InputOperationParameterKind.Constant
: InputOperationParameterKind.Client
: InputOperationParameterKind.Method;
return {
Name: param.name,
NameInRequest: name,
Expand Down
8 changes: 7 additions & 1 deletion src/CADL.Extension/Emitter.Csharp/src/lib/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,13 @@ export function mapCadlTypeToCSharpInputTypeKind(
case "Enum":
return InputTypeKind.Enum;
case "Number":
return InputTypeKind.Int32;
let nubmerValue = cadlType.value;
if (nubmerValue % 1 === 0) {
return InputTypeKind.Int32;
}
return InputTypeKind.Float64;
case "Boolean":
return InputTypeKind.Boolean;
case "String":
if (format === "date") return InputTypeKind.DateTime;
if (format === "uri") return InputTypeKind.Uri;
Expand Down
41 changes: 41 additions & 0 deletions test/CadlRanchMockApis/src/FirstTest-Cadl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { passOnSuccess, ScenarioMockApi, mockapi, json } from "@azure-tools/cadl-ranch-api";

/**
* Test mock server for `FirstTest-cadl` test project.
*/
export const Scenarios: Record<string, ScenarioMockApi> = {};

Scenarios.FirstTestCadl_CreateLiteral = passOnSuccess([
mockapi.post("/literal", (req) => {
req.expect.bodyEquals({
name: "test",
requiredUnion: "test",
requiredBadDescription: "abc",
requiredLiteralString: "accept",
requiredLiteralInt: 123,
requiredLiteralDouble: 1.23,
requiredLiteralBool: false,
optionalLiteralString: "reject",
optionalLiteralInt: 456,
optionalLiteralDouble: 4.56,
optionalLiteralBool: true,
});
return {
status: 200,
body: json({
name: "literal",
requiredUnion: "union",
requiredBadDescription: "def",
// below are useless
requiredLiteralString: "reject",
requiredLiteralInt: 12345,
requiredLiteralDouble: 123.45,
requiredLiteralBool: true,
optionalLiteralString: "accept",
optionalLiteralInt: 12345,
optionalLiteralDouble: 123.45,
optionalLiteralBool: false,
})
};
}),
]);
Loading