Files
ebean/ebean-querybean/src/test/java/org/querytest/QOrderTest.java
T
Rob Bygrave 79fd689e9a Add support for raw SQL SubQuery expressions IN,EQ,NE,GT,GE,LT,LE,EXISTS,Not IN, Not EXISTS
For these expressions the SQL SubQuery is not parsed by ebean and
just used as is.
2023-03-24 22:38:52 +13:00

534 lines
15 KiB
Java

package org.querytest;
import io.ebean.DB;
import io.ebean.FetchGroup;
import io.ebean.Query;
import io.ebean.test.LoggedSql;
import org.example.domain.Customer;
import org.example.domain.Order;
import org.example.domain.OrderDetail;
import org.example.domain.otherpackage.PhoneNumber;
import org.example.domain.query.QCustomer;
import org.example.domain.query.QOrder;
import org.example.domain.query.QOrderDetail;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.List;
import static io.ebean.StdOperators.*;
import static org.assertj.core.api.Assertions.assertThat;
public class QOrderTest {
private static final QCustomer cu = QCustomer.alias();
private static final QOrder or = QOrder.alias();
private static final FetchGroup<Customer> fgC = QCustomer.forFetchGroup()
.select(cu.name, cu.phoneNumber)
.buildFetchGroup();
private static final FetchGroup<Order> fgNested1 = QOrder.forFetchGroup()
.select(or.status, or.shipDate)
.customer.fetch(fgC)
.buildFetchGroup();
private static final FetchGroup<Order> fgNested_fetchQuery = QOrder.forFetchGroup()
.select(or.status)
.customer.fetchQuery(fgC)
.buildFetchGroup();
private static final FetchGroup<Order> fgNested_fetchCache = QOrder.forFetchGroup()
.select(or.status)
.customer.fetchCache(fgC)
.buildFetchGroup();
private static final FetchGroup<Order> fg = QOrder.forFetchGroup()
.select(or.status, or.shipDate)
.customer.fetchCache(cu.name, cu.status, cu.registered, cu.comments)
.buildFetchGroup();
private static final FetchGroup<Order> fg2 = QOrder.forFetchGroup()
.select(or.status)
.customer.fetch(cu.name)
.buildFetchGroup();
private static Order order;
private static Customer customer;
@BeforeAll
public static void before() {
setupData();
}
@AfterAll
public static void after() {
DB.delete(order);
DB.delete(customer);
}
@Test
public void fetchCache() {
new QOrder()
.status.eq(Order.Status.NEW)
.customer.fetchCache(cu.name, cu.registered)
.findList();
new QOrder()
.status.eq(Order.Status.NEW)
.customer.fetchCache()
.findList();
}
@Test
public void viaFetchGraph() {
DB.getDefault();
LoggedSql.start();
new QOrder()
.status.eq(Order.Status.NEW)
.select(fg)
.findList();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t0.customer_id from o_order t0 where");
}
@Test
public void viaFetchGraph_withJoin() {
DB.getDefault();
LoggedSql.start();
new QOrder()
.status.eq(Order.Status.NEW)
.select(fg2)
.findList();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id where");
}
@Test
public void viaFetchGraph_withNested() {
DB.getDefault();
LoggedSql.start();
new QOrder()
.status.eq(Order.Status.NEW)
.select(fgNested1)
.findList();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t1.id, t1.name, t1.phone_number from o_order t0 join be_customer t1 on t1.id = t0.customer_id where");
}
@Test
public void viaFetchGraph_withNested_fetchQuery() {
DB.getDefault();
LoggedSql.start();
final Order found = new QOrder()
.id.eq(order.getId())
.select(fgNested_fetchQuery)
.findOne();
final List<String> sql = LoggedSql.stop();
// assert fetching customer via fetchQuery
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?");
assertThat(sql.get(1)).contains("select t0.id, t0.name, t0.phone_number from be_customer t0 where t0.id = ?");
assertThat(found.getCustomer().getPhoneNumber().getMsisdn()).isEqualTo("Ph1");
}
@Test
public void viaFetchGraph_withNested_fetchCache() {
DB.getDefault();
// ensure the customer is loaded in the L2 cache
new QCustomer().id.eq(customer.getId()).findOne();
LoggedSql.start();
final Order found = new QOrder()
.id.eq(order.getId())
.select(fgNested_fetchCache) // cache hit for customer
.findOne();
final String msisdn = found.getCustomer().getPhoneNumber().getMsisdn();
assertThat(msisdn).isEqualTo("Ph1");
final List<String> sql = LoggedSql.stop();
// assert we only hit DB for order
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?");
}
@Test
public void select_partial() {
DB.getDefault();
LoggedSql.start();
final QOrder o = QOrder.alias();
new QOrder()
.select(o.status, o.orderDate)
.findList();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date from o_order t0");
}
@Test
public void fetch_partial() {
DB.getDefault();
LoggedSql.start();
final QOrder o = QOrder.alias();
final QCustomer c = QCustomer.alias();
new QOrder()
.select(o.status)
.customer.fetch(c.email, c.name)
.findList();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.email, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id");
}
@Test
public void updateQuery() {
LoggedSql.start();
new QOrder()
.status.eq(Order.Status.COMPLETE)
.orderDate.gt(new java.sql.Date(System.currentTimeMillis()))
.asUpdate()
.set(QOrder.Alias.version, 56L)
.setNull(QOrder.Alias.orderDate)
.update();
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("update o_order set version=?, order_date=null where status = ? and order_date > ?");
}
@Test
public void stdExpression_iLikeConcatCoalesce() {
QOrder o = QOrder.alias();
// LOWER(CONCAT(COALESCE(a.name, ""), ":", a.description)) LIKE LOWER(:param)
Query<Order> query = new QOrder()
.select(o.id, o.status)
.add(ilike(concat(coalesce(o.customer.name, "Not-Provided"), ":", o.status), "rob"))
.query();
query.findList();
String generatedSql = query.getGeneratedSql();
assertThat(generatedSql).contains("where lower(concat(coalesce(t1.name,'Not-Provided'),':',t0.status)) like ? escape''");
}
@Test
public void stdExpression_gtCoalesce() {
QOrder o = QOrder.alias();
Query<Order> query = new QOrder()
.select(o.id, o.status)
.or()
.add(gt(coalesce(o.customer.version, 0), 42L))
.id.lt(12)
.endOr()
.query();
query.findList();
String sql = query.getGeneratedSql();
assertThat(sql).contains(" where (coalesce(t1.version,0) > ? or t0.id < ?)");
assertThat(sql).isEqualTo("select t0.id, t0.status from o_order t0 join be_customer t1 on t1.id = t0.customer_id where (coalesce(t1.version,0) > ? or t0.id < ?)");
}
@Test
void geSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.geSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(o.order_date) as foo from o_order o)");
}
@Test
void gtSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.gtSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered > (select max(o.order_date) as foo from o_order o)");
}
@Test
void leSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.leSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(o.order_date) as foo from o_order o)");
}
@Test
void ltSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.ltSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(o.order_date) as foo from o_order o)");
}
@Test
void eqSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.eqSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(o.order_date) as foo from o_order o)");
}
@Test
void neSqlSubQuery() {
var c = QCustomer.alias();
var query = new QCustomer()
.select(c.id)
.registered.neSubQuery("select max(o.order_date) as foo from o_order o")
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(o.order_date) as foo from o_order o)");
}
@Test
void geSubQuery() {
var c = QCustomer.alias();
var o = QOrder.alias();
var subQuery = new QOrder()
.select(max(o.orderDate))
.query();
var query = new QCustomer()
.select(c.id)
.registered.ge(subQuery)
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(t0.order_date) from o_order t0)");
}
@Test
void gtSubQuery() {
var subQuery = new QOrder()
.select(sum(QOrder.Alias.version))
.query();
var query = new QCustomer()
.select(QCustomer.Alias.id)
.version.gt(subQuery)
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.version > (select sum(t0.version) from o_order t0)");
}
@Test
void leSubQuery() {
var subQuery = new QOrder()
.select(max(QOrder.Alias.orderDate))
.query();
var query = new QCustomer()
.select(QCustomer.Alias.id)
.registered.le(subQuery)
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(t0.order_date) from o_order t0)");
}
@Test
void ltSubQuery() {
var subQuery = new QOrder()
.select(max(QOrder.Alias.orderDate))
.query();
var query = new QCustomer()
.select(QCustomer.Alias.id)
.registered.lt(subQuery)
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(t0.order_date) from o_order t0)");
}
@Test
void eqSubQuery() {
var subQuery = new QOrder()
.select("max(orderDate)")
.query();
var query = new QCustomer()
.select(QCustomer.Alias.id)
.registered.eq(subQuery)
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(t0.order_date) from o_order t0)");
}
@Test
void neSubQuery() {
var subQuery = new QOrder()
.select(max(QOrder.Alias.orderDate))
.query();
var query = new QCustomer()
.select(QCustomer.Alias.id)
.registered.ne(subQuery)
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(t0.order_date) from o_order t0)");
}
@Test
void propertyCompare() {
Query<Order> query = new QOrder()
.orderDate.lt(QOrder.Alias.shipDate) // have to be the exact same type, in this case java.sql.Date
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains(" from o_order t0 where t0.order_date < t0.ship_date");
}
@Test
void subQueryExists() {
Query<OrderDetail> subQuery = new QOrderDetail()
.alias("od")
.orderQty.gt(10)
.id.eq(QOrder.Alias.details.id)
//.where().raw("details.id = od.id")
.query();
Query<Order> query = new QOrder()
.exists(subQuery)
.orderBy("orderDate").query();
query.findList();
// select distinct t0.id, t0.status, t0.order_date, t0.ship_date, t0.version, t0.when_created, t0.when_updated, t0.customer_id, t0.shipping_address_id, t0.order_date
// from o_order t0
// left join o_order_detail t1 on t1.order_id = t0.id
// where exists (select 1 from o_order_detail od where od.order_qty > ? and od.id = t1.id) order by t0.order_date
String sql = query.getGeneratedSql();
assertThat(sql).contains(" exists (select 1 from o_order_detail od where od.order_qty > ? and od.id = t1.id)");
}
@Test
void sqlSubQueryExists() {
Query<Order> query = new QOrder()
.exists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10)
.orderBy("orderDate").query();
query.findList();
String sql = query.getGeneratedSql();
assertThat(sql).contains(" exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id) order by t0.order_date");
}
@Test
void sqlSubQueryNotExists() {
Query<Order> query = new QOrder()
.notExists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10)
.orderBy("orderDate").query();
query.findList();
String sql = query.getGeneratedSql();
assertThat(sql).contains(" not exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id) order by t0.order_date");
}
@Test
void subQueryNotExists() {
Query<OrderDetail> subQuery = new QOrderDetail()
.alias("od")
.orderQty.gt(10)
.id.eq(QOrder.Alias.details.id)
//.where().raw("details.id = od.id")
.query();
Query<Order> query = new QOrder()
.notExists(subQuery)
.orderBy("orderDate")
.query();
query.findList();
// select distinct t0.id, t0.status, t0.order_date, t0.ship_date, t0.version, t0.when_created, t0.when_updated, t0.customer_id, t0.shipping_address_id, t0.order_date
// from o_order t0
// left join o_order_detail t1 on t1.order_id = t0.id
// where not exists (select 1 from o_order_detail od where od.order_qty > ? and od.id = t1.id) order by t0.order_date
String sql = query.getGeneratedSql();
assertThat(sql).contains(" not exists (select 1 from o_order_detail od where od.order_qty > ? and od.id = t1.id)");
}
private static void setupData() {
customer = new Customer();
customer.name = "Fred";
customer.phoneNumber = new PhoneNumber("Ph1");
customer.save();
order = new Order();
order.setCustomer(customer);
order.save();
}
}