[Database] restored id on Artist, Genre and Release tables. Added basic MusicBrainz ID support. Improved search filters a bit

This commit is contained in:
emeric
2015-07-26 20:29:19 +02:00
parent b8e5113914
commit d59a04f5da
44 changed files with 1600 additions and 686 deletions
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Artist.hpp"
#include "SqlQuery.hpp"
#include "logger/Logger.hpp"
namespace Database
{
Artist::Artist(const std::string& name, const std::string& MBID)
: _name(std::string(name, 0 , _maxNameLength)),
_MBID(MBID)
{
}
std::vector<Artist::pointer>
Artist::getByName(Wt::Dbo::Session& session, const std::string& name)
{
Wt::Dbo::collection<Artist::pointer> res = session.find<Artist>().where("name = ?").bind( std::string(name, 0, _maxNameLength) );
return std::vector<Artist::pointer>(res.begin(), res.end());
}
Artist::pointer
Artist::getByMBID(Wt::Dbo::Session& session, const std::string& mbid)
{
return session.find<Artist>().where("mbid = ?").bind(mbid);
}
Artist::pointer
Artist::create(Wt::Dbo::Session& session, const std::string& name, const std::string& MBID)
{
return session.add(new Artist(name, MBID));
}
Artist::pointer
Artist::getNone(Wt::Dbo::Session& session)
{
std::vector<pointer> res = getByName(session, "<None>");
if (res.empty())
return create(session, "<None>");
return res.front();
}
std::vector<Artist::pointer>
Artist::getAll(Wt::Dbo::Session& session, int offset, int size)
{
Wt::Dbo::collection<pointer> res = session.find<Artist>().offset(offset).limit(size);
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<Artist::pointer>
Artist::getAllOrphans(Wt::Dbo::Session& session)
{
Wt::Dbo::collection<Artist::pointer> res = session.query< Wt::Dbo::ptr<Artist> >("select a from artist a LEFT OUTER JOIN Track t ON a.id = t.artist_id WHERE t.id IS NULL");
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<Artist::pointer>
Artist::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
Wt::Dbo::collection<Artist::pointer> res = getQuery(session, filter).limit(size).offset(offset);
return std::vector<pointer>(res.begin(), res.end());
}
Wt::Dbo::Query<Artist::pointer>
Artist::getQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<pointer> query
= session.query<pointer>( "SELECT a FROM artist a INNER JOIN track t ON t.artist_id = a.id INNER JOIN release r ON r.id = t.release_id INNER JOIN genre g ON g.id = t_g.genre_id INNER JOIN track_genre t_g ON t_g.track_id = t.id " + sqlQuery.where().get()).groupBy("a.id").orderBy("a.name");
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
Wt::Dbo::Query<Artist::UIQueryResult>
Artist::getUIQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<UIQueryResult> query
= session.query<UIQueryResult>( "SELECT a.id, a.name, COUNT(DISTINCT r.id), COUNT(DISTINCT t.id) FROM artist a INNER JOIN track t ON t.artist_id = a.id INNER JOIN release r ON r.id = t.release_id INNER JOIN genre g ON g.id = t_g.genre_id INNER JOIN track_genre t_g ON t_g.track_id = t.id " + sqlQuery.where().get()).groupBy("a.id").orderBy("a.name");
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
void
Artist::updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<UIQueryResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
{
Wt::Dbo::Query<UIQueryResult> query = getUIQuery(session, filter);
model.setQuery(query, columnNames.empty() ? true : false);
// TODO do something better
if (columnNames.size() == 3)
{
model.addColumn( "a.name", columnNames.at(0));
model.addColumn( "COUNT(DISTINCT r.id)", columnNames.at(1) );
model.addColumn( "COUNT(DISTINCT t.id)", columnNames.at(2) );
}
}
} // namespace Database
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2015 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DB_ARTIST_HPP_
#define _DB_ARTIST_HPP_
#include <string>
#include <vector>
#include <Wt/Dbo/Dbo>
#include <Wt/Dbo/QueryModel>
#include "SearchFilter.hpp"
namespace Database
{
class Track;
class Genre;
class Artist
{
public:
typedef Wt::Dbo::ptr<Artist> pointer;
typedef Wt::Dbo::dbo_traits<Artist>::IdType id_type;
Artist() {}
Artist(const std::string& name, const std::string& MBID = "");
// Accessors
static pointer getByMBID(Wt::Dbo::Session& session, const std::string& MBID);
static pointer getById(Wt::Dbo::Session& session, id_type id);
static pointer getNone(Wt::Dbo::Session& session); // Special entry
static std::vector<pointer> getByName(Wt::Dbo::Session& session, const std::string& name);
static std::vector<pointer> getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
static std::vector<pointer> getAll(Wt::Dbo::Session& session, int offset = -1, int size = -1);
static std::vector<pointer> getAllOrphans(Wt::Dbo::Session& session);
// Accessors
std::string getName(void) const { return _name; }
std::string getMBID(void) const { return _MBID; }
void setMBID(std::string mbid) { _MBID = mbid; }
// Create
static pointer create(Wt::Dbo::Session& session, const std::string& name, const std::string& MBID = "");
// MVC models for the user interface
// ID, Artist name, albums, tracks
typedef boost::tuple<id_type, std::string, int, int> UIQueryResult;
static Wt::Dbo::Query<UIQueryResult> getUIQuery(Wt::Dbo::Session& session, SearchFilter filter);
static void updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<UIQueryResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
bool isNone(void) const;
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::field(a, _MBID, "mbid");
Wt::Dbo::hasMany(a, _tracks, Wt::Dbo::ManyToOne, "artist");
}
private:
static Wt::Dbo::Query<pointer> getQuery(Wt::Dbo::Session& session, SearchFilter filter);
static const std::size_t _maxNameLength = 128;
std::string _name;
std::string _MBID; // Musicbrainz Identifier
Wt::Dbo::collection< Wt::Dbo::ptr<Track> > _tracks; // Tracks of this artist
};
} // namespace Database
#endif
+5 -2
View File
@@ -77,10 +77,12 @@ Handler::Handler(boost::filesystem::path db)
_dbBackend( db.string() )
{
_session.setConnection(_dbBackend);
_session.mapClass<Database::Artist>("artist");
_session.mapClass<Database::Genre>("genre");
_session.mapClass<Database::Track>("track");
_session.mapClass<Database::Playlist>("playlist");
_session.mapClass<Database::PlaylistEntry>("playlist_entry");
_session.mapClass<Database::Release>("release");
_session.mapClass<Database::Video>("video");
_session.mapClass<Database::MediaDirectory>("media_directory");
_session.mapClass<Database::MediaDirectorySettings>("media_directory_settings");
@@ -92,9 +94,10 @@ _dbBackend( db.string() )
try {
_session.createTables();
_dbBackend.executeSql("CREATE INDEX artist_name_idx ON track(artist_name)");
_dbBackend.executeSql("CREATE INDEX release_name_idx ON track(release_name)");
_dbBackend.executeSql("CREATE INDEX artist_name_idx ON artist(name)");
_dbBackend.executeSql("CREATE INDEX genre_name_idx ON genre(name)");
_dbBackend.executeSql("CREATE INDEX release_name_idx ON release(name)");
_dbBackend.executeSql("CREATE INDEX track_name_idx ON track(name)");
}
catch(std::exception& e) {
LMS_LOG(MOD_DB, SEV_ERROR) << "Cannot create tables: " << e.what();
+2
View File
@@ -22,6 +22,8 @@
#include <Wt/Dbo/Dbo>
#include <string>
namespace Database {
class PlaylistEntry;
+115
View File
@@ -0,0 +1,115 @@
#include "Release.hpp"
#include "SearchFilter.hpp"
#include "SqlQuery.hpp"
namespace Database
{
Release::Release(const std::string& name, const std::string& MBID)
: _name(std::string(name, 0 , _maxNameLength)),
_MBID(MBID)
{
}
std::vector<Release::pointer>
Release::getByName(Wt::Dbo::Session& session, const std::string& name)
{
Wt::Dbo::collection<Release::pointer> res = session.find<Release>().where("name = ?").bind( std::string(name, 0, _maxNameLength) );
return std::vector<Release::pointer>(res.begin(), res.end());
}
Release::pointer
Release::getByMBID(Wt::Dbo::Session& session, const std::string& mbid)
{
return session.find<Release>().where("mbid = ?").bind(mbid);
}
Release::pointer
Release::create(Wt::Dbo::Session& session, const std::string& name, const std::string& MBID)
{
return session.add(new Release(name, MBID));
}
Release::pointer
Release::getNone(Wt::Dbo::Session& session)
{
std::vector<pointer> res = getByName(session, "<None>");
if (res.empty())
return create(session, "<None>");
return res.front();
}
std::vector<Release::pointer>
Release::getAll(Wt::Dbo::Session& session, int offset, int size)
{
Wt::Dbo::collection<pointer> res = session.find<Release>().offset(offset).limit(size);
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<Release::pointer>
Release::getAllOrphans(Wt::Dbo::Session& session)
{
Wt::Dbo::collection<Release::pointer> res = session.query< Wt::Dbo::ptr<Release> >("select a from artist a LEFT OUTER JOIN Track t ON a.id = t.artist_id WHERE t.id IS NULL");
return std::vector<pointer>(res.begin(), res.end());
}
Wt::Dbo::Query<Release::pointer>
Release::getQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<pointer> query
= session.query<pointer>("SELECT r FROM release r INNER JOIN artist a ON a.id = t.artist_id INNER JOIN track t ON t.release_id = r.id INNER JOIN genre g ON g.id = t_g.genre_id INNER JOIN track_genre t_g ON t_g.track_id = t.id " + sqlQuery.where().get()).groupBy("r.id").orderBy("r.name");
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
Wt::Dbo::Query<Release::UIQueryResult>
Release::getUIQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
// TODO DATE of RELEASE
Wt::Dbo::Query<UIQueryResult> query
= session.query<UIQueryResult>("SELECT r.id, r.name, t.date, COUNT(DISTINCT t.id) FROM release r INNER JOIN track t ON t.release_id = r.id INNER JOIN artist a ON a.id = t.artist_id INNER JOIN genre g ON g.id = t_g.genre_id INNER JOIN track_genre t_g ON t_g.track_id = t.id " + sqlQuery.where().get()).groupBy("r.id").orderBy("r.name");
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
void
Release::updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<UIQueryResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
{
Wt::Dbo::Query<UIQueryResult> query = getUIQuery(session, filter);
model.setQuery(query, columnNames.empty() ? true : false);
// TODO do something better
if (columnNames.size() == 3)
{
model.addColumn( "r.name", columnNames[0]);
model.addColumn( "t.date", columnNames[1]);
model.addColumn( "COUNT(DISTINCT t.id)", columnNames[2]);
}
}
std::vector<Release::pointer>
Release::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
Wt::Dbo::collection<pointer> res = getQuery(session, filter).limit(size).offset(offset);
return std::vector<pointer>(res.begin(), res.end());
}
} // namespace Database
+93
View File
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2015 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DB_RELEASE_HPP_
#define _DB_RELEASE_HPP_
#include <Wt/Dbo/Dbo>
#include <Wt/Dbo/QueryModel>
#include "SearchFilter.hpp"
namespace Database
{
class Track;
class Release
{
public:
typedef Wt::Dbo::ptr<Release> pointer;
typedef Wt::Dbo::dbo_traits<Release>::IdType id_type;
Release() {}
Release(const std::string& name, const std::string& MBID = "");
// Accessors
static pointer getByMBID(Wt::Dbo::Session& session, const std::string& MBID);
static std::vector<pointer> getByName(Wt::Dbo::Session& session, const std::string& name);
static pointer getById(Wt::Dbo::Session& session, id_type id);
static pointer getNone(Wt::Dbo::Session& session); // Special entry
static std::vector<pointer> getAllOrphans(Wt::Dbo::Session& session);
static std::vector<pointer> getAll(Wt::Dbo::Session& session, int offset, int size);
static std::vector<pointer> getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
// Create
static pointer create(Wt::Dbo::Session& session, const std::string& name, const std::string& MBID = "");
// MVC models for the user interface
// ID, Release name, year, track counts
typedef boost::tuple<id_type, std::string, boost::posix_time::ptime, int> UIQueryResult;
static Wt::Dbo::Query<UIQueryResult> getUIQuery(Wt::Dbo::Session& session, SearchFilter filter);
static void updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel< UIQueryResult >& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
// Accessosrs
std::string getName() const { return _name; }
std::string getMBID() const { return _MBID; }
bool isNone(void) const;
boost::posix_time::time_duration getDuration(void) const;
void setMBID(std::string mbid) { _MBID = mbid; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::field(a, _MBID, "mbid");
Wt::Dbo::hasMany(a, _tracks, Wt::Dbo::ManyToOne, "release");
}
private:
static Wt::Dbo::Query<pointer> getQuery(Wt::Dbo::Session& session, SearchFilter filter);
static const std::size_t _maxNameLength = 128;
std::string _name;
std::string _MBID;
Wt::Dbo::collection< Wt::Dbo::ptr<Track> > _tracks; // Tracks in the release
};
} // namespace Database
#endif
+94
View File
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2015 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SearchFilter.hpp"
namespace Database
{
SqlQuery generatePartialQuery(SearchFilter& filter)
{
SqlQuery sqlQuery;
WhereClause likeWhereClause;
// Process name like parameters
for (auto nameLikeMatch : filter.nameLikeMatch)
{
// Artist
switch (nameLikeMatch.first)
{
case SearchFilter::Field::Artist:
for (const std::string& name : nameLikeMatch.second)
likeWhereClause.Or( WhereClause("a.name LIKE ?") ).bind("%%" + name + "%%");
break;
case SearchFilter::Field::Release:
for (const std::string& name : nameLikeMatch.second)
likeWhereClause.Or( WhereClause("r.name LIKE ?") ).bind("%%" + name + "%%");
break;
case SearchFilter::Field::Genre:
for (const std::string& name : nameLikeMatch.second)
likeWhereClause.Or( WhereClause("g.name LIKE ?") ).bind("%%" + name + "%%");
break;
case SearchFilter::Field::Track:
for (const std::string& name : nameLikeMatch.second)
likeWhereClause.Or( WhereClause("t.name LIKE ?") ).bind("%%" + name + "%%");
break;
}
}
sqlQuery.where().And( likeWhereClause );
// Process id exact match parameters
for (auto idMatch : filter.idMatch)
{
WhereClause idWhereClause;
switch (idMatch.first)
{
case SearchFilter::Field::Artist:
for (auto id : idMatch.second)
idWhereClause.Or( WhereClause("a.id = ?") ).bind( std::to_string(id));
break;
case SearchFilter::Field::Release:
for (auto id : idMatch.second)
idWhereClause.Or( WhereClause("r.id = ?") ).bind( std::to_string(id));
break;
case SearchFilter::Field::Genre:
for (auto id : idMatch.second)
idWhereClause.Or( WhereClause("g.id = ?") ).bind( std::to_string(id));
break;
case SearchFilter::Field::Track:
for (auto id : idMatch.second)
idWhereClause.Or( WhereClause("t.id = ?") ).bind( std::to_string(id));
break;
}
sqlQuery.where().And( idWhereClause );
}
return sqlQuery;
}
} // namespace Database
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2015 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DB_SEARCH_FILTER_HPP_
#define _DB_SEARCH_FILTER_HPP_
#include <string>
#include <vector>
#include <map>
#include <Wt/Dbo/Dbo>
#include "SqlQuery.hpp"
namespace Database
{
class SearchFilter
{
public:
enum class Field {
Artist, // artist
Release, // release
Genre, // genre
Track, // track
};
typedef std::map<Field, std::vector<std::string> > NameLikeMatchMap;
typedef std::map<Field, std::vector< Wt::Dbo::dbo_default_traits::IdType> > IdMatchMap;
SearchFilter() {}
static SearchFilter IdMatch( const IdMatchMap& _idMatch )
{
return SearchFilter(_idMatch);
}
static SearchFilter NameLikeMatch( const NameLikeMatchMap& _nameLikeMatch )
{
return SearchFilter(_nameLikeMatch);
}
// The filter is a AND of the following conditions:
// ((Field1.name LIKE STR1-1 OR Field1.name LIKE STR1-2 ...) OR (Field2.name LIKE STR2-1 OR Field2.name LIKE STR2-2 ...) ...
NameLikeMatchMap nameLikeMatch;
// ((Field1.id = ID1-1 OR Field1.id = ID1-2 ... ) AND ((Field2.id = ID2-1 OR Field2.id = ID2-2 ... ) ...
IdMatchMap idMatch;
private:
SearchFilter(const NameLikeMatchMap& _nameLikeMatch) : nameLikeMatch(_nameLikeMatch) {}
SearchFilter(const IdMatchMap& _idMatch) : idMatch(_idMatch) {}
};
SqlQuery generatePartialQuery(SearchFilter& filter);
} // namespace Database
#endif // _DB_SEARCH_FILTER_HPP_
+64 -231
View File
@@ -17,8 +17,6 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/foreach.hpp>
#include <Wt/Dbo/QueryModel>
#include "logger/Logger.hpp"
@@ -29,104 +27,6 @@
namespace Database {
static SqlQuery generatePartialQuery(SearchFilter& filter, bool forceGenreInnerJoin = false)
{
bool genreJoin = forceGenreInnerJoin;
SqlQuery sqlQuery;
// Process like searches
BOOST_FOREACH(SearchFilter::FieldValues& likeMatch, filter.likeMatches)
{
WhereClause likeWhereClause;
// Artist
{
WhereClause whereClause;
BOOST_FOREACH(const std::string& name, likeMatch[SearchFilter::Field::Artist])
whereClause.Or( WhereClause("t.artist_name LIKE ?") ).bind("%%" + name + "%%");
likeWhereClause.Or( whereClause );
}
// Release
{
WhereClause whereClause;
BOOST_FOREACH(const std::string& name, likeMatch[SearchFilter::Field::Release])
whereClause.Or( WhereClause("t.release_name LIKE ?") ).bind("%%" + name + "%%");
likeWhereClause.Or( whereClause );
}
// Genre
{
WhereClause whereClause;
BOOST_FOREACH(const std::string& name, likeMatch[SearchFilter::Field::Genre])
{
whereClause.Or( WhereClause("g.name LIKE ?") ).bind("%%" + name + "%%");
genreJoin = true;
}
likeWhereClause.Or( whereClause );
}
// Track
{
WhereClause whereClause;
BOOST_FOREACH(const std::string& name, likeMatch[SearchFilter::Field::Track])
whereClause.Or( WhereClause("t.name LIKE ?") ).bind("%%" + name + "%%");
likeWhereClause.Or( whereClause );
}
sqlQuery.where().And( likeWhereClause );
}
// Add exact search constraints
// Artist
{
WhereClause whereClause;
BOOST_FOREACH(const std::string& name, filter.exactMatch[SearchFilter::Field::Artist])
whereClause.Or( WhereClause("t.artist_name = ?") ).bind(name);
sqlQuery.where().And( whereClause );
}
// Release
{
WhereClause whereClause;
BOOST_FOREACH(const std::string& name, filter.exactMatch[SearchFilter::Field::Release])
whereClause.Or( WhereClause("t.release_name = ?") ).bind(name);
sqlQuery.where().And( whereClause );
}
// Genre
{
WhereClause whereClause;
BOOST_FOREACH(const std::string& name, filter.exactMatch[SearchFilter::Field::Genre])
{
whereClause.Or( WhereClause("g.name = ?") ).bind(name);
genreJoin = true;
}
sqlQuery.where().And( whereClause );
}
if (genreJoin)
{
sqlQuery.innerJoin().And( InnerJoinClause("genre g ON g.id = t_g.genre_id"));
sqlQuery.innerJoin().And( InnerJoinClause("track_genre t_g ON t_g.track_id = t.id"));
}
return sqlQuery;
}
Track::Track(const boost::filesystem::path& p)
:
_trackNumber(0),
@@ -148,7 +48,7 @@ Track::setGenres(std::vector<Genre::pointer> genres)
if (_genres.size())
_genres.clear();
BOOST_FOREACH(Genre::pointer genre, genres) {
for (Genre::pointer genre : genres) {
_genres.insert( genre );
}
}
@@ -156,7 +56,7 @@ Track::setGenres(std::vector<Genre::pointer> genres)
Track::pointer
Track::getByPath(Wt::Dbo::Session& session, const boost::filesystem::path& p)
{
return session.find<Track>().where("path = ?").bind(p.string());
return session.find<Track>().where("file_path = ?").bind(p.string());
}
Track::pointer
@@ -165,6 +65,11 @@ Track::getById(Wt::Dbo::Session& session, id_type id)
return session.find<Track>().where("id = ?").bind(id);
}
Track::pointer
Track::getByMBID(Wt::Dbo::Session& session, const std::string& mbid)
{
return session.find<Track>().where("mbid = ?").bind(mbid);
}
Track::pointer
Track::create(Wt::Dbo::Session& session, const boost::filesystem::path& p)
@@ -181,104 +86,52 @@ Track::getGenres(void) const
}
Wt::Dbo::Query< Track::pointer >
Track::getAllQuery(Wt::Dbo::Session& session, SearchFilter filter)
Track::getQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<pointer> query
= session.query<Track::pointer>( "SELECT t FROM track t " + sqlQuery.innerJoin().get() + " " + sqlQuery.where().get()).groupBy("t.id").orderBy("t.artist_name,t.date,t.release_name,t.disc_number,t.track_number");
= session.query<pointer>( "SELECT t FROM track t INNER JOIN artist a ON t.artist_id = a.id INNER JOIN genre g ON g.id = t_g.genre_id INNER JOIN track_genre t_g ON t_g.track_id = t.id INNER JOIN release r ON r.id = t.release_id " + sqlQuery.where().get()).groupBy("t.id").orderBy("a.name,t.date,r.name,t.disc_number,t.track_number");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs())
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
Wt::Dbo::Query< Track::UIQueryResult >
Track::getUIQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<UIQueryResult> query
= session.query<UIQueryResult>( "SELECT t.id, a.name, r.name, t.disc_number, t.track_number, t.name, t.duration, t.date, t.original_date, t.genre_list FROM track t INNER JOIN artist a ON t.artist_id = a.id INNER JOIN genre g ON g.id = t_g.genre_id INNER JOIN track_genre t_g ON t_g.track_id = t.id INNER JOIN release r ON r.id = t.release_id " + sqlQuery.where().get()).groupBy("t.id").orderBy("a.name,t.date,r.name,t.disc_number,t.track_number");
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
std::vector<Track::pointer>
Track::getAll(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
Track::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
Wt::Dbo::collection<Track::pointer> res = getAllQuery(session, filter).limit(size).offset(offset);
return std::vector<Track::pointer>(res.begin(), res.end());
}
Wt::Dbo::collection<pointer> res = getQuery(session, filter).limit(size).offset(offset);
std::vector<Track::pointer>
Track::getTracks(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
return getAll(session, filter, offset, size);
}
Wt::Dbo::Query<Track::ReleaseResult>
Track::getReleasesQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<ReleaseResult> query
= session.query<ReleaseResult>("SELECT t.release_name, t.date, COUNT(DISTINCT t.id) FROM track t " + sqlQuery.innerJoin().get() + " " + sqlQuery.where().get()).groupBy("t.release_name").orderBy("t.release_name");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
return std::vector<pointer>(res.begin(), res.end());
}
void
Track::updateReleaseQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<ReleaseResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
Track::updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel< UIQueryResult >& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
{
Wt::Dbo::Query<ReleaseResult> query = getReleasesQuery(session, filter);
model.setQuery(query, columnNames.empty() ? true : false);
// TODO do something better
if (columnNames.size() == 3)
{
model.addColumn( "t.release_name", columnNames[0]);
model.addColumn( "t.date", columnNames[1]);
model.addColumn( "COUNT(DISTINCT t.id)", columnNames[2] );
}
}
Wt::Dbo::Query<Track::ArtistResult>
Track::getArtistsQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<ArtistResult> query
= session.query<ArtistResult>( "SELECT t.artist_name, COUNT(DISTINCT t.release_name), COUNT(DISTINCT t.id) FROM track t " + sqlQuery.innerJoin().get() + " " + sqlQuery.where().get()).groupBy("t.artist_name").orderBy("t.artist_name");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
void
Track::updateArtistQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<ArtistResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
{
Wt::Dbo::Query<ArtistResult> query = getArtistsQuery(session, filter);
model.setQuery(query, columnNames.empty() ? true : false);
// TODO do something better
if (columnNames.size() == 3)
{
model.addColumn( "t.artist_name", columnNames.at(0));
model.addColumn( "COUNT(DISTINCT t.release_name)", columnNames.at(1) );
model.addColumn( "COUNT(DISTINCT t.id)", columnNames.at(2) );
}
}
void
Track::updateTracksQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel< pointer >& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
{
Wt::Dbo::Query< pointer > query = getAllQuery(session, filter);
Wt::Dbo::Query< UIQueryResult > query = getUIQuery(session, filter);
model.setQuery(query, columnNames.empty() ? true : false);
// TODO do something better
if (columnNames.size() == 9)
{
model.addColumn( "t.artist_name", columnNames[0] );
model.addColumn( "t.release_name", columnNames[1] );
model.addColumn( "a.name", columnNames[0] );
model.addColumn( "r.name", columnNames[1] );
model.addColumn( "t.disc_number", columnNames[2] );
model.addColumn( "t.track_number", columnNames[3] );
model.addColumn( "t.name", columnNames[4] );
@@ -290,48 +143,6 @@ Track::updateTracksQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel< po
}
std::vector<std::string>
Track::getArtists(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<std::string> query
= session.query<std::string>( "SELECT DISTINCT t.artist_name FROM track t " + sqlQuery.innerJoin().get() + " " + sqlQuery.where().get()).offset(offset).limit(size).orderBy("t.artist_name");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs())
query.bind(bindArg);
typedef Wt::Dbo::collection< std::string > ArtistNames;
ArtistNames artistNames(query);
std::vector<std::string> res;
for (ArtistNames::const_iterator it = artistNames.begin(); it != artistNames.end(); ++it)
res.push_back((*it));
return res;
}
std::vector<std::string>
Track::getReleases(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<std::string> query
= session.query<std::string>( "SELECT DISTINCT t.release_name FROM track t " + sqlQuery.innerJoin().get() + " " + sqlQuery.where().get()).offset(offset).limit(size).orderBy("t.release_name");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs())
query.bind(bindArg);
typedef Wt::Dbo::collection< std::string > ReleaseNames;
ReleaseNames releaseNames(query);
std::vector<std::string> res;
for (ReleaseNames::const_iterator it = releaseNames.begin(); it != releaseNames.end(); ++it)
res.push_back((*it));
return res;
}
Genre::Genre()
{
}
@@ -341,6 +152,12 @@ Genre::Genre(const std::string& name)
{
}
std::vector<Genre::pointer>
Genre::getAll(Wt::Dbo::Session& session, int offset, int size)
{
Wt::Dbo::collection<pointer> res = session.find<Genre>().offset(offset).limit(size);
return std::vector<Genre::pointer>(res.begin(), res.end());
}
Genre::pointer
Genre::getByName(Wt::Dbo::Session& session, const std::string& name)
@@ -370,30 +187,38 @@ Genre::create(Wt::Dbo::Session& session, const std::string& name)
return session.add(new Genre(name));
}
Wt::Dbo::collection<Genre::pointer>
Genre::getAll(Wt::Dbo::Session& session, int offset, int size)
Wt::Dbo::Query<Genre::pointer>
Genre::getQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
return session.find<Genre>().offset(offset).limit(size).orderBy("name");
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<pointer> query
= session.query<pointer>( "SELECT g FROM genre g INNER JOIN track_genre t_g ON t_g.genre_id = g.id INNER JOIN artist a ON t.artist_id = a.id INNER JOIN release r ON r.id = t.release_id INNER JOIN track t ON t.id = t_g.track_id " + sqlQuery.where().get()).groupBy("g.name").orderBy("g.name");
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
Wt::Dbo::Query<Genre::GenreResult>
Genre::getAllQuery(Wt::Dbo::Session& session, SearchFilter& filter)
Wt::Dbo::Query<Genre::UIQueryResult>
Genre::getUIQuery(Wt::Dbo::Session& session, SearchFilter filter)
{
SqlQuery sqlQuery = generatePartialQuery(filter, true);
SqlQuery sqlQuery = generatePartialQuery(filter);
Wt::Dbo::Query<Genre::GenreResult> query
= session.query<Genre::GenreResult>( "SELECT g.name, COUNT(DISTINCT t.id) FROM track t " + sqlQuery.innerJoin().get() + " " + sqlQuery.where().get()).groupBy("g.name").orderBy("g.name");
Wt::Dbo::Query<UIQueryResult> query
= session.query<UIQueryResult>( "SELECT g.id, g.name, COUNT(DISTINCT t.id) FROM genre g INNER JOIN track_genre t_g ON t_g.genre_id = g.id INNER JOIN artist a ON t.artist_id = a.id INNER JOIN release r ON r.id = t.release_id INNER JOIN track t ON t.id = t_g.track_id " + sqlQuery.where().get()).groupBy("g.name").orderBy("g.name");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs())
for (const std::string& bindArg : sqlQuery.where().getBindArgs())
query.bind(bindArg);
return query;
}
void
Genre::updateGenreQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<Genre::GenreResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
Genre::updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<UIQueryResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames)
{
Wt::Dbo::Query<Genre::GenreResult> query = getAllQuery(session, filter);
Wt::Dbo::Query<UIQueryResult> query = getUIQuery(session, filter);
model.setQuery(query, columnNames.empty() ? true : false);
// TODO do something better
@@ -404,5 +229,13 @@ Genre::updateGenreQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<Gen
}
}
std::vector<Genre::pointer>
Genre::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size)
{
Wt::Dbo::collection<pointer> res = getQuery(session, filter).limit(size).offset(offset);
return std::vector<pointer>(res.begin(), res.end());
}
} // namespace Database
+53 -50
View File
@@ -32,25 +32,9 @@
namespace Database {
// Find utilities
struct SearchFilter
{
enum class Field {
Artist, // artist name
Release, // release name
Genre, // genre name
Track, // track name
};
typedef std::map<Field, std::vector<std::string> > FieldValues;
// Formulas :
// ((like1-1 LIKE ? OR like1-2 LIKE = ? ...) AND (like2-1 LIKE ? OR like2-2 LIKE ? ...)) AND exact1 = ? AND exact2 = ? ...
std::vector<FieldValues> likeMatches;
FieldValues exactMatch;
};
class Artist;
class Release;
class Track;
class PlaylistEntry;
@@ -67,10 +51,14 @@ class Genre
// Find utility
static pointer getByName(Wt::Dbo::Session& session, const std::string& name);
static pointer getNone(Wt::Dbo::Session& session);
static Wt::Dbo::collection<pointer> getAll(Wt::Dbo::Session& session, int offset = -1, int size = -1);
typedef boost::tuple<std::string, int> GenreResult;
static Wt::Dbo::Query<GenreResult> getAllQuery(Wt::Dbo::Session& session, SearchFilter& filter);
static void updateGenreQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<GenreResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
static std::vector<pointer> getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
static std::vector<pointer> getAll(Wt::Dbo::Session& session, int offset = -1, int size = -1);
// MVC models for the user interface
// Genre ID, name, track count
typedef boost::tuple<id_type, std::string, int> UIQueryResult;
static Wt::Dbo::Query<UIQueryResult> getUIQuery(Wt::Dbo::Session& session, SearchFilter filter);
static void updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<UIQueryResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
// Create utility
static pointer create(Wt::Dbo::Session& session, const std::string& name);
@@ -88,6 +76,8 @@ class Genre
}
private:
static Wt::Dbo::Query<pointer> getQuery(Wt::Dbo::Session& session, SearchFilter filter);
static const std::size_t _maxNameLength = 128;
std::string _name;
@@ -114,22 +104,28 @@ class Track
// Find utility functions
static pointer getByPath(Wt::Dbo::Session& session, const boost::filesystem::path& p);
static pointer getById(Wt::Dbo::Session& session, id_type id);
static pointer getByMBID(Wt::Dbo::Session& session, const std::string& MBID);
static Wt::Dbo::collection< pointer > getAll(Wt::Dbo::Session& session);
// Used for remote
static std::vector<pointer> getAll(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
static std::vector<pointer> getTracks(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
static std::vector<std::string> getReleases(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
static std::vector<std::string> getArtists(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
static std::vector<pointer> getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset = -1, int size = -1);
// Utility fonctions
// MVC models for the user interface
static void updateTracksQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel< pointer >& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
// Release name, year, track counts
typedef boost::tuple<std::string, boost::posix_time::ptime, int> ReleaseResult;
static void updateReleaseQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<ReleaseResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
// Artist name, albums, tracks
typedef boost::tuple<std::string, int, int> ArtistResult;
static void updateArtistQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel<ArtistResult>& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
// ID, Artist name, Release Name, DiscNumber, TrackNumber, Name, duration, date, original date, genre list
typedef boost::tuple<id_type, //ID
std::string, // Artist name
std::string, // Release Name
int, // Disc Number
int, // Track Number
std::string, // Name
boost::posix_time::time_duration, // Duration
boost::posix_time::ptime, // Date
boost::posix_time::ptime, // Original date
std::string> // genre list
UIQueryResult;
static Wt::Dbo::Query< UIQueryResult > getUIQuery(Wt::Dbo::Session& session, SearchFilter filter);
static void updateUIQueryModel(Wt::Dbo::Session& session, Wt::Dbo::QueryModel< UIQueryResult >& model, SearchFilter filter, const std::vector<Wt::WString>& columnNames = std::vector<Wt::WString>());
// Create utility
static pointer create(Wt::Dbo::Session& session, const boost::filesystem::path& p);
@@ -138,32 +134,35 @@ class Track
void setTrackNumber(int num) { _trackNumber = num; }
void setDiscNumber(int num) { _discNumber = num; }
void setName(const std::string& name) { _name = std::string(name, 0, _maxNameLength); }
void setArtistName(const std::string& name) { _artistName = std::string(name, 0, _maxNameLength); }
void setReleaseName(const std::string& name) { _releaseName = std::string(name, 0, _maxNameLength); }
void setDuration(boost::posix_time::time_duration duration) { _duration = duration; }
void setLastWriteTime(boost::posix_time::ptime time) { _fileLastWrite = time; }
void setAddedTime(boost::posix_time::ptime time) { _fileAdded = time; }
void setChecksum(const std::vector<unsigned char>& checksum) { _fileChecksum = checksum; }
void setDate(const boost::posix_time::ptime& date) { _date = date; }
void setOriginalDate(const boost::posix_time::ptime& date) { _originalDate = date; }
void setGenres(const std::string& genreList) { _genreList = genreList; }
void setGenres(std::vector<Genre::pointer> genres);
void setCoverType(CoverType coverType) { _coverType = coverType; }
void setMBID(const std::string& MBID) { _MBID = MBID; }
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
void setGenres(std::vector<Genre::pointer> genres);
int getTrackNumber(void) const { return _trackNumber; }
int getDiscNumber(void) const { return _discNumber; }
std::string getName(void) const { return _name; }
std::string getArtistName(void) const { return _artistName; }
std::string getReleaseName(void) const { return _releaseName; }
boost::filesystem::path getPath(void) const { return _filePath; }
boost::posix_time::time_duration getDuration(void) const { return _duration; }
boost::posix_time::ptime getDate(void) const { return _date; }
boost::posix_time::ptime getOriginalDate(void) const { return _originalDate; }
bool hasGenre(Genre::pointer genre) const { return _genres.count(genre); }
std::vector< Genre::pointer > getGenres(void) const;
boost::posix_time::ptime getLastWriteTime(void) const { return _fileLastWrite; }
boost::posix_time::ptime getAddedTime(void) const { return _fileAdded; }
const std::vector<unsigned char>& getChecksum(void) const { return _fileChecksum; }
CoverType getCoverType(void) const { return _coverType; }
const std::string& getMBID(void) const { return _MBID; }
Wt::Dbo::ptr<Artist> getArtist(void) const { return _artist; }
Wt::Dbo::ptr<Release> getRelease(void) const { return _release; }
std::vector< Genre::pointer > getGenres(void) const;
bool hasGenre(Genre::pointer genre) const { return _genres.count(genre); }
template<class Action>
void persist(Action& a)
@@ -171,25 +170,25 @@ class Track
Wt::Dbo::field(a, _trackNumber, "track_number");
Wt::Dbo::field(a, _discNumber, "disc_number");
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::field(a, _artistName, "artist_name");
Wt::Dbo::field(a, _releaseName, "release_name");
Wt::Dbo::field(a, _duration, "duration");
Wt::Dbo::field(a, _date, "date");
Wt::Dbo::field(a, _originalDate, "original_date");
Wt::Dbo::field(a, _genreList, "genre_list");
Wt::Dbo::field(a, _filePath, "path");
Wt::Dbo::field(a, _fileLastWrite, "last_write");
Wt::Dbo::field(a, _filePath, "file_path");
Wt::Dbo::field(a, _fileLastWrite, "file_last_write");
Wt::Dbo::field(a, _fileAdded, "file_added");
Wt::Dbo::field(a, _fileChecksum, "checksum");
Wt::Dbo::field(a, _coverType, "cover_type");
Wt::Dbo::field(a, _MBID, "mbid");
Wt::Dbo::belongsTo(a, _release, "release", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _genres, Wt::Dbo::ManyToMany, "track_genre", "", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
}
private:
static Wt::Dbo::Query< pointer > getAllQuery(Wt::Dbo::Session& session, SearchFilter filter);
static Wt::Dbo::Query<ReleaseResult> getReleasesQuery(Wt::Dbo::Session& session, SearchFilter filter);
static Wt::Dbo::Query<ArtistResult> getArtistsQuery(Wt::Dbo::Session& session, SearchFilter filter);
static Wt::Dbo::Query< pointer > getQuery(Wt::Dbo::Session& session, SearchFilter filter);
static const std::size_t _maxNameLength = 128;
@@ -200,14 +199,18 @@ class Track
std::string _releaseName;
boost::posix_time::time_duration _duration;
boost::posix_time::ptime _date;
boost::posix_time::ptime _originalDate;
boost::posix_time::ptime _originalDate; // original date time
std::string _genreList;
std::string _filePath;
std::vector<unsigned char> _fileChecksum;
boost::posix_time::ptime _fileLastWrite;
boost::posix_time::ptime _fileAdded;
CoverType _coverType;
std::string _MBID; // Musicbrainz Identifier
Wt::Dbo::collection< Genre::pointer > _genres; // Genres that are related to this track
Wt::Dbo::ptr<Artist> _artist;
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::collection< Genre::pointer > _genres; // Genres that are related to this track
Wt::Dbo::collection< Wt::Dbo::ptr<PlaylistEntry> > _playlistEntries;
};
+2
View File
@@ -19,8 +19,10 @@
// header file aimed to ease database class declarations
#include "Artist.hpp"
#include "Track.hpp"
#include "Playlist.hpp"
#include "Release.hpp"
#include "Video.hpp"
#include "MediaDirectory.hpp"
#include "User.hpp"