public DataNode getDataNode() throws BigDBException { if (contributions.isEmpty()) return DataNode.NULL; // FIXME: There's probably a cleaner way to do this instead of // hard-coding the different types of logical data nodes here. switch (schemaNode.getNodeType()) { case CONTAINER: return LogicalContainerDataNode.fromContributions( schemaNode, contributions, includeDefaultValues); case LIST_ELEMENT: return LogicalListElementDataNode.fromContributions( schemaNode, contributions, includeDefaultValues); case LIST: ListSchemaNode listSchemaNode = (ListSchemaNode) schemaNode; if (listSchemaNode.isKeyedList()) { return LogicalKeyedListDataNode.fromContributions( schemaNode, contributions, includeDefaultValues); } else { Set<String> dataSources = schemaNode.getDataSources(); assert dataSources.size() == 1; String dataSourceName = dataSources.iterator().next(); Contribution contribution = contributions.get(dataSourceName); return LogicalUnkeyedListDataNode.fromContribution( schemaNode, contribution, includeDefaultValues); } default: // There currently aren't logical wrappers for the physical // leaf or leaf list data nodes since they always come from a single // data source and don't need logical aggregation. Also, default // value substitution is done in the LogicalDictionaryDataNode. // When we support mutation operations it might make sense to have // logical wrappers for leaf and leaf list nodes so that we have // access to the schema node throw new BigDBException("Invalid logical data node type"); } }
@Override protected Iterable<DataNodeWithPath> queryWithPath( SchemaNode schemaNode, LocationPathExpression queryPath, boolean expandTrailingList, boolean includeEmptyContainers) throws BigDBException { // The path must always contain the step for this node, so it's an // error if it's called with an empty path. if (queryPath.size() == 0) { throw new BigDBException("Query path argument cannot be empty"); } ListSchemaNode listSchemaNode = (ListSchemaNode) schemaNode; SchemaNode listElementSchemaNode = listSchemaNode.getListElementSchemaNode(); LocationPathExpression remainingQueryPath = queryPath.subpath(1); Step listStep = queryPath.getStep(0); String listName = listStep.getName(); List<DataNodeWithPath> result = new ArrayList<DataNodeWithPath>(); if (expandTrailingList || (queryPath.size() > 1)) { // Currently we only support querying the entire unkeyed list or else // a single index list element, so check to see if there's a // non-negative integer index predicate. int index = listStep.getIndexPredicate(); Iterable<DataNode> listElementDataNodes; boolean singleListElement = (index >= 0); if (singleListElement) { DataNode elementDataNode = getChild(index); listElementDataNodes = Collections.singletonList(elementDataNode); } else { listElementDataNodes = this; index = 0; } // Iterate over the range of list elements set above for (DataNode listElementDataNode : listElementDataNodes) { Step listElementStep = DataNodeUtilities.getListElementStep(listName, index++); if (singleListElement || matchesPredicates( listElementSchemaNode, listElementDataNode, listElementStep, listStep)) { LocationPathExpression listElementPath = LocationPathExpression.ofStep(listElementStep); if (queryPath.size() > 1) { // There are more steps in the query path, so we need to // call // query recursively LocationPathExpression listElementQueryPath = LocationPathExpression.ofPaths(listElementPath, remainingQueryPath); Iterable<DataNodeWithPath> listElementResult = listElementDataNode.queryWithPath( listElementSchemaNode, listElementQueryPath, expandTrailingList); // Add the results to the results for the overall list for (DataNodeWithPath dataNodeWithPath : listElementResult) { result.add(dataNodeWithPath); } } else { // No more query path to evaluate, so just make a // DataNodeWithPath // for the list element data node. DataNodeWithPath dataNodeWithPath = new DataNodeWithPathImpl(listElementPath, listElementDataNode); result.add(dataNodeWithPath); } } } } else { // Return the list node itself rather than expanding to the // matching list elements. DataNodeWithPath dataNodeWithPath = new DataNodeWithPathImpl(LocationPathExpression.ofStep(Step.of(listName)), this); result.add(dataNodeWithPath); } return result; }