oglimmer/lunchy

View on GitHub
src/main/java/de/oglimmer/lunchy/database/dao/FinderDao.java

Summary

Maintainability
A
2 hrs
Test Coverage
package de.oglimmer.lunchy.database.dao;

import static de.oglimmer.lunchy.database.generated.tables.Location.LOCATION;
import static de.oglimmer.lunchy.database.generated.tables.Reviews.REVIEWS;
import static de.oglimmer.lunchy.database.generated.tables.Users.USERS;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.SneakyThrows;

import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.SelectWhereStep;
import org.jooq.impl.DSL;

import de.oglimmer.lunchy.beanMapping.BeanMappingProvider;
import de.oglimmer.lunchy.database.connection.DBConn;
import de.oglimmer.lunchy.database.generated.tables.records.LocationRecord;
import de.oglimmer.lunchy.rest.dto.LocationResponse;
import de.oglimmer.lunchy.rest.resources.FinderResource.QueryResponse;
import de.oglimmer.lunchy.rest.resources.FinderResource.QueryResponseSectionLine;
import de.oglimmer.lunchy.rest.resources.FinderResource.RatingResponse;

public enum FinderDao {
    INSTANCE;

    public List<QueryResponse> query(Set<String> tags, Set<String> partners, Integer maxTime, Integer selectedMinRating, int fkCommunity,
            Integer fkCurrentUser, int selectedOffice) {
        Result<LocationRecord> locations = queryLocations(tags, maxTime, fkCommunity, selectedOffice);
        Result<Record> reviews = queryReviews(partners, getLocationId(locations), fkCurrentUser);

        Map<Integer, Map<String, Integer>> reviewsByLocation = groupReviewsByLocation(reviews);

        List<QueryResponse> resultQueryList = new ArrayList<>();

        for (LocationRecord locRec : locations) {

            QueryResponseSectionLine qrsl = new QueryResponseSectionLine();
            qrsl.setRatings(toList(reviewsByLocation.get(locRec.getId())));
            int minRating = getMinRating(qrsl.getRatings());            
            if (hasNotRating1(minRating) && hasMinimumRating(selectedMinRating, minRating)) {

                qrsl.setLocation(BeanMappingProvider.INSTANCE.map(locRec, LocationResponse.class));

                QueryResponse qr = get(resultQueryList, minRating);
                if (qr == null) {
                    qr = new QueryResponse();
                    qr.setMinRating(minRating);
                    qr.setSectionLines(new ArrayList<QueryResponseSectionLine>());
                    resultQueryList.add(qr);
                }

                qr.getSectionLines().add(qrsl);
            }
        }

        Collections.sort(resultQueryList, new Comparator<QueryResponse>() {
            @Override
            public int compare(QueryResponse o1, QueryResponse o2) {
                return -1 * Integer.compare(o1.getMinRating(), o2.getMinRating());
            }
        });

        return resultQueryList;
    }

    private boolean hasMinimumRating(Integer selectedMinRating, int minRating) {
        return selectedMinRating == null || minRating0(selectedMinRating, minRating)
                || minRatingIsHigher(selectedMinRating, minRating);
    }

    private boolean minRating0(Integer selectedMinRating, int minRating) {
        return minRating == 0 && selectedMinRating == 0;
    }

    private boolean minRatingIsHigher(Integer selectedMinRating, int minRating) {
        return minRating >= selectedMinRating && selectedMinRating != 0;
    }

    private boolean hasNotRating1(int minRating) {
        return minRating != 1;
    }

    private List<RatingResponse> toList(Map<String, Integer> reviews) {
        if (reviews == null) {
            return Collections.emptyList();
        }
        List<RatingResponse> reviewList = new ArrayList<>();
        for (Map.Entry<String, Integer> en : reviews.entrySet()) {
            reviewList.add(new RatingResponse(en.getKey(), en.getValue()));
        }
        return reviewList;
    }

    private QueryResponse get(List<QueryResponse> resultQueryList, int minRating) {
        for (QueryResponse qr : resultQueryList) {
            if (qr.getMinRating() == minRating) {
                return qr;
            }
        }
        return null;
    }

    private Map<Integer, Map<String, Integer>> groupReviewsByLocation(Result<Record> reviews) {
        Map<Integer, Map<String, Integer>> uberMap = new HashMap<Integer, Map<String, Integer>>();

        for (Record reviewRec : reviews) {
            int fkLocation = reviewRec.getValue(REVIEWS.FK_LOCATION);
            int rating = reviewRec.getValue(REVIEWS.RATING);
            String displayname = reviewRec.getValue(USERS.DISPLAYNAME);

            Map<String, Integer> locMap = uberMap.get(fkLocation);
            if (locMap == null) {
                locMap = new HashMap<>();
                uberMap.put(fkLocation, locMap);
            }

            locMap.put(displayname, rating);
        }

        return uberMap;
    }

    private int getMinRating(List<RatingResponse> ratings) {
        if (ratings == null || ratings.isEmpty()) {
            return 0;
        }
        int min = Integer.MAX_VALUE;
        for (RatingResponse rating : ratings) {
            if (min > rating.getScore()) {
                min = rating.getScore();
            }
        }
        return min;
    }

    private Set<Integer> getLocationId(Result<LocationRecord> locations) {
        Set<Integer> locationIds = new HashSet<>();
        for (LocationRecord locRec : locations) {
            locationIds.add(locRec.getId());
        }
        return locationIds;
    }

    @SneakyThrows(value = SQLException.class)
    public Result<Record> queryReviews(Set<String> userNamess, Set<Integer> locationIds, Integer fkCurrentUser) {
        try (Connection conn = DBConn.INSTANCE.get()) {
            DSLContext create = DaoBackend.getContext(conn);

            return create
                    .select()
                    .select(REVIEWS.FK_LOCATION, USERS.DISPLAYNAME, REVIEWS.RATING)
                    .from(REVIEWS.join(USERS).on(REVIEWS.FK_USER.equal(USERS.ID)))
                    .where(REVIEWS.FK_LOCATION.in(locationIds).and(
                            USERS.DISPLAYNAME.in(userNamess).or(REVIEWS.FK_USER.equal(fkCurrentUser)))).fetch();
        }
    }

    @SneakyThrows(value = SQLException.class)
    public Result<LocationRecord> queryLocations(Set<String> tags, Integer maxTime, int fkCommunity, int fkOffice) {
        try (Connection conn = DBConn.INSTANCE.get()) {
            DSLContext create = DaoBackend.getContext(conn);

            SelectWhereStep<LocationRecord> sjs = create.selectFrom(LOCATION);

            Condition cond = DSL.falseCondition();
            for (String tag : tags) {
                cond = cond.or(LOCATION.TAGS.like("%" + tag + "%"));
            }

            Condition turnAroundIsNull = LOCATION.TURN_AROUND_TIME.isNull();
            Condition turnAroundMeetsMaxTime = LOCATION.TURN_AROUND_TIME.lessOrEqual(maxTime);
            Condition turnAround = turnAroundIsNull.or(turnAroundMeetsMaxTime);
            Condition fkCommunityCond = LOCATION.FK_COMMUNITY.equal(fkCommunity);
            Condition fkOfficeCond = LOCATION.FK_OFFICE.equal(fkOffice);
            return sjs.where(cond).and(LOCATION.ARCHIVED.equal(0)).and(turnAround.and(fkCommunityCond.and(fkOfficeCond))).fetch();
        }
    }

}