Make dao layer more db vendor agnostic

- Removed usages of TOP
- Dont send null for autogenerate columns

Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>
master
Andrew DeMaria 8 years ago
parent f60811e51b
commit 18e793c64d
No known key found for this signature in database
GPG Key ID: 0A3F5E91F8364EDF
  1. 19
      libresonic-main/src/main/java/org/libresonic/player/dao/AbstractDao.java
  2. 38
      libresonic-main/src/main/java/org/libresonic/player/dao/AlbumDao.java
  3. 19
      libresonic-main/src/main/java/org/libresonic/player/dao/ArtistDao.java
  4. 14
      libresonic-main/src/main/java/org/libresonic/player/dao/AvatarDao.java
  5. 9
      libresonic-main/src/main/java/org/libresonic/player/dao/BookmarkDao.java
  6. 2
      libresonic-main/src/main/java/org/libresonic/player/dao/DaoHelper.java
  7. 19
      libresonic-main/src/main/java/org/libresonic/player/dao/GenericDaoHelper.java
  8. 7
      libresonic-main/src/main/java/org/libresonic/player/dao/InternetRadioDao.java
  9. 66
      libresonic-main/src/main/java/org/libresonic/player/dao/MediaFileDao.java
  10. 9
      libresonic-main/src/main/java/org/libresonic/player/dao/MusicFolderDao.java
  11. 9
      libresonic-main/src/main/java/org/libresonic/player/dao/PlayQueueDao.java
  12. 13
      libresonic-main/src/main/java/org/libresonic/player/dao/PlayerDao.java
  13. 17
      libresonic-main/src/main/java/org/libresonic/player/dao/PlaylistDao.java
  14. 29
      libresonic-main/src/main/java/org/libresonic/player/dao/PodcastDao.java
  15. 13
      libresonic-main/src/main/java/org/libresonic/player/dao/ShareDao.java
  16. 9
      libresonic-main/src/main/java/org/libresonic/player/dao/TranscodingDao.java
  17. 9
      libresonic-main/src/main/webapp/WEB-INF/applicationContext-db.xml
  18. 2
      libresonic-main/src/test/java/org/libresonic/player/dao/DaoTestCaseBase.java
  19. 9
      libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-service.xml

@ -19,15 +19,23 @@
*/ */
package org.libresonic.player.dao; package org.libresonic.player.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.*; import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.libresonic.player.Logger; import org.libresonic.player.Logger;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.Assert;
/** /**
* Abstract superclass for all DAO's. * Abstract superclass for all DAO's.
@ -107,6 +115,16 @@ public class AbstractDao {
return result; return result;
} }
protected <T> List<T> namedQueryWithLimit(String sql, RowMapper<T> rowMapper, Map<String, Object> args, int limit) {
long t = System.nanoTime();
JdbcTemplate jdbcTemplate = new JdbcTemplate(daoHelper.getDataSource());
jdbcTemplate.setMaxRows(limit);
NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
List<T> result = namedTemplate.query(sql, args, rowMapper);
log(sql, t);
return result;
}
protected List<String> queryForStrings(String sql, Object... args) { protected List<String> queryForStrings(String sql, Object... args) {
long t = System.nanoTime(); long t = System.nanoTime();
List<String> result = getJdbcTemplate().queryForList(sql, args, String.class); List<String> result = getJdbcTemplate().queryForList(sql, args, String.class);
@ -173,4 +191,5 @@ public class AbstractDao {
public void setDaoHelper(DaoHelper daoHelper) { public void setDaoHelper(DaoHelper daoHelper) {
this.daoHelper = daoHelper; this.daoHelper = daoHelper;
} }
} }

@ -41,10 +41,11 @@ import org.libresonic.player.util.FileUtil;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class AlbumDao extends AbstractDao { public class AlbumDao extends AbstractDao {
private static final String INSERT_COLUMNS = "path, name, artist, song_count, duration_seconds, cover_art_path, " +
private static final String COLUMNS = "id, path, name, artist, song_count, duration_seconds, cover_art_path, " +
"year, genre, play_count, last_played, comment, created, last_scanned, present, folder_id"; "year, genre, play_count, last_played, comment, created, last_scanned, present, folder_id";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private final RowMapper rowMapper = new AlbumMapper(); private final RowMapper rowMapper = new AlbumMapper();
/** /**
@ -55,7 +56,7 @@ public class AlbumDao extends AbstractDao {
* @return The album or null. * @return The album or null.
*/ */
public Album getAlbum(String artistName, String albumName) { public Album getAlbum(String artistName, String albumName) {
return queryOne("select " + COLUMNS + " from album where artist=? and name=?", rowMapper, artistName, albumName); return queryOne("select " + QUERY_COLUMNS + " from album where artist=? and name=?", rowMapper, artistName, albumName);
} }
/** /**
@ -67,7 +68,7 @@ public class AlbumDao extends AbstractDao {
public Album getAlbumForFile(MediaFile file) { public Album getAlbumForFile(MediaFile file) {
// First, get all albums with the correct album name (irrespective of artist). // First, get all albums with the correct album name (irrespective of artist).
List<Album> candidates = query("select " + COLUMNS + " from album where name=?", rowMapper, file.getAlbumName()); List<Album> candidates = query("select " + QUERY_COLUMNS + " from album where name=?", rowMapper, file.getAlbumName());
if (candidates.isEmpty()) { if (candidates.isEmpty()) {
return null; return null;
} }
@ -91,7 +92,7 @@ public class AlbumDao extends AbstractDao {
} }
public Album getAlbum(int id) { public Album getAlbum(int id) {
return queryOne("select " + COLUMNS + " from album where id=?", rowMapper, id); return queryOne("select " + QUERY_COLUMNS + " from album where id=?", rowMapper, id);
} }
public List<Album> getAlbumsForArtist(final String artist, final List<MusicFolder> musicFolders) { public List<Album> getAlbumsForArtist(final String artist, final List<MusicFolder> musicFolders) {
@ -102,7 +103,8 @@ public class AlbumDao extends AbstractDao {
put("artist", artist); put("artist", artist);
put("folders", MusicFolder.toIdList(musicFolders)); put("folders", MusicFolder.toIdList(musicFolders));
}}; }};
return namedQuery("select " + COLUMNS + " from album where artist = :artist and present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS
+ " from album where artist = :artist and present and folder_id in (:folders) " +
"order by name", "order by name",
rowMapper, args); rowMapper, args);
} }
@ -135,7 +137,7 @@ public class AlbumDao extends AbstractDao {
if (n == 0) { if (n == 0) {
update("insert into album (" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")", null, album.getPath(), update("insert into album (" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")", album.getPath(),
album.getName(), album.getArtist(), album.getSongCount(), album.getDurationSeconds(), album.getName(), album.getArtist(), album.getSongCount(), album.getDurationSeconds(),
album.getCoverArtPath(), album.getYear(), album.getGenre(), album.getPlayCount(), album.getLastPlayed(), album.getCoverArtPath(), album.getYear(), album.getGenre(), album.getPlayCount(), album.getLastPlayed(),
album.getComment(), album.getCreated(), album.getLastScanned(), album.isPresent(), album.getFolderId()); album.getComment(), album.getCreated(), album.getLastScanned(), album.isPresent(), album.getFolderId());
@ -164,7 +166,7 @@ public class AlbumDao extends AbstractDao {
put("offset", offset); put("offset", offset);
}}; }};
String orderBy = byArtist ? "artist, name" : "name"; String orderBy = byArtist ? "artist, name" : "name";
return namedQuery("select " + COLUMNS + " from album where present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS + " from album where present and folder_id in (:folders) " +
"order by " + orderBy + " limit :count offset :offset", rowMapper, args); "order by " + orderBy + " limit :count offset :offset", rowMapper, args);
} }
@ -185,7 +187,8 @@ public class AlbumDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from album where play_count > 0 and present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS
+ " from album where play_count > 0 and present and folder_id in (:folders) " +
"order by play_count desc limit :count offset :offset", rowMapper, args); "order by play_count desc limit :count offset :offset", rowMapper, args);
} }
@ -206,7 +209,8 @@ public class AlbumDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from album where last_played is not null and present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS
+ " from album where last_played is not null and present and folder_id in (:folders) " +
"order by last_played desc limit :count offset :offset", rowMapper, args); "order by last_played desc limit :count offset :offset", rowMapper, args);
} }
@ -227,7 +231,7 @@ public class AlbumDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from album where present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS + " from album where present and folder_id in (:folders) " +
"order by created desc limit :count offset :offset", rowMapper, args); "order by created desc limit :count offset :offset", rowMapper, args);
} }
@ -250,7 +254,7 @@ public class AlbumDao extends AbstractDao {
put("offset", offset); put("offset", offset);
put("username", username); put("username", username);
}}; }};
return namedQuery("select " + prefix(COLUMNS, "album") + " from starred_album, album where album.id = starred_album.album_id and " + return namedQuery("select " + prefix(QUERY_COLUMNS, "album") + " from starred_album, album where album.id = starred_album.album_id and " +
"album.present and album.folder_id in (:folders) and starred_album.username = :username " + "album.present and album.folder_id in (:folders) and starred_album.username = :username " +
"order by starred_album.created desc limit :count offset :offset", "order by starred_album.created desc limit :count offset :offset",
rowMapper, args); rowMapper, args);
@ -275,7 +279,7 @@ public class AlbumDao extends AbstractDao {
put("offset", offset); put("offset", offset);
put("genre", genre); put("genre", genre);
}}; }};
return namedQuery("select " + COLUMNS + " from album where present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS + " from album where present and folder_id in (:folders) " +
"and genre = :genre limit :count offset :offset", rowMapper, args); "and genre = :genre limit :count offset :offset", rowMapper, args);
} }
@ -302,18 +306,18 @@ public class AlbumDao extends AbstractDao {
put("toYear", toYear); put("toYear", toYear);
}}; }};
if (fromYear <= toYear) { if (fromYear <= toYear) {
return namedQuery("select " + COLUMNS + " from album where present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS + " from album where present and folder_id in (:folders) " +
"and year between :fromYear and :toYear order by year limit :count offset :offset", "and year between :fromYear and :toYear order by year limit :count offset :offset",
rowMapper, args); rowMapper, args);
} else { } else {
return namedQuery("select " + COLUMNS + " from album where present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS + " from album where present and folder_id in (:folders) " +
"and year between :toYear and :fromYear order by year desc limit :count offset :offset", "and year between :toYear and :fromYear order by year desc limit :count offset :offset",
rowMapper, args); rowMapper, args);
} }
} }
public void markNonPresent(Date lastScanned) { public void markNonPresent(Date lastScanned) {
int minId = queryForInt("select top 1 id from album where last_scanned != ? and present", 0, lastScanned); int minId = queryForInt("select min(id) from album where last_scanned != ? and present", 0, lastScanned);
int maxId = queryForInt("select max(id) from album where last_scanned != ? and present", 0, lastScanned); int maxId = queryForInt("select max(id) from album where last_scanned != ? and present", 0, lastScanned);
final int batchSize = 1000; final int batchSize = 1000;
@ -323,7 +327,7 @@ public class AlbumDao extends AbstractDao {
} }
public void expunge() { public void expunge() {
int minId = queryForInt("select top 1 id from album where not present", 0); int minId = queryForInt("select min(id) from album where not present", 0);
int maxId = queryForInt("select max(id) from album where not present", 0); int maxId = queryForInt("select max(id) from album where not present", 0);
final int batchSize = 1000; final int batchSize = 1000;

@ -41,7 +41,8 @@ import java.util.Map;
public class ArtistDao extends AbstractDao { public class ArtistDao extends AbstractDao {
private static final Logger LOG = Logger.getLogger(ArtistDao.class); private static final Logger LOG = Logger.getLogger(ArtistDao.class);
private static final String COLUMNS = "id, name, cover_art_path, album_count, last_scanned, present, folder_id"; private static final String INSERT_COLUMNS = "name, cover_art_path, album_count, last_scanned, present, folder_id";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private final RowMapper rowMapper = new ArtistMapper(); private final RowMapper rowMapper = new ArtistMapper();
@ -52,7 +53,7 @@ public class ArtistDao extends AbstractDao {
* @return The artist or null. * @return The artist or null.
*/ */
public Artist getArtist(String artistName) { public Artist getArtist(String artistName) {
return queryOne("select " + COLUMNS + " from artist where name=?", rowMapper, artistName); return queryOne("select " + QUERY_COLUMNS + " from artist where name=?", rowMapper, artistName);
} }
/** /**
@ -71,7 +72,7 @@ public class ArtistDao extends AbstractDao {
put("folders", MusicFolder.toIdList(musicFolders)); put("folders", MusicFolder.toIdList(musicFolders));
}}; }};
return namedQueryOne("select " + COLUMNS + " from artist where name = :name and folder_id in (:folders)", return namedQueryOne("select " + QUERY_COLUMNS + " from artist where name = :name and folder_id in (:folders)",
rowMapper, args); rowMapper, args);
} }
@ -82,7 +83,7 @@ public class ArtistDao extends AbstractDao {
* @return The artist or null. * @return The artist or null.
*/ */
public Artist getArtist(int id) { public Artist getArtist(int id) {
return queryOne("select " + COLUMNS + " from artist where id=?", rowMapper, id); return queryOne("select " + QUERY_COLUMNS + " from artist where id=?", rowMapper, id);
} }
/** /**
@ -102,7 +103,7 @@ public class ArtistDao extends AbstractDao {
int n = update(sql, artist.getCoverArtPath(), artist.getAlbumCount(), artist.getLastScanned(), artist.isPresent(), artist.getFolderId(), artist.getName()); int n = update(sql, artist.getCoverArtPath(), artist.getAlbumCount(), artist.getLastScanned(), artist.isPresent(), artist.getFolderId(), artist.getName());
if (n == 0) { if (n == 0) {
update("insert into artist (" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")", null, update("insert into artist (" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")",
artist.getName(), artist.getCoverArtPath(), artist.getAlbumCount(), artist.getLastScanned(), artist.isPresent(), artist.getFolderId()); artist.getName(), artist.getCoverArtPath(), artist.getAlbumCount(), artist.getLastScanned(), artist.isPresent(), artist.getFolderId());
} }
@ -128,7 +129,7 @@ public class ArtistDao extends AbstractDao {
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from artist where present and folder_id in (:folders) " + return namedQuery("select " + QUERY_COLUMNS + " from artist where present and folder_id in (:folders) " +
"order by name limit :count offset :offset", rowMapper, args); "order by name limit :count offset :offset", rowMapper, args);
} }
@ -153,7 +154,7 @@ public class ArtistDao extends AbstractDao {
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + prefix(COLUMNS, "artist") + " from starred_artist, artist " + return namedQuery("select " + prefix(QUERY_COLUMNS, "artist") + " from starred_artist, artist " +
"where artist.id = starred_artist.artist_id and " + "where artist.id = starred_artist.artist_id and " +
"artist.present and starred_artist.username = :username and " + "artist.present and starred_artist.username = :username and " +
"artist.folder_id in (:folders) " + "artist.folder_id in (:folders) " +
@ -166,7 +167,7 @@ public class ArtistDao extends AbstractDao {
} }
public void markNonPresent(Date lastScanned) { public void markNonPresent(Date lastScanned) {
int minId = queryForInt("select top 1 id from artist where last_scanned != ? and present", 0, lastScanned); int minId = queryForInt("select min(id) from artist where last_scanned != ? and present", 0, lastScanned);
int maxId = queryForInt("select max(id) from artist where last_scanned != ? and present", 0, lastScanned); int maxId = queryForInt("select max(id) from artist where last_scanned != ? and present", 0, lastScanned);
final int batchSize = 1000; final int batchSize = 1000;
@ -176,7 +177,7 @@ public class ArtistDao extends AbstractDao {
} }
public void expunge() { public void expunge() {
int minId = queryForInt("select top 1 id from artist where not present", 0); int minId = queryForInt("select min(id) from artist where not present", 0);
int maxId = queryForInt("select max(id) from artist where not present", 0); int maxId = queryForInt("select max(id) from artist where not present", 0);
final int batchSize = 1000; final int batchSize = 1000;

@ -33,7 +33,8 @@ import java.util.List;
*/ */
public class AvatarDao extends AbstractDao { public class AvatarDao extends AbstractDao {
private static final String COLUMNS = "id, name, created_date, mime_type, width, height, data"; private static final String INSERT_COLUMNS = "name, created_date, mime_type, width, height, data";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private final AvatarRowMapper rowMapper = new AvatarRowMapper(); private final AvatarRowMapper rowMapper = new AvatarRowMapper();
/** /**
@ -42,7 +43,7 @@ public class AvatarDao extends AbstractDao {
* @return All system avatars. * @return All system avatars.
*/ */
public List<Avatar> getAllSystemAvatars() { public List<Avatar> getAllSystemAvatars() {
String sql = "select " + COLUMNS + " from system_avatar"; String sql = "select " + QUERY_COLUMNS + " from system_avatar";
return query(sql, rowMapper); return query(sql, rowMapper);
} }
@ -53,7 +54,7 @@ public class AvatarDao extends AbstractDao {
* @return The avatar or <code>null</code> if not found. * @return The avatar or <code>null</code> if not found.
*/ */
public Avatar getSystemAvatar(int id) { public Avatar getSystemAvatar(int id) {
String sql = "select " + COLUMNS + " from system_avatar where id=" + id; String sql = "select " + QUERY_COLUMNS + " from system_avatar where id=" + id;
return queryOne(sql, rowMapper); return queryOne(sql, rowMapper);
} }
@ -64,7 +65,7 @@ public class AvatarDao extends AbstractDao {
* @return The avatar or <code>null</code> if not found. * @return The avatar or <code>null</code> if not found.
*/ */
public Avatar getCustomAvatar(String username) { public Avatar getCustomAvatar(String username) {
String sql = "select " + COLUMNS + " from custom_avatar where username=?"; String sql = "select " + QUERY_COLUMNS + " from custom_avatar where username=?";
return queryOne(sql, rowMapper, username); return queryOne(sql, rowMapper, username);
} }
@ -79,8 +80,9 @@ public class AvatarDao extends AbstractDao {
update(sql, username); update(sql, username);
if (avatar != null) { if (avatar != null) {
update("insert into custom_avatar(" + COLUMNS + ", username) values(" + questionMarks(COLUMNS) + ", ?)", update("insert into custom_avatar(" + INSERT_COLUMNS
null, avatar.getName(), avatar.getCreatedDate(), avatar.getMimeType(), + ", username) values(" + questionMarks(INSERT_COLUMNS) + ", ?)",
avatar.getName(), avatar.getCreatedDate(), avatar.getMimeType(),
avatar.getWidth(), avatar.getHeight(), avatar.getData(), username); avatar.getWidth(), avatar.getHeight(), avatar.getData(), username);
} }
} }

@ -34,7 +34,8 @@ import org.libresonic.player.domain.Bookmark;
*/ */
public class BookmarkDao extends AbstractDao { public class BookmarkDao extends AbstractDao {
private static final String COLUMNS = "id, media_file_id, position_millis, username, comment, created, changed"; private static final String INSERT_COLUMNS = "media_file_id, position_millis, username, comment, created, changed";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private BookmarkRowMapper bookmarkRowMapper = new BookmarkRowMapper(); private BookmarkRowMapper bookmarkRowMapper = new BookmarkRowMapper();
@ -44,7 +45,7 @@ public class BookmarkDao extends AbstractDao {
* @return Possibly empty list of all bookmarks. * @return Possibly empty list of all bookmarks.
*/ */
public List<Bookmark> getBookmarks() { public List<Bookmark> getBookmarks() {
String sql = "select " + COLUMNS + " from bookmark"; String sql = "select " + QUERY_COLUMNS + " from bookmark";
return query(sql, bookmarkRowMapper); return query(sql, bookmarkRowMapper);
} }
@ -54,7 +55,7 @@ public class BookmarkDao extends AbstractDao {
* @return Possibly empty list of all bookmarks for the user. * @return Possibly empty list of all bookmarks for the user.
*/ */
public List<Bookmark> getBookmarks(String username) { public List<Bookmark> getBookmarks(String username) {
String sql = "select " + COLUMNS + " from bookmark where username=?"; String sql = "select " + QUERY_COLUMNS + " from bookmark where username=?";
return query(sql, bookmarkRowMapper, username); return query(sql, bookmarkRowMapper, username);
} }
@ -66,7 +67,7 @@ public class BookmarkDao extends AbstractDao {
bookmark.getPositionMillis(), bookmark.getComment(), bookmark.getChanged(), bookmark.getMediaFileId(), bookmark.getUsername()); bookmark.getPositionMillis(), bookmark.getComment(), bookmark.getChanged(), bookmark.getMediaFileId(), bookmark.getUsername());
if (n == 0) { if (n == 0) {
update("insert into bookmark (" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")", null, update("insert into bookmark (" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")",
bookmark.getMediaFileId(), bookmark.getPositionMillis(), bookmark.getUsername(), bookmark.getComment(), bookmark.getMediaFileId(), bookmark.getPositionMillis(), bookmark.getUsername(), bookmark.getComment(),
bookmark.getCreated(), bookmark.getChanged()); bookmark.getCreated(), bookmark.getChanged());
int id = queryForInt("select id from bookmark where media_file_id=? and username=?", 0, bookmark.getMediaFileId(), bookmark.getUsername()); int id = queryForInt("select id from bookmark where media_file_id=? and username=?", 0, bookmark.getMediaFileId(), bookmark.getUsername());

@ -19,6 +19,7 @@
*/ */
package org.libresonic.player.dao; package org.libresonic.player.dao;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@ -43,4 +44,5 @@ public interface DaoHelper {
*/ */
NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(); NamedParameterJdbcTemplate getNamedParameterJdbcTemplate();
DataSource getDataSource();
} }

@ -1,19 +1,23 @@
package org.libresonic.player.dao; package org.libresonic.player.dao;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
public class GenericDaoHelper implements DaoHelper { public class GenericDaoHelper implements DaoHelper {
JdbcTemplate jdbcTemplate; final JdbcTemplate jdbcTemplate;
NamedParameterJdbcTemplate namedParameterJdbcTemplate; final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
final DataSource dataSource;
public GenericDaoHelper( public GenericDaoHelper(
JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate DataSource dataSource
) { ) {
this.jdbcTemplate = jdbcTemplate; this.dataSource = dataSource;
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; this.jdbcTemplate = new JdbcTemplate(dataSource);
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
} }
@Override @Override
@ -25,4 +29,9 @@ public class GenericDaoHelper implements DaoHelper {
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() { public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
return namedParameterJdbcTemplate; return namedParameterJdbcTemplate;
} }
@Override
public DataSource getDataSource() {
return dataSource;
}
} }

@ -36,7 +36,8 @@ import org.libresonic.player.domain.InternetRadio;
public class InternetRadioDao extends AbstractDao { public class InternetRadioDao extends AbstractDao {
private static final Logger LOG = Logger.getLogger(InternetRadioDao.class); private static final Logger LOG = Logger.getLogger(InternetRadioDao.class);
private static final String COLUMNS = "id, name, stream_url, homepage_url, enabled, changed"; private static final String INSERT_COLUMNS = "name, stream_url, homepage_url, enabled, changed";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private final InternetRadioRowMapper rowMapper = new InternetRadioRowMapper(); private final InternetRadioRowMapper rowMapper = new InternetRadioRowMapper();
/** /**
@ -45,7 +46,7 @@ public class InternetRadioDao extends AbstractDao {
* @return Possibly empty list of all internet radio stations. * @return Possibly empty list of all internet radio stations.
*/ */
public List<InternetRadio> getAllInternetRadios() { public List<InternetRadio> getAllInternetRadios() {
String sql = "select " + COLUMNS + " from internet_radio"; String sql = "select " + QUERY_COLUMNS + " from internet_radio";
return query(sql, rowMapper); return query(sql, rowMapper);
} }
@ -55,7 +56,7 @@ public class InternetRadioDao extends AbstractDao {
* @param radio The internet radio station to create. * @param radio The internet radio station to create.
*/ */
public void createInternetRadio(InternetRadio radio) { public void createInternetRadio(InternetRadio radio) {
String sql = "insert into internet_radio (" + COLUMNS + ") values (null, ?, ?, ?, ?, ?)"; String sql = "insert into internet_radio (" + INSERT_COLUMNS + ") values (?, ?, ?, ?, ?)";
update(sql, radio.getName(), radio.getStreamUrl(), radio.getHomepageUrl(), radio.isEnabled(), radio.getChanged()); update(sql, radio.getName(), radio.getStreamUrl(), radio.getHomepageUrl(), radio.isEnabled(), radio.getChanged());
LOG.info("Created internet radio station " + radio.getName()); LOG.info("Created internet radio station " + radio.getName());
} }

@ -40,15 +40,16 @@ import static org.libresonic.player.domain.MediaFile.MediaType.*;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class MediaFileDao extends AbstractDao { public class MediaFileDao extends AbstractDao {
private static final String INSERT_COLUMNS = "path, folder, type, format, title, album, artist, album_artist, disc_number, " +
private static final String COLUMNS = "id, path, folder, type, format, title, album, artist, album_artist, disc_number, " +
"track_number, year, genre, bit_rate, variable_bit_rate, duration_seconds, file_size, width, height, cover_art_path, " + "track_number, year, genre, bit_rate, variable_bit_rate, duration_seconds, file_size, width, height, cover_art_path, " +
"parent_path, play_count, last_played, comment, created, changed, last_scanned, children_last_updated, present, version"; "parent_path, play_count, last_played, comment, created, changed, last_scanned, children_last_updated, present, version";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private static final String GENRE_COLUMNS = "name, song_count, album_count"; private static final String GENRE_COLUMNS = "name, song_count, album_count";
public static final int VERSION = 4; public static final int VERSION = 4;
private final RowMapper rowMapper = new MediaFileMapper(); private final RowMapper<MediaFile> rowMapper = new MediaFileMapper();
private final RowMapper musicFileInfoRowMapper = new MusicFileInfoMapper(); private final RowMapper musicFileInfoRowMapper = new MusicFileInfoMapper();
private final RowMapper genreRowMapper = new GenreMapper(); private final RowMapper genreRowMapper = new GenreMapper();
@ -59,7 +60,7 @@ public class MediaFileDao extends AbstractDao {
* @return The media file or null. * @return The media file or null.
*/ */
public MediaFile getMediaFile(String path) { public MediaFile getMediaFile(String path) {
return queryOne("select " + COLUMNS + " from media_file where path=?", rowMapper, path); return queryOne("select " + QUERY_COLUMNS + " from media_file where path=?", rowMapper, path);
} }
/** /**
@ -69,7 +70,7 @@ public class MediaFileDao extends AbstractDao {
* @return The media file or null. * @return The media file or null.
*/ */
public MediaFile getMediaFile(int id) { public MediaFile getMediaFile(int id) {
return queryOne("select " + COLUMNS + " from media_file where id=?", rowMapper, id); return queryOne("select " + QUERY_COLUMNS + " from media_file where id=?", rowMapper, id);
} }
/** /**
@ -79,18 +80,18 @@ public class MediaFileDao extends AbstractDao {
* @return The list of children. * @return The list of children.
*/ */
public List<MediaFile> getChildrenOf(String path) { public List<MediaFile> getChildrenOf(String path) {
return query("select " + COLUMNS + " from media_file where parent_path=? and present", rowMapper, path); return query("select " + QUERY_COLUMNS + " from media_file where parent_path=? and present", rowMapper, path);
} }
public List<MediaFile> getFilesInPlaylist(int playlistId) { public List<MediaFile> getFilesInPlaylist(int playlistId) {
return query("select " + prefix(COLUMNS, "media_file") + " from playlist_file, media_file where " + return query("select " + prefix(QUERY_COLUMNS, "media_file") + " from playlist_file, media_file where " +
"media_file.id = playlist_file.media_file_id and " + "media_file.id = playlist_file.media_file_id and " +
"playlist_file.playlist_id = ? " + "playlist_file.playlist_id = ? " +
"order by playlist_file.id", rowMapper, playlistId); "order by playlist_file.id", rowMapper, playlistId);
} }
public List<MediaFile> getSongsForAlbum(String artist, String album) { public List<MediaFile> getSongsForAlbum(String artist, String album) {
return query("select " + COLUMNS + " from media_file where album_artist=? and album=? and present " + return query("select " + QUERY_COLUMNS + " from media_file where album_artist=? and album=? and present " +
"and type in (?,?,?) order by disc_number, track_number", rowMapper, "and type in (?,?,?) order by disc_number, track_number", rowMapper,
artist, album, MUSIC.name(), AUDIOBOOK.name(), PODCAST.name()); artist, album, MUSIC.name(), AUDIOBOOK.name(), PODCAST.name());
} }
@ -105,7 +106,8 @@ public class MediaFileDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from media_file where type = :type and present and folder in (:folders) " + return namedQuery("select " + QUERY_COLUMNS
+ " from media_file where type = :type and present and folder in (:folders) " +
"order by title limit :count offset :offset", rowMapper, args); "order by title limit :count offset :offset", rowMapper, args);
} }
@ -118,7 +120,7 @@ public class MediaFileDao extends AbstractDao {
put("name", name); put("name", name);
put("folders", MusicFolder.toPathList(musicFolders)); put("folders", MusicFolder.toPathList(musicFolders));
}}; }};
return namedQueryOne("select " + COLUMNS + " from media_file where type = :type and artist = :name " + return namedQueryOne("select " + QUERY_COLUMNS + " from media_file where type = :type and artist = :name " +
"and present and folder in (:folders)", rowMapper, args); "and present and folder in (:folders)", rowMapper, args);
} }
@ -175,7 +177,7 @@ public class MediaFileDao extends AbstractDao {
file.setPlayCount(musicFileInfo.getPlayCount()); file.setPlayCount(musicFileInfo.getPlayCount());
} }
update("insert into media_file (" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")", null, update("insert into media_file (" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")",
file.getPath(), file.getFolder(), file.getMediaType().name(), file.getFormat(), file.getTitle(), file.getAlbumName(), file.getArtist(), file.getPath(), file.getFolder(), file.getMediaType().name(), file.getFormat(), file.getTitle(), file.getAlbumName(), file.getArtist(),
file.getAlbumArtist(), file.getDiscNumber(), file.getTrackNumber(), file.getYear(), file.getGenre(), file.getBitRate(), file.getAlbumArtist(), file.getDiscNumber(), file.getTrackNumber(), file.getYear(), file.getGenre(), file.getBitRate(),
file.isVariableBitRate(), file.getDurationSeconds(), file.getFileSize(), file.getWidth(), file.getHeight(), file.isVariableBitRate(), file.getDurationSeconds(), file.getFileSize(), file.getWidth(), file.getHeight(),
@ -228,7 +230,8 @@ public class MediaFileDao extends AbstractDao {
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from media_file where type = :type and play_count > 0 and present and folder in (:folders) " + return namedQuery("select " + QUERY_COLUMNS
+ " from media_file where type = :type and play_count > 0 and present and folder in (:folders) " +
"order by play_count desc limit :count offset :offset", rowMapper, args); "order by play_count desc limit :count offset :offset", rowMapper, args);
} }
@ -250,7 +253,8 @@ public class MediaFileDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from media_file where type = :type and last_played is not null and present " + return namedQuery("select " + QUERY_COLUMNS
+ " from media_file where type = :type and last_played is not null and present " +
"and folder in (:folders) order by last_played desc limit :count offset :offset", rowMapper, args); "and folder in (:folders) order by last_played desc limit :count offset :offset", rowMapper, args);
} }
@ -273,7 +277,8 @@ public class MediaFileDao extends AbstractDao {
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from media_file where type = :type and folder in (:folders) and present " + return namedQuery("select " + QUERY_COLUMNS
+ " from media_file where type = :type and folder in (:folders) and present " +
"order by created desc limit :count offset :offset", rowMapper, args); "order by created desc limit :count offset :offset", rowMapper, args);
} }
@ -298,7 +303,8 @@ public class MediaFileDao extends AbstractDao {
}}; }};
String orderBy = byArtist ? "artist, album" : "album"; String orderBy = byArtist ? "artist, album" : "album";
return namedQuery("select " + COLUMNS + " from media_file where type = :type and folder in (:folders) and present " + return namedQuery("select " + QUERY_COLUMNS
+ " from media_file where type = :type and folder in (:folders) and present " +
"order by " + orderBy + " limit :count offset :offset", rowMapper, args); "order by " + orderBy + " limit :count offset :offset", rowMapper, args);
} }
@ -327,11 +333,13 @@ public class MediaFileDao extends AbstractDao {
}}; }};
if (fromYear <= toYear) { if (fromYear <= toYear) {
return namedQuery("select " + COLUMNS + " from media_file where type = :type and folder in (:folders) and present " + return namedQuery("select " + QUERY_COLUMNS
+ " from media_file where type = :type and folder in (:folders) and present " +
"and year between :fromYear and :toYear order by year limit :count offset :offset", "and year between :fromYear and :toYear order by year limit :count offset :offset",
rowMapper, args); rowMapper, args);
} else { } else {
return namedQuery("select " + COLUMNS + " from media_file where type = :type and folder in (:folders) and present " + return namedQuery("select " + QUERY_COLUMNS
+ " from media_file where type = :type and folder in (:folders) and present " +
"and year between :toYear and :fromYear order by year desc limit :count offset :offset", "and year between :toYear and :fromYear order by year desc limit :count offset :offset",
rowMapper, args); rowMapper, args);
} }
@ -358,7 +366,7 @@ public class MediaFileDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + COLUMNS + " from media_file where type = :type and folder in (:folders) " + return namedQuery("select " + QUERY_COLUMNS + " from media_file where type = :type and folder in (:folders) " +
"and present and genre = :genre limit :count offset :offset", rowMapper, args); "and present and genre = :genre limit :count offset :offset", rowMapper, args);
} }
@ -373,13 +381,14 @@ public class MediaFileDao extends AbstractDao {
put("offset", offset); put("offset", offset);
put("folders", MusicFolder.toPathList(musicFolders)); put("folders", MusicFolder.toPathList(musicFolders));
}}; }};
return namedQuery("select " + COLUMNS + " from media_file where type in (:types) and genre = :genre " + return namedQuery("select " + QUERY_COLUMNS + " from media_file where type in (:types) and genre = :genre " +
"and present and folder in (:folders) limit :count offset :offset", "and present and folder in (:folders) limit :count offset :offset",
rowMapper, args); rowMapper, args);
} }
public List<MediaFile> getSongsByArtist(String artist, int offset, int count) { public List<MediaFile> getSongsByArtist(String artist, int offset, int count) {
return query("select " + COLUMNS + " from media_file where type in (?,?,?) and artist=? and present limit ? offset ?", return query("select " + QUERY_COLUMNS
+ " from media_file where type in (?,?,?) and artist=? and present limit ? offset ?",
rowMapper, MUSIC.name(), PODCAST.name(), AUDIOBOOK.name(), artist, count, offset); rowMapper, MUSIC.name(), PODCAST.name(), AUDIOBOOK.name(), artist, count, offset);
} }
@ -393,7 +402,7 @@ public class MediaFileDao extends AbstractDao {
put("type", MUSIC.name()); put("type", MUSIC.name());
put("folders", MusicFolder.toPathList(musicFolders)); put("folders", MusicFolder.toPathList(musicFolders));
}}; }};
return namedQueryOne("select " + COLUMNS + " from media_file where artist = :artist " + return namedQueryOne("select " + QUERY_COLUMNS + " from media_file where artist = :artist " +
"and title = :title and type = :type and present and folder in (:folders)" , "and title = :title and type = :type and present and folder in (:folders)" ,
rowMapper, args); rowMapper, args);
} }
@ -419,7 +428,7 @@ public class MediaFileDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + prefix(COLUMNS, "media_file") + " from starred_media_file, media_file where media_file.id = starred_media_file.media_file_id and " + return namedQuery("select " + prefix(QUERY_COLUMNS, "media_file") + " from starred_media_file, media_file where media_file.id = starred_media_file.media_file_id and " +
"media_file.present and media_file.type = :type and media_file.folder in (:folders) and starred_media_file.username = :username " + "media_file.present and media_file.type = :type and media_file.folder in (:folders) and starred_media_file.username = :username " +
"order by starred_media_file.created desc limit :count offset :offset", "order by starred_media_file.created desc limit :count offset :offset",
rowMapper, args); rowMapper, args);
@ -446,7 +455,7 @@ public class MediaFileDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + prefix(COLUMNS, "media_file") + " from starred_media_file, media_file " + return namedQuery("select " + prefix(QUERY_COLUMNS, "media_file") + " from starred_media_file, media_file " +
"where media_file.id = starred_media_file.media_file_id and " + "where media_file.id = starred_media_file.media_file_id and " +
"media_file.present and media_file.type = :type and starred_media_file.username = :username and " + "media_file.present and media_file.type = :type and starred_media_file.username = :username and " +
"media_file.folder in (:folders) " + "media_file.folder in (:folders) " +
@ -475,7 +484,7 @@ public class MediaFileDao extends AbstractDao {
put("count", count); put("count", count);
put("offset", offset); put("offset", offset);
}}; }};
return namedQuery("select " + prefix(COLUMNS, "media_file") + " from starred_media_file, media_file where media_file.id = starred_media_file.media_file_id and " + return namedQuery("select " + prefix(QUERY_COLUMNS, "media_file") + " from starred_media_file, media_file where media_file.id = starred_media_file.media_file_id and " +
"media_file.present and media_file.type in (:types) and starred_media_file.username = :username and " + "media_file.present and media_file.type in (:types) and starred_media_file.username = :username and " +
"media_file.folder in (:folders) " + "media_file.folder in (:folders) " +
"order by starred_media_file.created desc limit :count offset :offset", "order by starred_media_file.created desc limit :count offset :offset",
@ -490,7 +499,6 @@ public class MediaFileDao extends AbstractDao {
Map<String, Object> args = new HashMap<String, Object>() {{ Map<String, Object> args = new HashMap<String, Object>() {{
put("folders", MusicFolder.toPathList(criteria.getMusicFolders())); put("folders", MusicFolder.toPathList(criteria.getMusicFolders()));
put("username", username); put("username", username);
put("count", criteria.getCount());
put("fromYear", criteria.getFromYear()); put("fromYear", criteria.getFromYear());
put("toYear", criteria.getToYear()); put("toYear", criteria.getToYear());
put("genre", criteria.getGenre()); put("genre", criteria.getGenre());
@ -508,7 +516,7 @@ public class MediaFileDao extends AbstractDao {
boolean joinAlbumRating = (criteria.getMinAlbumRating() != null || criteria.getMaxAlbumRating() != null); boolean joinAlbumRating = (criteria.getMinAlbumRating() != null || criteria.getMaxAlbumRating() != null);
boolean joinStarred = (criteria.isShowStarredSongs() ^ criteria.isShowUnstarredSongs()); boolean joinStarred = (criteria.isShowStarredSongs() ^ criteria.isShowUnstarredSongs());
String query = "select top :count " + prefix(COLUMNS, "media_file") + " from media_file "; String query = "select " + prefix(QUERY_COLUMNS, "media_file") + " from media_file ";
if (joinStarred) { if (joinStarred) {
query += "left outer join starred_media_file on media_file.id = starred_media_file.media_file_id and starred_media_file.username = :username "; query += "left outer join starred_media_file on media_file.id = starred_media_file.media_file_id and starred_media_file.username = :username ";
@ -587,7 +595,7 @@ public class MediaFileDao extends AbstractDao {
query += " order by rand()"; query += " order by rand()";
return namedQuery(query, rowMapper, args); return namedQueryWithLimit(query, rowMapper, args, criteria.getCount());
} }
public int getAlbumCount(final List<MusicFolder> musicFolders) { public int getAlbumCount(final List<MusicFolder> musicFolders) {
@ -649,7 +657,7 @@ public class MediaFileDao extends AbstractDao {
} }
public void markNonPresent(Date lastScanned) { public void markNonPresent(Date lastScanned) {
int minId = queryForInt("select top 1 id from media_file where last_scanned != ? and present", 0, lastScanned); int minId = queryForInt("select min(id) from media_file where last_scanned != ? and present", 0, lastScanned);
int maxId = queryForInt("select max(id) from media_file where last_scanned != ? and present", 0, lastScanned); int maxId = queryForInt("select max(id) from media_file where last_scanned != ? and present", 0, lastScanned);
final int batchSize = 1000; final int batchSize = 1000;
@ -661,7 +669,7 @@ public class MediaFileDao extends AbstractDao {
} }
public void expunge() { public void expunge() {
int minId = queryForInt("select top 1 id from media_file where not present", 0); int minId = queryForInt("select min(id) from media_file where not present", 0);
int maxId = queryForInt("select max(id) from media_file where not present", 0); int maxId = queryForInt("select max(id) from media_file where not present", 0);
final int batchSize = 1000; final int batchSize = 1000;

@ -36,7 +36,8 @@ import java.util.List;
public class MusicFolderDao extends AbstractDao { public class MusicFolderDao extends AbstractDao {
private static final Logger LOG = Logger.getLogger(MusicFolderDao.class); private static final Logger LOG = Logger.getLogger(MusicFolderDao.class);
private static final String COLUMNS = "id, path, name, enabled, changed"; private static final String INSERT_COLUMNS = "path, name, enabled, changed";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private final MusicFolderRowMapper rowMapper = new MusicFolderRowMapper(); private final MusicFolderRowMapper rowMapper = new MusicFolderRowMapper();
/** /**
@ -45,7 +46,7 @@ public class MusicFolderDao extends AbstractDao {
* @return Possibly empty list of all music folders. * @return Possibly empty list of all music folders.
*/ */
public List<MusicFolder> getAllMusicFolders() { public List<MusicFolder> getAllMusicFolders() {
String sql = "select " + COLUMNS + " from music_folder"; String sql = "select " + QUERY_COLUMNS + " from music_folder";
return query(sql, rowMapper); return query(sql, rowMapper);
} }
@ -55,7 +56,7 @@ public class MusicFolderDao extends AbstractDao {
* @param musicFolder The music folder to create. * @param musicFolder The music folder to create.
*/ */
public void createMusicFolder(MusicFolder musicFolder) { public void createMusicFolder(MusicFolder musicFolder) {
String sql = "insert into music_folder (" + COLUMNS + ") values (null, ?, ?, ?, ?)"; String sql = "insert into music_folder (" + INSERT_COLUMNS + ") values (?, ?, ?, ?)";
update(sql, musicFolder.getPath(), musicFolder.getName(), musicFolder.isEnabled(), musicFolder.getChanged()); update(sql, musicFolder.getPath(), musicFolder.getName(), musicFolder.isEnabled(), musicFolder.getChanged());
Integer id = queryForInt("select max(id) from music_folder", 0); Integer id = queryForInt("select max(id) from music_folder", 0);
@ -86,7 +87,7 @@ public class MusicFolderDao extends AbstractDao {
} }
public List<MusicFolder> getMusicFoldersForUser(String username) { public List<MusicFolder> getMusicFoldersForUser(String username) {
String sql = "select " + prefix(COLUMNS, "music_folder") + " from music_folder, music_folder_user " + String sql = "select " + prefix(QUERY_COLUMNS, "music_folder") + " from music_folder, music_folder_user " +
"where music_folder.id = music_folder_user.music_folder_id and music_folder_user.username = ?"; "where music_folder.id = music_folder_user.music_folder_id and music_folder_user.username = ?";
return query(sql, rowMapper, username); return query(sql, rowMapper, username);
} }

@ -33,11 +33,12 @@ import org.libresonic.player.domain.SavedPlayQueue;
*/ */
public class PlayQueueDao extends AbstractDao { public class PlayQueueDao extends AbstractDao {
private static final String COLUMNS = "id, username, current, position_millis, changed, changed_by"; private static final String INSERT_COLUMNS = "username, current, position_millis, changed, changed_by";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private final RowMapper rowMapper = new PlayQueueMapper(); private final RowMapper rowMapper = new PlayQueueMapper();
public synchronized SavedPlayQueue getPlayQueue(String username) { public synchronized SavedPlayQueue getPlayQueue(String username) {
SavedPlayQueue playQueue = queryOne("select " + COLUMNS + " from play_queue where username=?", rowMapper, username); SavedPlayQueue playQueue = queryOne("select " + QUERY_COLUMNS + " from play_queue where username=?", rowMapper, username);
if (playQueue == null) { if (playQueue == null) {
return null; return null;
} }
@ -48,8 +49,8 @@ public class PlayQueueDao extends AbstractDao {
public synchronized void savePlayQueue(SavedPlayQueue playQueue) { public synchronized void savePlayQueue(SavedPlayQueue playQueue) {
update("delete from play_queue where username=?", playQueue.getUsername()); update("delete from play_queue where username=?", playQueue.getUsername());
update("insert into play_queue(" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")", update("insert into play_queue(" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")",
null, playQueue.getUsername(), playQueue.getCurrentMediaFileId(), playQueue.getPositionMillis(), playQueue.getUsername(), playQueue.getCurrentMediaFileId(), playQueue.getPositionMillis(),
playQueue.getChanged(), playQueue.getChangedBy()); playQueue.getChanged(), playQueue.getChangedBy());
int id = queryForInt("select max(id) from play_queue", 0); int id = queryForInt("select max(id) from play_queue", 0);
playQueue.setId(id); playQueue.setId(id);

@ -35,8 +35,9 @@ import java.util.*;
public class PlayerDao extends AbstractDao { public class PlayerDao extends AbstractDao {
private static final Logger LOG = Logger.getLogger(PlayerDao.class); private static final Logger LOG = Logger.getLogger(PlayerDao.class);
private static final String COLUMNS = "id, name, type, username, ip_address, auto_control_enabled, m3u_bom_enabled, " + private static final String INSERT_COLUMNS = "name, type, username, ip_address, auto_control_enabled, m3u_bom_enabled, " +
"last_seen, cover_art_scheme, transcode_scheme, dynamic_ip, technology, client_id"; "last_seen, cover_art_scheme, transcode_scheme, dynamic_ip, technology, client_id";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private PlayerRowMapper rowMapper = new PlayerRowMapper(); private PlayerRowMapper rowMapper = new PlayerRowMapper();
private Map<String, PlayQueue> playlists = Collections.synchronizedMap(new HashMap<String, PlayQueue>()); private Map<String, PlayQueue> playlists = Collections.synchronizedMap(new HashMap<String, PlayQueue>());
@ -47,7 +48,7 @@ public class PlayerDao extends AbstractDao {
* @return Possibly empty list of all users. * @return Possibly empty list of all users.
*/ */
public List<Player> getAllPlayers() { public List<Player> getAllPlayers() {
String sql = "select " + COLUMNS + " from player"; String sql = "select " + QUERY_COLUMNS + " from player";
return query(sql, rowMapper); return query(sql, rowMapper);
} }
@ -61,10 +62,10 @@ public class PlayerDao extends AbstractDao {
*/ */
public List<Player> getPlayersForUserAndClientId(String username, String clientId) { public List<Player> getPlayersForUserAndClientId(String username, String clientId) {
if (clientId != null) { if (clientId != null) {
String sql = "select " + COLUMNS + " from player where username=? and client_id=?"; String sql = "select " + QUERY_COLUMNS + " from player where username=? and client_id=?";
return query(sql, rowMapper, username, clientId); return query(sql, rowMapper, username, clientId);
} else { } else {
String sql = "select " + COLUMNS + " from player where username=? and client_id is null"; String sql = "select " + QUERY_COLUMNS + " from player where username=? and client_id is null";
return query(sql, rowMapper, username); return query(sql, rowMapper, username);
} }
} }
@ -76,7 +77,7 @@ public class PlayerDao extends AbstractDao {
* @return The player with the given ID, or <code>null</code> if no such player exists. * @return The player with the given ID, or <code>null</code> if no such player exists.
*/ */
public Player getPlayerById(String id) { public Player getPlayerById(String id) {
String sql = "select " + COLUMNS + " from player where id=?"; String sql = "select " + QUERY_COLUMNS + " from player where id=?";
return queryOne(sql, rowMapper, id); return queryOne(sql, rowMapper, id);
} }
@ -92,7 +93,7 @@ public class PlayerDao extends AbstractDao {
} }
int id = existingMax + 1; int id = existingMax + 1;
player.setId(String.valueOf(id)); player.setId(String.valueOf(id));
String sql = "insert into player (" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")"; String sql = "insert into player (" + QUERY_COLUMNS + ") values (" + questionMarks(QUERY_COLUMNS) + ")";
update(sql, player.getId(), player.getName(), player.getType(), player.getUsername(), update(sql, player.getId(), player.getName(), player.getType(), player.getUsername(),
player.getIpAddress(), player.isAutoControlEnabled(), player.isM3uBomEnabled(), player.getIpAddress(), player.isAutoControlEnabled(), player.isM3uBomEnabled(),
player.getLastSeen(), CoverArtScheme.MEDIUM.name(), player.getLastSeen(), CoverArtScheme.MEDIUM.name(),

@ -40,15 +40,16 @@ import java.util.TreeMap;
public class PlaylistDao extends AbstractDao { public class PlaylistDao extends AbstractDao {
private static final Logger LOG = Logger.getLogger(PlaylistDao.class); private static final Logger LOG = Logger.getLogger(PlaylistDao.class);
private static final String COLUMNS = "id, username, is_public, name, comment, file_count, duration_seconds, " + private static final String INSERT_COLUMNS = "username, is_public, name, comment, file_count, duration_seconds, " +
"created, changed, imported_from"; "created, changed, imported_from";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private final RowMapper rowMapper = new PlaylistMapper(); private final RowMapper rowMapper = new PlaylistMapper();
public List<Playlist> getReadablePlaylistsForUser(String username) { public List<Playlist> getReadablePlaylistsForUser(String username) {
List<Playlist> result1 = getWritablePlaylistsForUser(username); List<Playlist> result1 = getWritablePlaylistsForUser(username);
List<Playlist> result2 = query("select " + COLUMNS + " from playlist where is_public", rowMapper); List<Playlist> result2 = query("select " + QUERY_COLUMNS + " from playlist where is_public", rowMapper);
List<Playlist> result3 = query("select " + prefix(COLUMNS, "playlist") + " from playlist, playlist_user where " + List<Playlist> result3 = query("select " + prefix(QUERY_COLUMNS, "playlist") + " from playlist, playlist_user where " +
"playlist.id = playlist_user.playlist_id and " + "playlist.id = playlist_user.playlist_id and " +
"playlist.username != ? and " + "playlist.username != ? and " +
"playlist_user.username = ?", rowMapper, username, username); "playlist_user.username = ?", rowMapper, username, username);
@ -68,20 +69,20 @@ public class PlaylistDao extends AbstractDao {
} }
public List<Playlist> getWritablePlaylistsForUser(String username) { public List<Playlist> getWritablePlaylistsForUser(String username) {
return query("select " + COLUMNS + " from playlist where username=?", rowMapper, username); return query("select " + QUERY_COLUMNS + " from playlist where username=?", rowMapper, username);
} }
public Playlist getPlaylist(int id) { public Playlist getPlaylist(int id) {
return queryOne("select " + COLUMNS + " from playlist where id=?", rowMapper, id); return queryOne("select " + QUERY_COLUMNS + " from playlist where id=?", rowMapper, id);
} }
public List<Playlist> getAllPlaylists() { public List<Playlist> getAllPlaylists() {
return query("select " + COLUMNS + " from playlist", rowMapper); return query("select " + QUERY_COLUMNS + " from playlist", rowMapper);
} }
public synchronized void createPlaylist(Playlist playlist) { public synchronized void createPlaylist(Playlist playlist) {
update("insert into playlist(" + COLUMNS + ") values(" + questionMarks(COLUMNS) + ")", update("insert into playlist(" + INSERT_COLUMNS + ") values(" + questionMarks(INSERT_COLUMNS) + ")",
null, playlist.getUsername(), playlist.isShared(), playlist.getName(), playlist.getComment(), playlist.getUsername(), playlist.isShared(), playlist.getName(), playlist.getComment(),
0, 0, playlist.getCreated(), playlist.getChanged(), playlist.getImportedFrom()); 0, 0, playlist.getCreated(), playlist.getChanged(), playlist.getImportedFrom());
int id = queryForInt("select max(id) from playlist", 0); int id = queryForInt("select max(id) from playlist", 0);

@ -36,9 +36,11 @@ import org.libresonic.player.domain.PodcastStatus;
*/ */
public class PodcastDao extends AbstractDao { public class PodcastDao extends AbstractDao {
private static final String CHANNEL_COLUMNS = "id, url, title, description, image_url, status, error_message"; private static final String CHANNEL_INSERT_COLUMNS = "url, title, description, image_url, status, error_message";
private static final String EPISODE_COLUMNS = "id, channel_id, url, path, title, description, publish_date, " + private static final String CHANNEL_QUERY_COLUMNS = "id, " + CHANNEL_INSERT_COLUMNS;
private static final String EPISODE_INSERT_COLUMNS = "channel_id, url, path, title, description, publish_date, " +
"duration, bytes_total, bytes_downloaded, status, error_message"; "duration, bytes_total, bytes_downloaded, status, error_message";
private static final String EPISODE_QUERY_COLUMNS = "id, " + EPISODE_INSERT_COLUMNS;
private PodcastChannelRowMapper channelRowMapper = new PodcastChannelRowMapper(); private PodcastChannelRowMapper channelRowMapper = new PodcastChannelRowMapper();
private PodcastEpisodeRowMapper episodeRowMapper = new PodcastEpisodeRowMapper(); private PodcastEpisodeRowMapper episodeRowMapper = new PodcastEpisodeRowMapper();
@ -50,8 +52,9 @@ public class PodcastDao extends AbstractDao {
* @return The ID of the newly created channel. * @return The ID of the newly created channel.
*/ */
public synchronized int createChannel(PodcastChannel channel) { public synchronized int createChannel(PodcastChannel channel) {
String sql = "insert into podcast_channel (" + CHANNEL_COLUMNS + ") values (" + questionMarks(CHANNEL_COLUMNS) + ")"; String sql = "insert into podcast_channel (" + CHANNEL_INSERT_COLUMNS + ") values (" + questionMarks(
update(sql, null, channel.getUrl(), channel.getTitle(), channel.getDescription(), channel.getImageUrl(), CHANNEL_INSERT_COLUMNS) + ")";
update(sql, channel.getUrl(), channel.getTitle(), channel.getDescription(), channel.getImageUrl(),
channel.getStatus().name(), channel.getErrorMessage()); channel.getStatus().name(), channel.getErrorMessage());
return getJdbcTemplate().queryForObject("select max(id) from podcast_channel", Integer.class); return getJdbcTemplate().queryForObject("select max(id) from podcast_channel", Integer.class);
@ -63,7 +66,7 @@ public class PodcastDao extends AbstractDao {
* @return Possibly empty list of all Podcast channels. * @return Possibly empty list of all Podcast channels.
*/ */
public List<PodcastChannel> getAllChannels() { public List<PodcastChannel> getAllChannels() {
String sql = "select " + CHANNEL_COLUMNS + " from podcast_channel"; String sql = "select " + CHANNEL_QUERY_COLUMNS + " from podcast_channel";
return query(sql, channelRowMapper); return query(sql, channelRowMapper);
} }
@ -71,7 +74,7 @@ public class PodcastDao extends AbstractDao {
* Returns a single Podcast channel. * Returns a single Podcast channel.
*/ */
public PodcastChannel getChannel(int channelId) { public PodcastChannel getChannel(int channelId) {
String sql = "select " + CHANNEL_COLUMNS + " from podcast_channel where id=?"; String sql = "select " + CHANNEL_QUERY_COLUMNS + " from podcast_channel where id=?";
return queryOne(sql, channelRowMapper, channelId); return queryOne(sql, channelRowMapper, channelId);
} }
@ -102,8 +105,9 @@ public class PodcastDao extends AbstractDao {
* @param episode The Podcast episode to create. * @param episode The Podcast episode to create.
*/ */
public void createEpisode(PodcastEpisode episode) { public void createEpisode(PodcastEpisode episode) {
String sql = "insert into podcast_episode (" + EPISODE_COLUMNS + ") values (" + questionMarks(EPISODE_COLUMNS) + ")"; String sql = "insert into podcast_episode (" + EPISODE_INSERT_COLUMNS + ") values (" + questionMarks(
update(sql, null, episode.getChannelId(), episode.getUrl(), episode.getPath(), EPISODE_INSERT_COLUMNS) + ")";
update(sql, episode.getChannelId(), episode.getUrl(), episode.getPath(),
episode.getTitle(), episode.getDescription(), episode.getPublishDate(), episode.getTitle(), episode.getDescription(), episode.getPublishDate(),
episode.getDuration(), episode.getBytesTotal(), episode.getBytesDownloaded(), episode.getDuration(), episode.getBytesTotal(), episode.getBytesDownloaded(),
episode.getStatus().name(), episode.getErrorMessage()); episode.getStatus().name(), episode.getErrorMessage());
@ -116,7 +120,7 @@ public class PodcastDao extends AbstractDao {
* reverse chronological order (newest episode first). * reverse chronological order (newest episode first).
*/ */
public List<PodcastEpisode> getEpisodes(int channelId) { public List<PodcastEpisode> getEpisodes(int channelId) {
String sql = "select " + EPISODE_COLUMNS + " from podcast_episode where channel_id = ? " + String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where channel_id = ? " +
"and status != ? order by publish_date desc"; "and status != ? order by publish_date desc";
return query(sql, episodeRowMapper, channelId, PodcastStatus.DELETED); return query(sql, episodeRowMapper, channelId, PodcastStatus.DELETED);
} }
@ -128,7 +132,8 @@ public class PodcastDao extends AbstractDao {
* reverse chronological order (newest episode first). * reverse chronological order (newest episode first).
*/ */
public List<PodcastEpisode> getNewestEpisodes(int count) { public List<PodcastEpisode> getNewestEpisodes(int count) {
String sql = "select " + EPISODE_COLUMNS + " from podcast_episode where status = ? and publish_date is not null " + String sql = "select " + EPISODE_QUERY_COLUMNS
+ " from podcast_episode where status = ? and publish_date is not null " +
"order by publish_date desc limit ?"; "order by publish_date desc limit ?";
return query(sql, episodeRowMapper, PodcastStatus.COMPLETED, count); return query(sql, episodeRowMapper, PodcastStatus.COMPLETED, count);
} }
@ -140,12 +145,12 @@ public class PodcastDao extends AbstractDao {
* @return The episode or <code>null</code> if not found. * @return The episode or <code>null</code> if not found.
*/ */
public PodcastEpisode getEpisode(int episodeId) { public PodcastEpisode getEpisode(int episodeId) {
String sql = "select " + EPISODE_COLUMNS + " from podcast_episode where id=?"; String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where id=?";
return queryOne(sql, episodeRowMapper, episodeId); return queryOne(sql, episodeRowMapper, episodeId);
} }
public PodcastEpisode getEpisodeByUrl(String url) { public PodcastEpisode getEpisodeByUrl(String url) {
String sql = "select " + EPISODE_COLUMNS + " from podcast_episode where url=?"; String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where url=?";
return queryOne(sql, episodeRowMapper, url); return queryOne(sql, episodeRowMapper, url);
} }

@ -38,7 +38,8 @@ import org.libresonic.player.domain.Share;
*/ */
public class ShareDao extends AbstractDao { public class ShareDao extends AbstractDao {
private static final String COLUMNS = "id, name, description, username, created, expires, last_visited, visit_count"; private static final String INSERT_COLUMNS = "name, description, username, created, expires, last_visited, visit_count";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private ShareRowMapper shareRowMapper = new ShareRowMapper(); private ShareRowMapper shareRowMapper = new ShareRowMapper();
private ShareFileRowMapper shareFileRowMapper = new ShareFileRowMapper(); private ShareFileRowMapper shareFileRowMapper = new ShareFileRowMapper();
@ -49,8 +50,8 @@ public class ShareDao extends AbstractDao {
* @param share The share to create. The ID of the share will be set by this method. * @param share The share to create. The ID of the share will be set by this method.
*/ */
public synchronized void createShare(Share share) { public synchronized void createShare(Share share) {
String sql = "insert into share (" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")"; String sql = "insert into share (" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")";
update(sql, null, share.getName(), share.getDescription(), share.getUsername(), share.getCreated(), update(sql, share.getName(), share.getDescription(), share.getUsername(), share.getCreated(),
share.getExpires(), share.getLastVisited(), share.getVisitCount()); share.getExpires(), share.getLastVisited(), share.getVisitCount());
int id = getJdbcTemplate().queryForObject("select max(id) from share", Integer.class); int id = getJdbcTemplate().queryForObject("select max(id) from share", Integer.class);
@ -63,17 +64,17 @@ public class ShareDao extends AbstractDao {
* @return Possibly empty list of all shares. * @return Possibly empty list of all shares.
*/ */
public List<Share> getAllShares() { public List<Share> getAllShares() {
String sql = "select " + COLUMNS + " from share"; String sql = "select " + QUERY_COLUMNS + " from share";
return query(sql, shareRowMapper); return query(sql, shareRowMapper);
} }
public Share getShareByName(String shareName) { public Share getShareByName(String shareName) {
String sql = "select " + COLUMNS + " from share where name=?"; String sql = "select " + QUERY_COLUMNS + " from share where name=?";
return queryOne(sql, shareRowMapper, shareName); return queryOne(sql, shareRowMapper, shareName);
} }
public Share getShareById(int id) { public Share getShareById(int id) {
String sql = "select " + COLUMNS + " from share where id=?"; String sql = "select " + QUERY_COLUMNS + " from share where id=?";
return queryOne(sql, shareRowMapper, id); return queryOne(sql, shareRowMapper, id);
} }

@ -36,7 +36,8 @@ import org.libresonic.player.domain.Transcoding;
public class TranscodingDao extends AbstractDao { public class TranscodingDao extends AbstractDao {
private static final Logger LOG = Logger.getLogger(TranscodingDao.class); private static final Logger LOG = Logger.getLogger(TranscodingDao.class);
private static final String COLUMNS = "id, name, source_formats, target_format, step1, step2, step3, default_active"; private static final String INSERT_COLUMNS = "name, source_formats, target_format, step1, step2, step3, default_active";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private TranscodingRowMapper rowMapper = new TranscodingRowMapper(); private TranscodingRowMapper rowMapper = new TranscodingRowMapper();
/** /**
@ -45,7 +46,7 @@ public class TranscodingDao extends AbstractDao {
* @return Possibly empty list of all transcodings. * @return Possibly empty list of all transcodings.
*/ */
public List<Transcoding> getAllTranscodings() { public List<Transcoding> getAllTranscodings() {
String sql = "select " + COLUMNS + " from transcoding2"; String sql = "select " + QUERY_COLUMNS + " from transcoding2";
return query(sql, rowMapper); return query(sql, rowMapper);
} }
@ -56,7 +57,7 @@ public class TranscodingDao extends AbstractDao {
* @return All active transcodings for the player. * @return All active transcodings for the player.
*/ */
public List<Transcoding> getTranscodingsForPlayer(String playerId) { public List<Transcoding> getTranscodingsForPlayer(String playerId) {
String sql = "select " + COLUMNS + " from transcoding2, player_transcoding2 " + String sql = "select " + QUERY_COLUMNS + " from transcoding2, player_transcoding2 " +
"where player_transcoding2.player_id = ? " + "where player_transcoding2.player_id = ? " +
"and player_transcoding2.transcoding_id = transcoding2.id"; "and player_transcoding2.transcoding_id = transcoding2.id";
return query(sql, rowMapper, playerId); return query(sql, rowMapper, playerId);
@ -87,7 +88,7 @@ public class TranscodingDao extends AbstractDao {
existingMax = 0; existingMax = 0;
} }
transcoding.setId(existingMax + 1); transcoding.setId(existingMax + 1);
String sql = "insert into transcoding2 (" + COLUMNS + ") values (" + questionMarks(COLUMNS) + ")"; String sql = "insert into transcoding2 (" + QUERY_COLUMNS + ") values (" + questionMarks(QUERY_COLUMNS) + ")";
update(sql, transcoding.getId(), transcoding.getName(), transcoding.getSourceFormats(), update(sql, transcoding.getId(), transcoding.getName(), transcoding.getSourceFormats(),
transcoding.getTargetFormat(), transcoding.getStep1(), transcoding.getTargetFormat(), transcoding.getStep1(),
transcoding.getStep2(), transcoding.getStep3(), transcoding.isDefaultActive()); transcoding.getStep2(), transcoding.getStep3(), transcoding.isDefaultActive());

@ -8,15 +8,6 @@
<import resource="applicationContext-db-legacy.xml" /> <import resource="applicationContext-db-legacy.xml" />
<bean id="daoHelper" class="org.libresonic.player.dao.GenericDaoHelper"> <bean id="daoHelper" class="org.libresonic.player.dao.GenericDaoHelper">
<constructor-arg name="jdbcTemplate" ref="jdbcTemplate" />
<constructor-arg name="namedParameterJdbcTemplate" ref="namedJdbcTemplate" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
<bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource" /> <constructor-arg name="dataSource" ref="dataSource" />
</bean> </bean>

@ -43,7 +43,7 @@ public abstract class DaoTestCaseBase extends TestCase {
protected DaoTestCaseBase() { protected DaoTestCaseBase() {
DataSource dataSource = createDataSource(); DataSource dataSource = createDataSource();
daoHelper = new GenericDaoHelper(new JdbcTemplate(dataSource), new NamedParameterJdbcTemplate(dataSource)); daoHelper = new GenericDaoHelper(dataSource);
runDatabaseMigration(dataSource); runDatabaseMigration(dataSource);

@ -68,15 +68,6 @@
</bean> </bean>
<bean id="daoHelper" class="org.libresonic.player.dao.GenericDaoHelper"> <bean id="daoHelper" class="org.libresonic.player.dao.GenericDaoHelper">
<constructor-arg name="jdbcTemplate" ref="jdbcTemplate" />
<constructor-arg name="namedParameterJdbcTemplate" ref="namedJdbcTemplate" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
<bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource" /> <constructor-arg name="dataSource" ref="dataSource" />
</bean> </bean>

Loading…
Cancel
Save