mirror of https://github.com/grafana/grafana
coremodels: Combine static and generic registries (#53246)
* Stop generating non-dynamic registry code * Remove generic, errors, s/static/base/ * Sort during codegen, not runtime * Not a method call * Precisiate a comment * Remove generic registry, fix assignability testpull/53262/head^2
parent
d54e55ea9a
commit
b11f66b4bb
@ -1,40 +1,59 @@ |
||||
package registry |
||||
|
||||
import ( |
||||
"sync" |
||||
|
||||
"github.com/google/wire" |
||||
"github.com/grafana/grafana/pkg/cuectx" |
||||
"github.com/grafana/grafana/pkg/framework/coremodel" |
||||
"github.com/grafana/thema" |
||||
) |
||||
|
||||
// ProvideStatic provides access to individual coremodels via explicit method calls.
|
||||
//
|
||||
// Prefer this to the ProvideGeneric type when your code works with known,
|
||||
// specific coremodels(s), rather than generically across all of them. This
|
||||
// allows standard Go static analysis tools to determine which code is depending
|
||||
// on particular coremodels.
|
||||
// CoremodelSet contains all of the wire-style providers related to coremodels.
|
||||
var CoremodelSet = wire.NewSet( |
||||
NewBase, |
||||
) |
||||
|
||||
// NewBase provides a registry of all coremodels, without any composition of
|
||||
// plugin-defined schemas.
|
||||
//
|
||||
// This will use the default Grafana thema.Library, defined in pkg/cuectx, which
|
||||
// will avoid duplicate parsing of Thema CUE schemas. If you need control over the
|
||||
// thema.Library in use, use ProvideStaticWithLib instead.
|
||||
func ProvideStatic() (*Static, error) { |
||||
return provideStatic(nil) |
||||
// The returned registry will use the default Grafana thema.Library, defined in
|
||||
// pkg/cuectx. If you need control over the thema.Library used by the coremodel
|
||||
// lineages, use NewBaseWithLib instead.
|
||||
func NewBase() *Base { |
||||
return provideBase(nil) |
||||
} |
||||
|
||||
// ProvideStaticWithLib is the same as ProvideStatic, but
|
||||
// allows control over the thema.Library used to initialize the underlying
|
||||
// coremodels.
|
||||
// NewBaseWithLib is the same as NewBase, but allows control over the
|
||||
// thema.Library used to initialize the underlying coremodels.
|
||||
//
|
||||
// Prefer ProvideStatic unless you absolutely need this control.
|
||||
func ProvideStaticWithLib(lib thema.Library) (*Static, error) { |
||||
return provideStatic(&lib) |
||||
// Prefer NewBase unless you absolutely need this control.
|
||||
func NewBaseWithLib(lib thema.Library) *Base { |
||||
return provideBase(&lib) |
||||
} |
||||
|
||||
// ProvideGeneric provides a simple Generic registry of all coremodels.
|
||||
//
|
||||
// Prefer this to the static ProvideStatic when your code needs to
|
||||
// work with all coremodels generically, rather than specific coremodels.
|
||||
func ProvideGeneric() (*Generic, error) { |
||||
return provideGeneric() |
||||
var ( |
||||
baseOnce sync.Once |
||||
defaultBase *Base |
||||
) |
||||
|
||||
func provideBase(lib *thema.Library) *Base { |
||||
if lib == nil { |
||||
baseOnce.Do(func() { |
||||
defaultBase = doProvideBase(cuectx.ProvideThemaLibrary()) |
||||
}) |
||||
return defaultBase |
||||
} |
||||
|
||||
return doProvideBase(*lib) |
||||
} |
||||
|
||||
// NOTE - no ProvideRegistryWithLib is defined because there are no anticipated
|
||||
// cases where a caller would need to operate generically across all coremodels,
|
||||
// and control the library they're initialized with. If that changes, add one.
|
||||
// All returns a slice of all registered coremodels.
|
||||
//
|
||||
// Prefer this method when operating generically across all coremodels.
|
||||
//
|
||||
// The returned slice is sorted lexicographically by coremodel name. It should
|
||||
// not be modified.
|
||||
func (s *Base) All() []coremodel.Interface { |
||||
return s.all |
||||
} |
||||
|
@ -1,80 +0,0 @@ |
||||
package registry |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"sync" |
||||
|
||||
"github.com/grafana/grafana/pkg/framework/coremodel" |
||||
"github.com/grafana/thema" |
||||
) |
||||
|
||||
var ( |
||||
// ErrModelAlreadyRegistered is returned when trying to register duplicate model to Generic.
|
||||
ErrModelAlreadyRegistered = errors.New("error registering duplicate model") |
||||
) |
||||
|
||||
// Generic is a registry of coremodel instances. It is intended for use in cases where
|
||||
// generic operations limited to coremodel.Interface are being performed.
|
||||
type Generic struct { |
||||
lock sync.RWMutex |
||||
models []coremodel.Interface |
||||
modelIdx map[string]coremodel.Interface |
||||
} |
||||
|
||||
// NewRegistry returns a new Generic with the provided coremodel instances.
|
||||
func NewRegistry(models ...coremodel.Interface) (*Generic, error) { |
||||
r := &Generic{ |
||||
models: make([]coremodel.Interface, 0, len(models)), |
||||
modelIdx: make(map[string]coremodel.Interface, len(models)), |
||||
} |
||||
|
||||
if err := r.addModels(models); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return r, nil |
||||
} |
||||
|
||||
// Register adds coremodels to the Generic.
|
||||
func (r *Generic) Register(models ...coremodel.Interface) error { |
||||
return r.addModels(models) |
||||
} |
||||
|
||||
// List returns all coremodels registered in this Generic.
|
||||
func (r *Generic) List() []coremodel.Interface { |
||||
r.lock.RLock() |
||||
defer r.lock.RUnlock() |
||||
|
||||
return r.models |
||||
} |
||||
|
||||
func (r *Generic) addModels(models []coremodel.Interface) error { |
||||
r.lock.Lock() |
||||
defer r.lock.Unlock() |
||||
|
||||
// Update model index and return an error if trying to register a duplicate.
|
||||
for _, m := range models { |
||||
k := m.Lineage().Name() |
||||
|
||||
// Ensure assignability first. TODO will this blow up for dashboards?
|
||||
if err := thema.AssignableTo(m.CurrentSchema(), m.GoType()); err != nil { |
||||
return fmt.Errorf("%s schema version %v not assignable to provided Go type: %w", k, m.CurrentSchema().Version(), err) |
||||
} |
||||
|
||||
if _, ok := r.modelIdx[k]; ok { |
||||
return ErrModelAlreadyRegistered |
||||
} |
||||
|
||||
r.modelIdx[k] = m |
||||
} |
||||
|
||||
// Remake model list.
|
||||
// TODO: this can be more performant (proper resizing, maybe single loop with index building, etc.).
|
||||
r.models = r.models[:0] |
||||
for _, m := range r.modelIdx { |
||||
r.models = append(r.models, m) |
||||
} |
||||
|
||||
return nil |
||||
} |
Loading…
Reference in new issue