package com.tutego.ch_05.jdbcTemplate;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.DataClassRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import java.sql.Statement;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.StringJoiner;
@ShellComponent
public class JdbcCommands {
private final JdbcTemplate jdbcTemplate;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public JdbcCommands(NamedParameterJdbcTemplate namedParameterJdbcTemplate /* just a wrapper */) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
this.jdbcTemplate = namedParameterJdbcTemplate.getJdbcTemplate();
}
@ShellMethod
public String cast(String nickname) {
var lengths = jdbcTemplate.queryForList(
"SELECT manelength FROM Profile WHERE nickname = ?",
Integer.class, // limited type support, not easily configurable
nickname
);
return lengths.isEmpty() ? "Unknown profile for nickname " + nickname : lengths.get(0).toString();
}
@ShellMethod
public String namedCast(String nickname) {
var lengths = namedParameterJdbcTemplate.queryForList(
"SELECT manelength FROM Profile WHERE nickname = :name",
new MapSqlParameterSource().addValue("name", nickname), // limited type support, not easily configurable
Integer.class
);
return lengths.isEmpty() ? "Unknown profile for nickname " + nickname : lengths.get(0).toString();
}
@ShellMethod
public List<NicknameLastSeen> rowMapper(String lastSeen) {
return jdbcTemplate.query(
"""
SELECT nickname, lastseen
FROM Profile WHERE lastseen > ?
ORDER BY lastseen
""",
// RowMapper<T>
(rs, rowNum) -> new NicknameLastSeen(
rs.getString("nickname"),
rs.getTimestamp("lastseen").toLocalDateTime()
),
lastSeen
);
}
@ShellMethod
public List<NicknameLastSeen> dataClassRowMapper(String lastSeen) {
return jdbcTemplate.query( // can also stream but the resource needs to be manually closed
"""
SELECT nickname AS name, lastseen AS seen
FROM Profile WHERE lastseen > ?
ORDER BY lastseen
""",
// class DataClassRowMapper<T> extends BeanPropertyRowMapper<T>
new DataClassRowMapper<>(NicknameLastSeen.class),
lastSeen
);
}
@ShellMethod
public List<ProfilePhoto> beanPropertyRowMapper() {
return jdbcTemplate.query(
// name AS imageName necessary to invoke the correct JavaBean setter
"SELECT id, name AS imageName FROM Photo WHERE is_profile_photo = TRUE",
// class BeanPropertyRowMapper<T> implements RowMapper<T>
new BeanPropertyRowMapper<>(ProfilePhoto.class)
);
}
@ShellMethod
public String rowCallbackHandler(int limit) {
var sql = "SELECT nickname FROM Profile ORDER BY RAND() LIMIT ?";
var joiner = new StringJoiner(", ", "Meet ", " and so many more!");
jdbcTemplate.query(
sql,
rs -> {
// RowCallbackHandler (side-effect)
joiner.add(rs.getString("nickname"));
}
, limit
);
return joiner.toString();
}
@ShellMethod
public String resultSetExtractor(int limit) {
var sql = "SELECT nickname FROM Profile ORDER BY RAND() LIMIT ?";
return jdbcTemplate.query(
sql,
rs -> {
// ResultSetExtractor
var joiner = new StringJoiner(", ", "Meet ", " and so many more!");
while (rs.next()) joiner.add(rs.getString("nickname"));
return joiner.toString();
},
limit
);
}
@ShellMethod
public long preparedStatementCreator(int profileFk, String name, boolean isProfilePhoto) {
PreparedStatementCreator preparedStmtCreator = connection -> {
var stmt = connection.prepareStatement(
"INSERT INTO Photo (profile_fk, name, is_profile_photo, created) VALUES (?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS
);
stmt.setInt(1, profileFk);
stmt.setString(2, name);
stmt.setBoolean(3, isProfilePhoto);
stmt.setTimestamp(4, Timestamp.valueOf(LocalDateTime.now()));
return stmt;
};
KeyHolder keyHolder = new GeneratedKeyHolder(); // glorified ArrayList<> pointer
jdbcTemplate.update(preparedStmtCreator, keyHolder);
return keyHolder.getKey().longValue();
}
}