diff --git a/readme.md b/readme.md index a4e6e87..0e55bde 100644 --- a/readme.md +++ b/readme.md @@ -301,6 +301,43 @@ Would result in the following value of `s`: } ``` +Assume you update the phone number and country code entries for the same object. And then you want to access the old history, i.e., the past values before the update. + +```java +d.setString("$.phones[0].number", "66666"); +d.setString("$.phones[0].country", "CA"); +String s = d.getPrettyPrintJson(); +``` + +Would result in the following value of `s`: + +```json +{ + "first_name": "Deepak", + "phones": [ + { + "type": "Home", + "number": "66666", + "country": "CA" + }, + { + "type": "Cell", + "number": "333333", + "country": "USA" + } + ] +} +``` + +And to access the previous values of phone and country code, you can use the following: + +```java +Map pathPreviousValue = d.getPathHistory(); +String previousNumber = pathPreviousValue.get("$.phones[0].number").toString(); // will return 222222 +String previousCountry = pathPreviousValue.get("$.phones[0].country").toString(); // will return USA +``` + + Note that a new element has been created in the array. The same effect could also have been achieved by the following: ```java diff --git a/src/main/java/com/americanexpress/unify/jdocs/CONSTS_JDOCS.java b/src/main/java/com/americanexpress/unify/jdocs/CONSTS_JDOCS.java index 0762342..2f4f0b1 100644 --- a/src/main/java/com/americanexpress/unify/jdocs/CONSTS_JDOCS.java +++ b/src/main/java/com/americanexpress/unify/jdocs/CONSTS_JDOCS.java @@ -44,6 +44,10 @@ private FORMAT_FIELDS() { public static final String MAX_VALUE = "max_value"; public static final String MIN_DATE = "min_date"; public static final String MAX_DATE = "max_date"; + public static final String CREATED_PATH="created_path"; + public static final String PATH_DOES_NOT_EXIST="path_does_not_exist"; + public static final String MODIFIED_PATH="modified_path"; + } diff --git a/src/main/java/com/americanexpress/unify/jdocs/Document.java b/src/main/java/com/americanexpress/unify/jdocs/Document.java index 532f182..eae11f2 100644 --- a/src/main/java/com/americanexpress/unify/jdocs/Document.java +++ b/src/main/java/com/americanexpress/unify/jdocs/Document.java @@ -18,6 +18,7 @@ import java.math.BigDecimal; import java.util.List; +import java.util.Map; /* * @author Deepak Arora @@ -31,6 +32,19 @@ public interface Document { */ boolean isTyped(); + /** + * + * @returns the modified values of the document + */ + Map getPathHistory(); + + /** + * Returns the status of the modified value of the document + */ + + + String getPathStatus(String path); + /** * Returns the type of the document */ diff --git a/src/main/java/com/americanexpress/unify/jdocs/JDocument.java b/src/main/java/com/americanexpress/unify/jdocs/JDocument.java index 6f5f32b..27af7fe 100644 --- a/src/main/java/com/americanexpress/unify/jdocs/JDocument.java +++ b/src/main/java/com/americanexpress/unify/jdocs/JDocument.java @@ -43,6 +43,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.americanexpress.unify.jdocs.CONSTS_JDOCS.FORMAT_FIELDS.CREATED_PATH; +import static com.americanexpress.unify.jdocs.CONSTS_JDOCS.FORMAT_FIELDS.MODIFIED_PATH; +import static com.americanexpress.unify.jdocs.CONSTS_JDOCS.FORMAT_FIELDS.PATH_DOES_NOT_EXIST; import static com.americanexpress.unify.jdocs.DataType.DATE; import static com.americanexpress.unify.jdocs.DataType.STRING; @@ -66,6 +69,9 @@ public class JDocument implements Document { private static CONSTS_JDOCS.VALIDATION_TYPE defaultValidationType = CONSTS_JDOCS.VALIDATION_TYPE.ALL_DATA_PATHS; + //to keep track of Modified values + private Map pathHistoricalVal =new HashMap<>(); + // type of the document private String docType = ""; @@ -248,6 +254,30 @@ private void init(String type, String json, CONSTS_JDOCS.VALIDATION_TYPE validat } } + /** + get a map of modified values + */ + @Override + public Map getPathHistory(){ + return pathHistoricalVal; + } + + + @Override + public String getPathStatus(String path){ + + if (!pathHistoricalVal.containsKey(path)) { + return PATH_DOES_NOT_EXIST; + } + if (pathHistoricalVal.get(path) == null) { + return CREATED_PATH; + } + // it is modified + return MODIFIED_PATH; + + + } + /** * Gets the type of the document. * @@ -1506,9 +1536,32 @@ protected final void setValue(String path, List tokenList, Object value, if (token.isArray()) { // set the value in the array ArrayToken at = (ArrayToken)token; + ArrayNode arrayNode= (ArrayNode) node; + + int index=at.getFilter().getIndex(); + if(index>=arrayNode.size()){ + pathHistoricalVal.put(tokenPath+"["+index+"]", null);// new element added + } + else{ + JsonNode oldValue = arrayNode.get(index); + if (!oldValue.equals(objectMapper.valueToTree(value))) {// only track if value changes + pathHistoricalVal.put(tokenPath + "[" + index + "]", oldValue.isTextual() ? oldValue.asText() : oldValue.deepCopy()); + } + } setArrayIndexValue((ArrayNode)node, at.getFilter().getIndex(), value); } else { + + //record the previous value for leaf node + ObjectNode objectNode = (ObjectNode)node; + JsonNode oldValue = objectNode.get(field); + // record addition or update + if (oldValue==null) { + pathHistoricalVal.put(tokenPath, null);// new element added + } + else if (oldValue != null && !oldValue.equals(objectMapper.valueToTree(value))) { + pathHistoricalVal.put(tokenPath , oldValue.isTextual() ? oldValue.asText() : oldValue.deepCopy()); + } setLeafNode((ObjectNode)node, field, value); } diff --git a/src/main/java/com/americanexpress/unify/jdocs/ReadOnlyDocument.java b/src/main/java/com/americanexpress/unify/jdocs/ReadOnlyDocument.java index cfc2fea..c22e57a 100644 --- a/src/main/java/com/americanexpress/unify/jdocs/ReadOnlyDocument.java +++ b/src/main/java/com/americanexpress/unify/jdocs/ReadOnlyDocument.java @@ -19,6 +19,7 @@ import java.math.BigDecimal; import java.util.List; +import java.util.Map; /* * @author Deepak Arora @@ -46,6 +47,16 @@ public boolean isTyped() { return d.isTyped(); } + @Override + public Map getPathHistory() { + return d.getPathHistory(); + } + + @Override + public String getPathStatus(String path) { + return d.getPathStatus(path); + } + @Override public String getType() { return d.getType(); diff --git a/src/test/java/com/americanexpress/unify/jdocs/DocumentTest.java b/src/test/java/com/americanexpress/unify/jdocs/DocumentTest.java index cb40f5e..5d21b98 100644 --- a/src/test/java/com/americanexpress/unify/jdocs/DocumentTest.java +++ b/src/test/java/com/americanexpress/unify/jdocs/DocumentTest.java @@ -22,6 +22,7 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; +import java.util.Map; import static com.americanexpress.unify.jdocs.CONSTS_JDOCS.VALIDATION_TYPE.*; import static org.junit.jupiter.api.Assertions.*; @@ -112,6 +113,32 @@ void testMisc() { b = d.isArray("$.house[0].family"); assertEquals(false, b); + d=new JDocument(); + String pathName="$.members[0].first_name"; + String pathLastName="$.members[0].last_name"; + d.setString(pathName, "Nilu"); + d.setString(pathLastName, "Did"); + + // Verify the value is set correctly + assertTrue(d.pathExists("$.members[0].first_name", "Nilu")); + // modify the first name, and store the last value the pathHistoricalVal map + d.setString(pathName,"Joerge"); + //check status of last name path , which is just created + assertEquals(d.getPathStatus(pathLastName),CONSTS_JDOCS.FORMAT_FIELDS.CREATED_PATH); + d.setString(pathLastName,"JJ"); + + //check status of last name path , which is modified now + assertEquals(d.getPathStatus(pathLastName),CONSTS_JDOCS.FORMAT_FIELDS.MODIFIED_PATH); + d.setString(pathName,"Sam"); + d.setString(pathLastName,"S"); + + Map pathPreviousValue = d.getPathHistory(); + // access the historical value (the previous value) of the first name and verify it + assertTrue(pathPreviousValue.containsKey(pathName)); // Ensure the path is tracked + assertEquals("Joerge", pathPreviousValue.get(pathName).toString()); + + + d = new JDocument("[]"); d.setString("$.[0].name", "Deepak"); d.setString("$.[1].name", "Nitika");