package org.nextprot.api.user.dao.impl;
import com.google.common.collect.Lists;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nextprot.api.commons.exception.NextProtException;
import org.nextprot.api.commons.spring.jdbc.DataSourceServiceLocator;
import org.nextprot.api.commons.utils.JdbcTemplateUtils;
import org.nextprot.api.commons.utils.KeyValuesJdbcBatchUpdater;
import org.nextprot.api.commons.utils.SQLDictionary;
import org.nextprot.api.user.dao.UserQueryDao;
import org.nextprot.api.user.domain.UserQuery;
import org.nextprot.api.user.utils.UserQueryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.stereotype.Repository;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
@Repository
@Lazy
public class UserQueryDaoImpl implements UserQueryDao {
private final Log Logger = LogFactory.getLog(UserQueryDaoImpl.class);
@Autowired private SQLDictionary sqlDictionary;
@Autowired private DataSourceServiceLocator dsLocator;
@Override
public List<UserQuery> getUserQueries(String username) {
String sql = sqlDictionary.getSQLQuery("read-user-queries-by-username");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("user_name", username);
return queryList(sql, namedParameters);
}
@Override
public UserQuery getUserQueryById(long queryId) {
String sql = sqlDictionary.getSQLQuery("read-user-query-by-id");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("query_id", queryId);
UserQuery query = new NamedParameterJdbcTemplate(dsLocator.getUserDataSource()).queryForObject(sql, namedParameters, new UserQueryRowMapper());
Map<Long, Set<String>> tags = getQueryTags(Arrays.asList(query.getUserQueryId()));
query.setTags(tags.get(queryId));
return query;
}
@Override
public UserQuery getUserQueryByPublicId(String publicId) {
String sql = sqlDictionary.getSQLQuery("read-user-query-by-pubid");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("public_id", publicId);
UserQuery query = new NamedParameterJdbcTemplate(dsLocator.getUserDataSource()).queryForObject(sql, namedParameters, new UserQueryRowMapper());
long queryId = query.getUserQueryId();
Map<Long, Set<String>> tags = getQueryTags(Arrays.asList(queryId));
query.setTags(tags.get(queryId));
return query;
}
@Override
public List<UserQuery> getUserQueriesByTag(String tag) {
String sql = sqlDictionary.getSQLQuery("read-user-queries-by-tag");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("tag_name", tag);
return queryList(sql, namedParameters);
}
@Override
public List<UserQuery> getPublishedQueries() {
String sql = sqlDictionary.getSQLQuery("read-published-user-queries");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
return queryList(sql, namedParameters);
}
@Override
public List<UserQuery> getTutorialQueries() {
String sql = sqlDictionary.getSQLQuery("read-tutorial-queries");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
return queryList(sql, namedParameters);
}
@Override
public Map<Long, Set<String>> getQueryTags(Collection<Long> queryIds) {
String sql = sqlDictionary.getSQLQuery("read-tags-by-user-query-ids");
SqlParameterSource namedParameters = new MapSqlParameterSource("query_ids", queryIds);
List<Tag> foundTags = new NamedParameterJdbcTemplate(dsLocator.getUserDataSource()).query(sql, namedParameters, new UserQueryTagRowMapper());
Map<Long, Set<String>> map = new HashMap<Long, Set<String>>();
Set<Long> foundQueries = new HashSet<Long>();
for (Tag tag : foundTags) {
foundQueries.add(tag.getQueryId());
if (!map.containsKey(tag.getQueryId())) {
map.put(tag.getQueryId(), new HashSet<String>());
}
map.get(tag.getQueryId()).add(tag.getName());
}
for (long queryId : queryIds) {
if (!foundQueries.contains(queryId))
map.put(queryId, new HashSet<String>());
}
return map;
}
@Override
public long createUserQuery(final UserQuery userQuery) {
final String INSERT_SQL = sqlDictionary.getSQLQuery("create-user-query");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("title", userQuery.getTitle());
namedParameters.addValue("description", userQuery.getDescription());
namedParameters.addValue("sparql", userQuery.getSparql());
namedParameters.addValue("published", userQuery.getPublished() ? 'Y' : 'N');
namedParameters.addValue("owner_id", userQuery.getOwnerId());
namedParameters.addValue("public_id", userQuery.getPublicId());
return JdbcTemplateUtils.insertAndGetKey(INSERT_SQL, "query_id", namedParameters, new NamedParameterJdbcTemplate(dsLocator.getUserDataSource())).longValue();
}
@Override
public void createUserQueryTags(final long queryId, final Set<String> tags) {
final String INSERT_SQL = sqlDictionary.getSQLQuery("create-user-query-tag");
KeyValuesJdbcBatchUpdater updater = new KeyValuesJdbcBatchUpdater(new JdbcTemplate(dsLocator.getUserDataSource()), queryId) {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, getValue(i));
ps.setLong(2, queryId);
}
};
updater.batchUpdate(INSERT_SQL, new ArrayList<String>(tags));
}
@Override
public void updateUserQuery(final UserQuery src) {
final String UPDATE_SQL = sqlDictionary.getSQLQuery("update-user-query");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
// key to identify query to update
namedParameters.addValue("query_id", src.getUserQueryId());
// values to update
namedParameters.addValue("title", src.getTitle());
namedParameters.addValue("description", src.getDescription());
namedParameters.addValue("sparql", src.getSparql());
namedParameters.addValue("published", src.getPublished() ? 'Y' : 'N');
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dsLocator.getUserDataSource());
int affectedRows = jdbcTemplate.update(UPDATE_SQL, namedParameters);
if (affectedRows != 1) {
String msg = "oops something wrong occurred" + affectedRows + " rows were affected instead of only 1.";
Logger.error(msg);
throw new NextProtException(msg);
}
}
@Override
public int deleteUserQuery(final long queryId) {
final String DELETE_SQL = sqlDictionary.getSQLQuery("delete-user-query");
Map<String, Object> params = new HashMap<String, Object>();
params.put("query_id", queryId);
return new NamedParameterJdbcTemplate(dsLocator.getUserDataSource()).update(DELETE_SQL, params);
}
@Override
public int deleteUserQueryTags(long queryId, Set<String> tags) {
final String DELETE_SQL = sqlDictionary.getSQLQuery("delete-user-query-tags");
Map<String, Object> params = new HashMap<String, Object>();
params.put("tags", tags);
return new NamedParameterJdbcTemplate(dsLocator.getUserDataSource()).update(DELETE_SQL, params);
}
/**
* Get user query list and extract tags
*
* @param sql the select from user_queries sql query
* @param source
* @return
*/
private List<UserQuery> queryList(String sql, SqlParameterSource source) {
List<UserQuery> userQueryList = new NamedParameterJdbcTemplate(dsLocator.getUserDataSource()).query(sql, source, new UserQueryRowMapper());
if (!userQueryList.isEmpty()) {
List<Long> queryIds = Lists.transform(userQueryList, UserQueryUtils.EXTRACT_QUERY_ID);
Map<Long, Set<String>> tags = getQueryTags(queryIds);
for (UserQuery query : userQueryList) {
Set<String> tagSet = tags.get(query.getUserQueryId());
//use hashset because google implementation is not serializable
query.setTags(new HashSet<String>(tagSet));
}
}
return userQueryList;
}
private static class UserQueryRowMapper implements ParameterizedRowMapper<UserQuery> {
public UserQuery mapRow(ResultSet resultSet, int row) throws SQLException {
UserQuery query = new UserQuery();
query.setUserQueryId(resultSet.getInt("query_id"));
query.setTitle(resultSet.getString("title"));
query.setDescription(resultSet.getString("description"));
query.setSparql(resultSet.getString("sparql"));
query.setPublished(resultSet.getString("published").equals("Y"));
query.setOwner(resultSet.getString("user_name"));
query.setPublicId(resultSet.getString("public_id"));
return query;
}
}
private static class Tag {
private String name;
private long queryId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getQueryId() {
return queryId;
}
public void setQueryId(long queryId) {
this.queryId = queryId;
}
}
private static class UserQueryTagRowMapper implements ParameterizedRowMapper<Tag> {
public Tag mapRow(ResultSet resultSet, int row) throws SQLException {
Tag tag = new Tag();
tag.setName(resultSet.getString("tag_name"));
tag.setQueryId(resultSet.getLong("query_id"));
return tag;
}
}
}