2024-10-24 12:20:33 +00:00
|
|
|
package resources
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/databricks/cli/bundle"
|
|
|
|
"github.com/databricks/cli/bundle/config"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Reference is a reference to a resource.
|
|
|
|
// It includes the resource type description, and a reference to the resource itself.
|
|
|
|
type Reference struct {
|
2024-10-24 13:24:30 +00:00
|
|
|
// Key is the unique key of the resource, e.g. "my_job".
|
|
|
|
Key string
|
|
|
|
|
|
|
|
// KeyWithType is the unique key of the resource, including the resource type, e.g. "jobs.my_job".
|
|
|
|
KeyWithType string
|
|
|
|
|
|
|
|
// Description is the resource type description.
|
2024-10-24 12:20:33 +00:00
|
|
|
Description config.ResourceDescription
|
2024-10-24 13:24:30 +00:00
|
|
|
|
|
|
|
// Resource is the resource itself.
|
|
|
|
Resource config.ConfigResource
|
2024-10-24 12:20:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Map is the core type for resource lookup and completion.
|
|
|
|
type Map map[string][]Reference
|
|
|
|
|
2024-10-24 13:24:30 +00:00
|
|
|
// Filter defines the function signature for filtering resources.
|
|
|
|
type Filter func(Reference) bool
|
|
|
|
|
|
|
|
// includeReference checks if the specified reference passes all filters.
|
|
|
|
// If the list of filters is empty, the reference is always included.
|
|
|
|
func includeReference(filters []Filter, ref Reference) bool {
|
|
|
|
for _, filter := range filters {
|
|
|
|
if !filter(ref) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-10-24 12:20:33 +00:00
|
|
|
// References returns maps of resource keys to a slice of [Reference].
|
|
|
|
//
|
|
|
|
// The first map is indexed by the resource key only.
|
|
|
|
// The second map is indexed by the resource type name and its key.
|
|
|
|
//
|
|
|
|
// While the return types allows for multiple resources to share the same key,
|
|
|
|
// this is confirmed not to happen in the [validate.UniqueResourceKeys] mutator.
|
2024-10-24 13:24:30 +00:00
|
|
|
func References(b *bundle.Bundle, filters ...Filter) (Map, Map) {
|
2024-10-24 12:20:33 +00:00
|
|
|
keyOnly := make(Map)
|
|
|
|
keyWithType := make(Map)
|
|
|
|
|
|
|
|
// Collect map of resource references indexed by their keys.
|
|
|
|
for _, group := range b.Config.Resources.AllResources() {
|
|
|
|
for k, v := range group.Resources {
|
|
|
|
ref := Reference{
|
2024-10-24 13:24:30 +00:00
|
|
|
Key: k,
|
|
|
|
KeyWithType: fmt.Sprintf("%s.%s", group.Description.PluralName, k),
|
2024-10-24 12:20:33 +00:00
|
|
|
Description: group.Description,
|
|
|
|
Resource: v,
|
|
|
|
}
|
|
|
|
|
2024-10-24 13:24:30 +00:00
|
|
|
// Skip resources that do not pass all filters.
|
|
|
|
if !includeReference(filters, ref) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
keyOnly[ref.Key] = append(keyOnly[ref.Key], ref)
|
|
|
|
keyWithType[ref.KeyWithType] = append(keyWithType[ref.KeyWithType], ref)
|
2024-10-24 12:20:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return keyOnly, keyWithType
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup returns the resource with the specified key.
|
|
|
|
// If the key maps to more than one resource, an error is returned.
|
|
|
|
// If the key does not map to any resource, an error is returned.
|
2024-10-24 13:24:30 +00:00
|
|
|
func Lookup(b *bundle.Bundle, key string, filters ...Filter) (Reference, error) {
|
|
|
|
keyOnlyRefs, keyWithTypeRefs := References(b, filters...)
|
2024-10-24 12:20:33 +00:00
|
|
|
refs, ok := keyOnlyRefs[key]
|
|
|
|
if !ok {
|
|
|
|
refs, ok = keyWithTypeRefs[key]
|
|
|
|
if !ok {
|
|
|
|
return Reference{}, fmt.Errorf("resource with key %q not found", key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case len(refs) == 1:
|
|
|
|
return refs[0], nil
|
|
|
|
case len(refs) > 1:
|
|
|
|
return Reference{}, fmt.Errorf("multiple resources with key %q found", key)
|
|
|
|
default:
|
|
|
|
panic("unreachable")
|
|
|
|
}
|
|
|
|
}
|