package marubinotto.piggydb.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import marubinotto.piggydb.impl.mapper.TagRowMapper;
import marubinotto.piggydb.model.Classifiable;
import marubinotto.piggydb.model.Classification;
import marubinotto.piggydb.model.MutableClassification;
import marubinotto.piggydb.model.Tag;
import marubinotto.piggydb.model.TagRepository;
import marubinotto.piggydb.model.entity.RawClassifiable;
import marubinotto.piggydb.model.entity.RawEntityFactory;
import marubinotto.piggydb.model.entity.RawTag;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class QueryUtils {
private static Log logger = LogFactory.getLog(QueryUtils.class);
public static final Byte TAGGING_TARGET_TAG = 1;
public static final Byte TAGGING_TARGET_FRAGMENT = 2;
public static final Byte TAGGING_TARGET_FILTER_INCLUDES = 3;
public static final Byte TAGGING_TARGET_FILTER_EXCLUDES = 4;
public static void appendLimit(StringBuilder sql, int pageSize, int pageIndex) {
sql.append(" limit ");
sql.append(pageSize * pageIndex);
sql.append(", ");
sql.append(pageSize);
}
public static void registerNewTagging(
long tagId,
long targetId,
Byte targetType,
JdbcTemplate jdbcTemplate) {
StringBuffer sql = new StringBuffer();
sql.append("insert into tagging (");
sql.append("tag_id, target_id, target_type");
sql.append(") values (?, ?, ?)");
Object[] params = new Object[]{
new Long(tagId), new Long(targetId), targetType};
jdbcTemplate.update(sql.toString(), params);
}
public static void deleteTagging(
long tagId,
long targetId,
Byte targetType,
JdbcTemplate jdbcTemplate) {
StringBuffer sql = new StringBuffer();
sql.append("delete from tagging");
sql.append(" where tag_id = ? and target_id = ? and target_type = ?");
Object[] params = new Object[]{
new Long(tagId), new Long(targetId), targetType};
jdbcTemplate.update(sql.toString(), params);
}
public static void registerTaggings(
Classifiable classifiable,
Byte targetType,
JdbcTemplate jdbcTemplate,
TagRepository tagRepository)
throws Exception {
registerTaggings(classifiable.getClassification(), classifiable.getId(),
targetType, jdbcTemplate, tagRepository);
}
public static void registerTaggings(
Classification classification,
Long targetId, Byte targetType,
JdbcTemplate jdbcTemplate,
TagRepository tagRepository)
throws Exception {
for (Tag tag : classification) {
Long tagId = tag.getId();
if (tagId == null) tagId = tagRepository.register(tag);
registerNewTagging(tagId, targetId, targetType, jdbcTemplate);
}
}
public static void updateTaggings(
RawClassifiable classifiable,
Byte targetType,
JdbcTemplate jdbcTemplate,
TagRepository tagRepository)
throws Exception {
updateTaggings(
classifiable.getClassification(),
classifiable.getId(),
targetType,
jdbcTemplate,
tagRepository);
}
public static void updateTaggings(
Classification classification,
Long targetId,
Byte targetType,
JdbcTemplate jdbcTemplate,
TagRepository tagRepository)
throws Exception {
List<Long> currentTagIds = getParentTagIds(targetId, targetType, jdbcTemplate);
for (Tag tag : classification) {
Long tagId = tag.getId();
if (tagId == null) tagId = tagRepository.register(tag);
if (!currentTagIds.remove(tagId))
registerNewTagging(tagId, targetId, targetType, jdbcTemplate);
}
for (Long tagToRemove : currentTagIds) { // the remains should be deleted
deleteTagging(tagToRemove, targetId, targetType, jdbcTemplate);
}
}
@SuppressWarnings("unchecked")
public static List<Long> getParentTagIds(
Long targetId,
Byte targetType,
JdbcTemplate jdbcTemplate) {
return (List<Long>) jdbcTemplate.queryForList(
"select tag_id from tagging where target_id = ? and target_type = ?",
new Object[] { targetId, targetType }, Long.class);
}
@SuppressWarnings("unchecked")
public static List<RawTag> getParentTags(
Long targetId,
Byte targetType,
JdbcTemplate jdbcTemplate,
RawEntityFactory<RawTag> entityFactory) {
TagRowMapper tagRowMapper = new TagRowMapper(entityFactory, "tag."); // TODO
StringBuffer sql = new StringBuffer();
sql.append("select ");
sql.append(tagRowMapper.selectAll());
sql.append(" from tagging, tag");
sql.append(" where tagging.tag_id = tag.tag_id");
sql.append(" and tagging.target_type = " + targetType);
sql.append(" and tagging.target_id = ?");
if (logger.isDebugEnabled())
logger.debug("getParentTags for: " + targetId + " (type: " + targetType + ")");
return jdbcTemplate.query(sql.toString(), new Object[] { targetId }, tagRowMapper);
}
public static Map<Long, RawTag> setOnlyParentTags(
RawClassifiable classifiable,
Byte targetType,
JdbcTemplate jdbcTemplate,
RawEntityFactory<RawTag> entityFactory)
throws Exception {
return setOnlyParentTags(classifiable.getMutableClassification(),
classifiable.getId(), targetType, jdbcTemplate, entityFactory);
}
public static Map<Long, RawTag> setOnlyParentTags(
MutableClassification classification,
Long targetId,
Byte targetType,
JdbcTemplate jdbcTemplate,
RawEntityFactory<RawTag> entityFactory)
throws Exception {
List<RawTag> parentTags = getParentTags(targetId, targetType, jdbcTemplate,
entityFactory);
Map<Long, RawTag> id2parents = new HashMap<Long, RawTag>();
for (RawTag parentTag : parentTags) {
classification.addTag(parentTag);
id2parents.put(parentTag.getId(), parentTag);
}
return id2parents;
}
/**
* The same tag object will be shared in the same level
*/
@SuppressWarnings("rawtypes")
public static void setTagsRecursively(
Map<Long, ? extends RawClassifiable> classifiables,
Byte targetType,
JdbcTemplate jdbcTemplate,
RawEntityFactory<RawTag> entityFactory)
throws Exception {
TagRowMapper tagRowMapper = new TagRowMapper(entityFactory, "tag.");
StringBuilder sql = new StringBuilder();
sql.append("select ");
sql.append(tagRowMapper.selectAll());
sql.append(", tagging.target_id");
sql.append(" from tag, tagging");
sql.append(" where tag.tag_id = tagging.tag_id");
sql.append(" and tagging.target_type = " + targetType);
sql.append(" and tagging.target_id in (");
boolean first = true;
for (Long id : classifiables.keySet()) {
if (first)
first = false;
else
sql.append(", ");
sql.append(id);
}
sql.append(")");
if (logger.isDebugEnabled())
logger.debug("setParentTags for: " + classifiables.values());
List tagMappings = jdbcTemplate.query(sql.toString(),
new TagMappingRowMapper(tagRowMapper));
if (tagMappings.size() == 0) return;
Map<Long, RawTag> tags = new HashMap<Long, RawTag>();
for (Object e : tagMappings) {
TagMapping tagMapping = (TagMapping) e;
// Restore a mapping
RawClassifiable target = classifiables.get(tagMapping.targetId);
target.getMutableClassification().addTag(tagMapping.tag);
// Collect tags
tags.put(tagMapping.tag.getId(), tagMapping.tag);
}
setTagsRecursively(tags, TAGGING_TARGET_TAG, jdbcTemplate, entityFactory);
}
private static class TagMapping {
public Long targetId;
public RawTag tag;
}
private static class TagMappingRowMapper implements RowMapper {
private TagRowMapper tagRowMapper;
private Map<Long, RawTag> tagCache = new HashMap<Long, RawTag>();
public TagMappingRowMapper(TagRowMapper tagRowMapper) {
this.tagRowMapper = tagRowMapper;
}
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
RawTag tag = this.tagRowMapper.mapRow(rs, rowNum);
if (this.tagCache.containsKey(tag.getId())) {
tag = this.tagCache.get(tag.getId());
}
else {
this.tagCache.put(tag.getId(), tag);
}
TagMapping tagMapping = new TagMapping();
tagMapping.tag = tag;
tagMapping.targetId = rs.getLong("tagging.target_id");
return tagMapping;
}
};
public static <T> Map<Long, T> getValuesForIds(
String tableName,
final String columnName,
Set<Long> ids,
JdbcTemplate jdbcTemplate)
throws Exception {
final Map<Long, T> values = new HashMap<Long, T>();
if (ids.isEmpty()) return values;
final String idName = tableName + "_id";
StringBuilder sql = new StringBuilder();
sql.append("select " + idName + ", " + columnName);
sql.append(" from " + tableName);
sql.append(" where " + idName + " in (");
boolean first = true;
for (Long tagId : ids) {
if (first)
first = false;
else
sql.append(", ");
sql.append(tagId);
}
sql.append(")");
jdbcTemplate.query(sql.toString(), new RowMapper() {
@SuppressWarnings("unchecked")
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
values.put(rs.getLong(idName), (T) rs.getObject(columnName));
return null;
}
});
return values;
}
}