Improve expr types, add r/w locking

This commit is contained in:
Denis Arh
2021-07-14 10:49:32 +02:00
parent d63f21c941
commit a7e2eec9fd
15 changed files with 795 additions and 304 deletions
+98 -35
View File
@@ -13,13 +13,17 @@ import (
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
. "github.com/cortezaproject/corteza-server/pkg/expr"
"sync"
)
var _ = context.Background
var _ = fmt.Errorf
// ComposeModule is an expression type, wrapper for *types.Module type
type ComposeModule struct{ value *types.Module }
type ComposeModule struct {
value *types.Module
mux sync.RWMutex
}
// NewComposeModule creates new instance of ComposeModule expression type
func NewComposeModule(val interface{}) (*ComposeModule, error) {
@@ -30,16 +34,24 @@ func NewComposeModule(val interface{}) (*ComposeModule, error) {
}
}
// Return underlying value on ComposeModule
func (t ComposeModule) Get() interface{} { return t.value }
// Get return underlying value on ComposeModule
func (t *ComposeModule) Get() interface{} {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return underlying value on ComposeModule
func (t ComposeModule) GetValue() *types.Module { return t.value }
// GetValue returns underlying value on ComposeModule
func (t *ComposeModule) GetValue() *types.Module {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return type name
// Type return type name
func (ComposeModule) Type() string { return "ComposeModule" }
// Convert value to *types.Module
// Cast converts value to *types.Module
func (ComposeModule) Cast(val interface{}) (TypedValue, error) {
return NewComposeModule(val)
}
@@ -57,6 +69,8 @@ func (t *ComposeModule) Assign(val interface{}) error {
}
func (t *ComposeModule) AssignFieldValue(key string, val TypedValue) error {
t.mux.Lock()
defer t.mux.Unlock()
return assignToComposeModule(t.value, key, val)
}
@@ -65,18 +79,24 @@ func (t *ComposeModule) AssignFieldValue(key string, val TypedValue) error {
// It allows gval lib to access ComposeModule's underlying value (*types.Module)
// and it's fields
//
func (t ComposeModule) SelectGVal(ctx context.Context, k string) (interface{}, error) {
func (t *ComposeModule) SelectGVal(ctx context.Context, k string) (interface{}, error) {
t.mux.RLock()
defer t.mux.RUnlock()
return composeModuleGValSelector(t.value, k)
}
// Select is field accessor for *types.Module
//
// Similar to SelectGVal but returns typed values
func (t ComposeModule) Select(k string) (TypedValue, error) {
func (t *ComposeModule) Select(k string) (TypedValue, error) {
t.mux.RLock()
defer t.mux.RUnlock()
return composeModuleTypedValueSelector(t.value, k)
}
func (t ComposeModule) Has(k string) bool {
func (t *ComposeModule) Has(k string) bool {
t.mux.RLock()
defer t.mux.RUnlock()
switch k {
case "ID", "moduleID":
return true
@@ -195,7 +215,10 @@ func assignToComposeModule(res *types.Module, k string, val interface{}) error {
}
// ComposeNamespace is an expression type, wrapper for *types.Namespace type
type ComposeNamespace struct{ value *types.Namespace }
type ComposeNamespace struct {
value *types.Namespace
mux sync.RWMutex
}
// NewComposeNamespace creates new instance of ComposeNamespace expression type
func NewComposeNamespace(val interface{}) (*ComposeNamespace, error) {
@@ -206,16 +229,24 @@ func NewComposeNamespace(val interface{}) (*ComposeNamespace, error) {
}
}
// Return underlying value on ComposeNamespace
func (t ComposeNamespace) Get() interface{} { return t.value }
// Get return underlying value on ComposeNamespace
func (t *ComposeNamespace) Get() interface{} {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return underlying value on ComposeNamespace
func (t ComposeNamespace) GetValue() *types.Namespace { return t.value }
// GetValue returns underlying value on ComposeNamespace
func (t *ComposeNamespace) GetValue() *types.Namespace {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return type name
// Type return type name
func (ComposeNamespace) Type() string { return "ComposeNamespace" }
// Convert value to *types.Namespace
// Cast converts value to *types.Namespace
func (ComposeNamespace) Cast(val interface{}) (TypedValue, error) {
return NewComposeNamespace(val)
}
@@ -233,6 +264,8 @@ func (t *ComposeNamespace) Assign(val interface{}) error {
}
func (t *ComposeNamespace) AssignFieldValue(key string, val TypedValue) error {
t.mux.Lock()
defer t.mux.Unlock()
return assignToComposeNamespace(t.value, key, val)
}
@@ -241,18 +274,24 @@ func (t *ComposeNamespace) AssignFieldValue(key string, val TypedValue) error {
// It allows gval lib to access ComposeNamespace's underlying value (*types.Namespace)
// and it's fields
//
func (t ComposeNamespace) SelectGVal(ctx context.Context, k string) (interface{}, error) {
func (t *ComposeNamespace) SelectGVal(ctx context.Context, k string) (interface{}, error) {
t.mux.RLock()
defer t.mux.RUnlock()
return composeNamespaceGValSelector(t.value, k)
}
// Select is field accessor for *types.Namespace
//
// Similar to SelectGVal but returns typed values
func (t ComposeNamespace) Select(k string) (TypedValue, error) {
func (t *ComposeNamespace) Select(k string) (TypedValue, error) {
t.mux.RLock()
defer t.mux.RUnlock()
return composeNamespaceTypedValueSelector(t.value, k)
}
func (t ComposeNamespace) Has(k string) bool {
func (t *ComposeNamespace) Has(k string) bool {
t.mux.RLock()
defer t.mux.RUnlock()
switch k {
case "ID", "namespaceID":
return true
@@ -363,7 +402,10 @@ func assignToComposeNamespace(res *types.Namespace, k string, val interface{}) e
}
// ComposeRecord is an expression type, wrapper for *types.Record type
type ComposeRecord struct{ value *types.Record }
type ComposeRecord struct {
value *types.Record
mux sync.RWMutex
}
// NewComposeRecord creates new instance of ComposeRecord expression type
func NewComposeRecord(val interface{}) (*ComposeRecord, error) {
@@ -374,16 +416,24 @@ func NewComposeRecord(val interface{}) (*ComposeRecord, error) {
}
}
// Return underlying value on ComposeRecord
func (t ComposeRecord) Get() interface{} { return t.value }
// Get return underlying value on ComposeRecord
func (t *ComposeRecord) Get() interface{} {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return underlying value on ComposeRecord
func (t ComposeRecord) GetValue() *types.Record { return t.value }
// GetValue returns underlying value on ComposeRecord
func (t *ComposeRecord) GetValue() *types.Record {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return type name
// Type return type name
func (ComposeRecord) Type() string { return "ComposeRecord" }
// Convert value to *types.Record
// Cast converts value to *types.Record
func (ComposeRecord) Cast(val interface{}) (TypedValue, error) {
return NewComposeRecord(val)
}
@@ -400,7 +450,9 @@ func (t *ComposeRecord) Assign(val interface{}) error {
}
}
func (t ComposeRecord) Has(k string) bool {
func (t *ComposeRecord) Has(k string) bool {
t.mux.RLock()
defer t.mux.RUnlock()
switch k {
case "ID", "recordID":
return true
@@ -551,7 +603,10 @@ func assignToComposeRecord(res *types.Record, k string, val interface{}) error {
}
// ComposeRecordValueErrorSet is an expression type, wrapper for *types.RecordValueErrorSet type
type ComposeRecordValueErrorSet struct{ value *types.RecordValueErrorSet }
type ComposeRecordValueErrorSet struct {
value *types.RecordValueErrorSet
mux sync.RWMutex
}
// NewComposeRecordValueErrorSet creates new instance of ComposeRecordValueErrorSet expression type
func NewComposeRecordValueErrorSet(val interface{}) (*ComposeRecordValueErrorSet, error) {
@@ -562,16 +617,24 @@ func NewComposeRecordValueErrorSet(val interface{}) (*ComposeRecordValueErrorSet
}
}
// Return underlying value on ComposeRecordValueErrorSet
func (t ComposeRecordValueErrorSet) Get() interface{} { return t.value }
// Get return underlying value on ComposeRecordValueErrorSet
func (t *ComposeRecordValueErrorSet) Get() interface{} {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return underlying value on ComposeRecordValueErrorSet
func (t ComposeRecordValueErrorSet) GetValue() *types.RecordValueErrorSet { return t.value }
// GetValue returns underlying value on ComposeRecordValueErrorSet
func (t *ComposeRecordValueErrorSet) GetValue() *types.RecordValueErrorSet {
t.mux.RLock()
defer t.mux.RUnlock()
return t.value
}
// Return type name
// Type return type name
func (ComposeRecordValueErrorSet) Type() string { return "ComposeRecordValueErrorSet" }
// Convert value to *types.RecordValueErrorSet
// Cast converts value to *types.RecordValueErrorSet
func (ComposeRecordValueErrorSet) Cast(val interface{}) (TypedValue, error) {
return NewComposeRecordValueErrorSet(val)
}
+11 -2
View File
@@ -98,6 +98,9 @@ var _ expr.DeepFieldAssigner = &ComposeRecord{}
// We need to reroute value assigning for record-value-sets because
// we loose the reference to record-value slice
func (t *ComposeRecord) AssignFieldValue(kk []string, val expr.TypedValue) error {
t.mux.Lock()
defer t.mux.Unlock()
switch kk[0] {
case "values":
return assignToComposeRecordValues(t.value, kk[1:], val)
@@ -115,7 +118,10 @@ var _ gval.Selector = &ComposeRecord{}
// It allows gval lib to access Record's underlying value (*types.Record)
// and it's fields
//
func (t ComposeRecord) SelectGVal(_ context.Context, k string) (interface{}, error) {
func (t *ComposeRecord) SelectGVal(_ context.Context, k string) (interface{}, error) {
t.mux.RLock()
defer t.mux.RUnlock()
if t.value != nil && k == "values" {
if t.value.Values == nil {
t.value.Values = types.RecordValueSet{}
@@ -134,7 +140,10 @@ func (t ComposeRecord) SelectGVal(_ context.Context, k string) (interface{}, err
// Select is field accessor for *types.ComposeRecord
//
// Similar to SelectGVal but returns typed values
func (t ComposeRecord) Select(k string) (expr.TypedValue, error) {
func (t *ComposeRecord) Select(k string) (expr.TypedValue, error) {
t.mux.RLock()
defer t.mux.RUnlock()
if t.value != nil && k == "values" {
if t.value.Values == nil {
t.value.Values = types.RecordValueSet{}
+4 -4
View File
@@ -69,13 +69,13 @@ func TestRecordFieldValuesAccess(t *testing.T) {
// same as &ComposeRecord{value: &types.Record{}},
"validRecZero": &ComposeRecord{value: &types.Record{ID: 0, Values: types.RecordValueSet{}}},
"validRecValidID": &ComposeRecord{&types.Record{ID: 42, Values: types.RecordValueSet{}}},
"validRecValidID": &ComposeRecord{value: &types.Record{ID: 42, Values: types.RecordValueSet{}}},
// "record" (not really) set to nil
"fooRec": nil,
// record with id and value set (this was) fixme
"record": &ComposeRecord{&types.Record{ID: 99, Values: rawValues}},
"record": &ComposeRecord{value: &types.Record{ID: 99, Values: rawValues}},
})
)
@@ -139,8 +139,8 @@ func TestRecordFieldValuesAccess(t *testing.T) {
e.SetEval(evaluable)
input, _ := expr.NewVars(map[string]expr.TypedValue{
"record": &ComposeRecord{inputRec},
"recordClone": &ComposeRecord{cloneRec},
"record": &ComposeRecord{value: inputRec},
"recordClone": &ComposeRecord{value: cloneRec},
})
output, err = (aTypes.ExprSet{e}).Eval(context.Background(), input)