VoteStore.java
/*
* Copyright © 2024-2025 The CTAN Team and individual authors
*
* This file is distributed under the 3-clause BSD license.
* See file LICENSE for details.
*/
package org.ctan.site.stores;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.ctan.site.domain.account.User;
import org.ctan.site.domain.catalogue.Pkg;
import org.ctan.site.domain.site.Vote;
import org.ctan.site.stores.base.AbstractStore;
import org.hibernate.SessionFactory;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import lombok.Builder;
import lombok.Data;
/**
* The class <code>VoteStore</code> contains the repository for votes.
*
* @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
*/
public class VoteStore extends AbstractStore<Vote> {
/**
* The class <code>CountInfo</code> contains the transport object for the
* statistics data.
*/
@Data
@Builder
public static class CountInfo {
/**
* The field <code>sum</code> contains the rating.
*/
private int sum;
/**
* The field <code>count</code> contains the number of items.
*/
private int count;
}
/**
* This is the constructor for the <code>VoteStore</code>.
*
* @param sessionFactory the session factory
*/
public VoteStore(SessionFactory sessionFactory) {
super(sessionFactory);
}
/**
* The method <code>count</code> provides means to retrieve a mean and
* number of votes for a package by its key.
*
* @param key the key of the package
* @return the summary
*/
public CountInfo count(String key) {
var query = criteriaQuery();
CriteriaBuilder cb = currentSession().getCriteriaBuilder();
Root<Vote> topic = query.from(Vote.class);
query.where(cb.equal(topic.get("pkg").get("key"), key));
var lst = list(query);
var sum = 0;
for (var v : lst) {
sum += v.getRating();
}
return CountInfo.builder()
.sum(sum)
.count(lst.size())
.build();
}
/**
* The method <code>findByAccount</code> provides means to retrieve the
* votes of a user.
*
* @param user the user
*/
public List<Vote> findByAccount(User user) {
CriteriaBuilder cb = currentSession().getCriteriaBuilder();
var query = criteriaQuery();
Root<Vote> root = query.from(Vote.class);
query.where(cb.equal(root.get("user"), user));
return list(query);
}
/**
* The method <code>findByPkg</code> provides means to retrieve a list of
* votes for a package.
*
* @param pkg the package key
*
* @return the list of votes ordered by modification time
*/
public List<Vote> findByPkg(Pkg pkg) {
CriteriaBuilder cb = currentSession().getCriteriaBuilder();
var query = criteriaQuery();
Root<Vote> root = query.from(Vote.class);
query.where(cb.equal(root.get("pkg"), pkg));
query.orderBy(cb.desc(root.get("lastModified")));
return list(query);
}
/**
* The method <code>getByAccountAndPkg</code> provides means to retrieve the
* vote of a user for a package.
*
* @param user the user
* @param pkg the package
*/
public Vote getByAccountAndPkg(User user, Pkg pkg) {
CriteriaBuilder cb = currentSession().getCriteriaBuilder();
var query = criteriaQuery();
Root<Vote> root = query.from(Vote.class);
query.where(cb.and(cb.equal(root.get("pkg"), pkg),
cb.equal(root.get("user"), user)));
return uniqueResult(query);
}
/**
* {@inheritDoc}
*
* @see org.ctan.site.stores.base.AbstractStore#listQuery(java.lang.String,
* jakarta.persistence.criteria.CriteriaBuilder,
* jakarta.persistence.criteria.CriteriaQuery)
*/
@Override
protected Root<Vote> listQuery(String term, CriteriaBuilder cb,
CriteriaQuery<Vote> query) {
Root<Vote> root = query.from(Vote.class);
if (term != null && !term.isBlank()) {
var t = "%" + term.toLowerCase() + "%";
query.where(cb.or(
cb.like(cb.lower(root.get("pkg")), t),
cb.like(cb.lower(root.get("user")), t),
cb.like(cb.lower(root.get("comment")), t)));
}
return root;
}
/**
* {@inheritDoc}
*
* @see org.ctan.site.stores.base.AbstractStore#map(java.util.List)
*/
@Override
protected List<Map<String, Object>> map(List<Vote> list) {
return list.stream()
.map(it -> it.toMap())
.collect(Collectors.toList());
}
}