2019-09-10 18:52:55 +03:00

205 lines
4.3 KiB
Go

// Copyright (c) 2018 Yandex LLC. All rights reserved.
// Author: Dmitry Novikov <novikoff@yandex-team.ru>
package sdkresolvers
import (
"fmt"
"reflect"
"github.com/yandex-cloud/go-sdk/pkg/sdkerrors"
)
const DefaultResolverPageSize = 100
func CreateResolverFilter(nameField string, value string) string {
// TODO(novikoff): should we add escaping or value validation?
return fmt.Sprintf(`%s = "%s"`, nameField, value)
}
type resolveOptions struct {
out *string
folderID string
cloudID string
clusterID string
}
type ResolveOption func(*resolveOptions)
func Out(out *string) ResolveOption {
return func(o *resolveOptions) {
o.out = out
}
}
// FolderID specifies folder id for resolvers that need it (most of the resolvers).
func FolderID(folderID string) ResolveOption {
return func(o *resolveOptions) {
o.folderID = folderID
}
}
// CloudID specifies cloud id for resolvers that need it, e.g. FolderResolver
func CloudID(cloudID string) ResolveOption {
return func(o *resolveOptions) {
o.cloudID = cloudID
}
}
// ClusterID specifies cluster id for resolvers that need it, e.g. DataprocSubclusterResolver
func ClusterID(clusterID string) ResolveOption {
return func(o *resolveOptions) {
o.clusterID = clusterID
}
}
func combineOpts(opts ...ResolveOption) *resolveOptions {
o := &resolveOptions{}
for _, opt := range opts {
opt(o)
}
return o
}
type BaseResolver struct {
Name string
id string
err error
opts *resolveOptions
}
func NewBaseResolver(name string, opts ...ResolveOption) BaseResolver {
return BaseResolver{
Name: name,
opts: combineOpts(opts...),
}
}
type BaseNameResolver struct {
BaseResolver
resolvingObjectType string
}
func NewBaseNameResolver(name string, resolvingObjectType string, opts ...ResolveOption) BaseNameResolver {
return BaseNameResolver{
BaseResolver: NewBaseResolver(name, opts...),
resolvingObjectType: resolvingObjectType,
}
}
func (r *BaseResolver) ID() string {
return r.id
}
func (r *BaseResolver) Err() error {
return r.err
}
func (r *BaseResolver) SetErr(err error) error {
if r.err != nil {
panic(fmt.Sprintf("Trying to change error. Old: %v; New: %v", r.err, err))
}
r.err = err
return r.err
}
func (r *BaseResolver) SetID(id string) {
r.id = id
r.writeOut()
}
func (r *BaseResolver) Set(entity Entity, err error) error {
if err != nil {
return r.SetErr(err)
}
r.SetID(entity.GetId())
return nil
}
type Entity interface {
GetId() string
}
func (r *BaseResolver) FolderID() string {
return r.opts.folderID
}
func (r *BaseResolver) CloudID() string {
return r.opts.cloudID
}
func (r *BaseResolver) ClusterID() string {
return r.opts.clusterID
}
func (r *BaseResolver) writeOut() {
if r.opts.out != nil {
*r.opts.out = r.id
}
}
func (r *BaseNameResolver) findName(slice interface{}, err error) error {
return r.SetErr(r.findNameImpl(slice, err))
}
func (r *BaseNameResolver) ensureFolderID() error {
if r.FolderID() == "" {
err := &ErrNotFound{error: fmt.Sprintf("can't resolve %v without folder id specified", r.resolvingObjectType)}
return r.SetErr(err)
}
return nil
}
func (r *BaseNameResolver) ensureCloudID() error {
if r.CloudID() == "" {
err := &ErrNotFound{error: fmt.Sprintf("can't resolve %v without cloud id specified", r.resolvingObjectType)}
return r.SetErr(err)
}
return nil
}
func NewErrNotFound(err string) error {
return &ErrNotFound{error: err}
}
type ErrNotFound struct {
error string
}
func (e *ErrNotFound) Error() string {
return e.error
}
func errNotFound(caption, name string) error {
return &ErrNotFound{error: fmt.Sprintf("%v with name \"%v\" not found", caption, name)}
}
func (r *BaseNameResolver) findNameImpl(slice interface{}, err error) error {
if err != nil {
return sdkerrors.WithMessagef(err, "failed to find %v with name \"%v\"", r.resolvingObjectType, r.Name)
}
rv := reflect.ValueOf(slice)
var found nameAndID
for i := 0; i < rv.Len(); i++ {
v := rv.Index(i).Interface().(nameAndID)
if v.GetName() == r.Name {
if found != nil {
return fmt.Errorf("multiple %v items with name \"%v\" found", r.resolvingObjectType, r.Name)
}
found = v
}
}
if found == nil {
return errNotFound(r.resolvingObjectType, r.Name)
}
r.SetID(found.GetId())
return nil
}
type nameAndID interface {
GetId() string
GetName() string
}