Add basic automation functions for compose

This commit is contained in:
Denis Arh
2021-03-12 13:12:07 +01:00
parent df7314ba74
commit 69dd1fc425
16 changed files with 2677 additions and 853 deletions
+605
View File
@@ -0,0 +1,605 @@
package automation
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
// compose/automation/expr_types.yaml
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
. "github.com/cortezaproject/corteza-server/pkg/expr"
)
var _ = context.Background
var _ = fmt.Errorf
// ComposeModule is an expression type, wrapper for *types.Module type
type ComposeModule struct{ value *types.Module }
// NewComposeModule creates new instance of ComposeModule expression type
func NewComposeModule(val interface{}) (*ComposeModule, error) {
if c, err := CastToComposeModule(val); err != nil {
return nil, fmt.Errorf("unable to create ComposeModule: %w", err)
} else {
return &ComposeModule{value: c}, nil
}
}
// Return underlying value on ComposeModule
func (t ComposeModule) Get() interface{} { return t.value }
// Return type name
func (ComposeModule) Type() string { return "ComposeModule" }
// Convert value to *types.Module
func (ComposeModule) Cast(val interface{}) (TypedValue, error) {
return NewComposeModule(val)
}
// Assign new value to ComposeModule
//
// value is first passed through CastToComposeModule
func (t *ComposeModule) Assign(val interface{}) error {
if c, err := CastToComposeModule(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
func (t *ComposeModule) AssignFieldValue(key string, val interface{}) error {
return assignToComposeModule(t.value, key, val)
}
// SelectGVal implements gval.Selector requirements
//
// 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) {
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) {
return composeModuleTypedValueSelector(t.value, k)
}
func (t ComposeModule) Has(k string) bool {
switch k {
case "ID":
return true
case "namespaceID":
return true
case "name":
return true
case "handle":
return true
case "labels":
return true
case "createdAt":
return true
case "updatedAt":
return true
case "deletedAt":
return true
}
return false
}
// composeModuleGValSelector is field accessor for *types.Module
func composeModuleGValSelector(res *types.Module, k string) (interface{}, error) {
switch k {
case "ID":
return res.ID, nil
case "namespaceID":
return res.NamespaceID, nil
case "name":
return res.Name, nil
case "handle":
return res.Handle, nil
case "labels":
return res.Labels, nil
case "createdAt":
return res.CreatedAt, nil
case "updatedAt":
return res.UpdatedAt, nil
case "deletedAt":
return res.DeletedAt, nil
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// composeModuleTypedValueSelector is field accessor for *types.Module
func composeModuleTypedValueSelector(res *types.Module, k string) (TypedValue, error) {
switch k {
case "ID":
return NewID(res.ID)
case "namespaceID":
return NewID(res.NamespaceID)
case "name":
return NewString(res.Name)
case "handle":
return NewHandle(res.Handle)
case "labels":
return NewKV(res.Labels)
case "createdAt":
return NewDateTime(res.CreatedAt)
case "updatedAt":
return NewDateTime(res.UpdatedAt)
case "deletedAt":
return NewDateTime(res.DeletedAt)
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// assignToComposeModule is field value setter for *types.Module
func assignToComposeModule(res *types.Module, k string, val interface{}) error {
switch k {
case "ID":
return fmt.Errorf("field '%s' is read-only", k)
case "namespaceID":
return fmt.Errorf("field '%s' is read-only", k)
case "name":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Name = aux
return nil
case "handle":
aux, err := CastToHandle(val)
if err != nil {
return err
}
res.Handle = aux
return nil
case "labels":
aux, err := CastToKV(val)
if err != nil {
return err
}
res.Labels = aux
return nil
case "createdAt":
return fmt.Errorf("field '%s' is read-only", k)
case "updatedAt":
return fmt.Errorf("field '%s' is read-only", k)
case "deletedAt":
return fmt.Errorf("field '%s' is read-only", k)
}
return fmt.Errorf("unknown field '%s'", k)
}
// ComposeNamespace is an expression type, wrapper for *types.Namespace type
type ComposeNamespace struct{ value *types.Namespace }
// NewComposeNamespace creates new instance of ComposeNamespace expression type
func NewComposeNamespace(val interface{}) (*ComposeNamespace, error) {
if c, err := CastToComposeNamespace(val); err != nil {
return nil, fmt.Errorf("unable to create ComposeNamespace: %w", err)
} else {
return &ComposeNamespace{value: c}, nil
}
}
// Return underlying value on ComposeNamespace
func (t ComposeNamespace) Get() interface{} { return t.value }
// Return type name
func (ComposeNamespace) Type() string { return "ComposeNamespace" }
// Convert value to *types.Namespace
func (ComposeNamespace) Cast(val interface{}) (TypedValue, error) {
return NewComposeNamespace(val)
}
// Assign new value to ComposeNamespace
//
// value is first passed through CastToComposeNamespace
func (t *ComposeNamespace) Assign(val interface{}) error {
if c, err := CastToComposeNamespace(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
func (t *ComposeNamespace) AssignFieldValue(key string, val interface{}) error {
return assignToComposeNamespace(t.value, key, val)
}
// SelectGVal implements gval.Selector requirements
//
// 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) {
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) {
return composeNamespaceTypedValueSelector(t.value, k)
}
func (t ComposeNamespace) Has(k string) bool {
switch k {
case "ID":
return true
case "name":
return true
case "slug", "handle":
return true
case "labels":
return true
case "createdAt":
return true
case "updatedAt":
return true
case "deletedAt":
return true
}
return false
}
// composeNamespaceGValSelector is field accessor for *types.Namespace
func composeNamespaceGValSelector(res *types.Namespace, k string) (interface{}, error) {
switch k {
case "ID":
return res.ID, nil
case "name":
return res.Name, nil
case "slug", "handle":
return res.Slug, nil
case "labels":
return res.Labels, nil
case "createdAt":
return res.CreatedAt, nil
case "updatedAt":
return res.UpdatedAt, nil
case "deletedAt":
return res.DeletedAt, nil
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// composeNamespaceTypedValueSelector is field accessor for *types.Namespace
func composeNamespaceTypedValueSelector(res *types.Namespace, k string) (TypedValue, error) {
switch k {
case "ID":
return NewID(res.ID)
case "name":
return NewString(res.Name)
case "slug", "handle":
return NewHandle(res.Slug)
case "labels":
return NewKV(res.Labels)
case "createdAt":
return NewDateTime(res.CreatedAt)
case "updatedAt":
return NewDateTime(res.UpdatedAt)
case "deletedAt":
return NewDateTime(res.DeletedAt)
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// assignToComposeNamespace is field value setter for *types.Namespace
func assignToComposeNamespace(res *types.Namespace, k string, val interface{}) error {
switch k {
case "ID":
return fmt.Errorf("field '%s' is read-only", k)
case "name":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Name = aux
return nil
case "slug", "handle":
aux, err := CastToHandle(val)
if err != nil {
return err
}
res.Slug = aux
return nil
case "labels":
aux, err := CastToKV(val)
if err != nil {
return err
}
res.Labels = aux
return nil
case "createdAt":
return fmt.Errorf("field '%s' is read-only", k)
case "updatedAt":
return fmt.Errorf("field '%s' is read-only", k)
case "deletedAt":
return fmt.Errorf("field '%s' is read-only", k)
}
return fmt.Errorf("unknown field '%s'", k)
}
// ComposeRecord is an expression type, wrapper for *types.Record type
type ComposeRecord struct{ value *types.Record }
// NewComposeRecord creates new instance of ComposeRecord expression type
func NewComposeRecord(val interface{}) (*ComposeRecord, error) {
if c, err := CastToComposeRecord(val); err != nil {
return nil, fmt.Errorf("unable to create ComposeRecord: %w", err)
} else {
return &ComposeRecord{value: c}, nil
}
}
// Return underlying value on ComposeRecord
func (t ComposeRecord) Get() interface{} { return t.value }
// Return type name
func (ComposeRecord) Type() string { return "ComposeRecord" }
// Convert value to *types.Record
func (ComposeRecord) Cast(val interface{}) (TypedValue, error) {
return NewComposeRecord(val)
}
// Assign new value to ComposeRecord
//
// value is first passed through CastToComposeRecord
func (t *ComposeRecord) Assign(val interface{}) error {
if c, err := CastToComposeRecord(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
func (t *ComposeRecord) AssignFieldValue(key string, val interface{}) error {
return assignToComposeRecord(t.value, key, val)
}
// Select is field accessor for *types.Record
//
// Similar to SelectGVal but returns typed values
func (t ComposeRecord) Select(k string) (TypedValue, error) {
return composeRecordTypedValueSelector(t.value, k)
}
func (t ComposeRecord) Has(k string) bool {
switch k {
case "ID":
return true
case "moduleID":
return true
case "namespaceID":
return true
case "values":
return true
case "labels":
return true
case "ownedBy":
return true
case "createdAt":
return true
case "createdBy":
return true
case "updatedAt":
return true
case "updatedBy":
return true
case "deletedAt":
return true
case "deletedBy":
return true
}
return false
}
// composeRecordGValSelector is field accessor for *types.Record
func composeRecordGValSelector(res *types.Record, k string) (interface{}, error) {
switch k {
case "ID":
return res.ID, nil
case "moduleID":
return res.ModuleID, nil
case "namespaceID":
return res.NamespaceID, nil
case "values":
return res.Values, nil
case "labels":
return res.Labels, nil
case "ownedBy":
return res.OwnedBy, nil
case "createdAt":
return res.CreatedAt, nil
case "createdBy":
return res.CreatedBy, nil
case "updatedAt":
return res.UpdatedAt, nil
case "updatedBy":
return res.UpdatedBy, nil
case "deletedAt":
return res.DeletedAt, nil
case "deletedBy":
return res.DeletedBy, nil
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// composeRecordTypedValueSelector is field accessor for *types.Record
func composeRecordTypedValueSelector(res *types.Record, k string) (TypedValue, error) {
switch k {
case "ID":
return NewID(res.ID)
case "moduleID":
return NewID(res.ModuleID)
case "namespaceID":
return NewID(res.NamespaceID)
case "values":
return NewComposeRecordValues(res.Values)
case "labels":
return NewKV(res.Labels)
case "ownedBy":
return NewID(res.OwnedBy)
case "createdAt":
return NewDateTime(res.CreatedAt)
case "createdBy":
return NewID(res.CreatedBy)
case "updatedAt":
return NewDateTime(res.UpdatedAt)
case "updatedBy":
return NewID(res.UpdatedBy)
case "deletedAt":
return NewDateTime(res.DeletedAt)
case "deletedBy":
return NewID(res.DeletedBy)
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// assignToComposeRecord is field value setter for *types.Record
func assignToComposeRecord(res *types.Record, k string, val interface{}) error {
switch k {
case "ID":
return fmt.Errorf("field '%s' is read-only", k)
case "moduleID":
return fmt.Errorf("field '%s' is read-only", k)
case "namespaceID":
return fmt.Errorf("field '%s' is read-only", k)
case "values":
aux, err := CastToComposeRecordValues(val)
if err != nil {
return err
}
res.Values = aux
return nil
case "labels":
aux, err := CastToKV(val)
if err != nil {
return err
}
res.Labels = aux
return nil
case "ownedBy":
aux, err := CastToID(val)
if err != nil {
return err
}
res.OwnedBy = aux
return nil
case "createdAt":
return fmt.Errorf("field '%s' is read-only", k)
case "createdBy":
return fmt.Errorf("field '%s' is read-only", k)
case "updatedAt":
return fmt.Errorf("field '%s' is read-only", k)
case "updatedBy":
return fmt.Errorf("field '%s' is read-only", k)
case "deletedAt":
return fmt.Errorf("field '%s' is read-only", k)
case "deletedBy":
return fmt.Errorf("field '%s' is read-only", k)
}
return fmt.Errorf("unknown field '%s'", k)
}
// ComposeRecordValueErrorSet is an expression type, wrapper for *types.RecordValueErrorSet type
type ComposeRecordValueErrorSet struct{ value *types.RecordValueErrorSet }
// NewComposeRecordValueErrorSet creates new instance of ComposeRecordValueErrorSet expression type
func NewComposeRecordValueErrorSet(val interface{}) (*ComposeRecordValueErrorSet, error) {
if c, err := CastToComposeRecordValueErrorSet(val); err != nil {
return nil, fmt.Errorf("unable to create ComposeRecordValueErrorSet: %w", err)
} else {
return &ComposeRecordValueErrorSet{value: c}, nil
}
}
// Return underlying value on ComposeRecordValueErrorSet
func (t ComposeRecordValueErrorSet) Get() interface{} { return t.value }
// Return type name
func (ComposeRecordValueErrorSet) Type() string { return "ComposeRecordValueErrorSet" }
// Convert value to *types.RecordValueErrorSet
func (ComposeRecordValueErrorSet) Cast(val interface{}) (TypedValue, error) {
return NewComposeRecordValueErrorSet(val)
}
// Assign new value to ComposeRecordValueErrorSet
//
// value is first passed through CastToComposeRecordValueErrorSet
func (t *ComposeRecordValueErrorSet) Assign(val interface{}) error {
if c, err := CastToComposeRecordValueErrorSet(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
// ComposeRecordValues is an expression type, wrapper for types.RecordValueSet type
type ComposeRecordValues struct{ value types.RecordValueSet }
// NewComposeRecordValues creates new instance of ComposeRecordValues expression type
func NewComposeRecordValues(val interface{}) (*ComposeRecordValues, error) {
if c, err := CastToComposeRecordValues(val); err != nil {
return nil, fmt.Errorf("unable to create ComposeRecordValues: %w", err)
} else {
return &ComposeRecordValues{value: c}, nil
}
}
// Return underlying value on ComposeRecordValues
func (t ComposeRecordValues) Get() interface{} { return t.value }
// Return type name
func (ComposeRecordValues) Type() string { return "ComposeRecordValues" }
// Convert value to types.RecordValueSet
func (ComposeRecordValues) Cast(val interface{}) (TypedValue, error) {
return NewComposeRecordValues(val)
}
// Assign new value to ComposeRecordValues
//
// value is first passed through CastToComposeRecordValues
func (t *ComposeRecordValues) Assign(val interface{}) error {
if c, err := CastToComposeRecordValues(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
+221
View File
@@ -0,0 +1,221 @@
package automation
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/spf13/cast"
"strings"
)
func CastToComposeNamespace(val interface{}) (out *types.Namespace, err error) {
switch val := val.(type) {
case expr.Iterator:
out = &types.Namespace{}
return out, val.Each(func(k string, v expr.TypedValue) error {
return assignToComposeNamespace(out, k, v)
})
}
switch val := expr.UntypedValue(val).(type) {
case *types.Namespace:
return val, nil
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func CastToComposeModule(val interface{}) (out *types.Module, err error) {
switch val := val.(type) {
case expr.Iterator:
out = &types.Module{}
return out, val.Each(func(k string, v expr.TypedValue) error {
return assignToComposeModule(out, k, v)
})
}
switch val := expr.UntypedValue(val).(type) {
case *types.Module:
return val, nil
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func CastToComposeRecord(val interface{}) (out *types.Record, err error) {
switch val := val.(type) {
case expr.Iterator:
out = &types.Record{}
return out, val.Each(func(k string, v expr.TypedValue) error {
return assignToComposeRecord(out, k, v)
})
}
switch val := expr.UntypedValue(val).(type) {
case *types.Record:
return val, nil
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
// SelectGVal implements gval.Selector requirements
//
// It allows gval lib to access Record's underlying value (*types.Record)
// and it's fields
//
func (t ComposeRecord) SelectGVal(ctx context.Context, k string) (interface{}, error) {
if k == "values" {
return t.value.Values.Dict(t.value.GetModule().Fields), nil
}
return composeRecordGValSelector(t.value, k)
}
func CastToComposeRecordValues(val interface{}) (out types.RecordValueSet, err error) {
out = types.RecordValueSet{}
switch val := val.(type) {
case expr.Iterator:
return out, val.Each(func(k string, v expr.TypedValue) error {
// try with slice of strings first:
if ss, err := cast.ToStringSliceE(expr.UntypedValue(v)); err == nil {
for i, v := range ss {
out = out.Set(&types.RecordValue{Name: k, Value: v, Place: uint(i)})
}
return nil
}
if str, err := expr.CastToString(v); err != nil {
return err
} else {
out = out.Set(&types.RecordValue{Name: k, Value: str})
return nil
}
})
}
switch val := expr.UntypedValue(val).(type) {
case *types.Record:
return val.Values, nil
case types.RecordValueSet:
return val, nil
case map[string]string:
out = types.RecordValueSet{}
for k, v := range val {
out = out.Set(&types.RecordValue{Name: k, Value: v})
}
return
case map[string][]string:
out = types.RecordValueSet{}
for k, vv := range val {
for i, v := range vv {
out = out.Set(&types.RecordValue{Name: k, Value: v, Place: uint(i)})
}
}
return
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func (t *ComposeRecordValues) AssignFieldValue(pp []string, val interface{}) error {
return assignToComposeRecordValues(&t.value, pp, val)
}
// SelectGVal implements gval.Selector requirements
//
// It allows gval lib to access Record's underlying value (*types.RecordValues)
// and it's fields
//
func (t ComposeRecordValues) SelectGVal(ctx context.Context, k string) (interface{}, error) {
return composeRecordValuesGValSelector(t.value, k)
}
// Select is field accessor for *types.Record
//
// Similar to SelectGVal but returns typed values
func (t ComposeRecordValues) Select(k string) (expr.TypedValue, error) {
return composeRecordValuesTypedValueSelector(t.value, k)
}
func (t ComposeRecordValues) Has(k string) bool {
return t.value.Get(k, 0) != nil
}
// recordGValSelector is field accessor for *types.RecordValueSet
func composeRecordValuesGValSelector(res types.RecordValueSet, k string) (interface{}, error) {
vv := res.FilterByName(k)
switch len(vv) {
case 0:
return nil, nil
case 1:
return vv[0].Value, nil
default:
out := make([]string, 0, len(vv))
return out, vv.Walk(func(v *types.RecordValue) error {
out = append(out, v.Value)
return nil
})
}
}
// recordValuesTypedValueSelector is field accessor for *types.RecordValueSet
//
// @todo return appropriate types (atm all values are returned as String)
func composeRecordValuesTypedValueSelector(res types.RecordValueSet, k string) (expr.TypedValue, error) {
vv := res.FilterByName(k)
switch {
case len(vv) == 0:
return nil, nil
case len(vv) == 1:
return expr.NewString(vv[0].Value)
default:
mval := make([]expr.TypedValue, 0, len(vv))
_ = vv.Walk(func(v *types.RecordValue) error {
mval = append(mval, expr.Must(expr.NewString(v.Value)))
return nil
})
return expr.NewArray(mval)
}
}
// assignToRecordValuesSet is field value setter for *types.Record
func assignToComposeRecordValues(res *types.RecordValueSet, pp []string, val interface{}) (err error) {
if len(pp) < 1 {
return fmt.Errorf("empty path used for assigning record values")
}
k := pp[0]
rv := &types.RecordValue{Name: k}
if rv.Value, err = cast.ToStringE(expr.UntypedValue(val)); err != nil {
return
}
if len(pp) == 2 {
if rv.Place, err = cast.ToUintE(expr.UntypedValue(pp[1])); err != nil {
return fmt.Errorf("failed to decode record value place from '%s': %w", strings.Join(pp, "."), err)
}
}
*res = res.Set(rv)
//return fmt.Errorf("unknown field '%s'", k)
return nil
}
func CastToComposeRecordValueErrorSet(val interface{}) (out *types.RecordValueErrorSet, err error) {
switch val := expr.UntypedValue(val).(type) {
case *types.RecordValueErrorSet:
return val, nil
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
+56
View File
@@ -0,0 +1,56 @@
package: automation
imports:
- github.com/cortezaproject/corteza-server/compose/types
types:
ComposeNamespace:
as: '*types.Namespace'
struct:
- { name: 'ID', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'name', exprType: 'String', goType: 'string' }
- { name: 'slug', exprType: 'Handle', goType: 'string', alias: 'handle'}
- { name: 'labels', exprType: 'KV', goType: 'map[string]string' }
- { name: 'createdAt', exprType: 'DateTime', goType: 'time.Time', mode: ro }
- { name: 'updatedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'deletedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
ComposeModule:
as: '*types.Module'
struct:
- { name: 'ID', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'namespaceID', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'name', exprType: 'String', goType: 'string' }
- { name: 'handle', exprType: 'Handle', goType: 'string' }
- { name: 'labels', exprType: 'KV', goType: 'map[string]string' }
- { name: 'createdAt', exprType: 'DateTime', goType: 'time.Time', mode: ro }
- { name: 'updatedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'deletedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
ComposeRecord:
as: '*types.Record'
struct:
- { name: 'ID', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'moduleID', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'namespaceID', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'values', exprType: 'ComposeRecordValues', goType: 'map[string]interface{}' }
- { name: 'labels', exprType: 'KV', goType: 'map[string]string' }
- { name: 'ownedBy', exprType: 'ID', goType: 'uint64' }
- { name: 'createdAt', exprType: 'DateTime', goType: 'time.Time', mode: ro }
- { name: 'createdBy', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'updatedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'updatedBy', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'deletedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'deletedBy', exprType: 'ID', goType: 'uint64', mode: ro }
customGValSelector: true
ComposeRecordValues:
as: 'types.RecordValueSet'
castFn: 'castComposeRecordValueSet'
ComposeRecordValueErrorSet:
as: '*types.RecordValueErrorSet'
#
# Page:
# as: '*types.Page'
# Chart:
# as: '*types.Chart'
+135
View File
@@ -0,0 +1,135 @@
package automation
import (
"context"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/stretchr/testify/require"
"testing"
)
func TestSetRecordValuesWithPath(t *testing.T) {
t.Run("some basic aerobics", func(t *testing.T) {
var (
r = require.New(t)
rvs = &RecordValues{types.RecordValueSet{}}
)
r.NoError(expr.Assign(rvs, "field1", "a"))
r.NoError(expr.Assign(rvs, "field1.1", "a"))
r.True(rvs.value.Has("field1", 0))
r.True(rvs.value.Has("field1", 1))
})
t.Run("cast string map", func(t *testing.T) {
var (
r = require.New(t)
rvs, err = CastToRecordValues(map[string]string{"field2": "b"})
)
r.NoError(err)
r.True(rvs.Has("field2", 0))
})
t.Run("cast string slice map", func(t *testing.T) {
var (
r = require.New(t)
rvs, err = CastToRecordValues(map[string][]string{"field2": []string{"a", "b"}})
)
r.NoError(err)
r.True(rvs.Has("field2", 0))
r.True(rvs.Has("field2", 1))
})
}
func TestRecordFieldValuesAccess(t *testing.T) {
var (
err error
v expr.TypedValue
mod = &types.Module{Fields: types.ModuleFieldSet{
&types.ModuleField{Name: "s1", Multi: false},
&types.ModuleField{Name: "m1", Multi: true},
&types.ModuleField{Name: "m2", Multi: true},
&types.ModuleField{Name: "s2", Multi: false},
}}
raw = &types.Record{Values: types.RecordValueSet{
&types.RecordValue{Name: "s1", Value: "sVal1"},
&types.RecordValue{Name: "m1", Value: "mVal1.0"},
&types.RecordValue{Name: "m1", Value: "mVal1.1", Place: 1},
&types.RecordValue{Name: "m1", Value: "mVal1.2", Place: 2},
&types.RecordValue{Name: "m2", Value: "mVal2.0"},
}}
tval = &Record{value: raw}
scope = expr.RVars{"rec": tval}.Vars()
)
// @todo see not above re. back-ref to record
raw.SetModule(mod)
t.Run("via typed value", func(t *testing.T) {
var (
req = require.New(t)
)
v, err = expr.Select(scope, "rec.values.s1")
req.NoError(err)
req.NotEmpty(v)
req.Equal("sVal1", v.Get())
v, err = expr.Select(scope, "rec.values.m1.0")
req.NoError(err)
req.NotEmpty(v)
req.Equal("mVal1.0", v.Get())
v, err = expr.Select(scope, "rec.values.m1.1")
req.NoError(err)
req.NotEmpty(v)
req.Equal("mVal1.1", v.Get())
// @todo when RecordValueSet supports back-ref to record,
// we can employ better field access:
// - no error on missing values when field exists
// - proper handling of multi-value field values
// - proper value-types that corelate to field types
//v, err = expr.Select(scope, "rec.values.m2.0")
//req.NoError(err)
//req.NotEmpty(v)
//req.Equal("mVal2.0", v.Get())
})
t.Run("via gval selector", func(t *testing.T) {
var (
req = require.New(t)
parser = expr.NewParser()
)
eval, err := parser.Parse(`rec.values.s1 == "sVal1"`)
req.NoError(err)
req.True(eval.Test(context.Background(), scope))
eval, err = parser.Parse(`rec.values.s1 != "foo"`)
req.NoError(err)
req.True(eval.Test(context.Background(), scope))
eval, err = parser.Parse(`rec.values.m1[0] == "mVal1.0"`)
req.NoError(err)
req.True(eval.Test(context.Background(), scope))
eval, err = parser.Parse(`rec.values.m1[1] == "mVal1.1"`)
req.NoError(err)
req.True(eval.Test(context.Background(), scope))
eval, err = parser.Parse(`rec.values.m2[0] == "mVal2.0"`)
req.NoError(err)
req.True(eval.Test(context.Background(), scope))
})
}
+24 -533
View File
@@ -13,7 +13,6 @@ import (
atypes "github.com/cortezaproject/corteza-server/automation/types"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/wfexec"
)
@@ -28,19 +27,12 @@ type (
func (h modulesHandler) register() {
h.reg.AddFunctions(
h.LookupByID(),
h.Save(),
h.Create(),
h.Update(),
h.Delete(),
h.Lookup(),
)
}
type (
modulesLookupByIDArgs struct {
hasRecordID bool
RecordID uint64
modulesLookupArgs struct {
hasModule bool
Module interface{}
moduleID uint64
@@ -54,64 +46,55 @@ type (
namespaceRes *types.Namespace
}
modulesLookupByIDResults struct {
Record *types.Record
modulesLookupResults struct {
Module *types.Module
}
)
func (a modulesLookupByIDArgs) GetModule() (bool, uint64, string, *types.Module) {
func (a modulesLookupArgs) GetModule() (bool, uint64, string, *types.Module) {
return a.hasModule, a.moduleID, a.moduleHandle, a.moduleRes
}
func (a modulesLookupByIDArgs) GetNamespace() (bool, uint64, string, *types.Namespace) {
func (a modulesLookupArgs) GetNamespace() (bool, uint64, string, *types.Namespace) {
return a.hasNamespace, a.namespaceID, a.namespaceHandle, a.namespaceRes
}
// LookupByID function Lookup for compose record by ID
// Lookup function Lookup for compose Lookup by ID
//
// expects implementation of lookupByID function:
// func (h modulesHandler) lookupByID(ctx context.Context, args *modulesLookupByIDArgs) (results *modulesLookupByIDResults, err error) {
// expects implementation of lookup function:
// func (h modulesHandler) lookup(ctx context.Context, args *modulesLookupArgs) (results *modulesLookupResults, err error) {
// return
// }
func (h modulesHandler) LookupByID() *atypes.Function {
func (h modulesHandler) Lookup() *atypes.Function {
return &atypes.Function{
Ref: "composeModulesLookupByID",
Ref: "composeModulesLookup",
Kind: "function",
Meta: &atypes.FunctionMeta{
Short: "Lookup for compose record by ID",
Short: "Lookup for compose Lookup by ID",
},
Parameters: []*atypes.Param{
{
Name: "recordID",
Types: []string{"ID"}, Required: true,
},
{
Name: "module",
Types: []string{"ID", "String", "ComposeModule"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Module to set record type",
Description: "Even with unique record ID across all modules, module needs to be known\nbefore doing any record operations. Mainly because records of different\nmodules can be located in different stores.",
},
Types: []string{"ID", "Handle", "ComposeModule"}, Required: true,
},
{
Name: "namespace",
Types: []string{"ID", "String", "ComposeNamespace"}, Required: true,
Types: []string{"ID", "Handle", "ComposeNamespace"}, Required: true,
},
},
Results: []*atypes.Param{
{
Name: "record",
Types: []string{"ComposeRecord"},
Name: "module",
Types: []string{"ComposeModule"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &modulesLookupByIDArgs{
hasRecordID: in.Has("recordID"),
args = &modulesLookupArgs{
hasModule: in.Has("module"),
hasNamespace: in.Has("namespace"),
}
@@ -127,7 +110,7 @@ func (h modulesHandler) LookupByID() *atypes.Function {
switch aux.Type() {
case h.reg.Type("ID").Type():
args.moduleID = aux.Get().(uint64)
case h.reg.Type("String").Type():
case h.reg.Type("Handle").Type():
args.moduleHandle = aux.Get().(string)
case h.reg.Type("ComposeModule").Type():
args.moduleRes = aux.Get().(*types.Module)
@@ -140,29 +123,29 @@ func (h modulesHandler) LookupByID() *atypes.Function {
switch aux.Type() {
case h.reg.Type("ID").Type():
args.namespaceID = aux.Get().(uint64)
case h.reg.Type("String").Type():
case h.reg.Type("Handle").Type():
args.namespaceHandle = aux.Get().(string)
case h.reg.Type("ComposeNamespace").Type():
args.namespaceRes = aux.Get().(*types.Namespace)
}
}
var results *modulesLookupByIDResults
if results, err = h.lookupByID(ctx, args); err != nil {
var results *modulesLookupResults
if results, err = h.lookup(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Record (*types.Record) to ComposeRecord
// converting results.Module (*types.Module) to ComposeModule
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("ComposeRecord").Cast(results.Record); err != nil {
if tval, err = h.reg.Type("ComposeModule").Cast(results.Module); err != nil {
return
} else if err = expr.Assign(out, "record", tval); err != nil {
} else if err = expr.Assign(out, "module", tval); err != nil {
return
}
}
@@ -171,495 +154,3 @@ func (h modulesHandler) LookupByID() *atypes.Function {
},
}
}
type (
modulesSaveArgs struct {
hasRecord bool
Record *types.Record
}
modulesSaveResults struct {
Record *types.Record
}
)
// Save function Save record
//
// expects implementation of save function:
// func (h modulesHandler) save(ctx context.Context, args *modulesSaveArgs) (results *modulesSaveResults, err error) {
// return
// }
func (h modulesHandler) Save() *atypes.Function {
return &atypes.Function{
Ref: "composeModulesSave",
Kind: "function",
Meta: &atypes.FunctionMeta{
Short: "Save record",
},
Parameters: []*atypes.Param{
{
Name: "record",
Types: []string{"ComposeRecord"}, Required: true,
},
},
Results: []*atypes.Param{
{
Name: "record",
Types: []string{"ComposeRecord"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &modulesSaveArgs{
hasRecord: in.Has("record"),
}
)
if err = in.Decode(args); err != nil {
return
}
var results *modulesSaveResults
if results, err = h.save(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Record (*types.Record) to ComposeRecord
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("ComposeRecord").Cast(results.Record); err != nil {
return
} else if err = expr.Assign(out, "record", tval); err != nil {
return
}
}
return
},
}
}
type (
modulesCreateArgs struct {
hasModule bool
Module interface{}
moduleID uint64
moduleHandle string
moduleRes *types.Module
hasNamespace bool
Namespace interface{}
namespaceID uint64
namespaceHandle string
namespaceRes *types.Namespace
hasValues bool
Values types.RecordValueSet
hasLabels bool
Labels label.Labels
hasOwnedBy bool
OwnedBy uint64
}
modulesCreateResults struct {
Record *types.Record
}
)
func (a modulesCreateArgs) GetModule() (bool, uint64, string, *types.Module) {
return a.hasModule, a.moduleID, a.moduleHandle, a.moduleRes
}
func (a modulesCreateArgs) GetNamespace() (bool, uint64, string, *types.Namespace) {
return a.hasNamespace, a.namespaceID, a.namespaceHandle, a.namespaceRes
}
// Create function Creates and stores a new record
//
// expects implementation of create function:
// func (h modulesHandler) create(ctx context.Context, args *modulesCreateArgs) (results *modulesCreateResults, err error) {
// return
// }
func (h modulesHandler) Create() *atypes.Function {
return &atypes.Function{
Ref: "composeModulesCreate",
Kind: "function",
Meta: &atypes.FunctionMeta{
Short: "Creates and stores a new record",
},
Parameters: []*atypes.Param{
{
Name: "module",
Types: []string{"ID", "String", "ComposeModule"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Module to set record type",
Description: "Even with unique record ID across all modules, module needs to be known\nbefore doing any record operations. Mainly because records of different\nmodules can be located in different stores.",
},
},
{
Name: "namespace",
Types: []string{"ID", "String", "ComposeNamespace"}, Required: true,
},
{
Name: "values",
Types: []string{"KV"},
},
{
Name: "labels",
Types: []string{"KV"},
},
{
Name: "ownedBy",
Types: []string{"ID"},
Meta: &atypes.ParamMeta{
Label: "Record owner",
Visual: map[string]interface{}{"ref": "users"},
},
},
},
Results: []*atypes.Param{
{
Name: "record",
Types: []string{"ComposeRecord"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &modulesCreateArgs{
hasModule: in.Has("module"),
hasNamespace: in.Has("namespace"),
hasValues: in.Has("values"),
hasLabels: in.Has("labels"),
hasOwnedBy: in.Has("ownedBy"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Module argument
if args.hasModule {
aux := expr.Must(expr.Select(in, "module"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.moduleID = aux.Get().(uint64)
case h.reg.Type("String").Type():
args.moduleHandle = aux.Get().(string)
case h.reg.Type("ComposeModule").Type():
args.moduleRes = aux.Get().(*types.Module)
}
}
// Converting Namespace argument
if args.hasNamespace {
aux := expr.Must(expr.Select(in, "namespace"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.namespaceID = aux.Get().(uint64)
case h.reg.Type("String").Type():
args.namespaceHandle = aux.Get().(string)
case h.reg.Type("ComposeNamespace").Type():
args.namespaceRes = aux.Get().(*types.Namespace)
}
}
var results *modulesCreateResults
if results, err = h.create(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Record (*types.Record) to ComposeRecord
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("ComposeRecord").Cast(results.Record); err != nil {
return
} else if err = expr.Assign(out, "record", tval); err != nil {
return
}
}
return
},
}
}
type (
modulesUpdateArgs struct {
hasModule bool
Module interface{}
moduleID uint64
moduleHandle string
moduleRes *types.Module
hasNamespace bool
Namespace interface{}
namespaceID uint64
namespaceHandle string
namespaceRes *types.Namespace
hasValues bool
Values types.RecordValueSet
hasLabels bool
Labels label.Labels
hasOwnedBy bool
OwnedBy uint64
}
modulesUpdateResults struct {
Record *types.Record
}
)
func (a modulesUpdateArgs) GetModule() (bool, uint64, string, *types.Module) {
return a.hasModule, a.moduleID, a.moduleHandle, a.moduleRes
}
func (a modulesUpdateArgs) GetNamespace() (bool, uint64, string, *types.Namespace) {
return a.hasNamespace, a.namespaceID, a.namespaceHandle, a.namespaceRes
}
// Update function Updates an existing record
//
// expects implementation of update function:
// func (h modulesHandler) update(ctx context.Context, args *modulesUpdateArgs) (results *modulesUpdateResults, err error) {
// return
// }
func (h modulesHandler) Update() *atypes.Function {
return &atypes.Function{
Ref: "composeModulesUpdate",
Kind: "function",
Meta: &atypes.FunctionMeta{
Short: "Updates an existing record",
},
Parameters: []*atypes.Param{
{
Name: "module",
Types: []string{"ID", "String", "ComposeModule"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Module to set record type",
Description: "Even with unique record ID across all modules, module needs to be known\nbefore doing any record operations. Mainly because records of different\nmodules can be located in different stores.",
},
},
{
Name: "namespace",
Types: []string{"ID", "String", "ComposeNamespace"}, Required: true,
},
{
Name: "values",
Types: []string{"KV"},
},
{
Name: "labels",
Types: []string{"KV"},
},
{
Name: "ownedBy",
Types: []string{"ID"},
Meta: &atypes.ParamMeta{
Label: "Record owner",
Visual: map[string]interface{}{"ref": "users"},
},
},
},
Results: []*atypes.Param{
{
Name: "record",
Types: []string{"ComposeRecord"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &modulesUpdateArgs{
hasModule: in.Has("module"),
hasNamespace: in.Has("namespace"),
hasValues: in.Has("values"),
hasLabels: in.Has("labels"),
hasOwnedBy: in.Has("ownedBy"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Module argument
if args.hasModule {
aux := expr.Must(expr.Select(in, "module"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.moduleID = aux.Get().(uint64)
case h.reg.Type("String").Type():
args.moduleHandle = aux.Get().(string)
case h.reg.Type("ComposeModule").Type():
args.moduleRes = aux.Get().(*types.Module)
}
}
// Converting Namespace argument
if args.hasNamespace {
aux := expr.Must(expr.Select(in, "namespace"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.namespaceID = aux.Get().(uint64)
case h.reg.Type("String").Type():
args.namespaceHandle = aux.Get().(string)
case h.reg.Type("ComposeNamespace").Type():
args.namespaceRes = aux.Get().(*types.Namespace)
}
}
var results *modulesUpdateResults
if results, err = h.update(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Record (*types.Record) to ComposeRecord
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("ComposeRecord").Cast(results.Record); err != nil {
return
} else if err = expr.Assign(out, "record", tval); err != nil {
return
}
}
return
},
}
}
type (
modulesDeleteArgs struct {
hasRecordID bool
RecordID uint64
hasModule bool
Module interface{}
moduleID uint64
moduleHandle string
moduleRes *types.Module
hasNamespace bool
Namespace interface{}
namespaceID uint64
namespaceHandle string
namespaceRes *types.Namespace
}
)
func (a modulesDeleteArgs) GetModule() (bool, uint64, string, *types.Module) {
return a.hasModule, a.moduleID, a.moduleHandle, a.moduleRes
}
func (a modulesDeleteArgs) GetNamespace() (bool, uint64, string, *types.Namespace) {
return a.hasNamespace, a.namespaceID, a.namespaceHandle, a.namespaceRes
}
// Delete function Soft deletes compose record by ID
//
// expects implementation of delete function:
// func (h modulesHandler) delete(ctx context.Context, args *modulesDeleteArgs) (err error) {
// return
// }
func (h modulesHandler) Delete() *atypes.Function {
return &atypes.Function{
Ref: "composeModulesDelete",
Kind: "function",
Meta: &atypes.FunctionMeta{
Short: "Soft deletes compose record by ID",
},
Parameters: []*atypes.Param{
{
Name: "recordID",
Types: []string{"ID"}, Required: true,
},
{
Name: "module",
Types: []string{"ID", "String", "ComposeModule"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Module to set record type",
Description: "Even with unique record ID across all modules, module needs to be known\nbefore doing any record operations. Mainly because records of different\nmodules can be located in different stores.",
},
},
{
Name: "namespace",
Types: []string{"ID", "String", "ComposeNamespace"}, Required: true,
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &modulesDeleteArgs{
hasRecordID: in.Has("recordID"),
hasModule: in.Has("module"),
hasNamespace: in.Has("namespace"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Module argument
if args.hasModule {
aux := expr.Must(expr.Select(in, "module"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.moduleID = aux.Get().(uint64)
case h.reg.Type("String").Type():
args.moduleHandle = aux.Get().(string)
case h.reg.Type("ComposeModule").Type():
args.moduleRes = aux.Get().(*types.Module)
}
}
// Converting Namespace argument
if args.hasNamespace {
aux := expr.Must(expr.Select(in, "namespace"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.namespaceID = aux.Get().(uint64)
case h.reg.Type("String").Type():
args.namespaceHandle = aux.Get().(string)
case h.reg.Type("ComposeNamespace").Type():
args.namespaceRes = aux.Get().(*types.Namespace)
}
}
return out, h.delete(ctx, args)
},
}
}
+44 -119
View File
@@ -2,157 +2,82 @@ package automation
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
)
type (
recordService interface {
FindByID(ctx context.Context, namespaceID, moduleID, recordID uint64) (*types.Record, error)
Find(ctx context.Context, filter types.RecordFilter) (set types.RecordSet, f types.RecordFilter, err error)
Create(ctx context.Context, record *types.Record) (*types.Record, error)
Update(ctx context.Context, record *types.Record) (*types.Record, error)
Bulk(ctx context.Context, oo ...*types.RecordBulkOperation) (types.RecordSet, error)
DeleteByID(ctx context.Context, namespaceID, moduleID uint64, recordID ...uint64) error
}
moduleService interface {
FindByID(ctx context.Context, namespaceID, moduleID uint64) (*types.Module, error)
FindByHandle(ctx context.Context, namespaceID uint64, handle string) (*types.Module, error)
Find(ctx context.Context, filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error)
Create(ctx context.Context, module *types.Module) (*types.Module, error)
Update(ctx context.Context, module *types.Module) (*types.Module, error)
DeleteByID(ctx context.Context, namespaceID uint64, moduleID uint64) error
}
namespaceService interface {
FindByID(ctx context.Context, namespaceID uint64) (*types.Namespace, error)
FindByHandle(ctx context.Context, handle string) (*types.Namespace, error)
}
recordsHandlers struct {
reg recordsHandlerRegistry
modulesHandler struct {
reg modulesHandlerRegistry
ns namespaceService
mod moduleService
rec recordService
}
moduleLookup interface {
GetModule() (bool, uint64, string, *types.Module)
}
)
func RecordsHandlers(reg recordsHandlerRegistry, ns namespaceService, mod moduleService, rec recordService) *recordsHandlers {
h := &recordsHandlers{
func ModulesHandler(reg modulesHandlerRegistry, ns namespaceService, mod moduleService) *modulesHandler {
h := &modulesHandler{
reg: reg,
ns: ns,
mod: mod,
rec: rec,
}
h.register()
return h
}
func resolveNamespace(ctx context.Context, svc namespaceService, id *uint64, handle string, res *types.Namespace) (err error) {
if *id == 0 {
if len(handle) > 0 {
if res, err = svc.FindByHandle(ctx, handle); err != nil {
return
}
}
if res != nil {
*id = res.ID
}
}
func (h modulesHandler) lookup(ctx context.Context, args *modulesLookupArgs) (results *modulesLookupResults, err error) {
results = &modulesLookupResults{}
results.Module, err = lookupModule(ctx, h.ns, h.mod, args)
return
}
func resolveModule(ctx context.Context, svc moduleService, namespaceID uint64, id *uint64, handle string, res *types.Module) (err error) {
if *id == 0 {
if len(handle) > 0 {
if res, err = svc.FindByHandle(ctx, namespaceID, handle); err != nil {
return
}
}
if res != nil {
*id = res.ID
}
func getModuleID(ctx context.Context, nsSvc namespaceService, modSvc moduleService, args moduleLookup) (namespaceID uint64, moduleID uint64, err error) {
namespaceID, err = getNamespaceID(ctx, nsSvc, args.(namespaceLookup))
if err != nil {
return
}
return
var mod *types.Module
if _, moduleID, _, _ = args.GetModule(); moduleID > 0 {
return
} else if mod, err = lookupModule(ctx, nsSvc, modSvc, args); err != nil {
return
} else {
return namespaceID, mod.ID, nil
}
}
func (h recordsHandlers) lookupByID(ctx context.Context, args *recordsLookupByIDArgs) (results *recordsLookupByIDResults, err error) {
results = &recordsLookupByIDResults{}
if err = resolveNamespace(ctx, h.ns, &args.namespaceID, args.namespaceHandle, args.namespaceRes); err != nil {
return nil, err
func lookupModule(ctx context.Context, nsSvc namespaceService, modSvc moduleService, args moduleLookup) (*types.Module, error) {
namespaceID, err := getNamespaceID(ctx, nsSvc, args.(namespaceLookup))
if err != nil {
return nil, fmt.Errorf("could not load namespace: %w", err)
}
if err = resolveModule(ctx, h.mod, args.namespaceID, &args.moduleID, args.moduleHandle, args.moduleRes); err != nil {
return nil, err
_, ID, handle, module := args.GetModule()
switch {
case module != nil:
return module, nil
case ID > 0:
return modSvc.FindByID(ctx, namespaceID, ID)
case len(handle) > 0:
return modSvc.FindByHandle(ctx, namespaceID, handle)
}
results.Record, err = h.rec.FindByID(ctx, args.namespaceID, args.moduleID, args.RecordID)
return
}
func (h recordsHandlers) create(ctx context.Context, args *recordsCreateArgs) (results *recordsCreateResults, err error) {
results = &recordsCreateResults{}
if err = resolveNamespace(ctx, h.ns, &args.namespaceID, args.namespaceHandle, args.namespaceRes); err != nil {
return nil, err
}
if err = resolveModule(ctx, h.mod, args.namespaceID, &args.moduleID, args.moduleHandle, args.moduleRes); err != nil {
return nil, err
}
rec := &types.Record{
ModuleID: args.moduleID,
NamespaceID: args.namespaceID,
Values: args.Values,
Labels: args.Labels,
OwnedBy: args.OwnedBy,
}
results.Record, err = h.rec.Create(ctx, rec)
return
}
func (h recordsHandlers) save(ctx context.Context, args *recordsSaveArgs) (results *recordsSaveResults, err error) {
results = &recordsSaveResults{}
results.Record, err = h.rec.Update(ctx, args.Record)
return
}
func (h recordsHandlers) update(ctx context.Context, args *recordsUpdateArgs) (results *recordsUpdateResults, err error) {
results = &recordsUpdateResults{}
if err = resolveNamespace(ctx, h.ns, &args.namespaceID, args.namespaceHandle, args.namespaceRes); err != nil {
return nil, err
}
if err = resolveModule(ctx, h.mod, args.namespaceID, &args.moduleID, args.moduleHandle, args.moduleRes); err != nil {
return nil, err
}
rec := &types.Record{
ModuleID: args.moduleID,
NamespaceID: args.namespaceID,
Values: args.Values,
Labels: args.Labels,
OwnedBy: args.OwnedBy,
}
results.Record, err = h.rec.Update(ctx, rec)
return
}
func (h recordsHandlers) delete(ctx context.Context, args *recordsDeleteArgs) (err error) {
if err = resolveNamespace(ctx, h.ns, &args.namespaceID, args.namespaceHandle, args.namespaceRes); err != nil {
return err
}
if err = resolveModule(ctx, h.mod, args.namespaceID, &args.moduleID, args.moduleHandle, args.moduleRes); err != nil {
return err
}
return h.rec.DeleteByID(ctx, args.namespaceID, args.moduleID, args.RecordID)
return nil, fmt.Errorf("empty module lookup params")
}
+15 -107
View File
@@ -2,123 +2,31 @@ prefix: compose
imports:
- github.com/cortezaproject/corteza-server/compose/types
- github.com/cortezaproject/corteza-server/pkg/label
# - time
params:
module: &module
moduleLookup: &moduleLookup
required: true
types:
- { wf: ID, go: uint64, suffix: ID }
- { wf: String, go: string, suffix: handle }
- { wf: ComposeModule, go: "*types.Module", suffix: res }
meta:
label: Module to set record type
description: |-
Even with unique record ID across all modules, module needs to be known
before doing any record operations. Mainly because records of different
modules can be located in different stores.
- { wf: ID, }
- { wf: Handle, }
- { wf: ComposeModule, suffix: res }
namespace: &namespace
namespaceLookup: &namespaceLookup
required: true
types:
- { wf: ID, go: uint64, suffix: ID }
- { wf: String, go: string, suffix: handle }
- { wf: ComposeNamespace, go: "*types.Namespace", suffix: res }
- { wf: ID, }
- { wf: Handle, }
- { wf: ComposeNamespace, suffix: res }
record: &record
required: true
types:
- { wf: ComposeRecord, go: "*types.Record" }
recordID: &recordID
required: true
types:
- { wf: ID, go: uint64 }
values: &values
types: [ { wf: KV, go: 'types.RecordValueSet' }]
labels: &labels
types: [ { wf: KV, go: 'label.Labels' }]
ownedBy: &ownedBy
types: [ { wf: ID, go: uint64 } ]
meta:
label: Record owner
visual:
ref: users
recordReturnValue: &recordReturnValue
wf: ComposeRecord
go: "*types.Record"
rvModule: &rvModule
wf: ComposeModule
functions:
lookupByID:
lookup:
meta:
short: Lookup for compose record by ID
short: Lookup for compose Lookup by ID
params:
recordID: *recordID
module: *module
namespace: *namespace
module: *moduleLookup
namespace: *namespaceLookup
results:
record: *recordReturnValue
save:
meta:
short: Save record
params:
record: *record
results:
record: *recordReturnValue
# @todo validate
# -> record
# <- errors RVSE
# <- valid (bool)
# @todo copy
# -> source Record
# -> target Record
# -> include []string list of fields from source record to copy
# -> exclude []string list of fields from source record to copy
create:
meta:
short: Creates and stores a new record
params:
module: *module
namespace: *namespace
values: *values
labels: *labels
ownedBy: *ownedBy
results:
record: *recordReturnValue
update:
meta:
short: Updates an existing record
params:
module: *module
namespace: *namespace
values: *values
labels: *labels
ownedBy: *ownedBy
results:
record: *recordReturnValue
delete:
meta:
short: Soft deletes compose record by ID
params:
recordID: *recordID
module: *module
namespace: *namespace
# restore:
# meta:
# short: Soft deletes compose record by ID
# params:
# recordID: *recordID
# module: *module
# namespace: *namespace
module: *rvModule
+10 -35
View File
@@ -33,11 +33,6 @@ func (h namespacesHandler) register() {
type (
namespacesLookupArgs struct {
hasModule bool
Module interface{}
moduleID uint64
moduleHandle string
hasNamespace bool
Namespace interface{}
namespaceID uint64
@@ -46,19 +41,15 @@ type (
}
namespacesLookupResults struct {
Module *types.Module
Namespace *types.Namespace
}
)
func (a namespacesLookupArgs) GetModule() (bool, uint64, string) {
return a.hasModule, a.moduleID, a.moduleHandle
}
func (a namespacesLookupArgs) GetNamespace() (bool, uint64, string, *types.Namespace) {
return a.hasNamespace, a.namespaceID, a.namespaceHandle, a.namespaceRes
}
// Lookup function Lookup for compose module by ID
// Lookup function Lookup for compose namespace by ID
//
// expects implementation of lookup function:
// func (h namespacesHandler) lookup(ctx context.Context, args *namespacesLookupArgs) (results *namespacesLookupResults, err error) {
@@ -69,32 +60,27 @@ func (h namespacesHandler) Lookup() *atypes.Function {
Ref: "composeNamespacesLookup",
Kind: "function",
Meta: &atypes.FunctionMeta{
Short: "Lookup for compose module by ID",
Short: "Lookup for compose namespace by ID",
},
Parameters: []*atypes.Param{
{
Name: "module",
Types: []string{"ID", "String"}, Required: true,
},
{
Name: "namespace",
Types: []string{"ID", "String", "ComposeNamespace"}, Required: true,
Types: []string{"ID", "Handle", "ComposeNamespace"}, Required: true,
},
},
Results: []*atypes.Param{
{
Name: "module",
Types: []string{"ComposeModule"},
Name: "namespace",
Types: []string{"ComposeNamespace"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &namespacesLookupArgs{
hasModule: in.Has("module"),
hasNamespace: in.Has("namespace"),
}
)
@@ -103,24 +89,13 @@ func (h namespacesHandler) Lookup() *atypes.Function {
return
}
// Converting Module argument
if args.hasModule {
aux := expr.Must(expr.Select(in, "module"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.moduleID = aux.Get().(uint64)
case h.reg.Type("String").Type():
args.moduleHandle = aux.Get().(string)
}
}
// Converting Namespace argument
if args.hasNamespace {
aux := expr.Must(expr.Select(in, "namespace"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.namespaceID = aux.Get().(uint64)
case h.reg.Type("String").Type():
case h.reg.Type("Handle").Type():
args.namespaceHandle = aux.Get().(string)
case h.reg.Type("ComposeNamespace").Type():
args.namespaceRes = aux.Get().(*types.Namespace)
@@ -135,14 +110,14 @@ func (h namespacesHandler) Lookup() *atypes.Function {
out = &expr.Vars{}
{
// converting results.Module (*types.Module) to ComposeModule
// converting results.Namespace (*types.Namespace) to ComposeNamespace
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("ComposeModule").Cast(results.Module); err != nil {
if tval, err = h.reg.Type("ComposeNamespace").Cast(results.Namespace); err != nil {
return
} else if err = expr.Assign(out, "module", tval); err != nil {
} else if err = expr.Assign(out, "namespace", tval); err != nil {
return
}
}
+41 -42
View File
@@ -2,72 +2,71 @@ package automation
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
)
type (
moduleService interface {
FindByID(ctx context.Context, namespaceID, moduleID uint64) (*types.Module, error)
FindByHandle(ctx context.Context, namespaceID uint64, handle string) (*types.Module, error)
Find(ctx context.Context, filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error)
Create(ctx context.Context, module *types.Module) (*types.Module, error)
Update(ctx context.Context, module *types.Module) (*types.Module, error)
DeleteByID(ctx context.Context, namespaceID uint64, moduleID ...uint64) error
}
moduleNamespaceService interface {
namespaceService interface {
FindByID(ctx context.Context, namespaceID uint64) (*types.Namespace, error)
FindByHandle(ctx context.Context, handle string) (*types.Namespace, error)
Find(ctx context.Context, filter types.NamespaceFilter) (set types.NamespaceSet, f types.NamespaceFilter, err error)
Create(ctx context.Context, namespace *types.Namespace) (*types.Namespace, error)
Update(ctx context.Context, namespace *types.Namespace) (*types.Namespace, error)
DeleteByID(ctx context.Context, namespaceID uint64) error
}
modulesHandlers struct {
reg modulesHandlerRegistry
ns moduleNamespaceService
mod moduleService
namespacesHandler struct {
reg namespacesHandlerRegistry
ns namespaceService
}
namespaceLookup interface {
GetNamespace() (bool, uint64, string, *types.Namespace)
}
)
func ModulesHandlers(reg modulesHandlerRegistry, ns moduleNamespaceService, rec moduleService) *modulesHandlers {
h := &modulesHandlers{
func NamespacesHandler(reg namespacesHandlerRegistry, ns namespaceService) *namespacesHandler {
h := &namespacesHandler{
reg: reg,
ns: ns,
mod: rec,
}
h.register()
return h
}
func (h modulesHandlers) resolveNamespace(ctx context.Context, id *uint64, handle string, res *types.Namespace) (err error) {
if *id == 0 {
if len(handle) > 0 {
if res, err = h.ns.FindByHandle(ctx, handle); err != nil {
return
}
}
if res != nil {
*id = res.ID
}
}
func (h namespacesHandler) lookup(ctx context.Context, args *namespacesLookupArgs) (results *namespacesLookupResults, err error) {
results = &namespacesLookupResults{}
results.Namespace, err = lookupNamespace(ctx, h.ns, args)
return
}
func (h modulesHandlers) lookup(ctx context.Context, args *modulesLookupArgs) (results *modulesLookupResults, err error) {
results = &modulesLookupResults{}
if err = h.resolveNamespace(ctx, &args.namespaceID, args.namespaceHandle, args.namespaceRes); err != nil {
return nil, err
}
if args.moduleID > 0 {
results.Module, err = h.mod.FindByID(ctx, args.namespaceID, args.moduleID)
func getNamespaceID(ctx context.Context, svc namespaceService, args namespaceLookup) (uint64, error) {
_, ID, _, _ := args.GetNamespace()
if ID > 0 {
return ID, nil
} else if ns, err := lookupNamespace(ctx, svc, args); err != nil {
return 0, err
} else {
results.Module, err = h.mod.FindByHandle(ctx, args.namespaceID, args.moduleHandle)
return ns.ID, nil
}
}
func lookupNamespace(ctx context.Context, svc namespaceService, args namespaceLookup) (*types.Namespace, error) {
_, ID, handle, namespace := args.GetNamespace()
switch {
case namespace != nil:
return namespace, nil
case ID > 0:
return svc.FindByID(ctx, ID)
case len(handle) > 0:
return svc.FindByHandle(ctx, handle)
}
return
return nil, fmt.Errorf("empty namespace lookup params")
}
+9 -17
View File
@@ -4,29 +4,21 @@ imports:
- github.com/cortezaproject/corteza-server/compose/types
params:
module: &module
namespaceLookup: &namespaceLookup
required: true
types:
- { wf: ID, go: uint64, suffix: ID }
- { wf: String, go: string, suffix: handle }
- { wf: ID, }
- { wf: Handle, }
- { wf: ComposeNamespace, suffix: res }
namespace: &namespace
required: true
types:
- { wf: ID, go: uint64, suffix: ID }
- { wf: String, go: string, suffix: handle }
- { wf: ComposeNamespace, go: "*types.Namespace", suffix: res }
moduleReturnValue: &moduleReturnValue
wf: ComposeModule
go: "*types.Module"
rvNamespace: &rvNamespace
wf: ComposeNamespace
functions:
lookup:
meta:
short: Lookup for compose module by ID
short: Lookup for compose namespace by ID
params:
module: *module
namespace: *namespace
namespace: *namespaceLookup
results:
module: *moduleReturnValue
namespace: *rvNamespace
File diff suppressed because it is too large Load Diff
+259
View File
@@ -0,0 +1,259 @@
package automation
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
. "github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/wfexec"
)
type (
recordService interface {
FindByID(ctx context.Context, namespaceID, moduleID, recordID uint64) (*types.Record, error)
Find(ctx context.Context, filter types.RecordFilter) (set types.RecordSet, f types.RecordFilter, err error)
Create(ctx context.Context, record *types.Record) (*types.Record, error)
Update(ctx context.Context, record *types.Record) (*types.Record, error)
Bulk(ctx context.Context, oo ...*types.RecordBulkOperation) (types.RecordSet, error)
Validate(ctx context.Context, rec *types.Record) error
DeleteByID(ctx context.Context, namespaceID, moduleID uint64, recordID ...uint64) error
}
recordsHandler struct {
reg recordsHandlerRegistry
ns namespaceService
mod moduleService
rec recordService
}
recordSetIterator struct {
ptr int
set types.RecordSet
filter types.RecordFilter
}
recordLookup interface {
GetRecord() (bool, uint64, *types.Record)
}
)
func RecordsHandler(reg recordsHandlerRegistry, ns namespaceService, mod moduleService, rec recordService) *recordsHandler {
h := &recordsHandler{
reg: reg,
ns: ns,
mod: mod,
rec: rec,
}
h.register()
return h
}
func (h recordsHandler) lookup(ctx context.Context, args *recordsLookupArgs) (results *recordsLookupResults, err error) {
results = &recordsLookupResults{}
results.Record, err = h.lookupRecord(ctx, args)
return
}
func (h recordsHandler) search(ctx context.Context, args *recordsSearchArgs) (results *recordsSearchResults, err error) {
results = &recordsSearchResults{}
var (
f = types.RecordFilter{
Query: args.Query,
Labels: args.Labels,
Deleted: filter.State(args.Deleted),
}
)
if ns, mod, err := h.loadCombo(ctx, args); err != nil {
return nil, err
} else {
f.ModuleID = mod.ID
f.NamespaceID = ns.ID
}
if args.hasSort {
if err = f.Sort.Set(args.Sort); err != nil {
return
}
}
if args.hasPageCursor {
if err = f.PageCursor.Decode(args.PageCursor); err != nil {
return
}
}
f.IncTotal = args.IncTotal
f.IncPageNavigation = args.IncPageNavigation
if args.hasLabels {
f.Labels = args.Labels
}
if args.hasLimit {
f.Limit = uint(args.Limit)
}
results.Records, _, err = h.rec.Find(ctx, f)
return
}
func (h recordsHandler) each(ctx context.Context, args *recordsEachArgs) (out wfexec.IteratorHandler, err error) {
var (
i = &recordSetIterator{}
f = types.RecordFilter{
Query: args.Query,
Labels: args.Labels,
Deleted: filter.State(args.Deleted),
}
)
if ns, mod, err := h.loadCombo(ctx, args); err != nil {
return nil, err
} else {
f.ModuleID = mod.ID
f.NamespaceID = ns.ID
}
if args.hasSort {
if err = f.Sort.Set(args.Sort); err != nil {
return nil, err
}
}
if args.hasPageCursor {
if err = f.PageCursor.Decode(args.PageCursor); err != nil {
return nil, err
}
}
f.IncTotal = args.IncTotal
f.IncPageNavigation = args.IncPageNavigation
if args.hasLabels {
f.Labels = args.Labels
}
if args.hasLimit {
f.Limit = uint(args.Limit)
}
i.set, i.filter, err = h.rec.Find(ctx, f)
return i, err
}
func (h recordsHandler) validate(ctx context.Context, args *recordsValidateArgs) (*recordsValidateResults, error) {
results := &recordsValidateResults{Valid: true}
if err := h.rec.Validate(ctx, args.Record); err != nil {
results.Valid = false
//if rves, is := err.(*types.RecordValueErrorSet); is {
// results.Errors = rves
//} else {
// return nil, err
//}
}
return results, nil
}
func (h recordsHandler) new(ctx context.Context, args *recordsNewArgs) (*recordsNewResults, error) {
results := &recordsNewResults{}
namespace, module, err := h.loadCombo(ctx, args)
if err != nil {
return nil, err
}
results.Record = &types.Record{
ModuleID: module.ID,
NamespaceID: namespace.ID,
}
results.Record.SetModule(module)
return results, nil
}
func (h recordsHandler) create(ctx context.Context, args *recordsCreateArgs) (results *recordsCreateResults, err error) {
results = &recordsCreateResults{}
results.Record, err = h.rec.Create(ctx, args.Record)
return
}
func (h recordsHandler) update(ctx context.Context, args *recordsUpdateArgs) (results *recordsUpdateResults, err error) {
results = &recordsUpdateResults{}
results.Record, err = h.rec.Update(ctx, args.Record)
return
}
func (h recordsHandler) delete(ctx context.Context, args *recordsDeleteArgs) error {
if rec, err := h.lookupRecord(ctx, args); err != nil {
return err
} else {
return h.rec.DeleteByID(ctx, rec.NamespaceID, rec.ModuleID, rec.ID)
}
}
func (h recordsHandler) lookupRecord(ctx context.Context, args recordLookup) (record *types.Record, err error) {
var (
namespace *types.Namespace
module *types.Module
recordID uint64
)
if _, recordID, record = args.GetRecord(); record != nil {
return
}
if namespace, module, err = h.loadCombo(ctx, args); err != nil {
return
}
return h.rec.FindByID(ctx, namespace.ID, module.ID, recordID)
}
func (h recordsHandler) loadCombo(ctx context.Context, args interface{}) (namespace *types.Namespace, module *types.Module, err error) {
if lkp, is := args.(namespaceLookup); is {
if namespace, err = lookupNamespace(ctx, h.ns, lkp); err != nil {
err = fmt.Errorf("could not load namespace: %w", err)
return
}
} else {
err = fmt.Errorf("could not extract namespace lookup arguments")
return
}
if lkp, is := args.(moduleLookup); is {
if module, err = lookupModule(ctx, h.ns, h.mod, lkp); err != nil {
err = fmt.Errorf("could not load module: %w", err)
return
}
} else {
err = fmt.Errorf("could not extract module lookup arguments")
return
}
return
}
func (i *recordSetIterator) More(context.Context, *Vars) (bool, error) {
return i.ptr < len(i.set), nil
}
func (i *recordSetIterator) Start(context.Context, *Vars) error { i.ptr = 0; return nil }
func (i *recordSetIterator) Next(context.Context, *Vars) (*Vars, error) {
out := RVars{
"record": Must(NewComposeRecord(i.set[i.ptr])),
"index": Must(NewUnsignedInteger(i.ptr)),
"total": Must(NewUnsignedInteger(i.filter.Total)),
}
i.ptr++
return out.Vars(), nil
}
+170
View File
@@ -0,0 +1,170 @@
prefix: compose
imports:
- github.com/cortezaproject/corteza-server/compose/types
params:
moduleLookup: &moduleLookup
required: true
types:
- { wf: ID, }
- { wf: Handle, }
- { wf: ComposeModule, suffix: res }
meta:
label: Module to set record type
description: |-
Even with unique record ID across all modules, module needs to be known
before doing any record operations. Mainly because records of different
modules can be located in different stores.
namespaceLookup: &namespaceLookup
required: true
types:
- { wf: ID, }
- { wf: Handle, }
- { wf: ComposeNamespace, suffix: res }
recordLookup: &recordLookup
required: true
types:
- { wf: ID, }
- { wf: ComposeRecord, suffix: res }
record: &record
required: true
types:
- { wf: ComposeRecord, }
rvRecord: &rvRecord
wf: ComposeRecord
rvTotal: &rvTotal
wf: UnsignedInteger
meta:
label: Total records found
description: |-
Total items that satisfy given conditions.
Needs to be explicitly requested with incTotal argument
rvIndex: &rvIndex
wf: UnsignedInteger
meta:
label: Iteration counter
description: |-
Zero-based number iteration counter
rvPageCursor: &rvPageCursor
wf: String
filterParams: &filterParams
module: *moduleLookup
namespace: *namespaceLookup
query:
types:
- { wf: String }
labels:
types:
- { wf: KV }
deleted:
types:
- { wf: UnsignedInteger }
sort:
types:
- { wf: String }
limit:
types:
- { wf: UnsignedInteger }
incTotal:
types:
- { wf: Boolean }
incPageNavigation:
types:
- { wf: Boolean }
pageCursor:
types:
- { wf: String }
functions:
lookup:
meta:
short: Lookup for compose record by ID
params:
module: *moduleLookup
namespace: *namespaceLookup
record: *recordLookup
results:
record: *rvRecord
search:
meta:
short: Searches for records and returns them
params: *filterParams
results:
records:
<<: *rvRecord
isArray: true
total: *rvTotal
pageCursor: *rvPageCursor
each:
kind: iterator
meta:
short: Searches for records and iterates over results
params: *filterParams
results:
record: *rvRecord
index: *rvIndex
total: *rvTotal
new:
meta:
short: Make a new record
params:
module: *moduleLookup
namespace: *namespaceLookup
results:
record: *rvRecord
validate:
meta:
short: Validate record
params:
record: *record
results:
valid:
wf: Boolean
meta:
label: Set to true when record is valid
create:
meta:
short: Creates and stores a new record
params:
record:
<<: *record
required: true
results:
record: *rvRecord
update:
meta:
short: Updates an existing record
params:
record:
<<: *record
required: true
results:
record: *rvRecord
delete:
meta:
short: Soft deletes compose record by ID
params:
record: *recordLookup
# undelete:
# meta:
# short: Recovers deleted record by ID
# params:
# record: *recordLookup
+11
View File
@@ -84,6 +84,8 @@ type (
Update(ctx context.Context, record *types.Record) (*types.Record, error)
Bulk(ctx context.Context, oo ...*types.RecordBulkOperation) (types.RecordSet, error)
Validate(ctx context.Context, rec *types.Record) error
DeleteByID(ctx context.Context, namespaceID, moduleID uint64, recordID ...uint64) error
Organize(ctx context.Context, namespaceID, moduleID, recordID uint64, sortingField, sortingValue, sortingFilter, valueField, value string) error
@@ -1120,6 +1122,15 @@ func (svc record) Organize(ctx context.Context, namespaceID, moduleID, recordID
return svc.recordAction(ctx, aProps, RecordActionOrganize, err)
}
func (svc record) Validate(ctx context.Context, rec *types.Record) error {
if m, err := loadModule(ctx, svc.store, rec.ModuleID); err != nil {
return err
} else {
rec.Values = values.Sanitizer().Run(m, rec.Values)
return values.Validator().Run(ctx, svc.store, m, rec)
}
}
// TriggerScript loads requested record sanitizes and validates values and passes all to the automation script
//
// For backward compatibility (of controllers), it returns module+record
+27
View File
@@ -3,6 +3,8 @@ package service
import (
"context"
"fmt"
automationService "github.com/cortezaproject/corteza-server/automation/service"
"github.com/cortezaproject/corteza-server/compose/automation"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/corredor"
@@ -151,6 +153,31 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, c Config)
RegisterIteratorProviders()
automationService.Registry().AddTypes(
automation.ComposeNamespace{},
automation.ComposeModule{},
automation.ComposeRecord{},
automation.ComposeRecordValues{},
)
automation.RecordsHandler(
automationService.Registry(),
DefaultNamespace,
DefaultModule,
DefaultRecord,
)
automation.ModulesHandler(
automationService.Registry(),
DefaultNamespace,
DefaultModule,
)
automation.NamespacesHandler(
automationService.Registry(),
DefaultNamespace,
)
return nil
}
+4
View File
@@ -108,6 +108,10 @@ func (r *Record) SetModule(m *Module) {
}
}
func (r *Record) GetModule() *Module {
return r.module
}
func (r Record) Clone() *Record {
c := &r
c.Values = r.Values.Clone()