mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-08 12:37:49 +00:00
Added contains, minContains and maxContains to schema #28
Added support for missing 3.1 schema properties, however it does not cover the `boolean` case
This commit is contained in:
@@ -55,9 +55,14 @@ type Schema struct {
|
|||||||
// in 3.1 prefixItems provides tuple validation support.
|
// in 3.1 prefixItems provides tuple validation support.
|
||||||
PrefixItems []*SchemaProxy
|
PrefixItems []*SchemaProxy
|
||||||
|
|
||||||
|
// In 3.1 contains is used by arrays to define a single schema
|
||||||
|
Contains *SchemaProxy
|
||||||
|
MinContains *int64
|
||||||
|
MaxContains *int64
|
||||||
|
|
||||||
// Compatible with all versions
|
// Compatible with all versions
|
||||||
Not []*SchemaProxy
|
Not []*SchemaProxy
|
||||||
Items []*SchemaProxy
|
Items *SchemaProxy
|
||||||
Properties map[string]*SchemaProxy
|
Properties map[string]*SchemaProxy
|
||||||
Title string
|
Title string
|
||||||
MultipleOf *int64
|
MultipleOf *int64
|
||||||
@@ -139,6 +144,19 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
if !schema.MinProperties.IsEmpty() {
|
if !schema.MinProperties.IsEmpty() {
|
||||||
s.MinProperties = &schema.MinProperties.Value
|
s.MinProperties = &schema.MinProperties.Value
|
||||||
}
|
}
|
||||||
|
if !schema.MaxContains.IsEmpty() {
|
||||||
|
s.MaxContains = &schema.MaxContains.Value
|
||||||
|
}
|
||||||
|
if !schema.MinContains.IsEmpty() {
|
||||||
|
s.MinContains = &schema.MinContains.Value
|
||||||
|
}
|
||||||
|
if !schema.Contains.IsEmpty() {
|
||||||
|
s.Contains = &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{
|
||||||
|
ValueNode: schema.Contains.ValueNode,
|
||||||
|
Value: schema.Contains.Value,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
s.Pattern = schema.Pattern.Value
|
s.Pattern = schema.Pattern.Value
|
||||||
s.Format = schema.Format.Value
|
s.Format = schema.Format.Value
|
||||||
|
|
||||||
@@ -197,6 +215,8 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
}
|
}
|
||||||
s.Enum = enum
|
s.Enum = enum
|
||||||
|
|
||||||
|
// build out
|
||||||
|
|
||||||
// async work.
|
// async work.
|
||||||
// any polymorphic properties need to be handled in their own threads
|
// any polymorphic properties need to be handled in their own threads
|
||||||
// any properties each need to be processed in their own thread.
|
// any properties each need to be processed in their own thread.
|
||||||
@@ -312,7 +332,9 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
s.OneOf = oneOf
|
s.OneOf = oneOf
|
||||||
s.AnyOf = anyOf
|
s.AnyOf = anyOf
|
||||||
s.AllOf = allOf
|
s.AllOf = allOf
|
||||||
s.Items = items
|
if len(items) > 0 {
|
||||||
|
s.Items = items[0]
|
||||||
|
}
|
||||||
s.PrefixItems = prefixItems
|
s.PrefixItems = prefixItems
|
||||||
s.Not = not
|
s.Not = not
|
||||||
return s
|
return s
|
||||||
|
|||||||
@@ -191,7 +191,11 @@ minProperties: 1
|
|||||||
nullable: true
|
nullable: true
|
||||||
readOnly: true
|
readOnly: true
|
||||||
writeOnly: false
|
writeOnly: false
|
||||||
deprecated: true`
|
deprecated: true
|
||||||
|
contains:
|
||||||
|
type: int
|
||||||
|
minContains: 1
|
||||||
|
maxContains: 10`
|
||||||
|
|
||||||
var compNode yaml.Node
|
var compNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
||||||
@@ -213,6 +217,11 @@ deprecated: true`
|
|||||||
assert.NotNil(t, compiled)
|
assert.NotNil(t, compiled)
|
||||||
assert.Nil(t, schemaProxy.GetBuildError())
|
assert.Nil(t, schemaProxy.GetBuildError())
|
||||||
|
|
||||||
|
// check contains
|
||||||
|
assert.Equal(t, "int", compiled.Contains.Schema().Type[0])
|
||||||
|
assert.Equal(t, int64(10), *compiled.MaxContains)
|
||||||
|
assert.Equal(t, int64(1), *compiled.MinContains)
|
||||||
|
|
||||||
wentLow := compiled.GoLow()
|
wentLow := compiled.GoLow()
|
||||||
assert.Equal(t, 114, wentLow.AdditionalProperties.ValueNode.Line)
|
assert.Equal(t, 114, wentLow.AdditionalProperties.ValueNode.Line)
|
||||||
|
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ func TestNewDocument_Components_Schemas(t *testing.T) {
|
|||||||
assert.Equal(t, 445, b.Schema().GoLow().FindProperty("name").ValueNode.Line)
|
assert.Equal(t, 445, b.Schema().GoLow().FindProperty("name").ValueNode.Line)
|
||||||
|
|
||||||
f := h.Components.Schemas["Fries"]
|
f := h.Components.Schemas["Fries"]
|
||||||
assert.Equal(t, "salt", f.Schema().Properties["seasoning"].Schema().Items[0].Schema().Example)
|
assert.Equal(t, "salt", f.Schema().Properties["seasoning"].Schema().Items.Schema().Example)
|
||||||
assert.Len(t, f.Schema().Properties["favoriteDrink"].Schema().Properties["drinkType"].Schema().Enum, 2)
|
assert.Len(t, f.Schema().Properties["favoriteDrink"].Schema().Properties["drinkType"].Schema().Enum, 2)
|
||||||
|
|
||||||
d := h.Components.Schemas["Drink"]
|
d := h.Components.Schemas["Drink"]
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const (
|
|||||||
XMLLabel = "xml"
|
XMLLabel = "xml"
|
||||||
ItemsLabel = "items"
|
ItemsLabel = "items"
|
||||||
PrefixItemsLabel = "prefixItems"
|
PrefixItemsLabel = "prefixItems"
|
||||||
|
ContainsLabel = "contains"
|
||||||
AllOfLabel = "allOf"
|
AllOfLabel = "allOf"
|
||||||
AnyOfLabel = "anyOf"
|
AnyOfLabel = "anyOf"
|
||||||
OneOfLabel = "oneOf"
|
OneOfLabel = "oneOf"
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ type Schema struct {
|
|||||||
Examples low.NodeReference[[]low.ValueReference[any]]
|
Examples low.NodeReference[[]low.ValueReference[any]]
|
||||||
// in 3.1 PrefixItems provides tuple validation using prefixItems.
|
// in 3.1 PrefixItems provides tuple validation using prefixItems.
|
||||||
PrefixItems low.NodeReference[[]low.ValueReference[*SchemaProxy]]
|
PrefixItems low.NodeReference[[]low.ValueReference[*SchemaProxy]]
|
||||||
|
// in 3.1 Contains is used by arrays and points to a Schema.
|
||||||
|
Contains low.NodeReference[*SchemaProxy]
|
||||||
|
MinContains low.NodeReference[int64]
|
||||||
|
MaxContains low.NodeReference[int64]
|
||||||
|
|
||||||
// Compatible with all versions
|
// Compatible with all versions
|
||||||
Title low.NodeReference[string]
|
Title low.NodeReference[string]
|
||||||
@@ -367,6 +371,17 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
if s.Example.Value != nil {
|
if s.Example.Value != nil {
|
||||||
d = append(d, low.GenerateHashString(s.Example.Value))
|
d = append(d, low.GenerateHashString(s.Example.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contains
|
||||||
|
if !s.Contains.IsEmpty() {
|
||||||
|
d = append(d, low.GenerateHashString(s.Contains.Value))
|
||||||
|
}
|
||||||
|
if !s.MinContains.IsEmpty() {
|
||||||
|
d = append(d, fmt.Sprint(s.MinContains.Value))
|
||||||
|
}
|
||||||
|
if !s.MaxContains.IsEmpty() {
|
||||||
|
d = append(d, fmt.Sprint(s.MaxContains.Value))
|
||||||
|
}
|
||||||
if !s.Examples.IsEmpty() {
|
if !s.Examples.IsEmpty() {
|
||||||
var xph []string
|
var xph []string
|
||||||
for w := range s.Examples.Value {
|
for w := range s.Examples.Value {
|
||||||
@@ -632,6 +647,7 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var allOf, anyOf, oneOf, not, items, prefixItems []low.ValueReference[*SchemaProxy]
|
var allOf, anyOf, oneOf, not, items, prefixItems []low.ValueReference[*SchemaProxy]
|
||||||
|
var contains low.ValueReference[*SchemaProxy]
|
||||||
|
|
||||||
_, allOfLabel, allOfValue := utils.FindKeyNodeFullTop(AllOfLabel, root.Content)
|
_, allOfLabel, allOfValue := utils.FindKeyNodeFullTop(AllOfLabel, root.Content)
|
||||||
_, anyOfLabel, anyOfValue := utils.FindKeyNodeFullTop(AnyOfLabel, root.Content)
|
_, anyOfLabel, anyOfValue := utils.FindKeyNodeFullTop(AnyOfLabel, root.Content)
|
||||||
@@ -639,6 +655,7 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
_, notLabel, notValue := utils.FindKeyNodeFullTop(NotLabel, root.Content)
|
_, notLabel, notValue := utils.FindKeyNodeFullTop(NotLabel, root.Content)
|
||||||
_, itemsLabel, itemsValue := utils.FindKeyNodeFullTop(ItemsLabel, root.Content)
|
_, itemsLabel, itemsValue := utils.FindKeyNodeFullTop(ItemsLabel, root.Content)
|
||||||
_, prefixItemsLabel, prefixItemsValue := utils.FindKeyNodeFullTop(PrefixItemsLabel, root.Content)
|
_, prefixItemsLabel, prefixItemsValue := utils.FindKeyNodeFullTop(PrefixItemsLabel, root.Content)
|
||||||
|
_, containsLabel, containsValue := utils.FindKeyNodeFullTop(ContainsLabel, root.Content)
|
||||||
|
|
||||||
errorChan := make(chan error)
|
errorChan := make(chan error)
|
||||||
allOfChan := make(chan schemaProxyBuildResult)
|
allOfChan := make(chan schemaProxyBuildResult)
|
||||||
@@ -647,6 +664,7 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
itemsChan := make(chan schemaProxyBuildResult)
|
itemsChan := make(chan schemaProxyBuildResult)
|
||||||
prefixItemsChan := make(chan schemaProxyBuildResult)
|
prefixItemsChan := make(chan schemaProxyBuildResult)
|
||||||
notChan := make(chan schemaProxyBuildResult)
|
notChan := make(chan schemaProxyBuildResult)
|
||||||
|
containsChan := make(chan schemaProxyBuildResult)
|
||||||
|
|
||||||
totalBuilds := countSubSchemaItems(allOfValue) +
|
totalBuilds := countSubSchemaItems(allOfValue) +
|
||||||
countSubSchemaItems(anyOfValue) +
|
countSubSchemaItems(anyOfValue) +
|
||||||
@@ -673,6 +691,10 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
if notValue != nil {
|
if notValue != nil {
|
||||||
go buildSchema(notChan, notLabel, notValue, errorChan, idx)
|
go buildSchema(notChan, notLabel, notValue, errorChan, idx)
|
||||||
}
|
}
|
||||||
|
if containsValue != nil {
|
||||||
|
totalBuilds++
|
||||||
|
go buildSchema(containsChan, containsLabel, containsValue, errorChan, idx)
|
||||||
|
}
|
||||||
|
|
||||||
completeCount := 0
|
completeCount := 0
|
||||||
for completeCount < totalBuilds {
|
for completeCount < totalBuilds {
|
||||||
@@ -697,6 +719,9 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
case r := <-notChan:
|
case r := <-notChan:
|
||||||
completeCount++
|
completeCount++
|
||||||
not = append(not, r.v)
|
not = append(not, r.v)
|
||||||
|
case r := <-containsChan:
|
||||||
|
completeCount++
|
||||||
|
contains = r.v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,6 +768,13 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
ValueNode: prefixItemsValue,
|
ValueNode: prefixItemsValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !contains.IsEmpty() {
|
||||||
|
s.Contains = low.NodeReference[*SchemaProxy]{
|
||||||
|
Value: contains.Value,
|
||||||
|
KeyNode: containsLabel,
|
||||||
|
ValueNode: containsValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,11 @@ enum:
|
|||||||
x-pizza: tasty
|
x-pizza: tasty
|
||||||
examples:
|
examples:
|
||||||
- hey
|
- hey
|
||||||
- hi!`
|
- hi!
|
||||||
|
contains:
|
||||||
|
type: int
|
||||||
|
maxContains: 10
|
||||||
|
minContains: 1`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Schema(t *testing.T) {
|
func Test_Schema(t *testing.T) {
|
||||||
@@ -271,6 +275,12 @@ func Test_Schema(t *testing.T) {
|
|||||||
assert.Equal(t, "cat", mv.Value)
|
assert.Equal(t, "cat", mv.Value)
|
||||||
mv = sch.Discriminator.Value.FindMappingValue("pizza")
|
mv = sch.Discriminator.Value.FindMappingValue("pizza")
|
||||||
assert.Equal(t, "party", mv.Value)
|
assert.Equal(t, "party", mv.Value)
|
||||||
|
|
||||||
|
// check contains
|
||||||
|
assert.Equal(t, "int", sch.Contains.Value.Schema().Type.Value.A)
|
||||||
|
assert.Equal(t, int64(1), sch.MinContains.Value)
|
||||||
|
assert.Equal(t, int64(10), sch.MaxContains.Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchema_Hash(t *testing.T) {
|
func TestSchema_Hash(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user