veyron/services/store/memstore/query: Better handling of slashes in selection.

Ensure that selection of sub-sub-fields works.  Also, allow for aliases to
contain slashes.  I don't see any reason why they can't, and it matches the
behavior of selection of sub-sub-fields.

Fix a bug in selection: if an intermediate result does not have a value
for one of the sub pipelines, use nil as the value instead of aborting
the query (without an error message).

Change-Id: I631f7f80b562096f725ef566b648fe711534b94a
diff --git a/services/store/memstore/query/eval.go b/services/store/memstore/query/eval.go
index 73fa455..783fbd8 100644
--- a/services/store/memstore/query/eval.go
+++ b/services/store/memstore/query/eval.go
@@ -501,7 +501,6 @@
 		pos:          p.Pos,
 	}
 	for i, a := range p.SubPipelines {
-		// TODO(kash): Protect against aliases that have slashes in them?
 		e.subpipelines[i] = alias{convertPipeline(a.Pipeline), a.Alias, a.Hidden}
 	}
 	return e
@@ -580,10 +579,9 @@
 			case <-c.abort:
 				return false
 			case sub, ok := <-out:
-				if !ok {
-					return false
+				if ok {
+					value = sub.Value
 				}
-				value = sub.Value
 			}
 		} else {
 			value = out
diff --git a/services/store/memstore/query/eval_test.go b/services/store/memstore/query/eval_test.go
index 6367a9f..65359b2 100644
--- a/services/store/memstore/query/eval_test.go
+++ b/services/store/memstore/query/eval_test.go
@@ -40,6 +40,9 @@
 	bettyID := put(t, sn, "/players/betty", player{"betty", 23})
 	bobID := put(t, sn, "/players/bob", player{"bob", 21})
 
+	put(t, sn, "/players/betty/bio", "")
+	put(t, sn, "/players/betty/bio/hometown", "Tampa")
+
 	put(t, sn, "/teams", "")
 	put(t, sn, "/teams/cardinals", team{"cardinals", "CA"})
 	put(t, sn, "/teams/sharks", team{"sharks", "NY"})
@@ -434,6 +437,31 @@
 				},
 			},
 		},
+		// Test for selection of a nested name ('bio/hometown').  Only betty has this
+		// nested name, so other players should get a nil value.
+		{
+			"", "'players/*' | type player | {Name, 'bio/hometown'} | ? Name == 'alfred' || Name == 'betty' | sort()",
+			[]*store.QueryResult{
+				&store.QueryResult{
+					0,
+					"players/alfred",
+					map[string]vdlutil.Any{
+						"Name":         "alfred",
+						"bio/hometown": nil,
+					},
+					nil,
+				},
+				&store.QueryResult{
+					0,
+					"players/betty",
+					map[string]vdlutil.Any{
+						"Name":         "betty",
+						"bio/hometown": "Tampa",
+					},
+					nil,
+				},
+			},
+		},
 	}
 	for _, test := range tests {
 		vlog.VI(1).Infof("Testing %s\n", test.query)