#include "mysql.h" #include <QSqlQuery> #include <QtSql> #include "exaptions.h" #include <QSettings> #include <QMediaPlaylist> namespace syncLib{ MySql::MySql(const QString &databasename): db(nullptr), qyery(nullptr) { initDB(databasename); } bool MySql::exec(QSqlQuery *sq,const QString& sqlFile){ QFile f(sqlFile); bool result=true; if(f.open(QIODevice::ReadOnly)){ QString temp,delimiter=";"; QTextStream stream(&f); stream.setCodec("UTF8"); while(!stream.atEnd()){ temp+=stream.readLine(); if(temp.lastIndexOf("delimiter",-1,Qt::CaseInsensitive)>-1){ temp.remove("delimiter",Qt::CaseInsensitive); int last=temp.indexOf(QRegularExpression("[^ \f\n\r\t\v]"))+1; int begin=temp.lastIndexOf(QRegularExpression("[^ \f\n\r\t\v]")); delimiter=temp.mid(begin,last-begin); temp=""; }else{ if(temp.lastIndexOf(delimiter)>-1){ temp.remove(delimiter); (result=result&&sq->exec(temp)); temp=""; } } } return result; } return false; } void MySql::initDB(const QString &database){ if(db) return; dataBaseName = database; QSettings settings; songDir = settings.value(MAIN_FOLDER_KEY, QDir::homePath() + "/soundBand").toString(); db = new QSqlDatabase(); *db = QSqlDatabase::addDatabase("QSQLITE", database); QDir d(QString("./%0").arg(dataBaseName)); db->setDatabaseName(d.absolutePath()); if(db->open()){ qyery = new QSqlQuery(*db); QString qyer = QString("CREATE TABLE IF NOT EXISTS songs(" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "name VARCHAR(100), " "size INT NOT NULL, " "data TEXT NOT NULL " ")"); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); throw InitDBError(); delete db; return; } qyer = QString("CREATE UNIQUE INDEX IF NOT EXISTS isongs ON songs(name,size)"); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); throw InitDBError(); delete db; return; } qyer = QString("CREATE TABLE IF NOT EXISTS playlists(" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "name VARCHAR(50) NOT NULL UNIQUE, " "description VARCHAR(1000) DEFAULT 'without description', " "image BLOB " ")"); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); throw InitDBError(); delete db; return; } qyer = QString("CREATE TABLE IF NOT EXISTS playlistsdata(" "playlist INT NOT NULL," "song INT NOT NULL," "FOREIGN KEY(playlist) REFERENCES playlists(name)" " ON UPDATE CASCADE" " ON DELETE CASCADE," "FOREIGN KEY(song) REFERENCES songs(id)" " ON UPDATE CASCADE" " ON DELETE CASCADE" ")"); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); throw InitDBError(); delete db; return; } qyer = QString("CREATE UNIQUE INDEX IF NOT EXISTS iplaylistsdata ON " "playlistsdata(playlist,song)"); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); throw InitDBError(); delete db; return; } } } bool MySql::find(const QMediaContent &song, SongStorage &response){ QList<SongStorage> songs; if(!updateAvailableSongs(songs)){ return false; } for(SongStorage &i: songs){ if(i == song){ response = i; return true; } } return false; } bool MySql::find(const QMediaContent &song, SongHeader &response){ QList<SongStorage> songs; if(!updateAvailableSongs(songs)){ return false; } for(SongStorage &i: songs){ if(i == song){ response = (SongHeader&)i; return true; } } return false; } bool MySql::find(const SongHeader &song, QMediaContent &response){ QList<SongStorage> songs; if(!updateAvailableSongs(songs)){ return false; } for(SongStorage &i: songs){ if((SongHeader&)i == song){ response = i.toMedia(); return true; } } return false; } void MySql::setSoundDir(const QString &str){ songDir = str; QSettings().setValue(MAIN_FOLDER_KEY, songDir); } bool MySql::saveToStorage(QUrl &url, const Song &song) const{ if(!song.isValid()){ return false; } QFile file(songDir + "/" + song.name); if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)){ return false; } file.write(song.source.data(), song.source.length()); file.close(); url = QUrl::fromLocalFile(songDir + "/" + song.name); return url.isValid(); } void MySql::sqlErrorLog(const QString &qyery)const{ #ifdef QT_DEBUG qDebug()<< qyery << ": fail:\n " <<this->qyery->lastError(); #endif } int MySql::save(const Song &song , bool onlyDataBase){ QString qyer = QString("SELECT id from songs where name='%0' and size=%1").arg(song.name, QString::number(song.size)); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return -1; } if(qyery->next()){ return qyery->value(0).toInt(); } QUrl url; if(!onlyDataBase && !saveToStorage(url, song)){ return false; } qyer = QString("INSERT INTO songs (name,size,data) VALUES" "('%0',%1,'%2')").arg(song.name, QString::number(song.size), url.path()); if(!qyery->exec()){ sqlErrorLog(qyer); return -1; } if(!qyery->exec(QString("SELECT MAX(id) from songs"))){ sqlErrorLog(qyer); return -1; } if(!qyery->next()) return -1; int result = qyery->value(0).toInt(); return result; } int MySql::save(const QString &url){ SongStorage song(QUrl::fromLocalFile(url)); if(!song.isNameValid()){ return -1; } return save(song, true); } bool MySql::load(const SongHeader &song, SongStorage &result){ if(song.id > -1){ QString qyer = QString("SELECT * from songs where id=%0").arg(song.id); if(!qyery->exec(qyer)){ return false; } }else if(!song.name.isEmpty() && song.size > 0){ QString qyer = QString("SELECT * from songs where name='%0' and size=%1").arg(song.name).arg(song.size); if(!qyery->exec(qyer)){ return false; } }else { return false; } if(!qyery->next()){ return false; } result.id = qyery->value(0).toInt(); result.name = qyery->value(1).toString(); result.size = qyery->value(2).toInt(); result.url = qyery->value(3).toUrl(); return true; } bool MySql::updateAvailableSongs(QList<SongStorage>& list, const QString& playList, bool forEditing){ QString qyer; if(playList.isEmpty() || playList == ALL_SONGS_LIST || forEditing){ qyer = QString("SELECT * from songs"); }else{ qyer = QString("SELECT * from songs where " "id in (select song from playlistsdata where " "playlist='%0')").arg(playList); } if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } list.clear(); while(qyery->next()){ SongStorage song; song.isSelected = !forEditing || playList == ALL_SONGS_LIST; song.id = qyery->value(0).toInt(); song.name = qyery->value(1).toString(); song.size = qyery->value(2).toInt(); song.url = qyery->value(3).toUrl(); list.push_back(song); } if(forEditing && list.size() > 0 && playList != ALL_SONGS_LIST){ QString qyer; qyer = QString("select song from playlistsdata where " " playlist='%0'").arg(playList); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } while(qyery->next()){ for(SongStorage& item:list){ int id = qyery->value(0).toInt(); if(item.id == id){ item.isSelected = true; break; } } } } return true; } bool MySql::updateAvailableSongs(QMediaPlaylist& list, const QString& playList){ QList<SongStorage> tempList; if(!updateAvailableSongs(tempList, playList)) return false; for(SongStorage &header : tempList){ list.addMedia(header.toMedia()); } return true; } bool MySql::removeSong(const SongHeader &header){ if(header.id > -1){ QString qyer = QString("DELETE from songs where id=%0").arg(header.id); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } }else if(!header.name.isEmpty() && header.size > 0){ QString qyer = QString("DELETE from songs where name='%0'" " and size=%1").arg(header.name).arg(header.size); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } }else { return false; } return true; } bool MySql::addPlayList(const QString &newPlayList, const QString& desc){ if(newPlayList == ALL_SONGS_LIST) return false; QString qyer = QString("INSERT INTO playlists(name, description)" " VALUES('%0', '%1')").arg(newPlayList, desc); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } return true; } bool MySql::addToPlayList(const SongHeader &header, const QString &newPlaylist){ if(newPlaylist == ALL_SONGS_LIST) return false; if(header.id > -1){ QString qyer = QString("INSERT INTO playlistsdata(song, playlist)" " VALUES(%0,'%1')").arg(header.id).arg(newPlaylist); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } }else if(!header.name.isEmpty() && header.size > 0){ QString qyer = QString("INSERT INTO playlistsdata(song, playlist) " "VALUES((SELECT id from songs where name='%0'" " and size='%1'),'%2')") .arg(header.name).arg(header.size).arg(newPlaylist); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } }else { return false; } return true; } bool MySql::removeFromPlayList(const SongHeader &header, const QString &playList){ if(playList == ALL_SONGS_LIST) return false; if(header.id > -1){ QString qyer = QString("DELETE from playlistsdata where song=%0 and playlist='%1'").arg(header.id).arg(playList); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } }else if(!header.name.isEmpty() && header.size > 0){ QString qyer = QString("DELETE from playlistsdata where " "song=(SELECT id from songs where name='%0' and size='%1')" " and playlist='%2'") .arg(header.name).arg(header.size).arg(playList); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } }else { return false; } return true; } bool MySql::removePlayList(const QString &playList){ if(playList == ALL_SONGS_LIST) return false; QString qyer = QString("DELETE from playlists where name='%0'").arg(playList); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } return true; } bool MySql::getPlayLists(QStringList &list)const{ QString qyer = QString("SELECT name from playlists"); if(!qyery->exec(qyer)){ sqlErrorLog(qyer); return false; } list.clear(); list.push_back(ALL_SONGS_LIST); while(qyery->next()){ list.push_back(qyery->value(0).toString()); } return true; } int MySql::getSongId(const QString &name){ if(name.isEmpty()){ return -1; } QString qyer = QString("SELECT id from songs where name='%0'").arg(name); if(!qyery->exec(qyer)){ return -1; } if(qyery->size() != 1){ throw DataBaseError(); } if(!qyery->next()){ return -1; } return qyery->value(0).toInt();; } void MySql::clear(){ qyery->exec("vacuum"); } MySql::~MySql(){ delete db; QSqlDatabase::removeDatabase(dataBaseName); } }