All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.crnk.jpa.JpaEntityRepository Maven / Gradle / Ivy

There is a newer version: 2.6.20180522184741
Show newest version
package io.crnk.jpa;

import io.crnk.core.engine.internal.utils.PreconditionUtil;
import io.crnk.core.queryspec.FilterOperator;
import io.crnk.core.queryspec.FilterSpec;
import io.crnk.core.queryspec.QuerySpec;
import io.crnk.core.repository.ResourceRepositoryV2;
import io.crnk.core.resource.list.ResourceList;
import io.crnk.core.resource.meta.HasMoreResourcesMetaInformation;
import io.crnk.core.resource.meta.MetaInformation;
import io.crnk.core.resource.meta.PagedMetaInformation;
import io.crnk.jpa.internal.JpaRepositoryBase;
import io.crnk.jpa.internal.JpaRepositoryUtils;
import io.crnk.jpa.internal.JpaRequestContext;
import io.crnk.jpa.mapping.JpaMapper;
import io.crnk.jpa.meta.MetaEntity;
import io.crnk.jpa.query.*;
import io.crnk.meta.model.MetaAttribute;

import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * Exposes a JPA entity as ResourceRepository.
 */
public class JpaEntityRepository extends JpaRepositoryBase implements ResourceRepositoryV2 {

	private MetaEntity meta;

	private MetaAttribute primaryKeyAttr;

	public JpaEntityRepository(JpaModule module, JpaRepositoryConfig config) {
		super(module, config);
		this.meta = module.getJpaMetaProvider().getMeta(config.getEntityClass());
		this.primaryKeyAttr = JpaRepositoryUtils.getPrimaryKeyAttr(meta);
	}

	@Override
	public final T findOne(I id, QuerySpec querySpec) {
		QuerySpec idQuerySpec = querySpec.duplicate();
		idQuerySpec.addFilter(new FilterSpec(Arrays.asList(primaryKeyAttr.getName()), FilterOperator.EQ, id));
		List results = findAll(idQuerySpec);
		return getUnique(results, id);
	}

	@Override
	public final ResourceList findAll(Iterable ids, QuerySpec querySpec) {
		QuerySpec idQuerySpec = querySpec.duplicate();
		idQuerySpec.addFilter(new FilterSpec(Arrays.asList(primaryKeyAttr.getName()), FilterOperator.EQ, ids));
		return findAll(idQuerySpec);
	}

	@Override
	public ResourceList findAll(QuerySpec querySpec) {
		Class entityClass = repositoryConfig.getEntityClass();
		QuerySpec filteredQuerySpec = filterQuerySpec(querySpec);
		JpaQueryFactory queryFactory = module.getQueryFactory();
		JpaQuery query = queryFactory.query(entityClass);
		query.setPrivateData(new JpaRequestContext(this, querySpec));

		ComputedAttributeRegistry computedAttributesRegistry = queryFactory.getComputedAttributes();
		Set computedAttrs = computedAttributesRegistry.getForType(entityClass);

		JpaRepositoryUtils.prepareQuery(query, filteredQuerySpec, computedAttrs);
		query = filterQuery(filteredQuerySpec, query);
		JpaQueryExecutor executor = query.buildExecutor();

		boolean fetchNext = isNextFetched(filteredQuerySpec);
		boolean fetchTotal = isTotalFetched(filteredQuerySpec);

		JpaRepositoryUtils.prepareExecutor(executor, filteredQuerySpec, fetchRelations(null));

		if (fetchNext) {
			executor.setLimit(executor.getLimit() + 1);
		}

		executor = filterExecutor(filteredQuerySpec, executor);

		List tuples = executor.getResultTuples();

		Boolean hasNext = null;
		if (fetchNext) {
			hasNext = tuples.size() == querySpec.getLimit() + 1;
			if (hasNext) {
				tuples = tuples.subList(0, querySpec.getLimit().intValue());
			}
		}

		tuples = filterTuples(filteredQuerySpec, tuples);

		ResourceList resources = repositoryConfig.newResultList();
		MetaInformation metaInfo = resources.getMeta();
		fillResourceList(tuples, resources);
		resources = filterResults(filteredQuerySpec, resources);
		if (fetchTotal) {
			long totalRowCount = executor.getTotalRowCount();
			((PagedMetaInformation) metaInfo).setTotalResourceCount(totalRowCount);
		}
		if (fetchNext) {
			((HasMoreResourcesMetaInformation) metaInfo).setHasMoreResources(hasNext);
		}

		return resources;
	}


	@Override
	public  S create(S resource) {
		return saveInternal(resource);
	}

	@Override
	public  S save(S resource) {
		return saveInternal(resource);
	}

	@SuppressWarnings("unchecked")
	private  S saveInternal(S resource) {
		JpaMapper mapper = repositoryConfig.getMapper();
		Object entity = mapper.unmap(resource);

		// PATCH reads, updates and saves entities, needs reattachment during
		// save since reads do a detach
		EntityManager em = module.getEntityManager();
		em.persist(entity);
		I id = (I) em.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(entity);

		// fetch again since we may have to fetch tuple data and do DTO mapping
		QuerySpec querySpec = new QuerySpec(repositoryConfig.getResourceClass());
		PreconditionUtil.verify(id != null, "id not available for entity %s", resource);
		return (S) findOne(id, querySpec);
	}

	@Override
	public void delete(I id) {
		EntityManager em = module.getEntityManager();

		Object object = em.find(repositoryConfig.getEntityClass(), id);
		if (object != null) {
			em.remove(object);
		}
	}

	@Override
	public Class getResourceClass() {
		return repositoryConfig.getResourceClass();
	}

	public Class getEntityClass() {
		return repositoryConfig.getEntityClass();
	}

}