From 9150b3852b1e29895a38d69d690770f26306393d Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Wed, 31 Mar 2021 14:38:52 +0200 Subject: [PATCH] Beter ref handling, some cleanups, added tests --- compose/automation/expr_types.go | 16 ++++++++++++---- compose/automation/expr_types_test.go | 2 ++ compose/service/module.go | 2 +- compose/service/record.go | 8 ++++---- compose/service/record_test.go | 18 +++++++++--------- compose/types/record_value.go | 7 +++++++ pkg/envoy/store/compose_record_marshal.go | 2 +- 7 files changed, 36 insertions(+), 19 deletions(-) diff --git a/compose/automation/expr_types.go b/compose/automation/expr_types.go index 1fd352b54..cb393c23a 100644 --- a/compose/automation/expr_types.go +++ b/compose/automation/expr_types.go @@ -8,6 +8,7 @@ import ( "github.com/cortezaproject/corteza-server/compose/types" "github.com/cortezaproject/corteza-server/pkg/expr" "github.com/spf13/cast" + "strconv" "strings" "time" ) @@ -289,7 +290,7 @@ func composeRecordValuesTypedValueSelector(res *types.Record, k string) (expr.Ty case len(vv) == 1 && !multiValueField: return recordValueToExprTypedValue(field, vv[0]) default: - return recordValueSetoToExprArray(field, vv...) + return recordValueSetToExprArray(field, vv...) } } @@ -339,7 +340,7 @@ func assignToComposeRecordValues(res *types.Record, pp []string, val interface{} ) // @todo this needs to be implemented properly - // we're just guessing here and puting out fires + // we're just guessing here and putting out fires switch utval := expr.UntypedValue(val).(type) { case time.Time: rv.Value = utval.Format(time.RFC3339) @@ -435,7 +436,14 @@ func recordValueToExprTypedValue(field *types.ModuleField, rv *types.RecordValue return expr.NewString(rv.Value) case field.IsRef(): - return expr.NewID(rv.Ref) + ref := rv.Ref + if ref == 0 && len(rv.Value) > 0 { + // Cover cases when we Ref is not set but Value is + // This happens when RVS is transferred as JSON + ref, _ = strconv.ParseUint(rv.Value, 10, 64) + } + + return expr.NewID(ref) default: if v, err := rv.Cast(field); err != nil { @@ -446,7 +454,7 @@ func recordValueToExprTypedValue(field *types.ModuleField, rv *types.RecordValue } } -func recordValueSetoToExprArray(field *types.ModuleField, vv ...*types.RecordValue) (arr *expr.Array, err error) { +func recordValueSetToExprArray(field *types.ModuleField, vv ...*types.RecordValue) (arr *expr.Array, err error) { var ( tv expr.TypedValue ) diff --git a/compose/automation/expr_types_test.go b/compose/automation/expr_types_test.go index e9694e948..2ca0cb6ba 100644 --- a/compose/automation/expr_types_test.go +++ b/compose/automation/expr_types_test.go @@ -99,6 +99,7 @@ func TestRecordFieldValuesAccess(t *testing.T) { // expecting valid value (false) even when boolean fields are not set {false, "rec.values.b0"}, {true, "rec.values.b1"}, + {uint64(2), "rec.values.ref2"}, } for _, tc := range tcc { @@ -167,6 +168,7 @@ func TestRecordFieldValuesAccess(t *testing.T) { {true, `rec.values.ref1 != 2`}, {true, `rec.values.ref2 == 2`}, + {true, `rec.values.ref2 == "2"`}, } for _, tc := range tcc { diff --git a/compose/service/module.go b/compose/service/module.go index b09a4f4bf..2adebee1b 100644 --- a/compose/service/module.go +++ b/compose/service/module.go @@ -601,7 +601,7 @@ func moduleFieldDefaultPreparer(ctx context.Context, s store.Storer, m *types.Mo return nil }) - if err = RecordValueSanitazion(m, vv); err != nil { + if err = RecordValueSanitization(m, vv); err != nil { return nil, err } diff --git a/compose/service/record.go b/compose/service/record.go index 111727cef..683ab8ebd 100644 --- a/compose/service/record.go +++ b/compose/service/record.go @@ -475,7 +475,7 @@ func (svc record) create(ctx context.Context, new *types.Record) (rec *types.Rec return nil, RecordErrNotAllowedToCreate() } - if err = RecordValueSanitazion(m, new.Values); err != nil { + if err = RecordValueSanitization(m, new.Values); err != nil { return } @@ -531,7 +531,7 @@ func (svc record) create(ctx context.Context, new *types.Record) (rec *types.Rec return } -// RecordValueSanitazion does basic field and format validation +// RecordValueSanitization does basic field and format validation // // Received values must fit the data model: on unknown fields // or multi/single value mismatch we return an error @@ -540,7 +540,7 @@ func (svc record) create(ctx context.Context, new *types.Record) (rec *types.Rec // we can assume that form builder (or whatever it was that assembled the record values) // was misconfigured and will most likely failed to properly parse the // record value errors payload too -func RecordValueSanitazion(m *types.Module, vv types.RecordValueSet) (err error) { +func RecordValueSanitization(m *types.Module, vv types.RecordValueSet) (err error) { var ( aProps = &recordActionProps{} numeric = regexp.MustCompile(`^[1-9](\d+)$`) @@ -725,7 +725,7 @@ func (svc record) update(ctx context.Context, upd *types.Record) (rec *types.Rec return nil, RecordErrStaleData() } - if err = RecordValueSanitazion(m, upd.Values); err != nil { + if err = RecordValueSanitization(m, upd.Values); err != nil { return } diff --git a/compose/service/record_test.go b/compose/service/record_test.go index b718419e1..dcb4d0501 100644 --- a/compose/service/record_test.go +++ b/compose/service/record_test.go @@ -34,36 +34,36 @@ func TestGeneralValueSetValidation(t *testing.T) { ) rvs = types.RecordValueSet{{Name: "single1", Value: "single"}} - err = RecordValueSanitazion(module, rvs) + err = RecordValueSanitization(module, rvs) req.NoError(err) rvs = types.RecordValueSet{{Name: "unknown", Value: "single"}} - err = RecordValueSanitazion(module, rvs) - req.True(err != nil, "expecting RecordValueSanitazion() to return an error, got nil") + err = RecordValueSanitization(module, rvs) + req.True(err != nil, "expecting RecordValueSanitization() to return an error, got nil") rvs = types.RecordValueSet{{Name: "single1", Value: "single"}, {Name: "single1", Value: "single2"}} - err = RecordValueSanitazion(module, rvs) + err = RecordValueSanitization(module, rvs) req.Error(err) rvs = types.RecordValueSet{{Name: "multi1", Value: "multi1"}, {Name: "multi1", Value: "multi1"}} - err = RecordValueSanitazion(module, rvs) + err = RecordValueSanitization(module, rvs) req.NoError(err) rvs = types.RecordValueSet{{Name: "ref1", Value: "non numeric value"}} - err = RecordValueSanitazion(module, rvs) + err = RecordValueSanitization(module, rvs) req.Error(err) rvs = types.RecordValueSet{{Name: "ref1", Value: "12345"}} - err = RecordValueSanitazion(module, rvs) + err = RecordValueSanitization(module, rvs) req.NoError(err) rvs = types.RecordValueSet{{Name: "multiRef1", Value: "12345"}, {Name: "multiRef1", Value: "67890"}} - err = RecordValueSanitazion(module, rvs) + err = RecordValueSanitization(module, rvs) req.NoError(err) req.Len(rvs, 2, "expecting 2 record values after sanitization, got %d", len(rvs)) rvs = types.RecordValueSet{{Name: "ref1", Value: ""}} - err = RecordValueSanitazion(module, rvs) + err = RecordValueSanitization(module, rvs) req.NoError(err) } diff --git a/compose/types/record_value.go b/compose/types/record_value.go index e15a447ea..826f50f17 100644 --- a/compose/types/record_value.go +++ b/compose/types/record_value.go @@ -7,6 +7,7 @@ import ( "github.com/cortezaproject/corteza-server/pkg/filter" "github.com/pkg/errors" "github.com/spf13/cast" + "strconv" "time" ) @@ -59,6 +60,12 @@ func (v RecordValue) Cast(f *ModuleField) (interface{}, error) { switch { case f.IsRef(): + if v.Ref == 0 && len(v.Value) > 0 { + // Cover cases when we Ref is not set but Value is + // This happens when RVS is transferred as JSON + v.Ref, _ = strconv.ParseUint(v.Value, 10, 64) + } + return v.Ref, nil case f.IsDateTime(): diff --git a/pkg/envoy/store/compose_record_marshal.go b/pkg/envoy/store/compose_record_marshal.go index daf1c6e47..647cf679b 100644 --- a/pkg/envoy/store/compose_record_marshal.go +++ b/pkg/envoy/store/compose_record_marshal.go @@ -301,7 +301,7 @@ func (n *composeRecord) Encode(ctx context.Context, pl *payload) (err error) { rvs = append(rvs, rv) } - if err = service.RecordValueSanitazion(mod, rvs); err != nil { + if err = service.RecordValueSanitization(mod, rvs); err != nil { return err }