Skip to content
Snippets Groups Projects

Add support for stored procedures in persistence

Merged Martin Lowe requested to merge malowe/master/0.6.6-version-rollover into master
4 files
+ 105
33
Compare changes
  • Side-by-side
  • Inline
Files
4
@@ -13,9 +13,13 @@ package org.eclipsefoundation.persistence.dao.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.ParameterMode;
import javax.persistence.Query;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
@@ -26,6 +30,7 @@ import org.eclipsefoundation.core.exception.MaintenanceException;
import org.eclipsefoundation.core.response.PaginatedResultsFilter;
import org.eclipsefoundation.persistence.dao.PersistenceDao;
import org.eclipsefoundation.persistence.dto.BareNode;
import org.eclipsefoundation.persistence.model.ParameterizedCallStatement;
import org.eclipsefoundation.persistence.model.ParameterizedSQLStatement.Clause;
import org.eclipsefoundation.persistence.model.RDBMSQuery;
import org.slf4j.Logger;
@@ -47,31 +52,41 @@ public abstract class BaseHibernateDao implements PersistenceDao {
if (isMaintenanceMode()) {
throw new MaintenanceException();
}
// handle root request parameters (setting headers to track limit and max count)
if (q.isRoot()) {
handleRoot(q);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Querying DB using the following query: {}", q.getFilter().getSelectSql());
// set up the query, either for stored procedures or standard SQL
Query query;
if (q.getFilter() instanceof ParameterizedCallStatement) {
query = getSecondaryEntityManager()
.createStoredProcedureQuery(((ParameterizedCallStatement) q.getFilter()).getCallStatement(), q.getDocType());
} else {
query = getSecondaryEntityManager().createQuery(q.getFilter().getSelectSql(), q.getDocType());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Querying DB using the following query: {}", q.getFilter().getSelectSql());
}
// handle root request parameters (setting headers to track limit and max count)
if (q.isRoot()) {
handleRoot(q);
}
// check if result set should be limited
if (q.getDTOFilter().useLimit() && q.useLimit()) {
LOGGER.debug("Querying DB using offset of {} and limit of {}", getOffset(q), getLimit(q));
query = query.setFirstResult(getOffset(q)).setMaxResults(getLimit(q));
}
}
// build base query
TypedQuery<T> query = getSecondaryEntityManager().createQuery(q.getFilter().getSelectSql(), q.getDocType());
// add ordinal parameters
int ord = 1;
for (Clause c : q.getFilter().getClauses()) {
for (Object param : c.getParams()) {
// for each of params, if processing call statement, add params as registered params
if (q.getFilter() instanceof ParameterizedCallStatement) {
((StoredProcedureQuery) query).registerStoredProcedureParameter(ord, param.getClass(), ParameterMode.IN);
}
query.setParameter(ord++, param);
}
}
// check if result set should be limited
if (q.getDTOFilter().useLimit() && q.useLimit()) {
LOGGER.debug("Querying DB using offset of {} and limit of {}", getOffset(q), getLimit(q));
query = query.setFirstResult(getOffset(q)).setMaxResults(getLimit(q));
}
// run the query
return query.getResultList();
return castResultsToType(query.getResultList(), q.getDocType());
}
@Transactional
@@ -138,10 +153,7 @@ public abstract class BaseHibernateDao implements PersistenceDao {
EntityManager em = getSecondaryEntityManager();
// build base query
TypedQuery<Long> query = em
.createQuery(
q.getFilter()
.getCountSql(), Long.class);
TypedQuery<Long> query = em.createQuery(q.getFilter().getCountSql(), Long.class);
// add ordinal parameters
int ord = 1;
for (Clause c : q.getFilter().getClauses()) {
@@ -161,8 +173,8 @@ public abstract class BaseHibernateDao implements PersistenceDao {
}
/**
* Handles operations that should happen on a "root" or main DB request for a fulfilled request. This is done to
* ensure that values such as DB max are abided.
* Handles operations that should happen on a "root" or main DB request for a fulfilled request. This is done to ensure
* that values such as DB max are abided.
*/
private void handleRoot(RDBMSQuery<?> q) {
// check if count has been performed, if not do so and set it to the response
@@ -171,12 +183,10 @@ public abstract class BaseHibernateDao implements PersistenceDao {
}
private int getLimit(RDBMSQuery<?> q) {
return q.getLimit() > 0
? Math.min(q.getLimit(),
ConfigProvider.getConfig().getOptionalValue("eclipse.db.default.limit", Integer.class)
.orElseGet(() -> 1000))
: ConfigProvider.getConfig().getOptionalValue("eclipse.db.default.limit.max", Integer.class)
.orElseGet(() -> 1000);
return q.getLimit() > 0 ? Math
.min(q.getLimit(),
ConfigProvider.getConfig().getOptionalValue("eclipse.db.default.limit", Integer.class).orElseGet(() -> 1000))
: ConfigProvider.getConfig().getOptionalValue("eclipse.db.default.limit.max", Integer.class).orElseGet(() -> 1000);
}
private int getOffset(RDBMSQuery<?> q) {
@@ -193,6 +203,19 @@ public abstract class BaseHibernateDao implements PersistenceDao {
return (limit * q.getPage()) - limit;
}
/**
* Checked casting of results to properly typed list.
*
* @param <T> the type to cast the list to
* @param l the list that needs to be cast to a type
* @param clazz the literal type to cast to
* @return the original list cast to the passed type
* @throws ClassCastException if the internal types do not match the passed type.
*/
private <T> List<T> castResultsToType(List<?> l, Class<T> clazz) {
return l.stream().map(clazz::cast).collect(Collectors.toList());
}
@Override
public HealthCheckResponse call() {
HealthCheckResponseBuilder b = HealthCheckResponse.named("DB readiness");
@@ -203,8 +226,7 @@ public abstract class BaseHibernateDao implements PersistenceDao {
}
protected boolean isMaintenanceMode() {
return ConfigProvider.getConfig().getOptionalValue("eclipse.db.maintenance", Boolean.class)
.orElseGet(() -> false);
return ConfigProvider.getConfig().getOptionalValue("eclipse.db.maintenance", Boolean.class).orElseGet(() -> false);
}
/**
@@ -218,9 +240,9 @@ public abstract class BaseHibernateDao implements PersistenceDao {
}
/**
* Allow for multiple connections to be associated with a datasource for separate read/write strategies. The
* secondary connection would be a read-only interface to reduce traffic on primary write enable database
* replicants. Default behaviour returns the the primary entity manager but this can be overriden.
* Allow for multiple connections to be associated with a datasource for separate read/write strategies. The secondary
* connection would be a read-only interface to reduce traffic on primary write enable database replicants. Default
* behaviour returns the the primary entity manager but this can be overriden.
*
* @return the secondary entity manager, defaults to the primary entity manager.
*/
Loading