Simplified db schema
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "TableFilter.hpp"
|
||||
#include "TableFilterGenre.hpp"
|
||||
#include "KeywordSearchFilter.hpp"
|
||||
#include "TrackView.hpp"
|
||||
#include "PlayQueue.hpp"
|
||||
@@ -49,17 +50,17 @@ _mediaPlayer(nullptr)
|
||||
Wt::WHBoxLayout *filterLayout = new Wt::WHBoxLayout();
|
||||
|
||||
{
|
||||
TableFilter *filter = new TableFilter(_db, "genre", "name");
|
||||
TableFilterGenre *filter = new TableFilterGenre(_db);
|
||||
filterLayout->addWidget(filter);
|
||||
_filterChain.addFilter(filter);
|
||||
}
|
||||
{
|
||||
TableFilter *filter = new TableFilter(_db, "artist", "name");
|
||||
TableFilter *filter = new TableFilter(_db, "track", "artist_name");
|
||||
filterLayout->addWidget(filter);
|
||||
_filterChain.addFilter(filter);
|
||||
}
|
||||
{
|
||||
TableFilter *filter = new TableFilter(_db, "release", "name");
|
||||
TableFilter *filter = new TableFilter(_db, "track", "release_name");
|
||||
filterLayout->addWidget(filter);
|
||||
_filterChain.addFilter(filter);
|
||||
}
|
||||
|
||||
@@ -52,9 +52,6 @@ FilterChain::updateFilters(std::size_t startIdx)
|
||||
|
||||
Filter::Constraint currentConstraint;
|
||||
|
||||
// TODO: replace with inner joins?
|
||||
currentConstraint.where.And( WhereClause( "track.artist_id = artist.id and track.release_id = release.id and track_genre.track_id = track.id and genre.id = track_genre.genre_id"));
|
||||
|
||||
for (std::size_t idFilter = 0; idFilter < _filters.size(); ++idFilter)
|
||||
{
|
||||
Filter* filter = _filters.at(idFilter);
|
||||
|
||||
@@ -39,7 +39,7 @@ KeywordSearchFilter::getConstraint(Constraint& constraint)
|
||||
// No active search means no constaint!
|
||||
if (!_lastEmittedText.empty()) {
|
||||
const std::string bindText ("%%" + _lastEmittedText + "%%");
|
||||
constraint.where.And( WhereClause("(track.name like ? or release.name like ? or artist.name like ?)").bind(bindText).bind(bindText).bind(bindText));
|
||||
constraint.where.And( WhereClause("(track.name like ? or track.release_name like ? or track.artist_name like ? or track.genre_list like ?)").bind(bindText).bind(bindText).bind(bindText).bind(bindText));
|
||||
}
|
||||
|
||||
// else no constraint!
|
||||
|
||||
@@ -87,7 +87,7 @@ PlayQueue::addTracks(const std::vector<Database::Track::id_type>& trackIds)
|
||||
|
||||
_model->setData(dataRow, 0, track.id());
|
||||
_model->setData(dataRow, 1, dataRow + 1);
|
||||
_model->setData(dataRow, 2, track->getArtist()->getName() + " - " + track->getName());
|
||||
_model->setData(dataRow, 2, track->getArtistName() + " - " + track->getName());
|
||||
_model->setData(dataRow, 3, track->getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ _db(db),
|
||||
_table(table),
|
||||
_field(field)
|
||||
{
|
||||
_queryModel.setQuery( _db.getSession().query< ResultType >("select " + _table + "." + _field + ",count(DISTINCT track.id),0 as ORDERBY from track,artist,release,genre,track_genre WHERE track.artist_id = artist.id and track.release_id = release.id and track_genre.track_id = track.id and genre.id = track_genre.genre_id GROUP BY " + _table + "." + _field + " UNION select '<All>',0,1 AS ORDERBY").orderBy("ORDERBY DESC," + _table + "." + _field));
|
||||
_queryModel.addColumn( _table + "." + _field, table);
|
||||
_queryModel.addColumn( "count(DISTINCT track.id)", "Tracks");
|
||||
_queryModel.setQuery( _db.getSession().query< ResultType >("select track." + _field + ", COUNT(DISTINCT track.id) from track GROUP BY track." + _field).orderBy("track." + _field));
|
||||
_queryModel.addColumn( "track." + _field, field);
|
||||
_queryModel.addColumn( "COUNT(DISTINCT track.id)", "tracks");
|
||||
|
||||
this->setSelectionMode(Wt::ExtendedSelection);
|
||||
this->setSortingEnabled(false);
|
||||
@@ -67,19 +67,16 @@ TableFilter::refresh(const Constraint& constraint)
|
||||
{
|
||||
SqlQuery sqlQuery;
|
||||
|
||||
sqlQuery.select(_table + "." + _field + ",count(DISTINCT track.id),0 as ORDERBY");
|
||||
sqlQuery.from().And( FromClause("artist,release,track,genre,track_genre")) ;
|
||||
sqlQuery.select("track." + _field + ", COUNT(DISTINCT track.id)");
|
||||
sqlQuery.from().And( FromClause("track")) ;
|
||||
sqlQuery.where().And(constraint.where); // Add constraint made by other filters
|
||||
sqlQuery.groupBy().And( _table + "." + _field); // Add constraint made by other filters
|
||||
sqlQuery.groupBy().And( "track." + _field); // Add constraint made by other filters
|
||||
|
||||
SqlQuery AllSqlQuery;
|
||||
AllSqlQuery.select("'<All>',0,1 AS ORDERBY");
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << _table << ", generated query = '" << sqlQuery.get() << "'";
|
||||
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << _table << ", generated query = '" << sqlQuery.get() + " UNION " + AllSqlQuery.get() << "'";
|
||||
Wt::Dbo::Query<ResultType> query = _db.getSession().query<ResultType>( sqlQuery.get() );
|
||||
|
||||
Wt::Dbo::Query<ResultType> query = _db.getSession().query<ResultType>( sqlQuery.get() + " UNION " + AllSqlQuery.get() );
|
||||
|
||||
query.orderBy("ORDERBY DESC," + _table + "." + _field);
|
||||
query.orderBy(_table + "." + _field);
|
||||
|
||||
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs()) {
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << "Binding value '" << bindArg << "'";
|
||||
@@ -108,13 +105,7 @@ TableFilter::getConstraint(Constraint& constraint)
|
||||
const ResultType& result = _queryModel.resultRow( index.row() );
|
||||
|
||||
// Get the track part
|
||||
std::string name( result.get<0>() );
|
||||
bool isAll( result.get<2>() ) ;
|
||||
|
||||
if (isAll) {
|
||||
// no constraint, just return
|
||||
return;
|
||||
}
|
||||
std::string name(result.get<0>());
|
||||
|
||||
clause.Or(_table + "." + _field + " = ?").bind(name);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class TableFilter : public Wt::WTableView, public Filter
|
||||
const std::string _field;
|
||||
|
||||
// Name, track count, special value that means 'all' if set to 1
|
||||
typedef boost::tuple<std::string, int, int> ResultType;
|
||||
typedef boost::tuple<std::string, int> ResultType;
|
||||
Wt::Dbo::QueryModel< ResultType > _queryModel;
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 <boost/foreach.hpp>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "TableFilterGenre.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
TableFilterGenre::TableFilterGenre(Database::Handler& db, Wt::WContainerWidget* parent)
|
||||
: Wt::WTableView( parent ),
|
||||
Filter(),
|
||||
_db(db)
|
||||
{
|
||||
_queryModel.setQuery( _db.getSession().query< ResultType >("select genre.name, COUNT(DISTINCT track.id) from genre INNER JOIN track_genre ON track_genre.genre_id = genre.id INNER JOIN track ON track.id = track_genre.track_id").orderBy("genre.name").groupBy("genre.name").orderBy("genre.name"));
|
||||
_queryModel.addColumn("genre.name", "Genre");
|
||||
_queryModel.addColumn("COUNT(DISTINCT track.id)", "tracks");
|
||||
|
||||
this->setSelectionMode(Wt::ExtendedSelection);
|
||||
this->setSortingEnabled(false);
|
||||
this->setAlternatingRowColors(true);
|
||||
this->setModel(&_queryModel);
|
||||
|
||||
this->selectionChanged().connect(this, &TableFilterGenre::emitUpdate);
|
||||
|
||||
setLayoutSizeAware(true);
|
||||
|
||||
_queryModel.setBatchSize(100);
|
||||
}
|
||||
|
||||
void
|
||||
TableFilterGenre::layoutSizeChanged (int width, int height)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << "LAYOUT CHANGED!";
|
||||
|
||||
/* TODO
|
||||
std::size_t trackColumnSize = this->columnWidth(1).toPixels() + 30 ;
|
||||
// Set the remaining size for the name column
|
||||
this->setColumnWidth(0, width - 7 - trackColumnSize);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
// Set constraints on this filter
|
||||
void
|
||||
TableFilterGenre::refresh(const Constraint& constraint)
|
||||
{
|
||||
SqlQuery sqlQuery;
|
||||
|
||||
sqlQuery.select("genre.name, COUNT(DISTINCT track.id)");
|
||||
sqlQuery.from().And( std::string("genre INNER JOIN track_genre ON track_genre.genre_id = genre.id INNER JOIN track ON track.id = track_genre.track_id") );
|
||||
sqlQuery.where().And(constraint.where); // Add constraint made by other filters
|
||||
sqlQuery.groupBy().And( std::string("genre.name") );
|
||||
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << "genre, generated query = '" << sqlQuery.get() << "'";
|
||||
|
||||
Wt::Dbo::Query<ResultType> query = _db.getSession().query<ResultType>( sqlQuery.get() );
|
||||
|
||||
query.orderBy("genre.name");
|
||||
|
||||
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs()) {
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << "Binding value '" << bindArg << "'";
|
||||
query.bind(bindArg);
|
||||
}
|
||||
|
||||
_queryModel.setQuery( query, true );
|
||||
|
||||
}
|
||||
|
||||
// Get constraint created by this filter
|
||||
void
|
||||
TableFilterGenre::getConstraint(Constraint& constraint)
|
||||
{
|
||||
Wt::WModelIndexSet indexSet = this->selectedIndexes();
|
||||
|
||||
// WHERE statement
|
||||
WhereClause clause;
|
||||
|
||||
BOOST_FOREACH(Wt::WModelIndex index, indexSet) {
|
||||
|
||||
if (!index.isValid())
|
||||
continue;
|
||||
|
||||
const ResultType& result = _queryModel.resultRow( index.row() );
|
||||
|
||||
// Get the track part
|
||||
std::string name(result.get<0>());
|
||||
|
||||
if (name == "<None>")
|
||||
clause.Or( std::string("track.genre_list = ?") ).bind("");
|
||||
else
|
||||
clause.Or( std::string("track.genre_list LIKE ?") ).bind("%%" + name + "%%");
|
||||
}
|
||||
|
||||
// Adding our WHERE clause
|
||||
constraint.where.And( clause );
|
||||
|
||||
}
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef TABLE_FILTER_GENRE_HPP
|
||||
#define TABLE_FILTER_GENRE_HPP
|
||||
|
||||
|
||||
#include <Wt/Dbo/QueryModel>
|
||||
#include <Wt/WTableView>
|
||||
|
||||
#include "Filter.hpp"
|
||||
#include "database/DatabaseHandler.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
class TableFilterGenre : public Wt::WTableView, public Filter
|
||||
{
|
||||
|
||||
public:
|
||||
TableFilterGenre(Database::Handler& db, Wt::WContainerWidget* parent = 0);
|
||||
|
||||
// Set constraints on this filter
|
||||
void refresh(const Constraint& constraint);
|
||||
|
||||
// Get constraints created by this filter
|
||||
void getConstraint(Constraint& constraint);
|
||||
|
||||
void layoutSizeChanged (int width, int height);
|
||||
|
||||
protected:
|
||||
|
||||
Database::Handler& _db;
|
||||
|
||||
// genre_name, count
|
||||
typedef boost::tuple<std::string, int> ResultType;
|
||||
Wt::Dbo::QueryModel< ResultType > _queryModel;
|
||||
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,9 +33,9 @@ TrackView::TrackView( Database::Handler& db, Wt::WContainerWidget* parent)
|
||||
: Wt::WTableView( parent ),
|
||||
_db(db)
|
||||
{
|
||||
_queryModel.setQuery(_db.getSession().query<ResultType>("select track,release,artist from track,release,artist where track.release_id = release.id and track.artist_id = artist.id" ).orderBy("artist.name,release.name,track.disc_number,track.track_number"));
|
||||
_queryModel.addColumn( "artist.name", "Artist" );
|
||||
_queryModel.addColumn( "release.name", "Album" );
|
||||
_queryModel.setQuery(_db.getSession().query<ResultType>("select track from track").orderBy("track.artist_name,track.date,track.release_name,track.disc_number,track.track_number"));
|
||||
_queryModel.addColumn( "track.artist_name", "Artist" );
|
||||
_queryModel.addColumn( "track.release_name", "Album" );
|
||||
_queryModel.addColumn( "track.disc_number", "Disc #" );
|
||||
_queryModel.addColumn( "track.track_number", "Track #" );
|
||||
_queryModel.addColumn( "track.name", "Track" );
|
||||
@@ -107,15 +107,15 @@ TrackView::refresh(const Constraint& constraint)
|
||||
|
||||
SqlQuery sqlQuery;
|
||||
|
||||
sqlQuery.select( "track,release,artist" );
|
||||
sqlQuery.from().And( FromClause("artist,release,track,genre,track_genre"));
|
||||
sqlQuery.select( "track" );
|
||||
sqlQuery.from().And( FromClause("track"));
|
||||
sqlQuery.where().And(constraint.where);
|
||||
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << "TRACK REQ = '" << sqlQuery.get() << "'";
|
||||
|
||||
Wt::Dbo::Query<ResultType> query = _db.getSession().query<ResultType>( sqlQuery.get() );
|
||||
|
||||
query.groupBy("track").orderBy("artist.name,track.date,release.name,track.disc_number,track.track_number");
|
||||
query.groupBy("track").orderBy("track.artist_name,track.date,track.release_name,track.disc_number,track.track_number");
|
||||
|
||||
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs()) {
|
||||
LMS_LOG(MOD_UI, SEV_DEBUG) << "Binding value '" << bindArg << "'";
|
||||
@@ -126,28 +126,6 @@ TrackView::refresh(const Constraint& constraint)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
void
|
||||
TrackView::handleTrackSelected(void)
|
||||
{
|
||||
Wt::WModelIndexSet indexSet = this->selectedIndexes();
|
||||
if (!indexSet.empty()) {
|
||||
Wt::WModelIndex currentIndex( *indexSet.begin() );
|
||||
|
||||
// Check there are remainin tracks!
|
||||
if (currentIndex.isValid())
|
||||
{
|
||||
ResultType result = _queryModel.resultRow( currentIndex.row());
|
||||
|
||||
// Get the track part
|
||||
Wt::Dbo::ptr<Database::Track> track ( result.get<0>() );
|
||||
|
||||
_trackSelected.emit( track->getPath() );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
void
|
||||
TrackView::getSelectedTracks(std::vector<Database::Track::id_type>& track_ids)
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ class TrackView : public Wt::WTableView, public Filter
|
||||
|
||||
Database::Handler& _db;
|
||||
|
||||
typedef boost::tuple<Database::Track::pointer, Database::Release::pointer, Database::Artist::pointer> ResultType;
|
||||
typedef boost::tuple<Database::Track::pointer> ResultType;
|
||||
Wt::Dbo::QueryModel< ResultType > _queryModel;
|
||||
Wt::WTableView* _tableView;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user