/** * This method trims doc (1st arg) according to projected (2nd arg), which may have been modified * by projection. This method works in-place, meaning that the doc may be mutated. */ private static void trim(DataMap doc, DataMap projected) { DataMap toAddDoc = new DataMap(); Set<String> fields = doc.keySet(); List<String> toRemoveDoc = new ArrayList<String>(fields.size()); for (String f : fields) { Object v = doc.get(f); if (f.equals(PatchConstants.DELETE_COMMAND)) { DataList deletedFields = (DataList) v; DataList filteredDeleteFields = new DataList(); for (Object patchDeleteField : deletedFields) { if (projected.containsKey(patchDeleteField)) { filteredDeleteFields.add(patchDeleteField); } } toRemoveDoc.add(f); if (!filteredDeleteFields.isEmpty()) { toAddDoc.put(PatchConstants.DELETE_COMMAND, filteredDeleteFields); } } else if (f.equals(PatchConstants.SET_COMMAND)) { DataMap setFields = (DataMap) v; Set<String> setFieldNames = setFields.keySet(); List<String> toRemove = new LinkedList<String>(); DataMap filteredSetFields = new DataMap(); for (String setFieldName : setFieldNames) { if (projected.containsKey(setFieldName)) { filteredSetFields.put(setFieldName, projected.get(setFieldName)); } toRemove.add(setFieldName); } for (String fieldToRemove : toRemove) { setFields.remove(fieldToRemove); if (filteredSetFields.containsKey(fieldToRemove)) { setFields.put(fieldToRemove, filteredSetFields.get(fieldToRemove)); } } if (setFields.isEmpty()) { toRemoveDoc.add(f); } } else if (v instanceof DataMap) { if (projected.containsKey(f)) { trim((DataMap) v, (DataMap) projected.get(f)); } else { toRemoveDoc.add(f); } } } // apply changes to doc for (String f : toRemoveDoc) { doc.remove(f); } for (String f : toAddDoc.keySet()) { doc.put(f, toAddDoc.get(f)); } }
// TODO modify this method to accept a CollectionRequest as it's first parameter once our server // code has been // updated to work with the new representation of BatchUpdateRequests and // BatchPartialUpdateRequests. As of now // we are still converting to the old representation using // CollectionRequestUtil.convertToBatchRequest private static void checkInput( DataMap dataMap, Map<Long, Greeting> inputMap, Set<String> uriIds) { Assert.assertEquals(dataMap.size(), uriIds.size()); for (String key : dataMap.keySet()) { DataMap inputDM = dataMap.getDataMap(key); Greeting expectedGreeting = inputMap.get(Long.parseLong(key)); Assert.assertTrue(uriIds.contains(key)); Assert.assertTrue(inputDM.equals(expectedGreeting.data())); } }
/** * This method 'exposes' changes conveyed in the patch's meta commands to the main document. * Contents of $set commands are moved to the node which contains $set command. Names of removed * fields from $delete commands are moved to the nod which contains $delete command. The effect is * that patch will resemble structurally document which it is supposed to modify. This allows * application of projection to such patch to discover which changes relate to fields specified by * that projection. Examples: $delete: ['x', 'y', 'z'] => x: true, y: true, z: true $set: {x: 10, * y: {z: 'yeey'}, t: [10]} => x: 10, y: {z: 'yeey'}, t: [10] * * <p>This method works in-place, meaning that the doc may be mutated. */ private static void expose(DataMap doc) { Set<String> fields = doc.keySet(); DataMap toAdd = new DataMap(); for (String f : fields) { Object v = doc.get(f); if (f.equals(PatchConstants.DELETE_COMMAND)) { for (Object removedFields : (DataList) v) { toAdd.put((String) removedFields, true); } } else if (f.equals(PatchConstants.SET_COMMAND)) { toAdd.putAll((DataMap) v); } else if (v instanceof DataMap) { expose((DataMap) v); } } doc.putAll(toAdd); }