Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
None
Description
For example, if the key is a UUID, then a query like this won't show the results even though there is one:
gfsh>query --query="select key from /data.entries where value.id = '55e907b6-a1fe-42ea-90a2-6a5698e9b27c'" Result : true Limit : 100 Rows : 1
But a query like this will:
gfsh>query --query="select key,value from /data.entries where value.id = '55e907b6-a1fe-42ea-90a2-6a5698e9b27c'" Result : true Limit : 100 Rows : 1 key | value -------------------------------------- | --------------------------------------------------------------------------------------- "55e907b6-a1fe-42ea-90a2-6a5698e9b27c" | {"id":"55e907b6-a1fe-42ea-90a2-6a5698e9b27c","cusip":"AAPL","shares":22,"price":352.32}
Thats because of the way DataCommandResult.resolveObjectToColumns works.
private void resolveObjectToColumns(Map<String, String> columnData, Object value) { if (value instanceof PdxInstance) { resolvePdxToColumns(columnData, (PdxInstance) value); } else if (value instanceof Struct) { resolveStructToColumns(columnData, (StructImpl) value); } else { ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.valueToTree(value); node.fieldNames().forEachRemaining(field -> { ... columnData.put(field, mapper.writeValueAsString(node.get(field))); }); } }
The value in the first query is a UUID so the last else clause is invoked. In this case, a JsonNode is used to determine the columns. ObjectMapper.valueToTree converts a UUID to a TextNode. TextNodes have no fieldNames, and JsonNode.fieldNames returns an EmptyIterator by default:
public Iterator<String> fieldNames() { return ClassUtil.emptyIterator(); }
So, resolveObjectToColumns doesn't fill in columnData, which causes the DataCommandResult.buildTable in the locator to not add any rows to the table.
The value in the second query is a Struct so the second else clause is invoked. The resolveStructToColumns method does:
private void resolveStructToColumns(Map<String, String> columnData, StructImpl struct) { for (String field : struct.getFieldNames()) { columnData.put(field, valueToJson(struct.get(field))); } }
I'm not sure if there is a way to make ObjectMapper.valueToTree handle UUIDs differently, but they can easily be special-cased like PdxInstances and Structs:
} else if (value instanceof UUID) { columnData.put("uuid", valueToJson(value));
I'm not sure if this is the best solution, but it works. With this clause added, the query does:
gfsh>query --query="select key from /data.entries where value.id = '55e907b6-a1fe-42ea-90a2-6a5698e9b27c'" Result : true Limit : 100 Rows : 1 uuid -------------------------------------- "55e907b6-a1fe-42ea-90a2-6a5698e9b27c"
Attachments
Issue Links
- links to