mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
chore: join owner, template, and org in new workspace view (#15116)
Joins in fields like `username`, `avatar_url`, `organization_name`, `template_name` to `workspaces` via a **view**. The view must be maintained moving forward, but this prevents needing to add RBAC permissions to fetch related workspace fields.
This commit is contained in:
144
testutil/reflect.go
Normal file
144
testutil/reflect.go
Normal file
@ -0,0 +1,144 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type Random struct {
|
||||
String func() string
|
||||
Bool func() bool
|
||||
Int func() int64
|
||||
Uint func() uint64
|
||||
Float func() float64
|
||||
Complex func() complex128
|
||||
Time func() time.Time
|
||||
}
|
||||
|
||||
func NewRandom() *Random {
|
||||
// Guaranteed to be random...
|
||||
return &Random{
|
||||
String: func() string { return "foo" },
|
||||
Bool: func() bool { return true },
|
||||
Int: func() int64 { return 500 },
|
||||
Uint: func() uint64 { return 126 },
|
||||
Float: func() float64 { return 3.14 },
|
||||
Complex: func() complex128 { return 6.24 },
|
||||
Time: func() time.Time { return time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC) },
|
||||
}
|
||||
}
|
||||
|
||||
// PopulateStruct does a best effort to populate a struct with random values.
|
||||
func PopulateStruct(s interface{}, r *Random) error {
|
||||
if r == nil {
|
||||
r = NewRandom()
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(s)
|
||||
if v.Kind() != reflect.Ptr || v.IsNil() {
|
||||
return xerrors.Errorf("s must be a non-nil pointer")
|
||||
}
|
||||
|
||||
v = v.Elem()
|
||||
if v.Kind() != reflect.Struct {
|
||||
return xerrors.Errorf("s must be a pointer to a struct")
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
fieldName := field.Name
|
||||
|
||||
fieldValue := v.Field(i)
|
||||
if !fieldValue.CanSet() {
|
||||
continue // Skip if field is unexported
|
||||
}
|
||||
|
||||
nv, err := populateValue(fieldValue, r)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("%s : %w", fieldName, err)
|
||||
}
|
||||
v.Field(i).Set(nv)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateValue(v reflect.Value, r *Random) (reflect.Value, error) {
|
||||
var err error
|
||||
|
||||
// Handle some special cases
|
||||
switch v.Type() {
|
||||
case reflect.TypeOf(time.Time{}):
|
||||
v.Set(reflect.ValueOf(r.Time()))
|
||||
return v, nil
|
||||
default:
|
||||
// Go to Kind instead
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
if err := PopulateStruct(v.Addr().Interface(), r); err != nil {
|
||||
return v, err
|
||||
}
|
||||
case reflect.String:
|
||||
v.SetString(r.String())
|
||||
case reflect.Bool:
|
||||
v.SetBool(true)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
v.SetInt(r.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
v.SetUint(r.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
v.SetFloat(r.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
v.SetComplex(r.Complex())
|
||||
case reflect.Array:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
nv, err := populateValue(v.Index(i), r)
|
||||
if err != nil {
|
||||
return v, xerrors.Errorf("array index %d : %w", i, err)
|
||||
}
|
||||
v.Index(i).Set(nv)
|
||||
}
|
||||
case reflect.Map:
|
||||
m := reflect.MakeMap(v.Type())
|
||||
|
||||
// Set a value in the map
|
||||
k := reflect.New(v.Type().Key())
|
||||
kv := reflect.New(v.Type().Elem())
|
||||
k, err = populateValue(k, r)
|
||||
if err != nil {
|
||||
return v, xerrors.Errorf("map key : %w", err)
|
||||
}
|
||||
kv, err = populateValue(kv, r)
|
||||
if err != nil {
|
||||
return v, xerrors.Errorf("map value : %w", err)
|
||||
}
|
||||
|
||||
m.SetMapIndex(k, kv)
|
||||
return m, nil
|
||||
case reflect.Pointer:
|
||||
return populateValue(v.Elem(), r)
|
||||
case reflect.Slice:
|
||||
s := reflect.MakeSlice(v.Type(), 2, 2)
|
||||
sv, err := populateValue(reflect.New(v.Type().Elem()), r)
|
||||
if err != nil {
|
||||
return v, xerrors.Errorf("slice value : %w", err)
|
||||
}
|
||||
|
||||
s.Index(0).Set(sv)
|
||||
s.Index(1).Set(sv)
|
||||
// reflect.AppendSlice(s, sv)
|
||||
|
||||
return s, nil
|
||||
case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func, reflect.Interface:
|
||||
// Unsupported
|
||||
return v, xerrors.Errorf("%s is not supported", v.Kind())
|
||||
default:
|
||||
return v, xerrors.Errorf("unsupported kind %s", v.Kind())
|
||||
}
|
||||
return v, nil
|
||||
}
|
Reference in New Issue
Block a user