diff --git a/CHANGELOG.md b/CHANGELOG.md index 3327630615..14babc79d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixes a bug where invalid C# code is generated when API path contains an underscore [#6698](https://github.com/microsoft/kiota/issues/6698) - Fixed a bug where union of integer and boolean types collection would not compile in dotnet. [#6834](https://github.com/microsoft/kiota/issues/6834) +- Fixed a bug where default values for query parameters are not generated in C#, Java, PHP, Python. [#6836](https://github.com/microsoft/kiota/issues/6836) ## [1.28.0] - 2025-07-11 diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index 2dc50ad5f7..80133ff207 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -1201,12 +1201,21 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten if (prop.IsOfKind(CodePropertyKind.Custom, CodePropertyKind.QueryParameter) && !propertyName.Equals(childIdentifier, StringComparison.Ordinal)) prop.SerializationName = childIdentifier; - if (kind == CodePropertyKind.Custom && - propertySchema?.Default is JsonValue stringDefaultJsonValue && - stringDefaultJsonValue.TryGetValue(out var stringDefaultValue) && - !string.IsNullOrEmpty(stringDefaultValue) && - !"null".Equals(stringDefaultValue, StringComparison.OrdinalIgnoreCase)) - prop.DefaultValue = $"\"{stringDefaultValue}\""; + if ((kind == CodePropertyKind.Custom || kind == CodePropertyKind.QueryParameter) && + propertySchema?.Default is JsonValue defaultJsonValue && + defaultJsonValue.TryGetValue(out var stringDefaultValue) && + !string.IsNullOrEmpty(stringDefaultValue) && + !"null".Equals(stringDefaultValue, StringComparison.OrdinalIgnoreCase)) + { + if ((propertySchema.Type & ~JsonSchemaType.Null) == JsonSchemaType.Integer && int.TryParse(stringDefaultValue, out var intValue)) + prop.DefaultValue = intValue.ToString(CultureInfo.InvariantCulture); + else if ((propertySchema.Type & ~JsonSchemaType.Null) == JsonSchemaType.Number && double.TryParse(stringDefaultValue, out var doubleValue)) + prop.DefaultValue = doubleValue.ToString(CultureInfo.InvariantCulture); + else if ((propertySchema.Type & ~JsonSchemaType.Null) == JsonSchemaType.Boolean && bool.TryParse(stringDefaultValue, out var boolValue)) + prop.DefaultValue = boolValue.ToString().ToLowerInvariant(); + else + prop.DefaultValue = $"\"{stringDefaultValue}\""; + } if (existingType == null) { diff --git a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs index 07d2272db5..a62ec3e9a8 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs @@ -38,6 +38,19 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ var setterAccessModifier = codeElement.ReadOnly && codeElement.Access > AccessModifier.Private ? "private " : string.Empty; var simpleBody = $"get; {setterAccessModifier}set;"; var defaultValue = string.Empty; + if (!string.IsNullOrEmpty(codeElement.DefaultValue)) + { + if (codeElement.Type is CodeType propertyCodeType && propertyCodeType.TypeDefinition is CodeEnum enumDefinition) + { + var enumTypeName = conventions.GetTypeString(codeElement.Type, codeElement, true, false); + var enumValue = codeElement.DefaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase(); + defaultValue = $" = {enumTypeName}.{enumValue};"; + } + else + { + defaultValue = $" = {codeElement.DefaultValue};"; + } + } switch (codeElement.Kind) { case CodePropertyKind.RequestBuilder: diff --git a/src/Kiota.Builder/Writers/Java/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Java/CodePropertyWriter.cs index 0f429430f0..d2b3ec43bf 100644 --- a/src/Kiota.Builder/Writers/Java/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodePropertyWriter.cs @@ -1,5 +1,6 @@ using System; using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Java; public class CodePropertyWriter : BaseElementWriter @@ -18,6 +19,19 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w string.Empty; conventions.WriteLongDescription(codeElement, writer, [returnRemark]); var defaultValue = string.Empty; + if (!string.IsNullOrEmpty(codeElement.DefaultValue)) + { + if (codeElement.Type is CodeType propertyCodeType && propertyCodeType.TypeDefinition is CodeEnum enumDefinition) + { + var enumTypeName = conventions.GetTypeString(codeElement.Type, codeElement); + var enumValue = codeElement.DefaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase(); + defaultValue = $" = {enumTypeName}.{enumValue}"; + } + else + { + defaultValue = $" = {codeElement.DefaultValue}"; + } + } conventions.WriteDeprecatedAnnotation(codeElement, writer); switch (codeElement.Kind) { diff --git a/src/Kiota.Builder/Writers/Php/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Php/CodePropertyWriter.cs index 211d3e7965..58d54607e5 100644 --- a/src/Kiota.Builder/Writers/Php/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodePropertyWriter.cs @@ -24,7 +24,21 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w break; default: WritePropertyDocComment(codeElement, writer); - writer.WriteLine($"{propertyAccess} {(codeElement.Type.IsNullable ? "?" : string.Empty)}{propertyType} ${propertyName}{(codeElement.Type.IsNullable ? " = null" : string.Empty)};"); + var defaultValue = codeElement.Type.IsNullable ? " = null" : string.Empty; + if (!string.IsNullOrEmpty(codeElement.DefaultValue)) + { + if (codeElement.Type is CodeType propertyCodeType && propertyCodeType.TypeDefinition is CodeEnum enumDefinition) + { + var enumTypeName = conventions.GetTypeString(codeElement.Type, codeElement); + var enumValue = codeElement.DefaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase(); + defaultValue = $" = {enumTypeName}::{enumValue}"; + } + else + { + defaultValue = $" = {codeElement.DefaultValue}"; + } + } + writer.WriteLine($"{propertyAccess} {(codeElement.Type.IsNullable ? "?" : string.Empty)}{propertyType} ${propertyName}{defaultValue};"); break; } writer.WriteLine(""); diff --git a/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs index 4e5c40cebd..80f515ca9a 100644 --- a/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs @@ -44,7 +44,16 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w var defaultValue = isNonNullableCollection ? "[]" : "None"; if (!string.IsNullOrEmpty(codeElement.DefaultValue)) { - defaultValue = codeElement.DefaultValue; + if (codeElement.Type is CodeType propertyCodeType && propertyCodeType.TypeDefinition is CodeEnum enumDefinition) + { + var enumTypeName = conventions.GetTypeString(codeElement.Type, codeElement); + var enumValue = codeElement.DefaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase(); + defaultValue = $"{enumTypeName}.{enumValue}"; + } + else + { + defaultValue = codeElement.DefaultValue; + } } writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)}{codeElement.NamePrefix}{codeElement.Name}: {(codeElement.Type.IsNullable ? "Optional[" : string.Empty)}{returnType}{(codeElement.Type.IsNullable ? "]" : string.Empty)} = {defaultValue}"); writer.WriteLine(); diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs index c0fec9dc0d..339173777b 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs @@ -88,6 +88,99 @@ public void WritesCustomProperty() Assert.Contains("get; set;", result); } [Fact] + public void WritesCustomPropertyWithDefaultValue() + { + property.Kind = CodePropertyKind.Custom; + property.DefaultValue = $"new {TypeName}()"; + writer.Write(property); + var result = tw.ToString(); + Assert.Contains($"{TypeName} {PropertyName}", result); + Assert.Contains("get; set;", result); + Assert.Contains($" = new {TypeName}()", result); + } + [Fact] + public void WritesQueryParameterWithDefaultEnumValue() + { + var enumProperty = new CodeProperty + { + Name = "EnumProperty", + Type = new CodeType + { + Name = "SomeEnum", + TypeDefinition = rootNamespace.AddEnum(new CodeEnum + { + Name = "SomeEnum" + }).First() + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "EnumValue2", + }; + parentClass.AddProperty(enumProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(enumProperty); + var result = tw.ToString(); + Assert.Contains("SomeEnum? EnumProperty { get; set; } = global::defaultNamespace.SomeEnum.EnumValue2;", result); + } + [Fact] + public void WritesQueryParameterWithDefaultIntValue() + { + var integerProperty = new CodeProperty + { + Name = "IntegerProperty", + Type = new CodeType + { + Name = "Int32" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "3", + }; + parentClass.AddProperty(integerProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(integerProperty); + var result = tw.ToString(); + Assert.Contains("Int32? IntegerProperty { get; set; } = 3;", result); + } + [Fact] + public void WritesQueryParameterWithDefaultStringValue() + { + var stringProperty = new CodeProperty + { + Name = "StringProperty", + Type = new CodeType + { + Name = "String" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "\"SomeString\"", + }; + parentClass.AddProperty(stringProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(stringProperty); + var result = tw.ToString(); + Assert.Contains("public String? StringProperty { get; set; } = \"SomeString\";", result); + } + [Fact] public void WritesPrivateSetter() { property.Kind = CodePropertyKind.Custom; diff --git a/tests/Kiota.Builder.Tests/Writers/Java/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Java/CodePropertyWriterTests.cs index d128067280..cf2b572202 100644 --- a/tests/Kiota.Builder.Tests/Writers/Java/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Java/CodePropertyWriterTests.cs @@ -123,4 +123,86 @@ public void WritesCollectionFlagEnumsAsOneDimensionalArray() Assert.Contains("List<", result); Assert.DoesNotContain("EnumSet", result); } + [Fact] + public void WritesQueryParameterWithDefaultEnumValue() + { + var enumProperty = new CodeProperty + { + Name = "EnumProperty", + Type = new CodeType + { + Name = "SomeEnum", + TypeDefinition = new CodeEnum + { + Name = "SomeEnum" + } + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "EnumValue2", + }; + parentClass.AddProperty(enumProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(enumProperty); + var result = tw.ToString(); + Assert.Contains("SomeEnum EnumProperty = SomeEnum.EnumValue2;", result); + } + [Fact] + public void WritesQueryParameterWithDefaultIntValue() + { + var integerProperty = new CodeProperty + { + Name = "IntegerProperty", + Type = new CodeType + { + Name = "Integer" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "3", + }; + parentClass.AddProperty(integerProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(integerProperty); + var result = tw.ToString(); + Assert.Contains("Integer IntegerProperty = 3;", result); + } + [Fact] + public void WritesQueryParameterWithDefaultStringValue() + { + var stringProperty = new CodeProperty + { + Name = "StringProperty", + Type = new CodeType + { + Name = "String" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "\"SomeString\"", + }; + parentClass.AddProperty(stringProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(stringProperty); + var result = tw.ToString(); + Assert.Contains("String StringProperty = \"SomeString\";", result); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs index 4b96585405..cc398600aa 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs @@ -103,7 +103,7 @@ public async Task WriteCollectionKindPropertyAsync() await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.PHP }, root); propertyWriter.WriteCodeElement(property, languageWriter); var result = stringWriter.ToString(); - Assert.Contains("private ?array $additionalData = null;", result); + Assert.Contains("private ?array $additionalData = [];", result); Assert.Contains("@var array|null", result); } @@ -268,4 +268,86 @@ public void WritePropertyWithDescription() var result = stringWriter.ToString(); Assert.DoesNotContain("/*/*", result); } + [Fact] + public void WritesQueryParameterWithDefaultEnumValue() + { + var enumProperty = new CodeProperty + { + Name = "EnumProperty", + Type = new CodeType + { + Name = "SomeEnum", + TypeDefinition = new CodeEnum + { + Name = "SomeEnum" + } + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "EnumValue2", + }; + parentClass.AddProperty(enumProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + propertyWriter.WriteCodeElement(enumProperty, languageWriter); + var result = stringWriter.ToString(); + Assert.Contains("SomeEnum $enumProperty = SomeEnum::EnumValue2;", result); + } + [Fact] + public void WritesQueryParameterWithDefaultIntValue() + { + var integerProperty = new CodeProperty + { + Name = "IntegerProperty", + Type = new CodeType + { + Name = "int" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "3", + }; + parentClass.AddProperty(integerProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + propertyWriter.WriteCodeElement(integerProperty, languageWriter); + var result = stringWriter.ToString(); + Assert.Contains("Int $integerProperty = 3;", result); + } + [Fact] + public void WritesQueryParameterWithDefaultStringValue() + { + var stringProperty = new CodeProperty + { + Name = "StringProperty", + Type = new CodeType + { + Name = "str" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "\"SomeString\"", + }; + parentClass.AddProperty(stringProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + propertyWriter.WriteCodeElement(stringProperty, languageWriter); + var result = stringWriter.ToString(); + Assert.Contains("Str $stringProperty = \"SomeString\";", result); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs index ce0163df05..98318fed50 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs @@ -149,4 +149,86 @@ public void WritePrimaryErrorMessagePropertyOption2() var result = tw.ToString(); Assert.Contains("return '' if self.error.message is None else self.error.message", result); } + [Fact] + public void WritesQueryParameterWithDefaultEnumValue() + { + var enumProperty = new CodeProperty + { + Name = "EnumProperty", + Type = new CodeType + { + Name = "SomeEnum", + TypeDefinition = new CodeEnum + { + Name = "SomeEnum" + } + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "EnumValue2", + }; + parentClass.AddProperty(enumProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(enumProperty); + var result = tw.ToString(); + Assert.Contains("EnumProperty: Optional[SomeEnum] = SomeEnum.EnumValue2", result); + } + [Fact] + public void WritesQueryParameterWithDefaultIntValue() + { + var integerProperty = new CodeProperty + { + Name = "IntegerProperty", + Type = new CodeType + { + Name = "int" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "3", + }; + parentClass.AddProperty(integerProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(integerProperty); + var result = tw.ToString(); + Assert.Contains("IntegerProperty: Optional[int] = 3", result); + } + [Fact] + public void WritesQueryParameterWithDefaultStringValue() + { + var stringProperty = new CodeProperty + { + Name = "StringProperty", + Type = new CodeType + { + Name = "str" + }, + Kind = CodePropertyKind.QueryParameter, + DefaultValue = "\"SomeString\"", + }; + parentClass.AddProperty(stringProperty, new() + { + Name = "queryParameter", + Kind = CodePropertyKind.QueryParameter, + Type = new CodeType + { + Name = "QueryParameter", + }, + }); + writer.Write(stringProperty); + var result = tw.ToString(); + Assert.Contains("StringProperty: Optional[str] = \"SomeString\"", result); + } }