Skip to content

Commit 9c1ed4a

Browse files
committed
fix: removal of nullable property
Signed-off-by: Vincent Biret <[email protected]>
1 parent 313ee7a commit 9c1ed4a

19 files changed

+613
-330
lines changed

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiEdmTypeSchemaGenerator.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ public static IOpenApiSchema CreateSchema(this ODataContext context, IEdmPrimiti
150150

151151
// Nullable properties are marked with the keyword nullable and a value of true.
152152
// nullable cannot be true when type is empty, often common in anyof/allOf since individual entries are nullable
153-
openApiSchema.Nullable = !string.IsNullOrEmpty(schema.Type.ToIdentifier()) && primitiveType.IsNullable;
153+
if (!string.IsNullOrEmpty(schema.Type.ToIdentifier()) && primitiveType.IsNullable)
154+
{
155+
openApiSchema.Type |= JsonSchemaType.Null;
156+
}
154157
}
155158

156159
return schema;
@@ -203,37 +206,35 @@ public static IOpenApiSchema CreateSchema(this ODataContext context, IEdmPrimiti
203206
case EdmPrimitiveTypeKind.Decimal when emitIEEECompatibleTypes: // decimal
204207
schema.OneOf =
205208
[
206-
new OpenApiSchema { Type = JsonSchemaType.Number, Format = Constants.DecimalFormat, Nullable = true },
207-
new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true },
209+
new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = Constants.DecimalFormat },
210+
new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null },
208211
];
209212
break;
210213
case EdmPrimitiveTypeKind.Decimal when !emitIEEECompatibleTypes: // decimal
211214
schema.Type = JsonSchemaType.Number;
212215
schema.Format = Constants.DecimalFormat;
213216
break;
214217
case EdmPrimitiveTypeKind.Double when emitV2CompatibleParameterTypes: // double
215-
schema.Type = JsonSchemaType.Number;
218+
schema.Type = JsonSchemaType.Number | JsonSchemaType.Null;
216219
schema.Format = "double";
217-
schema.Nullable = true;
218220
break;
219221
case EdmPrimitiveTypeKind.Double when !emitV2CompatibleParameterTypes: // double
220222
schema.OneOf =
221223
[
222-
new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double", Nullable = true },
223-
new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true },
224+
new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" },
225+
new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null },
224226
new OpenApiSchemaReference(Constants.ReferenceNumericName, document)
225227
];
226228
break;
227229
case EdmPrimitiveTypeKind.Single when emitV2CompatibleParameterTypes: // single
228-
schema.Type = JsonSchemaType.Number;
230+
schema.Type = JsonSchemaType.Number | JsonSchemaType.Null;
229231
schema.Format = "float";
230-
schema.Nullable = true;
231232
break;
232233
case EdmPrimitiveTypeKind.Single when !emitV2CompatibleParameterTypes: // single
233234
schema.OneOf =
234235
[
235-
new OpenApiSchema { Type = JsonSchemaType.Number, Format = "float", Nullable = true },
236-
new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true },
236+
new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "float"},
237+
new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null},
237238
new OpenApiSchemaReference(Constants.ReferenceNumericName, document)
238239
];
239240
break;
@@ -257,8 +258,8 @@ public static IOpenApiSchema CreateSchema(this ODataContext context, IEdmPrimiti
257258
case EdmPrimitiveTypeKind.Int64 when emitIEEECompatibleTypes:
258259
schema.OneOf =
259260
[
260-
new OpenApiSchema { Type = JsonSchemaType.Number, Format = Constants.Int64Format, Nullable = true },
261-
new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true }
261+
new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = Constants.Int64Format},
262+
new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null }
262263
];
263264
break;
264265
case EdmPrimitiveTypeKind.Int64 when !emitIEEECompatibleTypes:

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiErrorSchemaGenerator.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,14 @@ public static OpenApiSchema CreateErrorMainSchema(string rootNamespaceName, Open
130130
Properties = new Dictionary<string, IOpenApiSchema>
131131
{
132132
{
133-
"code", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = false }
133+
"code", new OpenApiSchema { Type = JsonSchemaType.String }
134134
},
135135
{
136-
"message", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = false, Extensions = new Dictionary<string, IOpenApiExtension>
136+
"message", new OpenApiSchema { Type = JsonSchemaType.String, Extensions = new Dictionary<string, IOpenApiExtension>
137137
{ { OpenApiPrimaryErrorMessageExtension.Name, new OpenApiPrimaryErrorMessageExtension { IsPrimaryErrorMessage = true } } } }
138138
},
139139
{
140-
"target", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true }
140+
"target", new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null }
141141
},
142142
{
143143
"details",
@@ -171,13 +171,13 @@ public static OpenApiSchema CreateErrorDetailSchema()
171171
Properties = new Dictionary<string, IOpenApiSchema>
172172
{
173173
{
174-
"code", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = false, }
174+
"code", new OpenApiSchema { Type = JsonSchemaType.String, }
175175
},
176176
{
177-
"message", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = false, }
177+
"message", new OpenApiSchema { Type = JsonSchemaType.String, }
178178
},
179179
{
180-
"target", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true, }
180+
"target", new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, }
181181
}
182182
}
183183
};

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ public static void AddSchemasToDocument(this ODataContext context, OpenApiDocume
6868
Type = JsonSchemaType.Object,
6969
Properties = new Dictionary<string, IOpenApiSchema>
7070
{
71-
{Constants.OdataId, new OpenApiSchema { Type = JsonSchemaType.String, Nullable = false }},
72-
{Constants.OdataType, new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true }},
71+
{Constants.OdataId, new OpenApiSchema { Type = JsonSchemaType.String }},
72+
{Constants.OdataType, new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null }},
7373
}
7474
});
7575

@@ -78,15 +78,14 @@ public static void AddSchemasToDocument(this ODataContext context, OpenApiDocume
7878
Type = JsonSchemaType.Object,
7979
Properties = new Dictionary<string, IOpenApiSchema>
8080
{
81-
{Constants.OdataId, new OpenApiSchema { Type = JsonSchemaType.String, Nullable = false }}
81+
{Constants.OdataId, new OpenApiSchema { Type = JsonSchemaType.String }}
8282
},
8383
AdditionalProperties = new OpenApiSchema { Type = JsonSchemaType.Object }
8484
});
8585

8686
document.AddComponent(Constants.ReferenceNumericName, new OpenApiSchema()
8787
{
88-
Type = JsonSchemaType.String,
89-
Nullable = true,
88+
Type = JsonSchemaType.String | JsonSchemaType.Null,
9089
Enum =
9190
[
9291
"-INF",

src/Microsoft.OpenApi.OData.Reader/OData/ODataConstants.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ internal static class ODataConstants
2424
/// <summary>
2525
/// @odata.nextLink KeyValue pair
2626
/// </summary>
27-
public static KeyValuePair<string, IOpenApiSchema> OdataNextLink = new("@odata.nextLink", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true });
27+
public static KeyValuePair<string, IOpenApiSchema> OdataNextLink = new("@odata.nextLink", new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null });
2828

2929
/// <summary>
3030
/// @odata.count KeyValue pair
3131
/// </summary>
32-
public static KeyValuePair<string, IOpenApiSchema> OdataCount = new("@odata.count", new OpenApiSchema { Type = JsonSchemaType.Number, Format = "int64", Nullable = true });
32+
public static KeyValuePair<string, IOpenApiSchema> OdataCount = new("@odata.count", new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "int64"});
3333

3434
/// <summary>
3535
/// @odata.deltaLink KeyValue pair
3636
/// </summary>
37-
public static KeyValuePair<string, IOpenApiSchema> OdataDeltaLink = new("@odata.deltaLink", new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true });
37+
public static KeyValuePair<string, IOpenApiSchema> OdataDeltaLink = new("@odata.deltaLink", new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null });
3838
}
3939
}

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiEdmTypeSchemaGeneratorTest.cs

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -405,19 +405,15 @@ public void CreateEdmTypeSchemaReturnSchemaForDecimal(bool isNullable, bool IEEE
405405
Assert.Null(schema.Type);
406406
Assert.NotNull(schema.OneOf);
407407
Assert.Equal(2, schema.OneOf.Count);
408-
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals(JsonSchemaType.Number));
409-
Assert.NotNull(numberSchema);
410-
Assert.True(numberSchema.Nullable);
411-
var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals(JsonSchemaType.String));
412-
Assert.NotNull(stringSchema);
413-
Assert.True(stringSchema.Nullable);
414-
Assert.False(schema.Nullable);
408+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.Number | JsonSchemaType.Null));
409+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.String | JsonSchemaType.Null));
410+
Assert.NotEqual(JsonSchemaType.Null, schema.Type & JsonSchemaType.Null);
415411
}
416412
else
417413
{
418-
Assert.Equal(JsonSchemaType.Number, schema.Type);
414+
Assert.Equal(JsonSchemaType.Number, schema.Type & JsonSchemaType.Number);
419415
Assert.Null(schema.OneOf);
420-
Assert.Equal(isNullable, schema.Nullable);
416+
Assert.Equal(isNullable, (schema.Type & JsonSchemaType.Null) is JsonSchemaType.Null);
421417
}
422418
}
423419

@@ -448,19 +444,15 @@ public void CreateEdmTypeSchemaReturnSchemaForInt64(bool isNullable, bool IEEE75
448444
Assert.Null(schema.Type);
449445
Assert.NotNull(schema.OneOf);
450446
Assert.Equal(2, schema.OneOf.Count);
451-
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals(JsonSchemaType.Number));
452-
Assert.NotNull(numberSchema);
453-
Assert.True(numberSchema.Nullable);
454-
var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals(JsonSchemaType.String));
455-
Assert.NotNull(stringSchema);
456-
Assert.True(stringSchema.Nullable);
457-
Assert.False(schema.Nullable);
447+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.Number | JsonSchemaType.Null));
448+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.String | JsonSchemaType.Null));
449+
Assert.NotEqual(JsonSchemaType.Null, schema.Type & JsonSchemaType.Null);
458450
}
459451
else
460452
{
461-
Assert.Equal(JsonSchemaType.Number, schema.Type);
453+
Assert.Equal(JsonSchemaType.Number, schema.Type & JsonSchemaType.Number);
462454
Assert.Null(schema.AnyOf);
463-
Assert.Equal(isNullable, schema.Nullable);
455+
Assert.Equal(isNullable, (schema.Type & JsonSchemaType.Null) is JsonSchemaType.Null);
464456
}
465457
}
466458

@@ -516,16 +508,11 @@ public void CreateEdmTypeSchemaReturnSchemaForDouble(bool isNullable)
516508
// & Assert
517509
Assert.Null(schema.Type);
518510

519-
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals(JsonSchemaType.Number));
520-
Assert.NotNull(numberSchema);
521-
Assert.True(numberSchema.Nullable);
522-
Assert.Equal("double", numberSchema.Format, StringComparer.OrdinalIgnoreCase);
511+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.Number | JsonSchemaType.Null) && x.Format.Equals("double", StringComparison.OrdinalIgnoreCase));
523512

524-
var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals(JsonSchemaType.String));
525-
Assert.NotNull(stringSchema);
526-
Assert.True(stringSchema.Nullable);
513+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.String | JsonSchemaType.Null));
527514

528-
Assert.False(schema.Nullable);
515+
Assert.NotEqual(JsonSchemaType.Null, schema.Type & JsonSchemaType.Null);
529516

530517
Assert.Null(schema.AnyOf);
531518

@@ -550,16 +537,11 @@ public void CreateEdmTypeSchemaReturnSchemaForSingle(bool isNullable)
550537
// & Assert
551538
Assert.Null(schema.Type);
552539

553-
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type != null && x.Type.HasValue && (x.Type & JsonSchemaType.Number) is JsonSchemaType.Number);
554-
Assert.NotNull(numberSchema);
555-
Assert.True(numberSchema.Nullable);
556-
Assert.Equal("float", numberSchema.Format, StringComparer.OrdinalIgnoreCase);
540+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.Number | JsonSchemaType.Null) && x.Format.Equals("float", StringComparison.OrdinalIgnoreCase));
557541

558-
var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type != null && x.Type.HasValue && (x.Type & JsonSchemaType.String) is JsonSchemaType.String);
559-
Assert.NotNull(stringSchema);
560-
Assert.True(stringSchema.Nullable);
561-
562-
Assert.False(schema.Nullable);
542+
Assert.Single(schema.OneOf, x => x.Type.Equals(JsonSchemaType.String | JsonSchemaType.Null));
543+
544+
Assert.NotEqual(JsonSchemaType.Null, schema.Type & JsonSchemaType.Null);
563545

564546
Assert.Null(schema.AnyOf);
565547

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiRequestBodyGeneratorTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void CreateRequestBodyForActionImportReturnCorrectRequestBody()
9595
Assert.NotNull(schema.Properties);
9696
var parameter = Assert.Single(schema.Properties);
9797
Assert.Equal("param", parameter.Key);
98-
Assert.Equal(JsonSchemaType.String, parameter.Value.Type);
98+
Assert.Equal(JsonSchemaType.String | JsonSchemaType.Null, parameter.Value.Type);
9999
}
100100

101101
[Fact]
@@ -156,7 +156,7 @@ public void CreateRequestBodyForActionReturnCorrectRequestBody()
156156
Assert.NotNull(schema.Properties);
157157
var parameter = Assert.Single(schema.Properties);
158158
Assert.Equal("param", parameter.Key);
159-
Assert.Equal(JsonSchemaType.String, parameter.Value.Type);
159+
Assert.Equal(JsonSchemaType.String | JsonSchemaType.Null, parameter.Value.Type);
160160
}
161161

162162
[Fact]

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiSchemaGeneratorTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ public async Task CreateComplexTypeWithBaseSchemaReturnCorrectSchema()
537537
Assert.Equal("Price", property.Key);
538538
Assert.Equal("decimal", property.Value.OneOf.FirstOrDefault(x => !string.IsNullOrEmpty(x.Format))?.Format);
539539
Assert.NotNull(property.Value.OneOf);
540-
Assert.Equal([JsonSchemaType.Number, JsonSchemaType.String], property.Value.OneOf.Select(e => e.Type));
540+
Assert.Equal([JsonSchemaType.Number | JsonSchemaType.Null, JsonSchemaType.String | JsonSchemaType.Null], property.Value.OneOf.Select(e => e.Type));
541541

542542
Assert.Equal("Complex type 'Tree' description.", declaredSchema.Description);
543543
Assert.Equal("Tree", declaredSchema.Title);
@@ -950,6 +950,7 @@ public async Task CreatePropertySchemaForNullableEnumPropertyReturnSchema(OpenAp
950950
"default": "yellow"
951951
}
952952
""",
953+
_ => throw new NotSupportedException()
953954
});
954955

955956
Assert.True(JsonNode.DeepEquals(expected, JsonNode.Parse(json)));

test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,8 @@
966966
"x-ms-primary-error-message": true
967967
},
968968
"target": {
969-
"type": "string"
969+
"type": "string",
970+
"x-nullable": true
970971
},
971972
"details": {
972973
"type": "array",
@@ -993,7 +994,8 @@
993994
"type": "string"
994995
},
995996
"target": {
996-
"type": "string"
997+
"type": "string",
998+
"x-nullable": true
997999
}
9981000
}
9991001
},
@@ -1012,7 +1014,8 @@
10121014
"type": "string"
10131015
},
10141016
"@odata.type": {
1015-
"type": "string"
1017+
"type": "string",
1018+
"x-nullable": true
10161019
}
10171020
}
10181021
},
@@ -1029,6 +1032,7 @@
10291032
},
10301033
"ReferenceNumeric": {
10311034
"type": "string",
1035+
"x-nullable": true,
10321036
"enum": [
10331037
"-INF",
10341038
"INF",

test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ definitions:
637637
x-ms-primary-error-message: true
638638
target:
639639
type: string
640+
x-nullable: true
640641
details:
641642
type: array
642643
items:
@@ -655,6 +656,7 @@ definitions:
655656
type: string
656657
target:
657658
type: string
659+
x-nullable: true
658660
DefaultNs.ODataErrors.InnerError:
659661
type: object
660662
description: The structure of this object is service-specific
@@ -668,6 +670,7 @@ definitions:
668670
type: string
669671
'@odata.type':
670672
type: string
673+
x-nullable: true
671674
ReferenceCreate:
672675
type: object
673676
properties:
@@ -677,6 +680,7 @@ definitions:
677680
type: object
678681
ReferenceNumeric:
679682
type: string
683+
x-nullable: true
680684
enum:
681685
- '-INF'
682686
- INF

test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -659,8 +659,8 @@ components:
659659
type: string
660660
x-ms-primary-error-message: true
661661
target:
662-
nullable: true
663662
type: string
663+
nullable: true
664664
details:
665665
type: array
666666
items:
@@ -678,8 +678,8 @@ components:
678678
message:
679679
type: string
680680
target:
681-
nullable: true
682681
type: string
682+
nullable: true
683683
DefaultNs.ODataErrors.InnerError:
684684
type: object
685685
description: The structure of this object is service-specific
@@ -692,8 +692,8 @@ components:
692692
'@odata.id':
693693
type: string
694694
'@odata.type':
695-
nullable: true
696695
type: string
696+
nullable: true
697697
ReferenceCreate:
698698
type: object
699699
properties:
@@ -706,8 +706,8 @@ components:
706706
- '-INF'
707707
- INF
708708
- NaN
709-
nullable: true
710709
type: string
710+
nullable: true
711711
DefaultNs.Color:
712712
title: Color
713713
enum:

0 commit comments

Comments
 (0)