Skip to content

Commit

Permalink
fix replace=true user/time mods in neuronjson
Browse files Browse the repository at this point in the history
  • Loading branch information
DocSavage committed Aug 18, 2023
1 parent 51923f4 commit f8438c8
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 9 deletions.
2 changes: 0 additions & 2 deletions datatype/neuronjson/memstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ func (d *Data) getMemDBbyVersion(v dvid.VersionID) (db *memdb, found bool) {
if err != nil {
return
}
metadata, _ := datastore.MarshalJSON()
dvid.Infof("Metadata:\n%s\n", string(metadata))

db, found = d.dbs.static[uuid]
if found {
Expand Down
24 changes: 23 additions & 1 deletion datatype/neuronjson/neuronjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,8 @@ func (d *Data) GetData(ctx storage.VersionedCtx, keyStr string, fieldMap map[str
// update _user and _time fields for any fields newly set or modified.
func updateJSON(origData, newData NeuronJSON, user string, conditionals []string, replace bool) {
// determine if any fields are being set for the first time or modified
newlySet := make(map[string]struct{}, len(newData))
newlySet := make(map[string]struct{}, len(newData)) // fields that aren't same as old data
newFields := make(map[string]struct{}, len(newData)) // fields that are not _user or _time
if origData == nil {
for field := range newData {
newlySet[field] = struct{}{}
Expand All @@ -1231,6 +1232,9 @@ func updateJSON(origData, newData NeuronJSON, user string, conditionals []string
if origValue, found := origData[field]; !found || !reflect.DeepEqual(value, origValue) {
newlySet[field] = struct{}{}
}
if !strings.HasSuffix(field, "_user") && !strings.HasSuffix(field, "_time") {
newFields[field] = struct{}{}
}
}

// carry forward any fields not being modified if replace option is not set
Expand Down Expand Up @@ -1269,6 +1273,24 @@ func updateJSON(origData, newData NeuronJSON, user string, conditionals []string
newData[field+"_time"] = timeStr
}
}
if replace { // keep _user and _time fields for unchanged fields
for field := range newFields {
if _, foundUser := newData[field+"_user"]; !foundUser {
oldUser, found := origData[field+"_user"]
if !found {
oldUser = user
}
newData[field+"_user"] = oldUser
}
if _, foundTime := newData[field+"_time"]; !foundTime {
oldTime, found := origData[field+"_time"]
if !found {
oldTime = timeStr
}
newData[field+"_time"] = oldTime
}
}
}
}

func (d *Data) storeAndUpdate(ctx *datastore.VersionedCtx, keyStr string, newData NeuronJSON, conditionals []string, replace bool) error {
Expand Down
24 changes: 18 additions & 6 deletions datatype/neuronjson/neuronjson_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -837,10 +837,11 @@ func TestKeyvalueRequests(t *testing.T) {

// Check if we replace or keep old _user and _time while changing and reusing value
value3modA := fmt.Sprintf(`{"a string": "goo modified", "a string_user": "bill", "a string_time": "%s", "a number_user": "donald", "a 2nd list": [26]}`, responseJSON["a string_time"])
key3modAreq := fmt.Sprintf("%snode/%s/%s/key/%s?u=frank&show=user", server.WebAPIPath, uuid, name, key3)
key3modAreq := fmt.Sprintf("%snode/%s/%s/key/%s?u=frank&show=all", server.WebAPIPath, uuid, name, key3)
server.TestHTTP(t, "POST", key3modAreq, strings.NewReader(value3modA))

returnValue = server.TestHTTP(t, "GET", key3modAreq, nil)
dvid.Infof("After 1st mod got back: %s\n", string(returnValue))

expectedValue = []byte(fmt.Sprintf(`{"a string": "goo modified", "a string_user": "bill", "a string_time": "%s", "a number": 3456, "a list": [23], "a 2nd list": [26]}`, responseJSON["a string_time"]))
if err := json.Unmarshal(expectedValue, &expectedJSON); err != nil {
Expand All @@ -861,6 +862,7 @@ func TestKeyvalueRequests(t *testing.T) {
if value, found := responseJSON["a number_user"]; !found || value != "donald" {
t.Fatalf("Bad response: %v\n", responseJSON)
}
old_time := responseJSON["a number_time"]
if value, found := responseJSON["a list"]; !found || !reflect.DeepEqual(value, []int64{23}) {
t.Fatalf("Bad response (type %s): %v\n", reflect.TypeOf(value), responseJSON)
}
Expand All @@ -874,12 +876,13 @@ func TestKeyvalueRequests(t *testing.T) {
t.Fatalf("Bad response: %v\n", responseJSON)
}

// Check if keys are re-POSTed using replace=true.
value3mod = `{"a string": "goo replaced", "only list": [1, 2]}`
key3modreq = fmt.Sprintf("%snode/%s/%s/key/%s?u=sandra&show=user&replace=true", server.WebAPIPath, uuid, name, key3)
// Check if keys are re-POSTed using replace=true. Don't modify "a number" field.
value3mod = `{"a string": "goo replaced", "only list": [1, 2], "a number": 3456}`
key3modreq = fmt.Sprintf("%snode/%s/%s/key/%s?u=sandra&show=all&replace=true", server.WebAPIPath, uuid, name, key3)
server.TestHTTP(t, "POST", key3modreq, strings.NewReader(value3mod))

returnValue = server.TestHTTP(t, "GET", key3modreq, nil)
dvid.Infof("After replace=true, got back: %s\n", string(returnValue))

expectedValue = []byte(value3mod)
if err := json.Unmarshal(expectedValue, &expectedJSON); err != nil {
Expand All @@ -888,8 +891,14 @@ func TestKeyvalueRequests(t *testing.T) {
if err := json.Unmarshal(returnValue, &responseJSON); err != nil {
t.Fatalf("Couldn't unmarshal response JSON: %s\n", string(returnValue))
}
if len(responseJSON) != 4 {
t.Fatalf("Expected only 4 fields in response after replace, got: %v\n", responseJSON)
if value, found := responseJSON["a number"]; !found || !reflect.DeepEqual(value, uint64(3456)) {
t.Fatalf("Bad response for number (type %s): %v\n", reflect.TypeOf(value), responseJSON)
}
if value, found := responseJSON["a number_user"]; !found || value != "donald" {
t.Fatalf("Bad response: %v\n", responseJSON)
}
if value, found := responseJSON["a number_time"]; !found || value != old_time {
t.Fatalf("Bad response: %v\n", responseJSON)
}
if value, found := responseJSON["a string"]; !found || value != "goo replaced" {
t.Fatalf("Bad response: %v\n", responseJSON)
Expand All @@ -903,6 +912,9 @@ func TestKeyvalueRequests(t *testing.T) {
if value, found := responseJSON["only list_user"]; !found || value != "sandra" {
t.Fatalf("Bad response: %v\n", responseJSON)
}
if len(responseJSON) != 9 {
t.Fatalf("Expected 9 fields in response after replace, got: %v\n", responseJSON)
}
}

var testData = []struct {
Expand Down

0 comments on commit f8438c8

Please sign in to comment.