// Copyright © 2015 HSL <https://www.hsl.fi>
// This program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses.
package fi.hsl.parkandride.back;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.MappingProjection;
import com.querydsl.core.types.dsl.ComparableExpression;
import com.querydsl.sql.postgresql.PostgreSQLQuery;
import com.querydsl.sql.postgresql.PostgreSQLQueryFactory;
import fi.hsl.parkandride.back.sql.QHub;
import fi.hsl.parkandride.back.sql.QRegion;
import fi.hsl.parkandride.core.domain.Region;
import fi.hsl.parkandride.core.domain.RegionWithHubs;
import fi.hsl.parkandride.core.service.TransactionalRead;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.querydsl.core.group.GroupBy.groupBy;
import static com.querydsl.core.group.GroupBy.set;
import static com.querydsl.spatial.GeometryExpressions.dwithin;
import static java.util.stream.Collectors.toList;
public class RegionDao implements RegionRepository {
private static final QRegion qRegion = QRegion.region;
private static final QHub qHub = QHub.hub;
private static final MultilingualStringMapping nameMapping = new MultilingualStringMapping(qRegion.nameFi, qRegion.nameSv, qRegion.nameEn);
private static final MappingProjection<Region> regionMapping = new MappingProjection<Region>(Region.class, qRegion.all()) {
@Override
protected Region map(Tuple row) {
Region region = new Region();
region.id = row.get(qRegion.id);
region.area = row.get(qRegion.area);
region.name = nameMapping.map(row);
return region;
}
};
private final PostgreSQLQueryFactory queryFactory;
public RegionDao(PostgreSQLQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
@Override
@TransactionalRead
public Collection<Region> getRegions() {
final PostgreSQLQuery<Region> qry = queryFactory.from(qRegion).select(regionMapping);
ComparableExpression<String> sortField = qRegion.nameFi.lower();
qry.orderBy(sortField.asc());
return qry.fetch();
}
@Override
@TransactionalRead
public Collection<RegionWithHubs> regionsWithHubs() {
final Collection<Region> regions = getRegions();
// We need two queries since dwithin did not seem to work in left join
// at least on H2
final Map<Long, Set<Long>> hubIdsByRegionIds = queryFactory.from(qRegion)
.join(qHub)
.on(dwithin(qRegion.area, qHub.location, 0.0))
.transform(groupBy(qRegion.id).as(set(qHub.id)));
return regions.stream()
.map(region -> new RegionWithHubs(region, hubIdsByRegionIds.getOrDefault(region.id, new HashSet<>())))
.collect(toList());
}
}