details;
+
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/OrderAggregate.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/OrderAggregate.java
new file mode 100644
index 000000000..0cd8381dc
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/OrderAggregate.java
@@ -0,0 +1,25 @@
+package org.tests.model.basic;
+
+import io.ebean.annotation.Sql;
+
+import javax.persistence.Entity;
+import javax.persistence.OneToOne;
+
+/**
+ * An example of an Aggregate object.
+ *
+ * Note the @Sql indicates to Ebean that this bean is not based on a table but
+ * instead uses RawSql.
+ *
+ */
+@Entity
+@Sql
+public class OrderAggregate {
+
+ @OneToOne
+ Order order;
+ Double maxAmount;
+ Double totalAmount;
+ Long totalItems;
+
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/OrderDetail.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/OrderDetail.java
new file mode 100644
index 000000000..4404c88b8
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/OrderDetail.java
@@ -0,0 +1,28 @@
+package org.tests.model.basic;
+
+import io.ebean.annotation.Cache;
+import io.ebean.annotation.DocEmbedded;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Version;
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+@Entity
+@Table(name = "o_order_detail")
+public class OrderDetail extends BasicDomain {
+
+ @ManyToOne(optional = false)
+ Order order;
+
+ Integer orderQty;
+ Integer shipQty;
+ Double unitPrice;
+
+ @ManyToOne
+ Product product;
+
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/Product.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/Product.java
new file mode 100644
index 000000000..ac1e86380
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/Product.java
@@ -0,0 +1,11 @@
+package org.tests.model.basic;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "o_product")
+public class Product extends BasicDomain {
+ String sku;
+ String name;
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/BaseTestCase.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/BaseTestCase.java
new file mode 100644
index 000000000..39427f5da
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/BaseTestCase.java
@@ -0,0 +1,21 @@
+package org.tests.model.basic.test;
+
+import io.ebean.DB;
+import io.ebean.annotation.Platform;
+import io.ebeaninternal.api.SpiEbeanServer;
+
+public class BaseTestCase {
+
+ protected boolean isSqlServer() {
+ return Platform.SQLSERVER == platform();
+ }
+
+ protected Platform platform() {
+ return spiEbeanServer().getDatabasePlatform().getPlatform().base();
+ }
+
+ protected SpiEbeanServer spiEbeanServer() {
+ return (SpiEbeanServer) DB.getDefault();
+ }
+
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/NamedDtoQueryTest.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/NamedDtoQueryTest.java
new file mode 100644
index 000000000..86e40ee86
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/NamedDtoQueryTest.java
@@ -0,0 +1,28 @@
+package org.tests.model.basic.test;
+
+import io.ebean.DB;
+import org.junit.Test;
+import org.tests.model.basic.CustDto;
+import org.tests.model.basic.Customer;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class NamedDtoQueryTest {
+
+ @Test
+ public void dto_findList_constructorMatch() {
+
+ Customer customer = new Customer();
+ customer.setName("dtoTest");
+ customer.save();
+
+ final List list = DB.getDefault().createNamedDtoQuery(CustDto.class, "findByName")
+ .setParameter("dtoT%")
+ .findList();
+
+ assertThat(list).hasSize(1);
+ assertThat(list.get(0).getId()).isEqualTo(customer.getId());
+ }
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/NamedLocalAndExternalTest.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/NamedLocalAndExternalTest.java
new file mode 100644
index 000000000..61776857f
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/NamedLocalAndExternalTest.java
@@ -0,0 +1,68 @@
+package org.tests.model.basic.test;
+
+import io.ebean.DB;
+import io.ebean.Database;
+import io.ebean.Query;
+import org.junit.Test;
+import org.tests.model.basic.Customer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Named queries both local to the entity bean and via external xml source.
+ */
+public class NamedLocalAndExternalTest extends BaseTestCase {
+
+ private Database server() {
+ return DB.getDefault();
+ }
+
+ private String sqlOf(Query> query) {
+ return query.getGeneratedSql();
+ }
+
+ @Test
+ public void namedQuery() {
+
+ Query name = server().createNamedQuery(Customer.class, "name");
+ name.findList();
+
+ assertThat(sqlOf(name)).contains("select t0.id, t0.name from o_customer t0 order by t0.name");
+ }
+
+ @Test
+ public void namedQuery_withStatus() {
+
+ Query name = server().createNamedQuery(Customer.class, "withStatus");
+ name.order().clear().asc("status");
+ name.findList();
+
+ assertThat(sqlOf(name)).contains("select t0.id, t0.name, t0.status from o_customer t0 order by t0.status");
+ }
+
+ @Test
+ public void namedQuery_fromXml() {
+
+ Query query = server()
+ .createNamedQuery(Customer.class, "withContactsById")
+ .setParameter("id", 1);
+
+ query.setUseCache(false);
+ query.findOne();
+
+ assertThat(sqlOf(query)).contains("from o_customer t0 left join contact t1 on t1.customer_id = t0.id ");
+ }
+
+ @Test
+ public void namedQuery_fromCustomXmlLocations() {
+
+ Query query = server()
+ .createNamedQuery(Customer.class, "withContactsById2")
+ .setParameter("id", 1);
+
+ query.setUseCache(false);
+ query.findOne();
+
+ assertThat(sqlOf(query)).contains("from o_customer t0 left join contact t1 on t1.customer_id = t0.id ");
+ }
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/OrderAggregateNamedRawSqlTest.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/OrderAggregateNamedRawSqlTest.java
new file mode 100644
index 000000000..578c4a6d3
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/OrderAggregateNamedRawSqlTest.java
@@ -0,0 +1,59 @@
+package org.tests.model.basic.test;
+
+import io.ebean.DB;
+import io.ebean.Query;
+import org.assertj.core.api.AbstractCharSequenceAssert;
+import org.junit.Test;
+import org.tests.model.basic.OrderAggregate;
+
+public class OrderAggregateNamedRawSqlTest {
+
+ protected AbstractCharSequenceAssert, String> assertSql(Query> query) {
+ return org.assertj.core.api.Assertions.assertThat(query.getGeneratedSql());
+ }
+
+ @Test
+ public void testDefaultNamedRawSql() {
+ Query query = DB.find(OrderAggregate.class);
+ query.findList();
+
+ assertSql(query).contains("count(*) as total_items, sum(order_qty*unit_price) as total_amount");
+ }
+
+ @Test
+ public void testNamedRawSql() {
+ Query query = DB.createNamedQuery(OrderAggregate.class, "withMax");
+ query.findList();
+ assertSql(query).contains("count(*) as total_items, sum(order_qty*unit_price) as total_amount, max(order_qty*unit_price) as maxAmount from o_order_detail");
+ }
+
+ @Test
+ public void testNamedRawSql_with_extraPredicates() {
+
+ Query query = DB.createNamedQuery(OrderAggregate.class, "withMax");
+ query
+ .where().gt("order.id", 1)
+ .having().gt("totalItems", 1)
+ .order().desc("totalAmount")
+ .findList();
+
+ assertSql(query).contains("count(*) as total_items, sum(order_qty*unit_price) as total_amount, max(order_qty*unit_price) as maxAmount from o_order_detail");
+ assertSql(query).contains("from o_order_detail where order_id > ? group by order_id having count(*) > ? order by sum(order_qty*unit_price) desc");
+ }
+
+ @Test
+ public void testNamedRawSql_with_param() {
+
+ Query query = DB.createNamedQuery(OrderAggregate.class, "withParam");
+ query
+ .setParameter("minId", 2)
+ .where().isNotNull("order.id")
+ .having().lt("totalAmount", 100)
+ .order().desc("totalAmount")
+ .setMaxRows(10)
+ .findList();
+
+ assertSql(query).contains("count(*) as totalItems, sum(order_qty*unit_price) as totalAmount, max(order_qty*unit_price) as maxAmount from o_order_detail");
+ assertSql(query).contains("from o_order_detail where id > ? and order_id is not null group by order_id having sum(order_qty*unit_price) < ? order by sum(order_qty*unit_price) desc");
+ }
+}
diff --git a/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/RawSqlOrmQueryTest.java b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/RawSqlOrmQueryTest.java
new file mode 100644
index 000000000..96667bb22
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/java/org/tests/model/basic/test/RawSqlOrmQueryTest.java
@@ -0,0 +1,77 @@
+package org.tests.model.basic.test;
+
+import io.ebean.DB;
+import io.ebean.Query;
+import org.junit.Test;
+import org.tests.model.basic.Order;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RawSqlOrmQueryTest extends BaseTestCase {
+
+ //@IgnorePlatform(Platform.ORACLE)
+ @Test
+ public void testNamed() {
+
+ Query query = DB.getDefault().createNamedQuery(Order.class, "myRawTest");
+ query.setParameter("orderStatus", Order.Status.NEW);
+ query.setMaxRows(10);
+ List list = query.findList();
+ for (Order order : list) {
+ order.getWhenCreated();
+ }
+
+ String sql = query.getGeneratedSql();
+ if (isSqlServer()) {
+ assertThat(sql).contains("select top 10 o.id,");
+ } else {
+ assertThat(sql).contains("select o.id,");
+ assertThat(sql).contains("limit 10");
+ }
+ assertThat(sql).contains("o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line1, a.line2, a.city from o_order o");
+ assertThat(sql).contains("join o_customer c on o.customer_id = c.id ");
+ assertThat(sql).contains("where o.status = ? order by c.name, c.id");
+ }
+
+ //@IgnorePlatform(Platform.ORACLE)
+ @Test
+ public void testNamed_fromCustomXmlLocations() {
+
+ //ResetBasicData.reset();
+
+ Query query = DB.getDefault().createNamedQuery(Order.class, "myRawTest2");
+ query.setParameter("orderStatus", Order.Status.NEW);
+ query.setMaxRows(10);
+ List list = query.findList();
+ for (Order order : list) {
+ order.getWhenModified();
+ }
+
+ String sql = query.getGeneratedSql();
+ if (isSqlServer()) {
+ assertThat(sql).contains("select top 10 o.id,");
+ } else {
+ assertThat(sql).contains("select o.id,");
+ assertThat(sql).contains("limit 10");
+ }
+ assertThat(sql).contains("o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line1, a.line2, a.city from o_order o");
+ assertThat(sql).contains("join o_customer c on o.customer_id = c.id ");
+ assertThat(sql).contains("where o.status = ? order by c.name, c.id");
+ }
+
+ //@IgnorePlatform(Platform.ORACLE)
+ @Test
+ public void testNamed_fromCustomXmlLocations_withComments() {
+
+ //ResetBasicData.reset();
+
+ Query query = DB.getDefault().createNamedQuery(Order.class, "myRawTest3");
+ query.setMaxRows(10);
+
+ query.findList();
+ assertThat(query.getGeneratedSql()).contains("-- must be unparsed raw sql");
+ }
+
+}
diff --git a/ebean-externalmapping-xml/src/test/resources/application-test.properties b/ebean-externalmapping-xml/src/test/resources/application-test.properties
new file mode 100644
index 000000000..15ecf2d07
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/resources/application-test.properties
@@ -0,0 +1,17 @@
+ebean.mappingLocations=classpath:/ebean-xml-mappings
+
+ebean.ddl.generate=true
+ebean.ddl.run=true
+datasource.default=h2
+
+datasource.db.username=sa
+datasource.db.password=
+datasource.db.url=jdbc:h2:mem:xm
+
+datasource.h2.username=sa
+datasource.h2.password=
+datasource.h2.url=jdbc:h2:mem:xm
+
+datasource.pg.username=sa
+datasource.pg.password=
+datasource.pg.url=jdbc:h2:mem:xm
diff --git a/ebean-core/src/test/resources/ebean-xml-mappings/CustomerMapping.xml b/ebean-externalmapping-xml/src/test/resources/ebean-xml-mappings/CustomerMapping.xml
similarity index 66%
rename from ebean-core/src/test/resources/ebean-xml-mappings/CustomerMapping.xml
rename to ebean-externalmapping-xml/src/test/resources/ebean-xml-mappings/CustomerMapping.xml
index b55626fbf..1d26d6e5f 100644
--- a/ebean-core/src/test/resources/ebean-xml-mappings/CustomerMapping.xml
+++ b/ebean-externalmapping-xml/src/test/resources/ebean-xml-mappings/CustomerMapping.xml
@@ -11,4 +11,12 @@
+
+
+
+ select id, name from o_customer where name like ?
+
+
+
+
diff --git a/ebean-core/src/test/resources/ebean-xml-mappings/OrderMapping.xml b/ebean-externalmapping-xml/src/test/resources/ebean-xml-mappings/OrderMapping.xml
similarity index 91%
rename from ebean-core/src/test/resources/ebean-xml-mappings/OrderMapping.xml
rename to ebean-externalmapping-xml/src/test/resources/ebean-xml-mappings/OrderMapping.xml
index 59e8ddc52..a4745ccbc 100644
--- a/ebean-core/src/test/resources/ebean-xml-mappings/OrderMapping.xml
+++ b/ebean-externalmapping-xml/src/test/resources/ebean-xml-mappings/OrderMapping.xml
@@ -6,9 +6,9 @@
- select o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line_1, a.line_2, a.city
+ select o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line1, a.line2, a.city
from o_order o
- join o_customer c on o.kcustomer_id = c.id
+ join o_customer c on o.customer_id = c.id
join o_address a on c.billing_address_id = a.id
where o.status = :orderStatus
order by c.name, c.id
diff --git a/ebean-core/src/test/resources/ebean.xml b/ebean-externalmapping-xml/src/test/resources/ebean.xml
similarity index 95%
rename from ebean-core/src/test/resources/ebean.xml
rename to ebean-externalmapping-xml/src/test/resources/ebean.xml
index 10cdbf265..8fe679451 100644
--- a/ebean-core/src/test/resources/ebean.xml
+++ b/ebean-externalmapping-xml/src/test/resources/ebean.xml
@@ -36,9 +36,9 @@
- select o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line_1, a.line_2, a.city
+ select o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line1, a.line2, a.city
from o_order o
- join o_customer c on o.kcustomer_id = c.id
+ join o_customer c on o.customer_id = c.id
join o_address a on c.billing_address_id = a.id
where o.status = :orderStatus
order by c.name, c.id
diff --git a/ebean-externalmapping-xml/src/test/resources/logback-test.xml b/ebean-externalmapping-xml/src/test/resources/logback-test.xml
new file mode 100644
index 000000000..8d97efd24
--- /dev/null
+++ b/ebean-externalmapping-xml/src/test/resources/logback-test.xml
@@ -0,0 +1,21 @@
+
+
+
+ TRACE
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ebean-core/src/test/resources/test-ebean.xml b/ebean-externalmapping-xml/src/test/resources/test-ebean.xml
similarity index 100%
rename from ebean-core/src/test/resources/test-ebean.xml
rename to ebean-externalmapping-xml/src/test/resources/test-ebean.xml
diff --git a/pom.xml b/pom.xml
index 7d9511325..3a2bfb23c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,6 +34,13 @@
test
+
+ org.avaje.composite
+ junit
+ 1.1
+ test
+
+
@@ -47,6 +54,8 @@
querybean-generator
kotlin-querybean-generator
ebean-querybean
+ ebean-externalmapping-api
+ ebean-externalmapping-xml