Skip to content

Commit

Permalink
Process resource without a parent first (#1282) (#1289)
Browse files Browse the repository at this point in the history
* Process resource without a parent first

Resources without a parent may be parents of other resources. For
deeper levels of nesting this can be a problem.

* Iterate over every previous element to ensure no parent was missed
  • Loading branch information
fixl authored and raphael committed Jun 28, 2017
1 parent 4c3d4d9 commit 06d44bb
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 3 deletions.
15 changes: 12 additions & 3 deletions design/definitions.go
Expand Up @@ -901,9 +901,18 @@ func (r *ResourceDefinition) UserTypes() map[string]*UserTypeDefinition {
// byParent makes it possible to sort resources - parents first the children.
type byParent []*ResourceDefinition

func (p byParent) Len() int { return len(p) }
func (p byParent) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p byParent) Less(i, j int) bool { return p[j].ParentName == p[i].Name }
func (p byParent) Len() int { return len(p) }
func (p byParent) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p byParent) Less(i, j int) bool {
for k := 0; k < i; k++ {
// We need to inspect _all_ previous fields to see if they are a parent. Sort doesn't do this.
if p[i].Name == p[k].ParentName {
return true
}
}

return false
}

// Context returns the generic definition name used in error messages.
func (cors *CORSDefinition) Context() string {
Expand Down
91 changes: 91 additions & 0 deletions design/definitions_test.go
Expand Up @@ -351,3 +351,94 @@ var _ = Describe("PathParams", func() {
})
})
})

var _ = Describe("IterateSets", func() {

var api *design.APIDefinition

BeforeEach(func() {
api = &design.APIDefinition{}
api.Name = "Test"
})

Context("ResourceDefinition", func() {
// a function that collects resource definitions for validation
var valFunc = func(validate func([]*design.ResourceDefinition)) func(s dslengine.DefinitionSet) error {
return func(s dslengine.DefinitionSet) error {
if len(s) == 0 {
return nil
}

if _, ok := s[0].(*design.ResourceDefinition); !ok {
return nil
}

resources := make([]*design.ResourceDefinition, len(s))
for i, res := range s {
resources[i] = res.(*design.ResourceDefinition)
}

validate(resources)

return nil
}
}

It("should order nested resources", func() {
inspected := false
api.Resources = make(map[string]*design.ResourceDefinition)

api.Resources["V"] = &design.ResourceDefinition{Name: "V", ParentName: "W"}
api.Resources["W"] = &design.ResourceDefinition{Name: "W", ParentName: "X"}
api.Resources["X"] = &design.ResourceDefinition{Name: "X", ParentName: "Y"}
api.Resources["Y"] = &design.ResourceDefinition{Name: "Y", ParentName: "Z"}
api.Resources["Z"] = &design.ResourceDefinition{Name: "Z"}

validate := func(s []*design.ResourceDefinition) {
Ω(s[0].Name).Should(Equal("Z"))
Ω(s[1].Name).Should(Equal("Y"))
Ω(s[2].Name).Should(Equal("X"))
Ω(s[3].Name).Should(Equal("W"))
Ω(s[4].Name).Should(Equal("V"))
inspected = true
}

api.IterateSets(valFunc(validate))

Ω(inspected).Should(BeTrue())
})

It("should order multiple nested resources", func() {
inspected := false
api.Resources = make(map[string]*design.ResourceDefinition)

api.Resources["A"] = &design.ResourceDefinition{Name: "A"}
api.Resources["B"] = &design.ResourceDefinition{Name: "B", ParentName: "A"}
api.Resources["C"] = &design.ResourceDefinition{Name: "C", ParentName: "A"}
api.Resources["I"] = &design.ResourceDefinition{Name: "I"}
api.Resources["J"] = &design.ResourceDefinition{Name: "J", ParentName: "K"}
api.Resources["K"] = &design.ResourceDefinition{Name: "K", ParentName: "I"}
api.Resources["X"] = &design.ResourceDefinition{Name: "X"}
api.Resources["Y"] = &design.ResourceDefinition{Name: "Y"}
api.Resources["Z"] = &design.ResourceDefinition{Name: "Z"}

validate := func(s []*design.ResourceDefinition) {
Ω(s[0].Name).Should(Equal("A"))
Ω(s[1].Name).Should(Equal("B"))
Ω(s[2].Name).Should(Equal("C"))
Ω(s[3].Name).Should(Equal("I"))
Ω(s[4].Name).Should(Equal("K"))
Ω(s[5].Name).Should(Equal("J"))
Ω(s[6].Name).Should(Equal("X"))
Ω(s[7].Name).Should(Equal("Y"))
Ω(s[8].Name).Should(Equal("Z"))
inspected = true
}

api.IterateSets(valFunc(validate))

Ω(inspected).Should(BeTrue())
})
})

})

0 comments on commit 06d44bb

Please sign in to comment.