Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
am.ik.blog.entry.jdbc.EntryJdbcMapper Maven / Gradle / Ivy
package am.ik.blog.entry.jdbc;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import am.ik.blog.entry.*;
import am.ik.blog.entry.criteria.SearchCriteria;
import am.ik.blog.entry.criteria.SearchCriteria.ClauseAndParams;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import static java.util.stream.Collectors.*;
@Repository
public class EntryJdbcMapper implements EntryMapper {
private final NamedParameterJdbcTemplate jdbcTemplate;
public EntryJdbcMapper(NamedParameterJdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public long count(SearchCriteria searchCriteria) {
ClauseAndParams clauseAndParams = searchCriteria.toWhereClause();
MapSqlParameterSource source = new MapSqlParameterSource();
source.addValues(clauseAndParams.params());
Long count = this.jdbcTemplate
.queryForObject("SELECT count(e.entry_id) FROM entry AS e "
+ searchCriteria.toJoinClause() + " WHERE 1=1 "
+ clauseAndParams.clauseForEntryId(), source, Long.class);
return count;
}
@Override
public Entry findOne(EntryId entryId, boolean excludeContent) {
MapSqlParameterSource source = new MapSqlParameterSource() //
.addValue("entry_id", entryId.getValue());
return this.jdbcTemplate.query("SELECT e.entry_id, e.title"
+ (excludeContent ? "" : ", e.content")
+ ", e.created_by, e.created_date, e.last_modified_by, e.last_modified_date, c.category_name"
+ " FROM entry AS e LEFT OUTER JOIN category AS c ON e.entry_id = c.entry_id"
+ " WHERE e.entry_id = :entry_id" + " ORDER BY c.category_order ASC",
source, EntryExtractors.forEntry(excludeContent)) //
.map(e -> {
List tags = this.jdbcTemplate.query(
"SELECT tag_name FROM entry_tag WHERE entry_id = :entry_id",
source, (rs, i) -> new Tag(rs.getString("tag_name")));
FrontMatter fm = e.getFrontMatter();
return e.copy().frontMatter(new FrontMatter(fm.title(),
fm.categories(), new Tags(tags), fm.date(), fm.updated()))
.build();
}).orElse(null);
}
Map tagsMap(List ids) {
MapSqlParameterSource source = new MapSqlParameterSource() //
.addValue("entry_ids", ids);
return this.jdbcTemplate.query(
"SELECT entry_id, tag_name FROM entry_tag WHERE entry_id IN (:entry_ids)",
source,
(rs, i) -> Tuples.of(new EntryId(rs.getLong("entry_id")),
new Tag(rs.getString("tag_name"))))
.stream() //
.collect(groupingBy(Tuple2::getT1)) //
.entrySet() //
.stream() //
.map(e -> Tuples.of(e.getKey(), new Tags(e.getValue() //
.stream() //
.map(Tuple2::getT2) //
.collect(toList()))))
.collect(toMap(Tuple2::getT1, Tuple2::getT2));
}
List entryIds(SearchCriteria searchCriteria, Pageable pageable,
ClauseAndParams clauseAndParams, MapSqlParameterSource source) {
return this.jdbcTemplate.query(
"SELECT e.entry_id FROM entry AS e " + searchCriteria.toJoinClause()
+ " WHERE 1=1 " + clauseAndParams.clauseForEntryId()
+ " ORDER BY e.last_modified_date DESC LIMIT "
+ pageable.getPageSize() + " OFFSET " + pageable.getOffset(),
source, (rs, i) -> rs.getLong("entry_id"));
}
String sqlForEntries(boolean excludeContent, ClauseAndParams clauseAndParams) {
return "SELECT e.entry_id, e.title" + (excludeContent ? "" : ", e.content")
+ ", e.created_by, e.created_date, e.last_modified_by, e.last_modified_date, c.category_name"
+ " FROM entry AS e LEFT JOIN category AS c ON e.entry_id = c.entry_id "
+ " WHERE e.entry_id IN (:entry_ids) " + clauseAndParams.clauseForEntry()
+ " ORDER BY e.last_modified_date DESC, c.category_order ASC";
}
@Override
public List findAll(SearchCriteria searchCriteria, Pageable pageable) {
ClauseAndParams clauseAndParams = searchCriteria.toWhereClause();
MapSqlParameterSource source = new MapSqlParameterSource();
source.addValues(clauseAndParams.params());
List ids = this.entryIds(searchCriteria, pageable, clauseAndParams, source);
source.addValue("entry_ids", ids);
boolean excludeContent = searchCriteria.isExcludeContent();
Map tagsMap = this.tagsMap(ids);
List entries = this.jdbcTemplate.query(
this.sqlForEntries(excludeContent, clauseAndParams), source,
EntryExtractors.forEntries(excludeContent));
return entries.stream() //
.map(e -> {
FrontMatter fm = e.getFrontMatter();
EntryId entryId = e.getEntryId();
Categories categories = fm.categories();
Tags tags = tagsMap.get(entryId);
return e.copy() //
.frontMatter(new FrontMatter(fm.title(), categories, tags,
fm.date(), fm.updated()))
.build();
}) //
.collect(toList());
}
@Override
public Flux collectAll(SearchCriteria searchCriteria, Pageable pageable) {
ClauseAndParams clauseAndParams = searchCriteria.toWhereClause();
MapSqlParameterSource source = new MapSqlParameterSource();
source.addValues(clauseAndParams.params());
List ids = this.entryIds(searchCriteria, pageable, clauseAndParams, source);
source.addValue("entry_ids", ids);
boolean excludeContent = searchCriteria.isExcludeContent();
Map tagsMap = this.tagsMap(ids);
return Flux.create(sink -> {
this.jdbcTemplate.query(this.sqlForEntries(excludeContent, clauseAndParams),
source, rs -> {
EntryExtractors.withEntries(rs, e -> {
FrontMatter fm = e.getFrontMatter();
EntryId entryId = e.getEntryId();
Categories categories = fm.categories();
Tags tags = tagsMap.get(entryId);
Entry entry = e.copy() //
.frontMatter(new FrontMatter(fm.title(), categories,
tags, fm.date(), fm.updated()))
.build();
sink.next(entry);
}, excludeContent);
});
sink.complete();
});
}
@Override
@Transactional
public void save(Entry entry) {
FrontMatter frontMatter = entry.frontMatter();
Author created = entry.getCreated();
Author updated = entry.getUpdated();
MapSqlParameterSource source = new MapSqlParameterSource() //
.addValue("entry_id", entry.entryId().getValue()) //
.addValue("title", frontMatter.title().getValue()) //
.addValue("content", entry.content().getValue()) //
.addValue("created_by", created.getName().getValue()) //
.addValue("created_date", created.getDate().getValue()) //
.addValue("last_modified_by", updated.getName().getValue()) //
.addValue("last_modified_date", updated.getDate().getValue()) //
;
this.jdbcTemplate.update(
"INSERT INTO entry (entry_id, title, content, created_by, created_date, last_modified_by, last_modified_date)"
+ " VALUES (:entry_id, :title, :content, :created_by, :created_date, :last_modified_by, :last_modified_date)"
+ " ON DUPLICATE KEY UPDATE" //
+ " title = :title," //
+ " content = :content," //
+ " created_by = :created_by," //
+ " created_date = :created_date," //
+ " last_modified_by = :last_modified_by," //
+ " last_modified_date = :last_modified_date",
source);
AtomicInteger order = new AtomicInteger(0);
SqlParameterSource[] categories = frontMatter.getCategories().getValue().stream()
.map(category -> new MapSqlParameterSource() //
.addValue("category_name", category.getValue()) //
.addValue("category_order", order.getAndIncrement()) //
.addValue("entry_id", entry.entryId().getValue()))
.toArray(SqlParameterSource[]::new);
this.jdbcTemplate.update("DELETE FROM category WHERE entry_id = :entry_id",
source);
this.jdbcTemplate.batchUpdate(
"INSERT INTO category (category_name, category_order, entry_id) VALUES (:category_name, :category_order, :entry_id)",
categories);
SqlParameterSource[] tags = frontMatter.getTags().getValue().stream()
.map(tag -> new MapSqlParameterSource() //
.addValue("tag", tag.getValue()) //
.addValue("entry_id", entry.entryId().getValue()))
.toArray(SqlParameterSource[]::new);
this.jdbcTemplate.update("DELETE FROM entry_tag WHERE entry_id = :entry_id",
source);
this.jdbcTemplate.batchUpdate(
"INSERT INTO tag (tag_name) VALUES (:tag) ON DUPLICATE KEY UPDATE tag_name = :tag",
tags);
this.jdbcTemplate.batchUpdate(
"INSERT INTO entry_tag (entry_id, tag_name) VALUES (:entry_id, :tag)",
tags);
}
@Override
@Transactional
public int delete(EntryId entryId) {
MapSqlParameterSource source = new MapSqlParameterSource().addValue("entry_id",
entryId.getValue());
return this.jdbcTemplate.update("DELETE FROM entry WHERE entry_id = :entry_id",
source);
}
}