Skip to content

Commit f1dc4fb

Browse files
alexrjonesdaveshanley
authored andcommitted
Transform 3.0 schema with allOf + nullable into oneOf
1 parent 0db7586 commit f1dc4fb

2 files changed

Lines changed: 140 additions & 0 deletions

File tree

helpers/schema_compiler.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,26 @@ func transformNullableSchema(schema map[string]interface{}) map[string]interface
187187
}
188188
}
189189
}
190+
allOf, hasAllOf := schema["allOf"]
191+
if hasAllOf {
192+
delete(schema, "allOf")
193+
oneOfAdditions := []interface{}{
194+
map[string]interface{}{
195+
"allOf": allOf,
196+
},
197+
map[string]interface{}{
198+
"type": "null",
199+
},
200+
}
201+
var oneOfSlice []interface{}
202+
oneOf, hasOneOf := schema["oneOf"]
203+
if hasOneOf {
204+
oneOfSlice, _ = oneOf.([]interface{})
205+
}
206+
oneOfSlice = append(oneOfSlice, oneOfAdditions...)
207+
schema["oneOf"] = oneOfSlice
208+
}
209+
190210
return schema
191211
}
192212

helpers/schema_compiler_test.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,126 @@ func TestTransformNullableSchema_ArrayTypeWithNull(t *testing.T) {
456456
assert.False(t, hasNullable)
457457
}
458458

459+
func TestTransformNullableSchema_NullableAllOf(t *testing.T) {
460+
schema := map[string]interface{}{
461+
"type": []interface{}{"object"},
462+
"allOf": []interface{}{
463+
map[string]interface{}{
464+
"type": "object",
465+
"properties": map[string]interface{}{
466+
"id": map[string]interface{}{
467+
"type": "string",
468+
}},
469+
},
470+
},
471+
"nullable": true,
472+
}
473+
474+
result := transformNullableSchema(schema)
475+
476+
schemaType, ok := result["type"]
477+
require.True(t, ok)
478+
479+
typeArray, ok := schemaType.([]interface{})
480+
require.True(t, ok)
481+
assert.Contains(t, typeArray, "object")
482+
assert.Contains(t, typeArray, "null")
483+
484+
oneOf, ok := result["oneOf"]
485+
require.True(t, ok)
486+
487+
oneOfSlice, ok := oneOf.([]interface{})
488+
require.True(t, ok)
489+
490+
assert.Len(t, oneOfSlice, 2)
491+
assert.Contains(t, oneOfSlice, map[string]interface{}{
492+
"allOf": []interface{}{
493+
map[string]interface{}{
494+
"type": "object",
495+
"properties": map[string]interface{}{
496+
"id": map[string]interface{}{
497+
"type": "string",
498+
}},
499+
},
500+
},
501+
})
502+
assert.Contains(t, oneOfSlice, map[string]interface{}{
503+
"type": "null",
504+
})
505+
506+
_, hasNullable := result["nullable"]
507+
assert.False(t, hasNullable)
508+
}
509+
510+
func TestTransformNullableSchema_NullableAllOfWithExistingOneOf(t *testing.T) {
511+
schema := map[string]interface{}{
512+
"type": []interface{}{"object"},
513+
"allOf": []interface{}{
514+
map[string]interface{}{
515+
"type": "object",
516+
"properties": map[string]interface{}{
517+
"id": map[string]interface{}{
518+
"type": "string",
519+
}},
520+
},
521+
},
522+
"oneOf": []interface{}{
523+
map[string]interface{}{
524+
"type": "object",
525+
"properties": map[string]interface{}{
526+
"id": map[string]interface{}{
527+
"type": "string",
528+
"const": []any{"val"},
529+
}},
530+
},
531+
},
532+
"nullable": true,
533+
}
534+
535+
result := transformNullableSchema(schema)
536+
537+
schemaType, ok := result["type"]
538+
require.True(t, ok)
539+
540+
typeArray, ok := schemaType.([]interface{})
541+
require.True(t, ok)
542+
assert.Contains(t, typeArray, "object")
543+
assert.Contains(t, typeArray, "null")
544+
545+
oneOf, ok := result["oneOf"]
546+
require.True(t, ok)
547+
548+
oneOfSlice, ok := oneOf.([]interface{})
549+
require.True(t, ok)
550+
551+
assert.Len(t, oneOfSlice, 3)
552+
assert.Contains(t, oneOfSlice, map[string]interface{}{
553+
"allOf": []interface{}{
554+
map[string]interface{}{
555+
"type": "object",
556+
"properties": map[string]interface{}{
557+
"id": map[string]interface{}{
558+
"type": "string",
559+
}},
560+
},
561+
},
562+
})
563+
assert.Contains(t, oneOfSlice, map[string]interface{}{
564+
"type": "null",
565+
})
566+
assert.Contains(t, oneOfSlice, map[string]interface{}{
567+
"type": "object",
568+
"properties": map[string]interface{}{
569+
"id": map[string]interface{}{
570+
"type": "string",
571+
"const": []any{"val"},
572+
}},
573+
})
574+
575+
_, hasNullable := result["nullable"]
576+
assert.False(t, hasNullable)
577+
}
578+
459579
func TestTransformSchemaForCoercion_ValidJSON(t *testing.T) {
460580
input := []byte(`{
461581
"type": "boolean"

0 commit comments

Comments
 (0)