AbstractStore.java

/*
 * Copyright © 2023-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.base;

import java.util.List;
import java.util.Map;

import org.hibernate.SessionFactory;

import io.dropwizard.hibernate.AbstractDAO;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import lombok.NonNull;

/**
 * The class <code>AbstractStore</code> contains the abstract repository for
 * CRUD operations on an entity.
 *
 * @param <T> the type of the entity
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
public abstract class AbstractStore<T> extends AbstractDAO<T> {

    /**
     * This is the constructor for <code>AbstractStore</code>.
     *
     * @param sessionFactory the session factory
     */
    public AbstractStore(SessionFactory sessionFactory) {

        super(sessionFactory);
    }

    /**
     * The method <code>getById</code> provides means to retrieve the entity by
     * its id.
     *
     * @param id the id
     * @return the entity or {@code null} if none is present
     */
    public T get(@NonNull Long id) {

        return super.get(id);
    }

    /**
     * The method <code>list</code> provides means to extract a page of items.
     *
     * @param term the search term
     * @param page the current page
     * @param pageSize the page size
     * @param orderBy the order
     * @param asc the indicator for ascending
     * @return the page
     */
    public GeneralPage list(String term, int page, int pageSize,
        String orderBy, boolean asc) {

        if (page < 0 || pageSize < 1) {
            return null;
        }
        CriteriaBuilder cb = currentSession().getCriteriaBuilder();
        var query = criteriaQuery();
        var root = listQuery(term, cb, query);
        if (orderBy != null && !orderBy.isBlank()) {
            if (asc) {
                query.orderBy(cb.asc(root.get(orderBy)));
            } else {
                query.orderBy(cb.desc(root.get(orderBy)));
            }
        }

        var hits = list(query);
        var hitCount = hits.size();
        var list = hits
            .subList(Math.min(page * pageSize, hitCount),
                Math.min((page + 1) * pageSize, hitCount));
        return new GeneralPage(hitCount, map(list));
    }

    /**
     * The method <code>listQuery</code> provides means to construct a query for
     * the list of entities for a search.
     *
     * @param term the search term
     * @param cb the criteria builder
     * @param query the query
     * @return the root
     */
    protected abstract Root<T> listQuery(String term, CriteriaBuilder cb,
        CriteriaQuery<T> query);

    /**
     * The method <code>map</code> provides means to format a list for external
     * use.
     *
     * @param list the list of entries
     * @return the formatted list
     */
    protected abstract List<Map<String, Object>> map(List<T> list);

    /**
     * The method <code>remove</code> provides means to remove a list of
     * entities.
     *
     * @param list the list of entries
     */
    public void remove(@NonNull List<T> list) {

        for (var it : list) {
            remove(it);
        }
    }

    /**
     * The method <code>remove</code> provides means to remove an entity by its
     * id.
     *
     * @param id the id
     * @return {@code true} iff something has been removed
     */
    public boolean remove(@NonNull Long id) {

        return remove(get(id));
    }

    /**
     * The method <code>remove</code> provides means to remove an entity.
     *
     * @param entity the entity
     * @return {@code true} iff something has been removed
     */
    public boolean remove(T entity) {

        if (entity == null) {
            return false;
        }
        currentSession().remove(entity);
        return true;
    }

    /**
     * The method <code>save</code> provides means to store an entity in the
     * database.
     *
     * @param entity the entity
     * @return the entity
     */
    public T save(@NonNull T entity) {

        currentSession().persist(entity);
        return entity;
    }

}