com.xlrit.gears.base.repository.JpaRepository Maven / Gradle / Ivy
package com.xlrit.gears.base.repository;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import com.xlrit.gears.base.execution.Execution;
import com.xlrit.gears.base.id.IdGenerator;
import org.hibernate.metamodel.spi.MetamodelImplementor;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
public abstract class JpaRepository extends AbstractRepository {
private static final Logger LOG = LoggerFactory.getLogger(JpaRepository.class);
@PersistenceContext
protected EntityManager em;
@Autowired
protected IdGenerator idGenerator;
protected JpaRepository(Class entityType) {
super(entityType);
}
public TypedQuery query(String qlString) {
return em.createQuery(qlString, entityType);
}
public TypedQuery query(Class resultType, String qlString) {
return em.createQuery(qlString, resultType);
}
public interface CriteriaQueryHandler {
void apply(CriteriaBuilder criteriaBuilder, CriteriaQuery query);
}
public TypedQuery query(CriteriaQueryHandler handler) {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery query = criteriaBuilder.createQuery(entityType);
handler.apply(criteriaBuilder, query);
return em.createQuery(query);
}
public TypedQuery query(Class resultClass, CriteriaQueryHandler f) {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery query = criteriaBuilder.createQuery(resultClass);
f.apply(criteriaBuilder, query);
return em.createQuery(query);
}
@Override
public T findById(String id) {
return em.find(entityType, id);
}
@Override
public List findAll() {
return em.createQuery("SELECT o FROM " + entityType.getName() + " o", entityType).getResultList();
}
@Override
public List findMany(Specification spec) {
query((cb, q) -> {
Root root = q.from(entityType);
if (spec != null) q.where(spec.toPredicate(root, q, cb));
}).getResultList();
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery query = criteriaBuilder.createQuery(entityType);
Root root = query.from(entityType);
if (spec != null) query.where(spec.toPredicate(root, query, criteriaBuilder));
return em.createQuery(query).getResultList();
}
@Override
protected T doCreate(Execution execution) {
T instance = newInstance(idGenerator.getNextId());
em.persist(instance);
return instance;
}
@Override
protected void doRemove(T instance, Execution execution) {
em.remove(instance);
}
public String getTableName() {
if (em.getMetamodel() instanceof MetamodelImplementor metamodel
&& metamodel.entityPersister(entityType) instanceof SingleTableEntityPersister entityPersister) {
return entityPersister.getTableName();
}
return null;
}
public List getColumnNames(List fieldNames) {
try {
if (em.getMetamodel() instanceof MetamodelImplementor metamodel
&& metamodel.entityPersister(entityType) instanceof SingleTableEntityPersister entityPersister) {
return fieldNames.stream()
.map(fieldName -> {
String[] columnNames = entityPersister.getPropertyColumnNames(fieldName);
if (columnNames.length != 1) throw new RuntimeException("Expected field '" + fieldName + "' to be mapped to exactly one column: " + columnNames);
return columnNames[0];
})
.toList();
}
}
catch (RuntimeException e) {
LOG.debug("Unable to map one or more field names to column names: {}", fieldNames);
}
return null;
}
}