From b9a49645f3fb0f68e66071014ef59b85482995c7 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Tue, 25 Feb 2020 08:16:23 +0100 Subject: [PATCH] Add updated & oldValue capabilities to record values --- compose/types/record_value.go | 57 +++++++++++++++++++++++------- compose/types/record_value_test.go | 10 +++--- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/compose/types/record_value.go b/compose/types/record_value.go index ebf02712b..a555c5a4a 100644 --- a/compose/types/record_value.go +++ b/compose/types/record_value.go @@ -3,6 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" + "fmt" "time" "github.com/pkg/errors" @@ -18,7 +19,8 @@ type ( Place uint `db:"place" json:"-"` DeletedAt *time.Time `db:"deleted_at" json:"deletedAt,omitempty"` - updated bool + updated bool + oldValue string } ) @@ -118,17 +120,12 @@ func (set RecordValueSet) GetUpdated() (out RecordValueSet) { return out } -// Replace old value set with new one +// Merge merges old value set with new one and expects unchanged values to be in the new set // -// Will remove all values that are not set in new set +// This satisfies current requirements where record values are always +// manipulated as a whole (not partial) // -// This satisfies current requirements where record is always -// manipulated as a whole -func (set RecordValueSet) Replace(new RecordValueSet) (out RecordValueSet) { - if len(new) == 0 { - return nil - } - +func (set RecordValueSet) Merge(new RecordValueSet) (out RecordValueSet) { if len(set) == 0 { for i := range new { new[i].updated = true @@ -143,27 +140,41 @@ func (set RecordValueSet) Replace(new RecordValueSet) (out RecordValueSet) { out = append(out, &RecordValue{ Name: set[s].Name, Value: set[s].Value, + Ref: set[s].Ref, Place: set[s].Place, DeletedAt: &time.Time{}, updated: true, + oldValue: set[s].Value, }) } for n := range new { if ex := out.Get(new[n].Name, new[n].Place); ex != nil { // Reset deleted flag - ex.DeletedAt = nil + ex.DeletedAt = new[n].DeletedAt - // Did value change? - ex.updated = ex.updated || ex.Value != new[n].Value + if ex.oldValue == new[n].Value { + ex.updated = false + } else if !ex.updated { + // Did value change? + ex.updated = ex.Value != new[n].Value + ex.oldValue = ex.Value + } ex.Value = new[n].Value + ex.Ref = new[n].Ref } else { + // Value not previously set, make new out = append(out, &RecordValue{ Name: new[n].Name, Value: new[n].Value, + Ref: new[n].Ref, Place: new[n].Place, updated: true, + + // verbose & explicit for clarity + oldValue: "", + DeletedAt: nil, }) } } @@ -189,6 +200,26 @@ func (set RecordValueSet) Value() (driver.Value, error) { return json.Marshal(set) } +// Simple RVS as string output utility fn that +// can help with debugging +func (set RecordValueSet) String() (o string) { + const tpl = "%-10s %2d %-20s %-20d %-20s %v %v\n" + for _, v := range set { + o += fmt.Sprintf( + tpl, + v.Name, + v.Place, + v.Value, + v.Ref, + v.oldValue, + v.updated, + v.DeletedAt, + ) + } + + return o +} + func (set RecordValueSet) Len() int { return len(set) } func (set RecordValueSet) Swap(i, j int) { set[i], set[j] = set[j], set[i] } func (set RecordValueSet) Less(i, j int) bool { return set[i].Place < set[j].Place } diff --git a/compose/types/record_value_test.go b/compose/types/record_value_test.go index cbf85f512..99071071c 100644 --- a/compose/types/record_value_test.go +++ b/compose/types/record_value_test.go @@ -42,7 +42,7 @@ func TestRecordValueSet_Set(t *testing.T) { } } -func TestRecordValueSet_Replace(t *testing.T) { +func TestRecordValueSet_Merge(t *testing.T) { tests := []struct { name string set RecordValueSet @@ -59,25 +59,25 @@ func TestRecordValueSet_Replace(t *testing.T) { name: "update with nil", set: RecordValueSet{{Name: "n", Value: "v"}}, new: nil, - want: nil, + want: RecordValueSet{{Name: "n", Value: "v", oldValue: "v", DeletedAt: &time.Time{}, updated: true}}, }, { name: "update with new value", set: RecordValueSet{{Name: "n", Value: "1"}}, new: RecordValueSet{{Name: "n", Value: "2"}}, - want: RecordValueSet{{Name: "n", Value: "2", updated: true}}, + want: RecordValueSet{{Name: "n", Value: "2", oldValue: "1", updated: true}}, }, { name: "update with less values", set: RecordValueSet{{Name: "n", Value: "1"}, {Name: "deleted", Value: "d"}}, new: RecordValueSet{{Name: "n", Value: "2"}}, - want: RecordValueSet{{Name: "n", Value: "2", updated: true}, {Name: "deleted", Value: "d", updated: true, DeletedAt: &time.Time{}}}, + want: RecordValueSet{{Name: "n", Value: "2", oldValue: "1", updated: true}, {Name: "deleted", Value: "d", oldValue: "d", updated: true, DeletedAt: &time.Time{}}}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.set.Replace(tt.new); !reflect.DeepEqual(got, tt.want) { + if got := tt.set.Merge(tt.new); !reflect.DeepEqual(got, tt.want) { t.Errorf("Update() = %+v, want %+v", got, tt.want) } })