package dev.lions.repositories; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import dev.lions.exceptions.RepositoryException; import java.lang.reflect.ParameterizedType; import java.util.List; import java.util.Optional; /** * Repository générique fournissant les opérations CRUD de base. * Cette classe abstract implémente les fonctionnalités communes à tous les repositories * de l'application en assurant une gestion cohérente des entités. * * @param Type de l'entité * @param Type de l'identifiant de l'entité */ @Slf4j public abstract class BaseRepository { @PersistenceContext protected EntityManager entityManager; private final Class entityClass; /** * Constructeur initialisant la classe d'entité via réflexion. */ @SuppressWarnings("unchecked") public BaseRepository() { Class currentClass = getClass(); while (!(currentClass.getGenericSuperclass() instanceof ParameterizedType)) { currentClass = currentClass.getSuperclass(); } this.entityClass = (Class) ((ParameterizedType) currentClass.getGenericSuperclass()) .getActualTypeArguments()[0]; log.debug("Repository initialisé pour l'entité : {}", entityClass.getSimpleName()); } /** * Persiste une nouvelle entité. * * @param entity Entité à persister * @return Entité persistée */ @Transactional public T save(T entity) { try { log.debug("Sauvegarde d'une nouvelle entité : {}", entityClass.getSimpleName()); entityManager.persist(entity); entityManager.flush(); log.info("Entité sauvegardée avec succès : {}", entity); return entity; } catch (Exception e) { throw new RepositoryException("Erreur lors de la sauvegarde de l'entité", e); } } /** * Met à jour une entité existante. * * @param entity Entité à mettre à jour * @return Entité mise à jour */ @Transactional public T update(T entity) { try { log.debug("Mise à jour d'une entité : {}", entityClass.getSimpleName()); T updatedEntity = entityManager.merge(entity); entityManager.flush(); log.info("Entité mise à jour avec succès : {}", entity); return updatedEntity; } catch (Exception e) { throw new RepositoryException("Erreur lors de la mise à jour de l'entité", e); } } /** * Recherche une entité par son identifiant. * * @param id Identifiant de l'entité * @return Entité trouvée (Optional) */ public Optional findById(ID id) { try { log.debug("Recherche de l'entité {} avec l'id : {}", entityClass.getSimpleName(), id); return Optional.ofNullable(entityManager.find(entityClass, id)); } catch (Exception e) { throw new RepositoryException("Erreur lors de la recherche de l'entité", e); } } /** * Récupère toutes les entités. * * @return Liste des entités */ public List findAll() { try { log.debug("Récupération de toutes les entités : {}", entityClass.getSimpleName()); CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(entityClass); cq.from(entityClass); TypedQuery query = entityManager.createQuery(cq); return query.getResultList(); } catch (Exception e) { throw new RepositoryException("Erreur lors de la récupération des entités", e); } } /** * Supprime une entité. * * @param entity Entité à supprimer */ @Transactional public void delete(T entity) { try { log.debug("Suppression de l'entité : {}", entity); if (!entityManager.contains(entity)) { entity = entityManager.merge(entity); } entityManager.remove(entity); entityManager.flush(); log.info("Entité supprimée avec succès : {}", entity); } catch (Exception e) { throw new RepositoryException("Erreur lors de la suppression de l'entité", e); } } /** * Supprime une entité par son identifiant. * * @param id Identifiant de l'entité à supprimer */ @Transactional public void deleteById(ID id) { try { log.debug("Suppression de l'entité {} avec l'id : {}", entityClass.getSimpleName(), id); findById(id).ifPresent(this::delete); } catch (Exception e) { throw new RepositoryException("Erreur lors de la suppression de l'entité", e); } } /** * Vérifie l'existence d'une entité par son identifiant. * * @param id Identifiant à vérifier * @return true si l'entité existe */ public boolean existsById(ID id) { try { log.debug("Vérification de l'existence de l'entité {} avec l'id : {}", entityClass.getSimpleName(), id); return findById(id).isPresent(); } catch (Exception e) { throw new RepositoryException( "Erreur lors de la vérification de l'existence de l'entité", e); } } /** * Compte le nombre total d'entités. * * @return Nombre total d'entités */ public long count() { try { log.debug("Comptage des entités : {}", entityClass.getSimpleName()); CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Long.class); cq.select(cb.count(cq.from(entityClass))); return entityManager.createQuery(cq).getSingleResult(); } catch (Exception e) { throw new RepositoryException( "Erreur lors du comptage des entités", e); } } }