mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
v4 refactor for diff() support
This commit is contained in:
@@ -5,10 +5,10 @@ import java.util.Map;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.util.ValueUtil;
|
||||
|
||||
/**
|
||||
* Helper to perform a diff given two beans of the same type.
|
||||
@@ -19,49 +19,55 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
public class DiffHelp {
|
||||
|
||||
|
||||
/**
|
||||
* Return a map of the differences between a and b.
|
||||
* <p>
|
||||
* A and B must be of the same type. B can be null, in which case the
|
||||
* 'OldValues' of a is used to compare with (as B).
|
||||
* </p>
|
||||
* <p>
|
||||
* This intentionally does not include as OneToMany or ManyToMany
|
||||
* properties.
|
||||
* </p>
|
||||
*/
|
||||
/**
|
||||
* Return a map of the differences between a and b.
|
||||
* <p>
|
||||
* A and B must be of the same type. B can be null, in which case the 'dirty
|
||||
* values' of a is returned.
|
||||
* </p>
|
||||
* <p>
|
||||
* This intentionally does not include as OneToMany or ManyToMany properties.
|
||||
* </p>
|
||||
*/
|
||||
public Map<String, ValuePair> diff(Object a, Object b, BeanDescriptor<?> desc) {
|
||||
|
||||
Map<String, ValuePair> map = new LinkedHashMap<String, ValuePair>();
|
||||
if (a instanceof EntityBean == false) {
|
||||
throw new IllegalArgumentException("First bean expected to be an enhanced EntityBean? bean:"+a);
|
||||
}
|
||||
|
||||
if (b != null) {
|
||||
if (b instanceof EntityBean == false) {
|
||||
throw new IllegalArgumentException("Second bean expected to be an enhanced EntityBean? bean:"+b);
|
||||
}
|
||||
if (!a.getClass().isAssignableFrom(b.getClass())) {
|
||||
throw new IllegalArgumentException("Second bean not assignable to the first bean?");
|
||||
}
|
||||
}
|
||||
|
||||
if (b == null) {
|
||||
// get the old values from a
|
||||
if (a instanceof EntityBean) {
|
||||
return ((EntityBean) a)._ebean_getIntercept().getDirtyValues();
|
||||
}
|
||||
return map;
|
||||
return ((EntityBean) a)._ebean_getIntercept().getDirtyValues();
|
||||
}
|
||||
|
||||
Map<String, ValuePair> map = new LinkedHashMap<String, ValuePair>();
|
||||
diff(null, map, (EntityBean)a, (EntityBean)b, desc);
|
||||
return map;
|
||||
}
|
||||
|
||||
public void diff(String prefix, Map<String, ValuePair> map, EntityBean first, EntityBean sec, BeanDescriptor<?> desc) {
|
||||
|
||||
// if (b == null) {
|
||||
// return map;
|
||||
// }
|
||||
//
|
||||
// // check the simple properties
|
||||
// BeanProperty[] base = desc.propertiesBaseScalar();
|
||||
// for (int i = 0; i < base.length; i++) {
|
||||
//
|
||||
// Object aval = base[i].getValue(a);
|
||||
// Object bval = base[i].getValue(b);
|
||||
// if (!ValueUtil.areEqual(aval, bval)) {
|
||||
// map.put(base[i].getName(), new ValuePair(aval, bval));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// diffAssocOne(a, b, desc, map);
|
||||
// diffEmbedded(a, b, desc, map, oldValues);
|
||||
// check the simple properties
|
||||
BeanProperty[] base = desc.propertiesBaseScalar();
|
||||
for (int i = 0; i < base.length; i++) {
|
||||
Object aval = base[i].getValue(first);
|
||||
Object bval = base[i].getValue(sec);
|
||||
if (!ValueUtil.areEqual(aval, bval)) {
|
||||
String propName = (prefix == null) ? base[i].getName() : prefix + base[i].getName();
|
||||
map.put(propName, new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
diffAssocOne(prefix, first, sec, desc, map);
|
||||
diffEmbedded(prefix, first, sec, desc, map);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,75 +77,61 @@ public class DiffHelp {
|
||||
* determined to be different as is added to the map.
|
||||
* </p>
|
||||
*/
|
||||
private void diffEmbedded(Object a, Object b, BeanDescriptor<?> desc, Map<String, ValuePair> map, boolean oldValues) {
|
||||
private void diffEmbedded(String prefix, EntityBean a, EntityBean b, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
|
||||
|
||||
// BeanPropertyAssocOne<?>[] emb = desc.propertiesEmbedded();
|
||||
//
|
||||
// for (int i = 0; i < emb.length; i++) {
|
||||
// Object aval = emb[i].getValue(a);
|
||||
// Object bval = emb[i].getValue(b);
|
||||
// if (oldValues) {
|
||||
// bval = null;//FIXME ((EntityBean) bval)._ebean_getIntercept().getOldValues();
|
||||
// if (bval == null) {
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!isBothNull(aval, bval)) {
|
||||
// if (isDiffNull(aval, bval)) {
|
||||
// // one of the embedded beans is null
|
||||
// map.put(emb[i].getName(), new ValuePair(aval, bval));
|
||||
//
|
||||
// } else {
|
||||
// // if ANY of the properties in an Embedded bean is
|
||||
// // different, treat the whole bean as being different
|
||||
// BeanProperty[] props = emb[i].getProperties();
|
||||
// for (int j = 0; j < props.length; j++) {
|
||||
// Object aEmbPropVal = props[j].getValue(aval);
|
||||
// Object bEmbPropVal = props[j].getValue(bval);
|
||||
// if (!ValueUtil.areEqual(aEmbPropVal, bEmbPropVal)) {
|
||||
//
|
||||
// // if one prop is different put the
|
||||
// // embedded bean in the map
|
||||
// map.put(emb[i].getName(), new ValuePair(aval, bval));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
BeanPropertyAssocOne<?>[] emb = desc.propertiesEmbedded();
|
||||
|
||||
for (int i = 0; i < emb.length; i++) {
|
||||
EntityBean aval = (EntityBean)emb[i].getValue(a);
|
||||
EntityBean bval = (EntityBean)emb[i].getValue(b);
|
||||
|
||||
if (!isBothNull(aval, bval)) {
|
||||
String propName = (prefix == null) ? emb[i].getName() : prefix + emb[i].getName();
|
||||
if (isDiffNull(aval, bval)) {
|
||||
// one of the embedded beans is null
|
||||
map.put(propName, new ValuePair(aval, bval));
|
||||
|
||||
} else {
|
||||
// recursively diff into the embedded bean
|
||||
BeanDescriptor<?> embDesc = emb[i].getTargetDescriptor();
|
||||
diff(emb[i].getName()+".", map, aval, bval, embDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the properties are different by null OR if the id value is different,
|
||||
* then add the Assoc One bean to the map.
|
||||
*/
|
||||
private void diffAssocOne(Object a, Object b, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
|
||||
private void diffAssocOne(String prefix, EntityBean a, EntityBean b, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
|
||||
|
||||
BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
|
||||
|
||||
// for (int i = 0; i < ones.length; i++) {
|
||||
// Object aval = ones[i].getValue(a);
|
||||
// Object bval = ones[i].getValue(b);
|
||||
//
|
||||
// if (!isBothNull(aval, bval)) {
|
||||
// if (isDiffNull(aval, bval)) {
|
||||
// // one of them is/was null
|
||||
// map.put(ones[i].getName(), new ValuePair(aval, bval));
|
||||
//
|
||||
// } else {
|
||||
// // check to see if the Id properties
|
||||
// // are different
|
||||
// BeanDescriptor<?> oneDesc = ones[i].getTargetDescriptor();
|
||||
// Object aOneId = oneDesc.getId(aval);
|
||||
// Object bOneId = oneDesc.getId(bval);
|
||||
//
|
||||
// if (!ValueUtil.areEqual(aOneId, bOneId)) {
|
||||
// // the ids are different
|
||||
// map.put(ones[i].getName(), new ValuePair(aval, bval));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
for (int i = 0; i < ones.length; i++) {
|
||||
Object aval = ones[i].getValue(a);
|
||||
Object bval = ones[i].getValue(b);
|
||||
|
||||
if (!isBothNull(aval, bval)) {
|
||||
String propName = (prefix == null) ? ones[i].getName() : prefix + ones[i].getName();
|
||||
if (isDiffNull(aval, bval)) {
|
||||
// one of them is/was null
|
||||
map.put(propName, new ValuePair(aval, bval));
|
||||
|
||||
} else {
|
||||
// check to see if the Id properties
|
||||
// are different
|
||||
BeanDescriptor<?> oneDesc = ones[i].getTargetDescriptor();
|
||||
Object aOneId = oneDesc.getId((EntityBean)aval);
|
||||
Object bOneId = oneDesc.getId((EntityBean)bval);
|
||||
|
||||
if (!ValueUtil.areEqual(aOneId, bOneId)) {
|
||||
// the ids are different
|
||||
map.put(propName, new ValuePair(aval, bval));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBothNull(Object aval, Object bval) {
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.tests.model.basic.Customer;
|
||||
import com.avaje.tests.model.basic.Order;
|
||||
import com.avaje.tests.model.basic.Order.Status;
|
||||
|
||||
public class TestDiffHelpSimple extends BaseTestCase {
|
||||
|
||||
DiffHelp diffHelp = new DiffHelp();
|
||||
|
||||
long firstTime = System.currentTimeMillis()-10000;
|
||||
long secondTime = System.currentTimeMillis();
|
||||
|
||||
EbeanServer server;
|
||||
BeanDescriptor<Order> orderDesc;
|
||||
|
||||
public TestDiffHelpSimple() {
|
||||
server = Ebean.getServer(null);
|
||||
SpiEbeanServer spiServer = (SpiEbeanServer)server;
|
||||
orderDesc = spiServer.getBeanDescriptor(Order.class);
|
||||
}
|
||||
|
||||
private Order createBaseOrder(EbeanServer server) {
|
||||
Order order1 = new Order();
|
||||
order1.setId(12);
|
||||
order1.setCretime(new Timestamp(firstTime));
|
||||
order1.setCustomer(server.getReference(Customer.class, 1234));
|
||||
order1.setStatus(Status.NEW);
|
||||
order1.setShipDate(new Date(firstTime));
|
||||
order1.setOrderDate(new Date(firstTime));
|
||||
return order1;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicChanges() {
|
||||
|
||||
|
||||
Order order1 = createBaseOrder(server);
|
||||
|
||||
Order order2 = new Order();
|
||||
order2.setId(14);
|
||||
order2.setCretime(new Timestamp(secondTime));
|
||||
order2.setCustomer(server.getReference(Customer.class, 2133));
|
||||
order2.setStatus(Status.COMPLETE);
|
||||
order2.setShipDate(new Date(secondTime));
|
||||
order2.setOrderDate(new Date(secondTime));
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(order1, order2, orderDesc);
|
||||
|
||||
Assert.assertEquals(5, diff.size());
|
||||
|
||||
Set<String> keySet = diff.keySet();
|
||||
Assert.assertTrue(keySet.contains("cretime"));
|
||||
Assert.assertTrue(keySet.contains("status"));
|
||||
Assert.assertTrue(keySet.contains("shipDate"));
|
||||
Assert.assertTrue(keySet.contains("orderDate"));
|
||||
Assert.assertTrue(keySet.contains("customer"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIdIgnored() {
|
||||
|
||||
Order order1 = createBaseOrder(server);
|
||||
Order order2 = createBaseOrder(server);
|
||||
order2.setId(14);
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(order1, order2, orderDesc);
|
||||
|
||||
Assert.assertEquals(0, diff.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecondValueNull() {
|
||||
|
||||
Order order1 = createBaseOrder(server);
|
||||
|
||||
Order order2 = createBaseOrder(server);
|
||||
order2.setCustomer(server.getReference(Customer.class, 2133));
|
||||
order2.setStatus(Status.COMPLETE);
|
||||
order2.setShipDate(null);
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(order1, order2, orderDesc);
|
||||
|
||||
Assert.assertEquals(3, diff.size());
|
||||
|
||||
Set<String> keySet = diff.keySet();
|
||||
Assert.assertTrue(keySet.contains("status"));
|
||||
Assert.assertTrue(keySet.contains("customer"));
|
||||
Assert.assertTrue(keySet.contains("shipDate"));
|
||||
|
||||
ValuePair shipDatePair = diff.get("shipDate");
|
||||
Assert.assertEquals(order1.getShipDate(),shipDatePair.getNewValue());
|
||||
Assert.assertEquals(order2.getShipDate(),shipDatePair.getOldValue());
|
||||
Assert.assertNull(shipDatePair.getOldValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFirstValueNull() {
|
||||
|
||||
Order order1 = createBaseOrder(server);
|
||||
order1.setShipDate(null);
|
||||
|
||||
Order order2 = createBaseOrder(server);
|
||||
order2.setShipDate(new Date(secondTime));
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(order1, order2, orderDesc);
|
||||
|
||||
Assert.assertEquals(1, diff.size());
|
||||
Set<String> keySet = diff.keySet();
|
||||
Assert.assertTrue(keySet.contains("shipDate"));
|
||||
|
||||
ValuePair shipDatePair = diff.get("shipDate");
|
||||
Assert.assertEquals(order1.getShipDate(),shipDatePair.getNewValue());
|
||||
Assert.assertEquals(order2.getShipDate(),shipDatePair.getOldValue());
|
||||
Assert.assertNull(shipDatePair.getNewValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBothNull() {
|
||||
|
||||
Order order1 = createBaseOrder(server);
|
||||
order1.setShipDate(null);
|
||||
|
||||
Order order2 = createBaseOrder(server);
|
||||
order2.setShipDate(null);
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(order1, order2, orderDesc);
|
||||
|
||||
Assert.assertEquals(0, diff.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.tests.model.embedded.EMain;
|
||||
import com.avaje.tests.model.embedded.Eembeddable;
|
||||
|
||||
public class TestDiffHelpWithEmbedded extends BaseTestCase {
|
||||
|
||||
DiffHelp diffHelp = new DiffHelp();
|
||||
|
||||
EbeanServer server;
|
||||
BeanDescriptor<EMain> emainDesc;
|
||||
|
||||
public TestDiffHelpWithEmbedded() {
|
||||
server = Ebean.getServer(null);
|
||||
SpiEbeanServer spiServer = (SpiEbeanServer)server;
|
||||
emainDesc = spiServer.getBeanDescriptor(EMain.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeExistingEmbedded() {
|
||||
|
||||
EMain emain1 = createEMain();
|
||||
EMain emain2 = createEMain();
|
||||
|
||||
emain2.getEmbeddable().setDescription("baz");
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(emain1, emain2, emainDesc);
|
||||
Assert.assertEquals(1, diff.size());
|
||||
ValuePair valuePair = diff.get("embeddable.description");
|
||||
|
||||
Assert.assertNotNull(valuePair);
|
||||
Assert.assertEquals("bar",valuePair.getNewValue());
|
||||
Assert.assertEquals("baz",valuePair.getOldValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Same result as testChangeExistingEmbedded.
|
||||
*/
|
||||
@Test
|
||||
public void testSetViaNewEmbedded() {
|
||||
|
||||
EMain emain1 = createEMain();
|
||||
EMain emain2 = createEMain();
|
||||
|
||||
Eembeddable embeddable = new Eembeddable();
|
||||
embeddable.setDescription("baz");
|
||||
emain2.setEmbeddable(embeddable);
|
||||
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(emain1, emain2, emainDesc);
|
||||
Assert.assertEquals(1, diff.size());
|
||||
ValuePair valuePair = diff.get("embeddable.description");
|
||||
|
||||
Assert.assertNotNull(valuePair);
|
||||
Assert.assertEquals("bar",valuePair.getNewValue());
|
||||
Assert.assertEquals("baz",valuePair.getOldValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFirstEmbeddedIsNull() {
|
||||
|
||||
EMain emain1 = createEMain();
|
||||
emain1.setEmbeddable(null);
|
||||
EMain emain2 = createEMain();
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(emain1, emain2, emainDesc);
|
||||
Assert.assertEquals(1, diff.size());
|
||||
ValuePair valuePair = diff.get("embeddable");
|
||||
|
||||
Assert.assertNotNull(valuePair);
|
||||
Assert.assertNull(valuePair.getNewValue());
|
||||
Assert.assertTrue(valuePair.getOldValue() instanceof Eembeddable);
|
||||
Assert.assertEquals("bar",((Eembeddable)valuePair.getOldValue()).getDescription());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecondEmbeddedIsNull() {
|
||||
|
||||
EMain emain1 = createEMain();
|
||||
EMain emain2 = createEMain();
|
||||
emain2.setEmbeddable(null);
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(emain1, emain2, emainDesc);
|
||||
Assert.assertEquals(1, diff.size());
|
||||
ValuePair valuePair = diff.get("embeddable");
|
||||
|
||||
Assert.assertNotNull(valuePair);
|
||||
Assert.assertNull(valuePair.getOldValue());
|
||||
Assert.assertTrue(valuePair.getNewValue() instanceof Eembeddable);
|
||||
Assert.assertEquals("bar",((Eembeddable)valuePair.getNewValue()).getDescription());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBothEmbeddedIsNull() {
|
||||
|
||||
EMain emain1 = createEMain();
|
||||
emain1.setEmbeddable(null);
|
||||
EMain emain2 = createEMain();
|
||||
emain2.setEmbeddable(null);
|
||||
|
||||
Map<String, ValuePair> diff = diffHelp.diff(emain1, emain2, emainDesc);
|
||||
Assert.assertEquals(0, diff.size());
|
||||
}
|
||||
|
||||
private EMain createEMain() {
|
||||
|
||||
EMain emain = new EMain();
|
||||
emain.setName("foo");
|
||||
emain.setVersion(13l);
|
||||
|
||||
Eembeddable embeddable = new Eembeddable();
|
||||
embeddable.setDescription("bar");
|
||||
emain.setEmbeddable(embeddable);
|
||||
|
||||
return emain;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user