mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1221 - ENH: Add a merge(bean) and merge(bean, paths)
This commit is contained in:
@@ -11,6 +11,7 @@ import io.ebean.Filter;
|
||||
import io.ebean.FutureIds;
|
||||
import io.ebean.FutureList;
|
||||
import io.ebean.FutureRowCount;
|
||||
import io.ebean.MergeOptions;
|
||||
import io.ebean.PagedList;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
@@ -236,6 +237,16 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(Object bean, MergeOptions options) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(Object bean, MergeOptions options, Transaction transaction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<Version<T>> findVersions(Query<T> query, Transaction transaction) {
|
||||
return null;
|
||||
@@ -551,6 +562,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Class<?> beanType, Object beanId, Transaction transaction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(Class<T> beanType, Object uid) {
|
||||
return null;
|
||||
|
||||
@@ -6,8 +6,8 @@ import io.ebeaninternal.server.core.PersistRequest;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanManager;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@@ -17,8 +17,7 @@ public class BatchedBeanHolderTest extends BaseTestCase {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Test
|
||||
public void testAppend() throws Exception {
|
||||
|
||||
public void testAppend() {
|
||||
|
||||
TDSpiEbeanServer server = new TDSpiEbeanServer("foo");
|
||||
|
||||
@@ -32,13 +31,13 @@ public class BatchedBeanHolderTest extends BaseTestCase {
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.setUpdtime(new Timestamp(System.currentTimeMillis()));
|
||||
PersistRequestBean req1 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, false, false);
|
||||
PersistRequestBean req1 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, 0);
|
||||
|
||||
|
||||
int size = holder.append(req1);
|
||||
assertEquals(1, size);
|
||||
|
||||
PersistRequestBean req2 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, false, false);
|
||||
PersistRequestBean req2 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, 0);
|
||||
size = holder.append(req2);
|
||||
assertEquals(0, size);
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package io.ebeaninternal.server.persist;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class FlagsTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
int state = 0;
|
||||
|
||||
state = Flags.setPublish(state);
|
||||
assertThat(Flags.isSet(state, Flags.PUBLISH)).isTrue();
|
||||
|
||||
state = Flags.setMerge(state);
|
||||
state = Flags.setInsert(state);
|
||||
assertThat(Flags.isSet(state, Flags.PUBLISH)).isTrue();
|
||||
assertThat(Flags.isSet(state, Flags.MERGE)).isTrue();
|
||||
assertThat(Flags.isSet(state, Flags.INSERT)).isTrue();
|
||||
|
||||
state = Flags.unsetPublish(state);
|
||||
assertThat(Flags.isSet(state, Flags.PUBLISH)).isFalse();
|
||||
assertThat(Flags.isSet(state, Flags.MERGE)).isTrue();
|
||||
assertThat(Flags.isSet(state, Flags.INSERT)).isTrue();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPublishOrMerge() {
|
||||
|
||||
assertThat(Flags.isPublishOrMerge(0)).isFalse();
|
||||
assertThat(Flags.isPublishOrMerge(Flags.INSERT)).isFalse();
|
||||
|
||||
assertThat(Flags.isPublishOrMerge(Flags.PUBLISH)).isTrue();
|
||||
assertThat(Flags.isPublishOrMerge(Flags.MERGE)).isTrue();
|
||||
|
||||
int mergePublish = Flags.setMerge(Flags.setPublish(0));
|
||||
assertThat(Flags.isPublishOrMerge(mergePublish)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class MAddress extends MBase {
|
||||
|
||||
private String street;
|
||||
|
||||
private String city;
|
||||
|
||||
public MAddress(String street, String city) {
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Version;
|
||||
import java.util.UUID;
|
||||
|
||||
@MappedSuperclass
|
||||
public class MBase {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@Version
|
||||
private long version;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class MContact extends MBase {
|
||||
|
||||
String email;
|
||||
String firstName;
|
||||
String lastName;
|
||||
|
||||
@ManyToOne
|
||||
MCustomer customer;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "contact")
|
||||
List<MContactMessage> messages;
|
||||
|
||||
public MContact(String email, String firstName, String lastName) {
|
||||
this.email = email;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public MCustomer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(MCustomer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public List<MContactMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public void setMessages(List<MContactMessage> messages) {
|
||||
this.messages = messages;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class MContactMessage extends MBase {
|
||||
|
||||
private String title;
|
||||
|
||||
private String subject;
|
||||
|
||||
private String notes;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
private MContact contact;
|
||||
|
||||
public MContactMessage(String title, String subject) {
|
||||
this.title = title;
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public void setSubject(String subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
public MContact getContact() {
|
||||
return contact;
|
||||
}
|
||||
|
||||
public void setContact(MContact contact) {
|
||||
this.contact = contact;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class MCustomer extends MBase {
|
||||
|
||||
private String name;
|
||||
|
||||
private String notes;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "customer")
|
||||
private List<MContact> contacts;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL)
|
||||
private MAddress shippingAddress;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL)
|
||||
private MAddress billingAddress;
|
||||
|
||||
public MCustomer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public List<MContact> getContacts() {
|
||||
return contacts;
|
||||
}
|
||||
|
||||
public void setContacts(List<MContact> contacts) {
|
||||
this.contacts = contacts;
|
||||
}
|
||||
|
||||
public MAddress getShippingAddress() {
|
||||
return shippingAddress;
|
||||
}
|
||||
|
||||
public void setShippingAddress(MAddress shippingAddress) {
|
||||
this.shippingAddress = shippingAddress;
|
||||
}
|
||||
|
||||
public MAddress getBillingAddress() {
|
||||
return billingAddress;
|
||||
}
|
||||
|
||||
public void setBillingAddress(MAddress billingAddress) {
|
||||
this.billingAddress = billingAddress;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.MergeOptions;
|
||||
import io.ebean.MergeOptionsBuilder;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.UUOne;
|
||||
import org.tests.model.basic.UUTwo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestMergeBasic extends BaseTestCase {
|
||||
|
||||
|
||||
private UUOne rebuildViaJson(UUOne input) {
|
||||
String asJson = Ebean.json().toJson(input);
|
||||
return Ebean.json().toBean(UUOne.class, asJson);
|
||||
}
|
||||
|
||||
private UUOne build() {
|
||||
UUOne uuOne = buildGraph();
|
||||
Ebean.save(uuOne);
|
||||
return rebuildViaJson(uuOne);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void with_setClientGeneratedIds_expect_noDifferenceWithToMany() {
|
||||
|
||||
UUOne one = build();
|
||||
|
||||
one.setDescription("mod");
|
||||
List<UUTwo> comments = one.getComments();
|
||||
comments.remove(0);
|
||||
comments.add(0, new UUTwo("twoMore", UUID.randomUUID()));
|
||||
comments.add(new UUTwo("twoExtra", UUID.randomUUID()));
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("comments")
|
||||
.setClientGeneratedIds()
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
Ebean.merge(one, options);
|
||||
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
// fetch the Ids ... used to identity inserts, updates and deletes
|
||||
assertThat(sql.get(0)).contains("select t0.id, t1.id from uuone t0 left join uutwo t1 on t1.master_id = t0.id where t0.id = ?");
|
||||
|
||||
// deletes of Ids that are no longer in the graph
|
||||
assertThat(sql.get(1)).contains("delete from uutwo where id=?");
|
||||
|
||||
// cascade persist ... master
|
||||
assertThat(sql.get(2)).contains("update uuone set name=?, description=?, version=? where id=? and version=?");
|
||||
|
||||
// persist children ...
|
||||
assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);");
|
||||
assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);");
|
||||
|
||||
assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?");
|
||||
assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?");
|
||||
assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
UUOne one = build();
|
||||
one.setDescription("mod");
|
||||
|
||||
List<UUTwo> comments = one.getComments();
|
||||
comments.remove(0);
|
||||
comments.add(0, new UUTwo("twoMore", UUID.randomUUID()));
|
||||
comments.add(new UUTwo("twoExtra", UUID.randomUUID()));
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("comments")
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
Ebean.merge(one, options);
|
||||
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
// fetch the Ids ... used to identity inserts, updates and deletes
|
||||
assertThat(sql.get(0)).contains("select t0.id, t1.id from uuone t0 left join uutwo t1 on t1.master_id = t0.id where t0.id = ?");
|
||||
|
||||
// deletes of Ids that are no longer in the graph
|
||||
assertThat(sql.get(1)).contains("delete from uutwo where id=?");
|
||||
|
||||
// cascade persist ... master
|
||||
assertThat(sql.get(2)).contains("update uuone set name=?, description=?, version=? where id=? and version=?");
|
||||
|
||||
// persist children ...
|
||||
assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);");
|
||||
assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);");
|
||||
|
||||
assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?");
|
||||
assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?");
|
||||
assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?");
|
||||
|
||||
}
|
||||
|
||||
private UUOne buildGraph() {
|
||||
UUOne one = new UUOne("one1", UUID.randomUUID());
|
||||
for (int i = 1; i < 5; i++) {
|
||||
UUTwo two = new UUTwo("two" + i, UUID.randomUUID());
|
||||
one.getComments().add(two);
|
||||
}
|
||||
return one;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
package org.tests.merge;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.MergeOptions;
|
||||
import io.ebean.MergeOptionsBuilder;
|
||||
import io.ebean.text.PathProperties;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestMergeCustomer extends BaseTestCase {
|
||||
|
||||
private Random random = new Random();
|
||||
|
||||
/**
|
||||
* So this is effectively the same as a stateless update.
|
||||
*/
|
||||
@Test
|
||||
public void customerOnly_expect_updateOnly() {
|
||||
|
||||
|
||||
MCustomer mCustomer = partial("cust1", "(id,name,version)");
|
||||
mCustomer.setName("NotCust1");
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder().build();
|
||||
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("update mcustomer set name=?, version=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerOnly_setClientGeneratedIds_expect_selectAndUpdate() {
|
||||
|
||||
|
||||
MCustomer mCustomer = partial("cust2", "(id,name,version)");
|
||||
mCustomer.setName("NotCust2");
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder().setClientGeneratedIds().build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server().merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select t0.id from mcustomer t0 where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("update mcustomer set name=?, version=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerWithAddresses_setClientGeneratedIds_expect_selectAndUpdate() {
|
||||
|
||||
|
||||
MCustomer mCustomer = partial("cust3", "(id,name,version,shippingAddress(*),billingAddress(*))");
|
||||
mCustomer.setName("NotCust3");
|
||||
mCustomer.getBillingAddress().setStreet("modBillStreet");
|
||||
mCustomer.getShippingAddress().setCity("modShipCity");
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("shippingAddress")
|
||||
.addPath("billingAddress")
|
||||
.setClientGeneratedIds()
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server().merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(4);
|
||||
assertThat(sql.get(0)).contains("select t0.id, t2.id, t1.id from mcustomer t0 left join maddress t2 on t2.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("update maddress set street=?, city=?, version=? where id=? and version=?");
|
||||
assertThat(sql.get(2)).contains("update maddress set street=?, city=?, version=? where id=? and version=?");
|
||||
assertThat(sql.get(3)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerWithAddresses_newAddress_setClientGeneratedIds_expect_insertAddress() {
|
||||
|
||||
|
||||
MCustomer mCustomer = partial("cust3", "(id,name,version,shippingAddress(*),billingAddress(*))");
|
||||
mCustomer.setName("NotCust3");
|
||||
|
||||
// new billing address - no Id value so must be insert
|
||||
mCustomer.setBillingAddress(new MAddress("Short", "Mid Wicket"));
|
||||
mCustomer.getShippingAddress().setCity("modShipCity");
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("shippingAddress")
|
||||
.addPath("billingAddress")
|
||||
.setClientGeneratedIds()
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server().merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(4);
|
||||
assertThat(sql.get(0)).contains("select t0.id, t2.id, t1.id from mcustomer t0 left join maddress t2 on t2.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("update maddress set street=?, city=?, version=? where id=? and version=?");
|
||||
assertThat(sql.get(2)).contains("insert into maddress (id, street, city, version) values (?,?,?,?);");
|
||||
assertThat(sql.get(3)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customerWithAddresses_newAddressWithId_setClientGeneratedIds_expect_additionalCheckForAddressInsert() {
|
||||
|
||||
|
||||
MCustomer mCustomer = partial("cust3", "(id,name,version,shippingAddress(*),billingAddress(*))");
|
||||
mCustomer.setName("NotCust3");
|
||||
|
||||
// new billing address - has Id value + setClientGeneratedIds ... so extra query to check
|
||||
MAddress mAddress = new MAddress("Short", "Mid Wicket");
|
||||
mAddress.setId(UUID.randomUUID());
|
||||
mCustomer.setBillingAddress(mAddress);
|
||||
mCustomer.getShippingAddress().setCity("modShipCity");
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("shippingAddress")
|
||||
.addPath("billingAddress")
|
||||
.setClientGeneratedIds() // As we are using clientIds ... we don't know if the new UUID is an insert or update without checking
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server().merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(5);
|
||||
assertThat(sql.get(0)).contains("select t0.id, t2.id, t1.id from mcustomer t0 left join maddress t2 on t2.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id where t0.id = ?");
|
||||
|
||||
// Additional check to see if the address with the unknown UUID is 'insert' or 'update'
|
||||
assertThat(sql.get(1)).contains("select t0.id from maddress t0 where t0.id = ?");
|
||||
|
||||
assertThat(sql.get(2)).contains("update maddress set street=?, city=?, version=? where id=? and version=?");
|
||||
assertThat(sql.get(3)).contains("insert into maddress (id, street, city, version) values (?,?,?,?);");
|
||||
assertThat(sql.get(4)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assocOne_onlineIsNull() {
|
||||
|
||||
MCustomer c = new MCustomer("Null Address");
|
||||
c.setBillingAddress(new MAddress("Cow corner", "Mid Wicket"));
|
||||
|
||||
Ebean.save(c);
|
||||
|
||||
MCustomer mCustomer = rebuildViaJson(c);
|
||||
|
||||
MAddress mAddress = new MAddress("Silly", "Mid Wicket");
|
||||
mAddress.setId(UUID.randomUUID());
|
||||
mCustomer.setShippingAddress(mAddress);
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("shippingAddress")
|
||||
.addPath("billingAddress")
|
||||
.setClientGeneratedIds()
|
||||
.build();
|
||||
|
||||
Ebean.merge(mCustomer, options);
|
||||
|
||||
}
|
||||
|
||||
private MCustomer rebuildViaJson(MCustomer input) {
|
||||
String asJson = Ebean.json().toJson(input);
|
||||
return Ebean.json().toBean(MCustomer.class, asJson);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenContacts_isNull_expect_deleteContacts() {
|
||||
|
||||
MCustomer mCustomer = partial("cust6", "(id,name,version,shippingAddress(id),billingAddress(id),contacts(*))");
|
||||
|
||||
// null contacts ... but in path so this means - delete all contacts
|
||||
mCustomer.setContacts(null);
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("contacts")
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
server().merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("select t0.id, t1.id from mcustomer t0 left join mcontact t1 on t1.customer_id = t0.id where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from mcontact_message where contact_id = ?");
|
||||
assertThat(sql.get(2)).contains("delete from mcontact where id=?");
|
||||
|
||||
assertThat(sql.get(13)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void whenContacts_isEmpty_expect_deleteContacts() {
|
||||
|
||||
MCustomer mCustomer = partial("cust6", "(id,name,version,shippingAddress(id),billingAddress(id),contacts(*))");
|
||||
|
||||
// empty contacts ... but in path so this means - delete all contacts
|
||||
mCustomer.setContacts(new ArrayList<>());
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("contacts")
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
server().merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("select t0.id, t1.id from mcustomer t0 left join mcontact t1 on t1.customer_id = t0.id where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from mcontact_message where contact_id = ?");
|
||||
assertThat(sql.get(2)).contains("delete from mcontact where id=?");
|
||||
|
||||
assertThat(sql.get(13)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenContacts_mixed_expect_deleteInsertUpdateContacts() {
|
||||
|
||||
MCustomer mCustomer = partial("cust6", "(id,name,version,shippingAddress(id),billingAddress(id),contacts(*))");
|
||||
List<MContact> contacts = mCustomer.getContacts();
|
||||
|
||||
MContact mContact = new MContact("z@a.com", "z", "zed");
|
||||
mContact.setId(UUID.randomUUID());
|
||||
|
||||
contacts.add(mContact);
|
||||
|
||||
contacts.get(0).setEmail("a@beta.com");
|
||||
contacts.get(1).setEmail("b@beta.com");
|
||||
contacts.remove(4);
|
||||
contacts.remove(2);
|
||||
|
||||
MContact mContactEnd = new MContact("z@z.com", "zx", "zedXtra");
|
||||
mContactEnd.setId(UUID.randomUUID());
|
||||
contacts.add(mContactEnd);
|
||||
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("contacts")
|
||||
.build();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
server().merge(mCustomer, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("select t0.id, t1.id from mcustomer t0 left join mcontact t1 on t1.customer_id = t0.id where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from mcontact_message where contact_id = ?");
|
||||
assertThat(sql.get(2)).contains("delete from mcontact where id=?");
|
||||
|
||||
assertThat(sql.get(5)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?");
|
||||
assertThat(sql.get(6)).contains("insert into mcontact");
|
||||
assertThat(sql.get(7)).contains("insert into mcontact");
|
||||
assertThat(sql.get(8)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?");
|
||||
assertThat(sql.get(11)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fullMonty() {
|
||||
|
||||
MCustomer cust1 = customer("monty1");
|
||||
|
||||
modify(cust1);
|
||||
|
||||
MergeOptions options = new MergeOptionsBuilder()
|
||||
.addPath("billingAddress")
|
||||
.addPath("shippingAddress")
|
||||
.addPath("contacts")
|
||||
.addPath("contacts.messages")
|
||||
.setClientGeneratedIds()
|
||||
.setDeletePermanent()
|
||||
.build();
|
||||
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
server().merge(cust1, options);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("select t0.id, t3.id, t1.id, t2.id from mcustomer t0 left join maddress t3 on t3.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id left join mcontact t2 on t2.customer_id = t0.id where t0.id = ?");
|
||||
if (isH2()) {
|
||||
// with nested OneToMany .. we need a second query to read the contact message ids
|
||||
assertThat(sql.get(1)).contains("select t0.contact_id, t0.id from mcontact_message t0 where (t0.contact_id) in (?, ?, ?, ?, ?, ?, ?, ?, ?, ? )");
|
||||
}
|
||||
assertThat(sql.get(2)).contains("delete from mcontact_message where contact_id = ?");
|
||||
assertThat(sql.get(3)).contains("delete from mcontact where id=?");
|
||||
assertThat(sql.get(4)).contains("delete from mcontact_message where contact_id = ?");
|
||||
assertThat(sql.get(5)).contains("delete from mcontact where id=?");
|
||||
|
||||
assertThat(sql.get(6)).contains("update maddress set street=?, city=?, version=? where id=? and version=?");
|
||||
assertThat(sql.get(7)).contains("update mcustomer set name=?, notes=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?");
|
||||
|
||||
assertThat(sql.get(8)).contains("insert into mcontact");
|
||||
assertThat(sql.get(9)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?");
|
||||
|
||||
assertThat(sql.get(13)).contains("update mcontact_message set title=?, subject=?, notes=?, version=?, contact_id=? where id=? and version=?");
|
||||
|
||||
}
|
||||
|
||||
private void modify(MCustomer cust) {
|
||||
|
||||
List<MContact> contacts = cust.getContacts();
|
||||
MContact mContact = new MContact("z@a.com", "z", "zed");
|
||||
mContact.setId(UUID.randomUUID());
|
||||
|
||||
contacts.add(mContact);
|
||||
|
||||
contacts.get(0).setEmail("a@beta.com");
|
||||
contacts.get(1).setEmail("b@beta.com");
|
||||
contacts.remove(4);
|
||||
contacts.remove(2);
|
||||
|
||||
cust.setName(cust.getName()+" modified");
|
||||
cust.getBillingAddress().setStreet("Short");
|
||||
|
||||
MAddress mAddress = new MAddress("Broken", "Dreams");
|
||||
mAddress.setId(UUID.randomUUID());
|
||||
cust.setShippingAddress(null);
|
||||
}
|
||||
|
||||
private MCustomer partial(String name, String fetchGraph) {
|
||||
MCustomer cust1 = buildCustomer(name);
|
||||
Ebean.save(cust1);
|
||||
|
||||
FetchPath fetchPath = PathProperties.parse(fetchGraph);
|
||||
String asJson = Ebean.json().toJson(cust1, fetchPath);
|
||||
return Ebean.json().toBean(MCustomer.class, asJson);
|
||||
}
|
||||
|
||||
private MCustomer customer(String name) {
|
||||
|
||||
MCustomer cust1 = buildCustomer(name);
|
||||
Ebean.save(cust1);
|
||||
|
||||
String asJson = Ebean.json().toJson(cust1);
|
||||
|
||||
return Ebean.json().toBean(MCustomer.class, asJson);
|
||||
}
|
||||
|
||||
private MCustomer buildCustomer(String name) {
|
||||
|
||||
MCustomer c = new MCustomer(name);
|
||||
c.setShippingAddress(new MAddress("Fleet st", "London"));
|
||||
c.setBillingAddress(new MAddress("Cow corner", "Mid Wicket"));
|
||||
|
||||
c.getContacts().add(addContact("a@a.com", "a", "alligator"));
|
||||
c.getContacts().add(addContact("b@a.com", "b", "beaver"));
|
||||
c.getContacts().add(addContact("c@a.com", "c", "crow"));
|
||||
c.getContacts().add(addContact("d@a.com", "d", "dog"));
|
||||
c.getContacts().add(addContact("e@a.com", "e", "ent"));
|
||||
c.getContacts().add(addContact("f@a.com", "f", "frog"));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private MContact addContact(String email, String first, String last) {
|
||||
MContact mContact = new MContact(email, first, last);
|
||||
int i = random.nextInt(2);
|
||||
for (int j = 0; j < i; j++) {
|
||||
mContact.getMessages().add(new MContactMessage(first+" "+i, last+" "+i));
|
||||
}
|
||||
return mContact;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -18,10 +19,22 @@ public class UUOne {
|
||||
|
||||
String name;
|
||||
|
||||
String description;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "master")
|
||||
List<UUTwo> comments;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
public UUOne() {
|
||||
}
|
||||
|
||||
public UUOne(String name, UUID id) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -38,6 +51,14 @@ public class UUOne {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public List<UUTwo> getComments() {
|
||||
return comments;
|
||||
}
|
||||
@@ -46,4 +67,11 @@ public class UUOne {
|
||||
this.comments = comments;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Version;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@@ -14,9 +15,22 @@ public class UUTwo {
|
||||
|
||||
String name;
|
||||
|
||||
String notes;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||
UUOne master;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
public UUTwo() {
|
||||
}
|
||||
|
||||
public UUTwo(String name, UUID id) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -33,6 +47,14 @@ public class UUTwo {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public UUOne getMaster() {
|
||||
return master;
|
||||
}
|
||||
@@ -41,4 +63,11 @@ public class UUTwo {
|
||||
this.master = master;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package org.tests.query.joins;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
import org.tests.model.basic.UUOne;
|
||||
import org.tests.model.basic.UUTwo;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.UUOne;
|
||||
import org.tests.model.basic.UUTwo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -58,11 +58,11 @@ public class TestDisjunctWhereOuterOnMany extends BaseTestCase {
|
||||
Assert.assertEquals(2, rowCount);
|
||||
|
||||
if (isPostgres()) {
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) ";
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name, t0.description, t0.version from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) ";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
|
||||
} else {
|
||||
String expectedSql = "select distinct t0.id, t0.name from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) ";
|
||||
String expectedSql = "select distinct t0.id, t0.name, t0.description, t0.version from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) ";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user