/* * Copyright (C) 2013-2016 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 . */ #include #include #include "utils/Logger.hpp" #include "SqlQuery.hpp" #include "Types.hpp" namespace Database { Track::Track(const boost::filesystem::path& p) : _trackNumber(0), _totalTrackNumber(0), _discNumber(0), _totalDiscNumber(0), _filePath( p.string() ), _coverType(CoverType::None) { } Wt::Dbo::collection< Track::pointer > Track::getAll(Wt::Dbo::Session& session) { return session.find(); } std::vector Track::getAllIds(Wt::Dbo::Session& session) { Wt::Dbo::Transaction transaction(session); Wt::Dbo::collection res = session.query("SELECT id from track"); return std::vector(res.begin(), res.end()); } Track::pointer Track::getByPath(Wt::Dbo::Session& session, const boost::filesystem::path& p) { return session.find().where("file_path = ?").bind(p.string()); } Track::pointer Track::getById(Wt::Dbo::Session& session, id_type id) { return session.find().where("id = ?").bind(id); } Track::pointer Track::getByMBID(Wt::Dbo::Session& session, const std::string& mbid) { return session.find().where("mbid = ?").bind(mbid); } Track::pointer Track::create(Wt::Dbo::Session& session, const boost::filesystem::path& p) { return session.add(new Track(p) ); } std::vector Track::getAllPaths(Wt::Dbo::Session& session) { Wt::Dbo::Transaction transaction(session); Wt::Dbo::collection res = session.query("SELECT file_path from track"); return std::vector(res.begin(), res.end()); } std::vector Track::getMBIDDuplicates(Wt::Dbo::Session& session) { Wt::Dbo::collection res = session.query( "SELECT track FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.disc_number,track.track_number,track.mbid"); return std::vector(res.begin(), res.end()); } std::vector Track::getChecksumDuplicates(Wt::Dbo::Session& session) { Wt::Dbo::collection res = session.query( "SELECT track FROM track WHERE checksum in (SELECT checksum FROM track WHERE Length(checksum) > 0 GROUP BY checksum HAVING COUNT(*) > 1)").orderBy("track.release_id,track.disc_number,track.track_number,track.checksum"); return std::vector(res.begin(), res.end()); } std::vector< Cluster::pointer > Track::getClusters(void) const { std::vector< Cluster::pointer > clusters; std::copy(_clusters.begin(), _clusters.end(), std::back_inserter(clusters)); return clusters; } static Wt::Dbo::Query< Track::pointer > getQuery(Wt::Dbo::Session& session, const std::set& clusterIds, const std::vector keywords) { WhereClause where; std::ostringstream oss; oss << "SELECT t FROM track t"; for (auto keyword : keywords) where.And(WhereClause("t.name LIKE ?")).bind("%%" + keyword + "%%"); if (!clusterIds.empty()) { oss << " INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id"; WhereClause clusterClause; for (auto id : clusterIds) clusterClause.Or(WhereClause("c.id = ?")).bind(std::to_string(id)); where.And(clusterClause); } oss << " " << where.get(); if (!clusterIds.empty()) oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size(); oss << " ORDER BY t.name"; Wt::Dbo::Query query = session.query( oss.str() ); for (const std::string& bindArg : where.getBindArgs()) query.bind(bindArg); return query; } Track::StatsQueryResult Track::getStats(Wt::Dbo::Session& session, SearchFilter filter) { SqlQuery sqlQuery = filter.generatePartialQuery(); Wt::Dbo::Query query = session.query( "SELECT COUNT(\"id\"), SUM(\"dur\") FROM (SELECT t.id as \"id\", t.duration as \"dur\" FROM track t INNER JOIN artist a ON t.artist_id = a.id INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN release r ON r.id = t.release_id " + sqlQuery.where().get() + " GROUP BY t.id)"); for (const std::string& bindArg : sqlQuery.where().getBindArgs()) query.bind(bindArg); return query; } std::vector Track::getByFilter(Wt::Dbo::Session& session, const std::set& clusterIds, const std::vector keywords, int offset, int size, bool& moreResults) { Wt::Dbo::collection collection = getQuery(session, clusterIds, keywords) .limit(size != -1 ? size + 1 : -1) .offset(offset); auto res = std::vector(collection.begin(), collection.end()); if (size != -1 && res.size() == static_cast(size) + 1) { moreResults = true; res.pop_back(); } else moreResults = false; return res; } std::vector Track::getByFilter(Wt::Dbo::Session& session, const std::set& clusters) { bool moreResults; return getByFilter(session, clusters, std::vector(), -1, -1, moreResults); } boost::optional Track::getTrackNumber(void) const { return (_trackNumber > 0) ? boost::make_optional(_trackNumber) : boost::none; } boost::optional Track::getTotalTrackNumber(void) const { return (_totalTrackNumber > 0) ? boost::make_optional(_totalTrackNumber) : boost::none; } boost::optional Track::getDiscNumber(void) const { return (_discNumber > 0) ? boost::make_optional(_discNumber) : boost::none; } boost::optional Track::getTotalDiscNumber(void) const { return (_totalDiscNumber > 0) ? boost::make_optional(_totalDiscNumber) : boost::none; } Cluster::Cluster() { } Cluster::Cluster(std::string type, std::string name) : _type( std::string(type, 0, _maxTypeLength)), _name( std::string(name, 0, _maxNameLength)) { } Wt::Dbo::collection Cluster::getAll(Wt::Dbo::Session& session) { return session.find(); } Cluster::pointer Cluster::get(Wt::Dbo::Session& session, std::string type, std::string name) { // TODO use like search return session.find().where("type = ?").where("name = ?").bind( std::string(type, 0, _maxTypeLength)).bind( std::string(name, 0, _maxNameLength)); } std::vector Cluster::getByType(Wt::Dbo::Session& session, std::string type) { Wt::Dbo::collection res = session.find().where("type = ?").bind( std::string(type, 0, _maxTypeLength)).orderBy("name"); return std::vector(res.begin(), res.end()); } Cluster::pointer Cluster::create(Wt::Dbo::Session& session, std::string type, std::string name) { return session.add(new Cluster(type, name)); } void Cluster::remove(Wt::Dbo::Session& session, std::string type) { Wt::Dbo::Transaction transaction(session); session.execute("DELETE FROM cluster WHERE type = ?").bind(type); } Wt::Dbo::Query Cluster::getQuery(Wt::Dbo::Session& session, SearchFilter filter) { SqlQuery sqlQuery = filter.generatePartialQuery(); Wt::Dbo::Query query = session.query( "SELECT g FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.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_c.track_id " + sqlQuery.where().get()).groupBy("c.name").orderBy("c.name"); for (const std::string& bindArg : sqlQuery.where().getBindArgs()) query.bind(bindArg); return query; } std::vector Cluster::getAllTypes(Wt::Dbo::Session& session) { Wt::Dbo::collection res = session.query("SELECT type from cluster").groupBy("type").orderBy("type"); return std::vector(res.begin(), res.end()); } std::vector Cluster::getByFilter(Wt::Dbo::Session& session, SearchFilter filter, int offset, int size) { Wt::Dbo::collection res = getQuery(session, filter).limit(size).offset(offset); return std::vector(res.begin(), res.end()); } } // namespace Database