117 lines
2.7 KiB
Go
117 lines
2.7 KiB
Go
package query
|
|
|
|
import "fmt"
|
|
|
|
type IndexedElement struct {
|
|
Name string
|
|
DisplayName *string
|
|
ReferencedData any
|
|
Parent *IndexedContainer
|
|
Containers []*IndexedContainer
|
|
}
|
|
|
|
func (e *IndexedElement) Init() {
|
|
for _, container := range e.Containers {
|
|
container.Parent = e
|
|
container.Init()
|
|
}
|
|
}
|
|
|
|
func (e *IndexedElement) String() string {
|
|
if e.Parent == nil {
|
|
panic("IndexedElement has no parent!")
|
|
}
|
|
return fmt.Sprintf("%s:%s", e.Parent.Parent, e.Name)
|
|
}
|
|
|
|
func (e *IndexedElement) PrintableName() string {
|
|
var result = e.Name
|
|
if e.DisplayName != nil {
|
|
result = *e.DisplayName
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (e *IndexedElement) Find(c *Container) QueryResult {
|
|
return findInContainers(c, e.Containers)
|
|
}
|
|
|
|
type IndexedContainer struct {
|
|
Name string
|
|
Parent *IndexedElement
|
|
Elements []*IndexedElement
|
|
}
|
|
|
|
func (c *IndexedContainer) Init() {
|
|
for _, element := range c.Elements {
|
|
element.Parent = c
|
|
element.Init()
|
|
}
|
|
}
|
|
|
|
func (c *IndexedContainer) String() string {
|
|
var parentStr = ""
|
|
|
|
if c.Parent != nil {
|
|
parentStr = c.Parent.String()
|
|
}
|
|
return fmt.Sprintf("%s%s", parentStr, c.Name)
|
|
}
|
|
|
|
func (c *IndexedContainer) PrintableName() string {
|
|
return c.Name
|
|
}
|
|
|
|
func (c *IndexedContainer) Find(e *Element) QueryResult {
|
|
for _, element := range c.Elements {
|
|
if e.Name == element.Name {
|
|
if e.NextContainer != nil {
|
|
// If the element is found but the query expression continues
|
|
// with a container query, delegate the search to the element
|
|
return element.Find(e.NextContainer)
|
|
} else {
|
|
// If not, return the found element
|
|
return QueryResult{element}
|
|
}
|
|
}
|
|
}
|
|
// Return an empty list if the element is not found
|
|
return make(QueryResult, 0)
|
|
}
|
|
|
|
// A query tree is a bipartite graph composed of containers and elements.
|
|
// Only elements can be queried.
|
|
type IndexedRoot struct {
|
|
Containers []*IndexedContainer
|
|
}
|
|
|
|
func (r *IndexedRoot) Find(q *Query) QueryResult {
|
|
return findInContainers(&q.Container, r.Containers)
|
|
}
|
|
|
|
func (r *IndexedRoot) FindByRef(ref Reference) (QueryResult, error) {
|
|
var query, err = ref.Parse()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return r.Find(query), nil
|
|
}
|
|
|
|
func findInContainers(queried *Container, containers []*IndexedContainer) QueryResult {
|
|
for _, container := range containers {
|
|
if queried.Name == container.Name {
|
|
if queried.NextElement != nil {
|
|
// If the container is found but the query expression continues
|
|
// with an element query, delegate the search to the container
|
|
return container.Find(queried.NextElement)
|
|
} else {
|
|
// If not, return all the elements in the found container
|
|
return container.Elements
|
|
}
|
|
}
|
|
}
|
|
// Return an empty list if the container is not found
|
|
return make(QueryResult, 0)
|
|
}
|