use of com.mysema.query.types.expr.BooleanExpression in project opencast by opencast.
the class AbstractASelectQuery method run.
private AResult run(JPAQueryFactory f) {
// run query and map the result to records
final long startTime = System.nanoTime();
// resolve AST
final SelectQueryContribution r = contributeSelect(f);
final boolean toFetchProperties = r.fetch.exists(Booleans.<Expression<?>>eq(QPropertyDto.propertyDto));
// # create Querydsl query
final JPAQuery q = f.query();
// # from
{
// Make sure that the snapshotDto is always contained in the from clause because the media package ID and
// the ID are always selected.
// Use a mutable hash set to be able to use the removeAll operation.
final Set<EntityPath<?>> from = Stream.<EntityPath<?>>mk(Q_SNAPSHOT).append(// all collected from clauses
r.from).append(// all from clauses from the joins
r.join.map(Join.getFrom)).toSet(SetB.MH);
// Now remove everything that will be joined. Adding them in both the from and a join
// clause is not allowed.
from.removeAll(r.join.map(Join.getJoin).toSet());
q.from(JpaFns.toEntityPathArray(from));
}
// # join
if (!r.join.isEmpty()) {
// Group joins by entity and combine all "on" clauses with "or" expressions.
// This way there is only one join clause per distinct entity which eliminates the need to alias entities
// like this `new QPropertyDto("alias")`.
// Entity aliasing produces many issues which seem to cause a huge rewrite of the query building mechanism
// so it should be prevented at all costs.
final Map<EntityPath<?>, BooleanExpression> joins = r.join.foldl(new HashMap<EntityPath<?>, BooleanExpression>(), new Fn2<Map<EntityPath<?>, BooleanExpression>, Join, Map<EntityPath<?>, BooleanExpression>>() {
@Override
public Map<EntityPath<?>, BooleanExpression> apply(Map<EntityPath<?>, BooleanExpression> sum, Join join) {
// get the on expression saved with the join, may be null
final BooleanExpression existing = sum.get(join.join);
final BooleanExpression combined;
// combine the existing and the current expression
if (existing == null) {
combined = join.on;
} else if (existing.equals(join.on)) {
// if both expressions are equal there is no need to combine them
combined = existing;
} else {
// if different combine with logical "or"
combined = existing.or(join.on);
}
sum.put(join.join, combined);
return sum;
}
});
for (final Map.Entry<EntityPath<?>, BooleanExpression> j : joins.entrySet()) {
q.leftJoin(j.getKey()).on(j.getValue());
}
}
// # where
q.where(r.where.orNull());
// # paging
for (Integer a : r.offset) {
q.offset(a);
}
for (Integer a : r.limit) {
q.limit(a);
}
// # order
for (OrderSpecifier<?> a : r.order) {
q.orderBy(a);
}
// # distinct
if (!toFetchProperties) {
// if no properties shall be fetched the result set can be distinct
q.distinct();
}
// # fetch
// create parameters for fetch clause, i.e. Querydsl's list() method
final List<Expression<?>> fetch;
{
// check if the media package ID needs to be selected separately
if (r.fetch.exists(MandatoryFetch.exists)) {
fetch = r.fetch.toList();
} else {
fetch = r.fetch.append(MandatoryFetch.fetch).toList();
}
}
// Run the query and transform the result into records
final Stream<ARecordImpl> records;
{
// run query
am.getDb().logQuery(q);
final List<Tuple> result = q.list(JpaFns.toExpressionArray(fetch));
logger.debug("Pure query ms " + (System.nanoTime() - startTime) / 1000000);
// map result based on the fact whether properties have been fetched or not
if (!toFetchProperties) {
// No properties have been fetched -> each result row (tuple) is a distinct record (snapshot).
records = $($(result).map(toARecord(r))).map(new Fn<ARecordImpl, ARecordImpl>() {
@Override
public ARecordImpl apply(ARecordImpl record) {
Opt<Snapshot> snapshotOpt = record.getSnapshot();
Snapshot snapshot = null;
if (snapshotOpt.isSome()) {
// make sure the delivered media package has valid URIs
snapshot = am.getHttpAssetProvider().prepareForDelivery(snapshotOpt.get());
}
return new ARecordImpl(record.getSnapshotId(), record.getMediaPackageId(), record.getProperties(), snapshot);
}
});
} else {
logger.trace("Fetched properties");
// Properties have been fetched -> there may be multiple rows (tuples) per snapshot because of the join with the property table.
// Extract records and properties and link them together.
// group properties after their media package ID and make sure that no duplicate properties occur
final Map<String, Set<Property>> propertiesPerMp = $(result).bind(toProperty).foldl(new HashMap<String, Set<Property>>(), new Fn2<Map<String, Set<Property>>, Property, Map<String, Set<Property>>>() {
@Override
public Map<String, Set<Property>> apply(Map<String, Set<Property>> sum, Property p) {
final String mpId = p.getId().getMediaPackageId();
final Set<Property> props = sum.get(mpId);
if (props != null) {
props.add(p);
} else {
sum.put(mpId, SetB.MH.mk(p));
}
return sum;
}
});
// group records after their media package ID
final Map<String, List<ARecordImpl>> distinctRecords = $($(result).map(toARecord(r)).toSet()).groupMulti(ARecordImpl.getMediaPackageId);
records = $(distinctRecords.values()).bind(new Fn<List<ARecordImpl>, Iterable<ARecordImpl>>() {
@Override
public Iterable<ARecordImpl> apply(List<ARecordImpl> records) {
return $(records).map(new Fn<ARecordImpl, ARecordImpl>() {
@Override
public ARecordImpl apply(ARecordImpl record) {
final Set<Property> properties = propertiesPerMp.get(record.getMediaPackageId());
final Stream<Property> p = properties != null ? $(properties) : Stream.<Property>empty();
Snapshot snapshot = null;
Opt<Snapshot> snapshotOpt = record.getSnapshot();
if (snapshotOpt.isSome()) {
// make sure the delivered media package has valid URIs
snapshot = am.getHttpAssetProvider().prepareForDelivery(snapshotOpt.get());
}
return new ARecordImpl(record.getSnapshotId(), record.getMediaPackageId(), p, snapshot);
}
});
}
});
}
}
final long searchTime = (System.nanoTime() - startTime) / 1000000;
logger.debug("Complete query ms " + searchTime);
return new AResultImpl(AbstractASelectQuery.<ARecord>vary(records), sizeOf(records), r.offset.getOr(0), r.limit.getOr(-1), searchTime);
}
use of com.mysema.query.types.expr.BooleanExpression in project opencast by opencast.
the class AbstractADeleteQuery method runQueries.
/**
* Run this in a transaction.
*/
private DeletionResult runQueries(JPAQueryFactory jpa, DeleteQueryContribution c) {
// # create Querydsl delete clause
// # from
// put into a set to remove duplicates
final EntityPath<?> from;
{
final Set<EntityPath<?>> f = c.from.toSet(SetB.MH);
if (f.size() == 1) {
from = $(f).head2();
} else {
throw new RuntimeException("Only one entity is allowed in the from clause");
}
}
//
if (from instanceof QSnapshotDto) {
// from Snapshot
//
final BooleanExpression where = Expressions.allOf(c.targetPredicate.orNull(), c.where.apply(Q_SNAPSHOT));
// get snapshots to delete
// TODO ATTENTION: this query has the potential to yield a massive amount of elements
// return the list of snapshots to delete them outside the transaction since
// it may take a while.
final List<Tuple> deletedSnapshots = jpa.query().from(Q_SNAPSHOT).where(where).list(Q_SNAPSHOT.organizationId, Q_SNAPSHOT.mediaPackageId, Q_SNAPSHOT.version);
// <BLOCK>
// TODO database only approach to determine deleted episodes
// TODO does not run with H2 so unit tests break
/*
SELECT
e.mediapackage_id,
count(*) AS v
FROM oc_assets_snapshot e
GROUP BY e.mediapackage_id
HAVING v = (SELECT count(*)
FROM oc_assets_snapshot e2
WHERE e.mediapackage_id = e2.mediapackage_id
AND
-- delete where clause
(e2.version = 2 OR e2.mediapackage_id = '24ec925e-ea57-43a5-a7bb-58dc5aae54dd')
GROUP BY mediapackage_id);
*/
// final QSnapshotDto e2 = new QSnapshotDto("eee");
// final List<String> deletedSnapshots = jpa.query()
// .from(e2)
// .groupBy(e2.mediaPackageId)
// .having(e2.count().eq(
// jpa.subQuery()
// .from(Q_SNAPSHOT)
// .where(Q_SNAPSHOT.mediaPackageId.eq(e2.mediaPackageId).and(where))
// .groupBy(Q_SNAPSHOT.mediaPackageId)
// .count()))
// .list(e2.mediaPackageId);
// </BLOCK>
// delete assets from database
final JPADeleteClause qAssets = jpa.delete(Q_ASSET).where(Q_ASSET.snapshotId.in(new JPASubQuery().from(Q_SNAPSHOT).where(where).list(Q_SNAPSHOT.id)));
am.getDb().logDelete(formatQueryName(c.name, "delete assets"), qAssets);
qAssets.execute();
// main delete query
final JPADeleteClause qMain = jpa.delete(Q_SNAPSHOT).where(where);
am.getDb().logDelete(formatQueryName(c.name, "main"), qMain);
final long deletedItems = qMain.execute();
// delete orphaned properties
deleteOrphanedProperties();
// <BLOCK>
// TODO Bad solution. Yields all media package IDs which can easily be thousands
// TODO The above SQL solution does not work with H2 so I suspect the query is not 100% clean
// TODO Rework the query and replace this code.
// calculate deleted episodes, i.e. where all snapshots have been deleted
final Set<String> deletedEpisodes;
{
final List<String> remainingSnapshots = jpa.query().from(Q_SNAPSHOT).distinct().list(Q_SNAPSHOT.mediaPackageId);
final Set<String> d = $(deletedSnapshots).map(new Fn<Tuple, String>() {
@Override
public String apply(Tuple tuple) {
return tuple.get(Q_SNAPSHOT.mediaPackageId);
}
}).toSet(SetB.MH);
d.removeAll(remainingSnapshots);
deletedEpisodes = Collections.unmodifiableSet(d);
}
// </BLOCK>
return new DeletionResult(deletedItems, deletedSnapshots, deletedEpisodes);
} else if (from instanceof QPropertyDto) {
// from Property
//
final BooleanExpression where;
{
final BooleanExpression w = c.where.apply(Q_PROPERTY);
if (w != null) {
/* The original sub query used an "ON" clause to filter the join by mediapackage id [1].
Unfortunately Eclipse link drops this clause completely when transforming the query
into SQL. It creates a cross join instead of the inner join, which is perfectly legal
if the "ON" clause would be moved to the "WHERE" clause.
The example [2] shows that neither an "ON" clause nor an additional "WHERE" predicate is generated.
[1]
new JPASubQuery()
.from(Q_PROPERTY)
.join(Q_SNAPSHOT) <- inner join
.on(Q_PROPERTY.mediaPackageId.eq(Q_SNAPSHOT.mediaPackageId)) <- dropped by Eclipse link
.where(Q_PROPERTY.mediaPackageId.eq(Q_SNAPSHOT.mediaPackageId).and(w))
.distinct()
.list(Q_PROPERTY.mediaPackageId)
[2]
SELECT DISTINCT t1.mediapackage_id FROM oc_assets_snapshot t2, oc_assets_properties t1 WHERE (t2.organization_id = ?)
*/
where = Q_PROPERTY.mediaPackageId.in(new JPASubQuery().from(Q_PROPERTY).join(Q_SNAPSHOT).where(Q_PROPERTY.mediaPackageId.eq(Q_SNAPSHOT.mediaPackageId).and(w)).distinct().list(Q_PROPERTY.mediaPackageId));
} else {
where = null;
}
}
final JPADeleteClause qProperties = jpa.delete(from).where(Expressions.allOf(c.targetPredicate.orNull(), where));
am.getDb().logDelete(formatQueryName(c.name, "main"), qProperties);
final long deletedItems = qProperties.execute();
return new DeletionResult(deletedItems, Collections.<Tuple>emptyList(), Collections.<String>emptySet());
} else {
// from contains an unsupported entity
throw new RuntimeException("[Bug]");
}
}
use of com.mysema.query.types.expr.BooleanExpression in project opencast by opencast.
the class PropertyPredicates method mkWhereDelete.
public static Where mkWhereDelete(final Opt<String> namespace, final Opt<String> propertyName, final Fn<QPropertyDto, Opt<BooleanExpression>> mkValueExpression) {
final Opt<BooleanExpression> valueExpression = mkValueExpression.apply(Q_PROPERTY);
final BooleanExpression propertyPredicate = (namespace.isSome() ? Q_PROPERTY.namespace.eq(namespace.get()) : // The isNotNull predicate prevents this.
Q_PROPERTY.namespace.isNotNull()).and(propertyName.isSome() ? Q_PROPERTY.propertyName.eq(propertyName.get()) : null).and(valueExpression.isSome() ? valueExpression.get() : null);
//
return new Where() {
@Override
public BooleanExpression fromSnapshot(QSnapshotDto e) {
return new JPASubQuery().from(Q_PROPERTY).where(e.mediaPackageId.eq(Q_PROPERTY.mediaPackageId).and(propertyPredicate)).exists();
}
@Override
public BooleanExpression fromProperty(QPropertyDto p) {
return p.mediaPackageId.in(new JPASubQuery().from(p).where(propertyPredicate).distinct().list(p.mediaPackageId));
}
};
}
use of com.mysema.query.types.expr.BooleanExpression in project dwoss by gg-net.
the class CustomerEao method find.
/**
* A more specific search based on parameters and possible wildcard handlig.
* All parameters witch are blank will be ignored. The search itself ist like based, so explicit as implicit wildcards are possible
* <p>
* @param companyName the {@link Company#name} of {@link Customer#companies}
* @param firstName the {@link Contact#firstName} of {@link Customer#contacts}
* @param lastName the {@link Contact#lastName} of {@link Customer#contacts}
* @param email the {@link Communication#identifier} with {@link Communication#type} == {@link Type#EMAIL} of {@link Contact#communications} of
* {@link Customer#contacts}
* @param appendWildcard if true, adds a '%' wildcard sign to all set parameters
* @return a list of customers matching the paramters.
*/
public List<Customer> find(String companyName, String firstName, String lastName, String email, boolean appendWildcard) {
WildCardHelper W = new WildCardHelper(appendWildcard);
JPAQuery query = new JPAQuery(em).from(customer);
if (!isBlank(companyName)) {
query.join(customer.companies, company).on(company.name.lower().like(W.trim(companyName)));
}
if (!isBlank(firstName) || !isBlank(lastName)) {
query.join(customer.contacts, contact).on();
BooleanExpression on = null;
if (!isBlank(firstName)) {
on = contact.firstName.lower().like(W.trim(firstName));
}
if (!isBlank(lastName)) {
BooleanExpression second = contact.lastName.lower().like(W.trim(lastName));
if (on != null)
on = on.and(second);
else
on = second;
}
query.on(on);
}
if (!isBlank(email)) {
query.join(customer.contacts, contact).join(contact.communications, communication).on(communication.type.eq(EMAIL).and(communication.identifier.lower().like(W.trim(email))));
}
L.debug("calling query");
List<Customer> list = query.list(customer);
L.debug("Query successful wiht {}", list);
return list;
}
Aggregations