com.excilys.ebi.bank.dao.impl.OperationDaoImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.excilys.ebi.bank.dao.impl.OperationDaoImpl.java

Source

/**
 * Copyright 2011-2012 eBusiness Information, Groupe Excilys (www.excilys.com)
 *
 * 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.excilys.ebi.bank.dao.impl;

import static com.excilys.ebi.bank.model.entity.QOperation.operation;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.YearMonth;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QueryDslRepositorySupport;
import org.springframework.stereotype.Repository;

import com.excilys.ebi.bank.dao.OperationDaoCustom;
import com.excilys.ebi.bank.model.entity.Card;
import com.excilys.ebi.bank.model.entity.Operation;
import com.excilys.ebi.bank.model.entity.QOperation;
import com.excilys.ebi.bank.model.entity.ref.OperationSign;
import com.excilys.ebi.bank.model.entity.ref.OperationStatus;
import com.excilys.ebi.bank.model.entity.ref.OperationType;
import com.google.common.base.Function;
import com.mysema.query.Tuple;
import com.mysema.query.jpa.JPQLQuery;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.QTuple;
import com.mysema.query.types.expr.BooleanExpression;

@Repository
public class OperationDaoImpl extends QueryDslRepositorySupport implements OperationDaoCustom {

    public OperationDaoImpl() {
        super(Operation.class);
    }

    protected JPQLQuery applyPagination(JPQLQuery query, Pageable pageable) {
        return pageable != null ? query.offset(pageable.getOffset()).limit(pageable.getPageSize()) : query;
    }

    @Override
    public Page<Operation> findNonCardByAccountIdAndYearMonth(Integer accountId, YearMonth yearMonth,
            Pageable pageable) {

        BooleanExpression predicate = operation.type.id.ne(OperationType.CARD)
                .and(operation.account.id.eq(accountId));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        JPQLQuery countQuery = from(operation).where(predicate);
        JPQLQuery query = applyPagination(from(operation).where(predicate).orderBy(operation.date.desc()),
                pageable);

        return buildPage(countQuery, query, pageable);
    }

    @Override
    public List<Operation> sumResolvedAmountByAccountIdAndYearMonthAndSignGroupByCard(Integer accountId,
            YearMonth yearMonth, OperationSign sign) {

        BooleanExpression predicate = operation.type.id.eq(OperationType.CARD)
                .and(operation.status.id.eq(OperationStatus.RESOLVED)).and(operation.account.id.eq(accountId))
                .and(buildOperationSignPredicate(sign));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        List<Tuple> tuples = from(operation).where(predicate).groupBy(operation.card.id)
                .list(new QTuple(operation.amount.sum(), operation.card.id));

        return newArrayList(transform(tuples, new Function<Tuple, Operation>() {
            @Override
            public Operation apply(Tuple input) {
                return Operation.newOperation().withAmount(input.get(operation.amount.sum()))
                        .withCard(Card.newCardBuilder().withId(input.get(operation.card.id)).build()).build();
            }
        }));
    }

    @Override
    public BigDecimal sumResolvedAmountByCardAndYearMonth(Card card, YearMonth yearMonth) {

        BooleanExpression predicate = operation.type.id.eq(OperationType.CARD)
                .and(operation.status.id.eq(OperationStatus.RESOLVED)).and(operation.card.eq(card));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        return from(operation).where(predicate).uniqueResult(operation.amount.sum());
    }

    private Predicate buildOperationSignPredicate(OperationSign sign) {
        return sign == OperationSign.CREDIT ? operation.amount.gt(BigDecimal.ZERO)
                : operation.amount.lt(BigDecimal.ZERO);
    }

    @Override
    public BigDecimal sumResolvedAmountByAccountIdAndYearMonthAndSign(Integer accountId, YearMonth yearMonth,
            OperationSign sign) {

        BooleanExpression predicate = operation.account.id.eq(accountId).and(buildOperationSignPredicate(sign))
                .and(operation.status.id.eq(OperationStatus.RESOLVED));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        return from(operation).where(predicate).uniqueResult(operation.amount.sum());
    }

    @Override
    public Page<Operation> findCardOperationsByAccountIdAndYearMonthAndStatus(Integer accountId,
            YearMonth yearMonth, OperationStatus status, Pageable pageable) {

        BooleanExpression predicate = operation.type.id.eq(OperationType.CARD)
                .and(operation.account.id.eq(accountId)).and(operation.status.id.eq(status));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        JPQLQuery countQuery = from(operation).where(predicate);
        JPQLQuery query = applyPagination(from(operation).where(predicate).orderBy(operation.date.desc()),
                pageable);

        return buildPage(countQuery, query, pageable);
    }

    @Override
    public BigDecimal sumCardAmountByAccountIdAndYearMonthAndSignAndStatus(Integer accountId, YearMonth yearMonth,
            OperationSign sign, OperationStatus status) {

        BooleanExpression predicate = operation.type.id.eq(OperationType.CARD)
                .and(operation.account.id.eq(accountId)).and(buildOperationSignPredicate(sign))
                .and(operation.status.id.eq(status));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        return from(operation).where(predicate).uniqueResult(operation.amount.sum());
    }

    @Override
    public Page<Operation> findCardOperationsByCardIdAndYearMonthAndStatus(Integer cardId, YearMonth yearMonth,
            OperationStatus status, Pageable pageable) {

        BooleanExpression predicate = operation.type.id.eq(OperationType.CARD).and(operation.card.id.eq(cardId))
                .and(operation.status.id.eq(status));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        JPQLQuery countQuery = from(operation).where(predicate);
        JPQLQuery query = applyPagination(from(operation).where(predicate).orderBy(operation.date.desc()),
                pageable);

        return buildPage(countQuery, query, pageable);
    }

    @Override
    public BigDecimal sumCardAmountByCardIdAndYearMonthAndSignAndStatus(Integer cardId, YearMonth yearMonth,
            OperationSign sign, OperationStatus status) {

        BooleanExpression predicate = operation.type.id.eq(OperationType.CARD).and(operation.card.id.eq(cardId))
                .and(buildOperationSignPredicate(sign)).and(operation.status.id.eq(status));
        predicate = addOperationYearMonthExpression(predicate, operation, yearMonth);

        return from(operation).where(predicate).uniqueResult(operation.amount.sum());
    }

    @Override
    public Page<Operation> findTransferByAccountId(Integer accountId, Pageable pageable) {

        BooleanExpression predicate = operation.type.id.eq(OperationType.TRANSFER)
                .and(operation.account.id.eq(accountId));

        JPQLQuery countQuery = from(operation).where(predicate);
        JPQLQuery query = applyPagination(from(operation).where(predicate).orderBy(operation.date.desc()),
                pageable);

        return buildPage(countQuery, query, pageable);
    }

    private BooleanExpression addOperationYearMonthExpression(BooleanExpression predicate, QOperation operation,
            YearMonth yearMonth) {

        if (yearMonth == null)
            return predicate;
        else {
            Interval range = yearMonth.toInterval();
            return predicate.and(operation.date.between(range.getStart(), range.getEnd()));
        }
    }

    private Page<Operation> buildPage(JPQLQuery countQuery, JPQLQuery query, Pageable pageable) {

        long count = countQuery.count();
        return count > 0 ? new PageImpl<Operation>(query.list(operation), pageable, count)
                : new PageImpl<Operation>(new ArrayList<Operation>(), pageable, 0);
    }

    @Override
    public DateTime getLastOperationDate() {
        return from(operation).uniqueResult(operation.date.max());
    }
}