/*
* Copyright 2014 - 2017 Blazebit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.blazebit.persistence.criteria;
import com.blazebit.persistence.CriteriaBuilder;
import com.blazebit.persistence.criteria.impl.BlazeCriteria;
import com.blazebit.persistence.testsuite.AbstractCoreTest;
import com.blazebit.persistence.testsuite.entity.Document;
import com.blazebit.persistence.testsuite.entity.Document_;
import com.blazebit.persistence.testsuite.entity.Person;
import com.blazebit.persistence.testsuite.entity.Person_;
import com.googlecode.catchexception.CatchException;
import org.junit.Test;
import javax.persistence.criteria.JoinType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
*
* @author Christian Beikov
* @since 1.2.0
*/
public class SubqueryTest extends AbstractCoreTest {
@Test
public void correlateSelectJoin() {
BlazeCriteriaQuery<Long> cq = BlazeCriteria.get(em, cbf, Long.class);
BlazeCriteriaBuilder cb = cq.getCriteriaBuilder();
BlazeRoot<Document> root = cq.from(Document.class, "document");
BlazeSubquery<Person> subquery = cq.subquery(Person.class);
BlazeRoot<Document> correlatedRoot = subquery.correlate(root);
BlazeJoin<Document, Person> correlatedJoin = correlatedRoot.join(Document_.people, "subPerson");
subquery.select(correlatedJoin);
cq.where(cb.exists(subquery));
cq.select(root.get(Document_.id));
CriteriaBuilder<?> criteriaBuilder = cq.createCriteriaBuilder();
assertEquals("SELECT document.id FROM Document document WHERE EXISTS (SELECT subPerson FROM document.people subPerson)", criteriaBuilder.getQueryString());
assertEquals(1, subquery.getCorrelatedJoins().size());
assertEquals(root, correlatedRoot.getCorrelationParent());
assertTrue(correlatedRoot.isCorrelated());
assertFalse(root.isCorrelated());
}
@Test
public void correlateSelectLiteralWhereGroupByHaving() {
BlazeCriteriaQuery<Long> cq = BlazeCriteria.get(em, cbf, Long.class);
BlazeCriteriaBuilder cb = cq.getCriteriaBuilder();
BlazeRoot<Document> root = cq.from(Document.class, "document");
BlazeSubquery<Integer> subquery = cq.subquery(Integer.class);
BlazeRoot<Document> correlatedRoot = subquery.correlate(root);
BlazeJoin<Document, Person> correlatedJoin = correlatedRoot.join(Document_.owner, "subOwner");
subquery.select(cb.literal(1));
subquery.where(cb.equal(correlatedJoin.get(Person_.id), 0));
subquery.groupBy(correlatedJoin.get(Person_.age));
subquery.having(cb.greaterThan(cb.count(correlatedJoin.get(Person_.id)), 2L));
cq.where(cb.exists(subquery));
cq.select(root.get(Document_.id));
CriteriaBuilder<?> criteriaBuilder = cq.createCriteriaBuilder();
assertEquals("SELECT document.id FROM Document document WHERE EXISTS (SELECT 1 FROM document.owner subOwner WHERE subOwner.id = 0L GROUP BY subOwner.age, 1 HAVING COUNT(subOwner.id) > 2L)", criteriaBuilder.getQueryString());
assertEquals(1, subquery.getCorrelatedJoins().size());
assertEquals(root, correlatedRoot.getCorrelationParent());
assertTrue(correlatedRoot.isCorrelated());
assertFalse(root.isCorrelated());
}
@Test
public void correlateSelectRootWithJoinInSubquery() {
BlazeCriteriaQuery<Long> cq = BlazeCriteria.get(em, cbf, Long.class);
BlazeCriteriaBuilder cb = cq.getCriteriaBuilder();
BlazeRoot<Document> root = cq.from(Document.class, "document");
BlazeJoin<Document, Person> people = root.join(Document_.people, "person");
BlazeSubquery<Person> subquery = cq.subquery(Person.class);
BlazeJoin<Document, Person> correlatedRoot = subquery.correlate(people);
BlazeJoin<Person, Document> correlatedJoin = correlatedRoot.join(Person_.ownedDocuments, "subDoc");
subquery.select(correlatedRoot);
subquery.where(cb.greaterThan(correlatedJoin.get(Document_.age), 1L));
cq.where(cb.exists(subquery));
cq.select(root.get(Document_.id));
CriteriaBuilder<?> criteriaBuilder = cq.createCriteriaBuilder();
assertEquals("SELECT document.id FROM Document document JOIN document.people person WHERE EXISTS (SELECT person FROM person.ownedDocuments subDoc WHERE subDoc.age > 1L)", criteriaBuilder.getQueryString());
assertEquals(1, subquery.getCorrelatedJoins().size());
assertEquals(people, correlatedRoot.getCorrelationParent());
assertTrue(correlatedRoot.isCorrelated());
assertFalse(root.isCorrelated());
}
@Test
public void correlateWithoutSelect() {
BlazeCriteriaQuery<Long> cq = BlazeCriteria.get(em, cbf, Long.class);
BlazeCriteriaBuilder cb = cq.getCriteriaBuilder();
BlazeRoot<Document> root = cq.from(Document.class, "document");
BlazeSubquery<Person> subquery = cq.subquery(Person.class);
BlazeRoot<Document> correlatedRoot = subquery.correlate(root);
BlazeJoin<Document, Person> correlatedJoin = correlatedRoot.join(Document_.people, "subPerson");
cq.where(cb.exists(subquery));
cq.select(root.get(Document_.id));
CriteriaBuilder<?> criteriaBuilder = cq.createCriteriaBuilder();
assertEquals("SELECT document.id FROM Document document WHERE EXISTS (SELECT subPerson FROM document.people subPerson)", criteriaBuilder.getQueryString());
assertEquals(1, subquery.getCorrelatedJoins().size());
assertEquals(root, correlatedRoot.getCorrelationParent());
assertTrue(correlatedRoot.isCorrelated());
assertFalse(root.isCorrelated());
}
@Test
public void uncorrelatedQuantor() {
BlazeCriteriaQuery<Long> cq = BlazeCriteria.get(em, cbf, Long.class);
BlazeCriteriaBuilder cb = cq.getCriteriaBuilder();
BlazeRoot<Document> root = cq.from(Document.class, "document");
BlazeSubquery<Person> subquery = cq.subquery(Person.class);
BlazeRoot<Person> subFrom = subquery.from(Person.class, "subPerson");
cq.where(cb.equal(root.get(Document_.owner), cb.all(subquery)));
cq.select(root.get(Document_.id));
CriteriaBuilder<?> criteriaBuilder = cq.createCriteriaBuilder();
assertEquals("SELECT document.id FROM Document document WHERE document.owner = ALL(SELECT subPerson FROM Person subPerson)", criteriaBuilder.getQueryString());
assertEquals(0, subquery.getCorrelatedJoins().size());
CatchException.verifyException(subFrom, IllegalStateException.class).getCorrelationParent();
assertFalse(subFrom.isCorrelated());
assertFalse(root.isCorrelated());
}
@Test
public void implicitCorrelation() {
BlazeCriteriaQuery<Long> cq = BlazeCriteria.get(em, cbf, Long.class);
BlazeCriteriaBuilder cb = cq.getCriteriaBuilder();
BlazeRoot<Document> root = cq.from(Document.class, "document");
BlazeSubquery<Person> subquery = cq.subquery(Person.class);
BlazeRoot<Person> subFrom = subquery.from(Person.class, "subPerson");
subquery.where(cb.equal(subFrom.get(Person_.age), root.get(Document_.age)));
cq.where(cb.exists(subquery));
cq.select(root.get(Document_.id));
CriteriaBuilder<?> criteriaBuilder = cq.createCriteriaBuilder();
assertEquals("SELECT document.id FROM Document document WHERE EXISTS (SELECT subPerson FROM Person subPerson WHERE subPerson.age = document.age)", criteriaBuilder.getQueryString());
// TODO: not quite sure what the outcome should be
assertEquals(0, subquery.getCorrelatedJoins().size());
CatchException.verifyException(subFrom, IllegalStateException.class).getCorrelationParent();
assertFalse(subFrom.isCorrelated());
assertFalse(root.isCorrelated());
}
}