diff --git a/flows/results.go b/flows/results.go index 6b40285f7..b0a0de81c 100644 --- a/flows/results.go +++ b/flows/results.go @@ -9,6 +9,7 @@ import ( "time" "github.com/go-playground/validator/v10" + "github.com/nyaruka/gocommon/stringsx" "github.com/nyaruka/goflow/envs" "github.com/nyaruka/goflow/excellent/types" "github.com/nyaruka/goflow/utils" @@ -39,7 +40,7 @@ func init() { // Result describes a value captured during a run's execution. It might have been implicitly created by a router, or explicitly // created by a [set_run_result](#action:set_run_result) action. type Result struct { - Name string `json:"name" validate:"required,result_name"` + Name string `json:"name" validate:"required"` // TODO add result_name validation when we're sure sessions no longer have invalid result names Value string `json:"value"` Category string `json:"category,omitempty"` CategoryLocalized string `json:"category_localized,omitempty"` @@ -161,3 +162,20 @@ func (r Results) format() string { sort.Strings(lines) return strings.Join(lines, "\n") } + +func (r *Results) UnmarshalJSON(data []byte) error { + var m map[string]*Result + if err := json.Unmarshal(data, &m); err != nil { + return err + } + + *r = make(Results, len(m)) + + // we enforce result names being at most 64 chars but old sessions may have longer names + for _, v := range m { + v.Name = strings.TrimSpace(stringsx.Truncate(v.Name, 64)) + (*r)[utils.Snakify(v.Name)] = v + } + + return nil +} diff --git a/flows/results_test.go b/flows/results_test.go index c18673a41..6edd705e7 100644 --- a/flows/results_test.go +++ b/flows/results_test.go @@ -1,6 +1,7 @@ package flows_test import ( + "encoding/json" "testing" "time" @@ -60,6 +61,28 @@ func TestResults(t *testing.T) { "values": types.NewXArray(types.NewXText("")), }), }), resultsAsContext) + + // test marshalling + marshaled, err := json.Marshal(results) + assert.NoError(t, err) + assert.JSONEq(t, `{ + "beer": {"category": "Skol", "created_on":"2019-04-05T14:16:30.000123456Z", "name": "Beer", "node_uuid": "26493ebb-a254-4461-a28d-c7761784e276", "value": "skol!"}, + "empty": {"created_on":"2019-04-05T14:16:30.000123456Z", "name": "Empty", "node_uuid": "26493ebb-a254-4461-a28d-c7761784e276", "value": ""} + }`, string(marshaled)) + + var unmarshaled flows.Results + err = json.Unmarshal(marshaled, &unmarshaled) + assert.NoError(t, err) + assert.Equal(t, results, unmarshaled) + + // test unmarshalling with result names/keys that are too long + err = json.Unmarshal([]byte(`{ + "beer_123456789012345678901234567890123456789012345678901234567890": {"category": "Skol", "created_on":"2019-04-05T14:16:30.000123456Z", "name": "Beer 123456789012345678901234567890123456789012345678901234567890", "node_uuid": "26493ebb-a254-4461-a28d-c7761784e276", "value": "skol!"}, + "empty_123456789012345678901234567890123456789012345678901234567890": {"created_on":"2019-04-05T14:16:30.000123456Z", "name": "Empty 123456789012345678901234567890123456789012345678901234567890", "node_uuid": "26493ebb-a254-4461-a28d-c7761784e276", "value": ""} + }`), &unmarshaled) + assert.NoError(t, err) + assert.Equal(t, "Beer 12345678901234567890123456789012345678901234567890123456789", unmarshaled.Get("beer_12345678901234567890123456789012345678901234567890123456789").Name) + assert.Equal(t, "Empty 1234567890123456789012345678901234567890123456789012345678", unmarshaled.Get("empty_1234567890123456789012345678901234567890123456789012345678").Name) } func TestResultNameAndCategoryValidation(t *testing.T) {