#include "database.h" #include "config.h" #include #include Database::Database() { sql.open(config::vm["audist.database"].as()); } Database::~Database() { sql.close(); } // NOTE: LIKE is case-insensitive by default on sqlite std::vector Database::find(std::map search) { soci::session sql(config::vm["audist.database"].as()); soci::statement st(sql); std::string filename, artist, album, title; st.exchange(soci::into(filename)); std::string query = "SELECT file_name FROM tracks WHERE "; std::vector where_conditions; if(search.find("artist") != search.end()) { where_conditions.push_back("artist_id IN (SELECT id FROM artists WHERE name LIKE :artist)"); artist = "%"+search["artist"]+"%"; st.exchange(soci::use(artist, "artist")); } if(search.find("album") != search.end()) { where_conditions.push_back("album_id IN (SELECT id FROM albums WHERE name LIKE :album)"); album = "%"+search["album"]+"%"; st.exchange(soci::use(album, "album")); } if(search.find("title") != search.end()) { where_conditions.push_back("name LIKE :title"); artist = "%"+search["title"]+"%"; st.exchange(soci::use(title, "title")); } query += boost::algorithm::join(where_conditions, " AND "); st.alloc(); st.prepare(query); st.define_and_bind(); st.execute(true); std::vector results; while(st.fetch()) { MusicListing::p ml(new MusicTrack(filename)); results.push_back(ml); } sql.close(); return results; } std::vector Database::find(std::string search) { soci::session sql(config::vm["audist.database"].as()); search = "%"+search+"%"; soci::rowset rs = (sql.prepare << "SELECT DISTINCT file_name FROM tracks WHERE name LIKE :search OR file_name LIKE :search OR " "artist_id IN (SELECT id FROM artists WHERE name LIKE :search) OR album_id IN (SELECT id FROM albums WHERE name LIKE :search)", soci::use(search, "search")); std::vector results; for(soci::rowset::const_iterator it = rs.begin(); it != rs.end(); it++) { MusicListing::p ml(new MusicTrack(*it)); results.push_back(ml); } return results; } // NOTE: last_insert_rowid() is sqlite-specific void Database::update(fs::path track, Tag::p tag) { int64_t artist_id = 0, album_id = 0, track_id = 0; if(tag->has_field("artist")) { sql << "SELECT id FROM artists WHERE name = :name", soci::use(tag->fields["artist"]), soci::into(artist_id); if(!sql.got_data()) { sql << "INSERT INTO artists (name) VALUES (:name)", soci::use(tag->fields["artist"]); sql << "SELECT last_insert_rowid()", soci::into(artist_id); } } if(tag->has_field("album")) { std::string query(boost::str(boost::format("SELECT id FROM albums WHERE %s AND name = :name") % (artist_id ? boost::str(boost::format("artist_id = %d") % artist_id) : "artist_id IS NULL"))); sql << query, soci::use(tag->fields["album"]), soci::into(album_id); if(!sql.got_data()) { soci::indicator ind = (artist_id ? soci::i_ok : soci::i_null); sql << "INSERT INTO albums (artist_id, name) VALUES (:artist_id, :name)", soci::use(artist_id, ind), soci::use(tag->fields["album"]); sql << "SELECT last_insert_rowid()", soci::into(album_id); } } if(tag->has_field("title")) { std::string query(boost::str(boost::format("SELECT id FROM tracks WHERE %s AND %s AND name = :name") % (artist_id ? boost::str(boost::format("artist_id = %d") % artist_id) : "artist_id IS NULL") % (album_id ? boost::str(boost::format("album_id = %d") % album_id) : "album_id IS NULL"))); sql << query, soci::use(tag->fields["title"]), soci::into(track_id); if(!sql.got_data()) { soci::indicator artist_ind = (artist_id ? soci::i_ok : soci::i_null), album_ind = (album_id ? soci::i_ok : soci::i_null); sql << "INSERT INTO tracks (artist_id, album_id, name, file_name) VALUES (:artist_id, :album_id, :name, :file_name)", soci::use(artist_id, artist_ind), soci::use(album_id, album_ind), soci::use(tag->fields["title"]), soci::use(track.string()); } } }