Merge "veyron/services/store/memstore/query: Implement the "hidden" keyword."
diff --git a/services/store/memstore/query/eval.go b/services/store/memstore/query/eval.go
index 48e991a..73fa455 100644
--- a/services/store/memstore/query/eval.go
+++ b/services/store/memstore/query/eval.go
@@ -63,6 +63,12 @@
results <-chan *store.QueryResult
}
+// hiddenResult wraps a value so evalIterator can elide it from
+// storage.QueryResult.Fields that are sent to the client.
+type hiddenResult struct {
+ value vdlutil.Any
+}
+
// Next implements the QueryStream method.
func (it *evalIterator) Next() bool {
it.mu.Lock()
@@ -102,17 +108,23 @@
// the result.Fields key to append them in reverse alphabetical order.
// We use reverse alphabetical order because it.results is a stack--
// we want to process them in alphabetical order.
+//
+// enqueueNestedChannels also removes any result.Fields that are of the
+// type hiddenResult.
func (it *evalIterator) enqueueNestedChannels(result *store.QueryResult) {
if result.Fields == nil {
return
}
var nestingKeys []string
for key, val := range result.Fields {
- // TODO(kash): If a stored value happens to be a store.QueryResult, we'll
- // do the wrong thing here. Once we store vom.Value instead of raw structs,
- // this should not be a problem.
- if _, ok := val.(chan *store.QueryResult); ok {
+ switch val.(type) {
+ case chan *store.QueryResult:
nestingKeys = append(nestingKeys, key)
+ case hiddenResult:
+ // If a field is "hidden", the value will be wrapped in the type
+ // hiddenResult to make it possible for evalIterator to elide it
+ // from the results sent to the client.
+ delete(result.Fields, key)
}
}
// Figure out the store.NestedResult values based on alphabetical order of
@@ -504,7 +516,6 @@
alias string
// hidden is true if this field in the selection should not be included
// in the results sent to the client.
- // TODO(kash): hidden is currently ignored during evaluation.
hidden bool
}
@@ -579,6 +590,12 @@
}
if a.alias != "" {
+ if a.hidden {
+ // If a field is "hidden", the value will be wrapped in the type
+ // hiddenResult to make it possible for evalIterator to elide it
+ // from the results sent to the client.
+ value = hiddenResult{value}
+ }
sel.Fields[a.alias] = value
} else {
sel.Fields[a.evaluator.name()] = value
@@ -1021,6 +1038,12 @@
e.name, result.Name, mapKeys(result.Fields))
return nil
}
+ // If a field is "hidden", the value will be wrapped in the type
+ // hiddenResult to make it possible for evalIterator to elide it
+ // from the results sent to the client.
+ if v, ok := val.(hiddenResult); ok {
+ return v.value
+ }
return val
}
fullpath := naming.Join(result.Name, e.name)
diff --git a/services/store/memstore/query/eval_test.go b/services/store/memstore/query/eval_test.go
index 2985265..6367a9f 100644
--- a/services/store/memstore/query/eval_test.go
+++ b/services/store/memstore/query/eval_test.go
@@ -358,6 +358,19 @@
},
},
{
+ "", "'teams/cardinals' | {Name as myname hidden, Location as myloc} | ? myname == 'cardinals'",
+ []*store.QueryResult{
+ &store.QueryResult{
+ 0,
+ "teams/cardinals",
+ map[string]vdlutil.Any{
+ "myloc": "CA",
+ },
+ nil,
+ },
+ },
+ },
+ {
"",
"'teams/*' | type team | {" +
" Name as myname," +
@@ -434,7 +447,7 @@
break
}
if got, want := result, test.expectedResults[i]; !reflect.DeepEqual(got, want) {
- t.Errorf("query: %s;\nGOT %s\nWANT %s", test.query, got, want)
+ t.Errorf("query: %s;\nGOT %v\nWANT %v", test.query, got, want)
}
i++
}