Commit f3a80076 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

Playlist: Add search

parent d0022eef
......@@ -116,6 +116,7 @@ class IMediaLibrary
* Search
*/
virtual std::vector<MediaPtr> searchAlbumTracks( const std::string& title ) const = 0;
virtual std::vector<PlaylistPtr> searchPlaylists( const std::string& name ) const = 0;
/**
* @brief discover Launch a discovery on the provided entry point.
......
......@@ -410,6 +410,11 @@ std::vector<MediaPtr> MediaLibrary::searchAlbumTracks( const std::string& title
return AlbumTrack::search( m_dbConnection.get(), title );
}
std::vector<PlaylistPtr> MediaLibrary::searchPlaylists( const std::string& name ) const
{
return Playlist::search( m_dbConnection.get(), name );
}
void MediaLibrary::startParser()
{
m_parser.reset( new Parser( m_dbConnection.get(), this, m_callback ) );
......
......@@ -91,6 +91,7 @@ class MediaLibrary : public IMediaLibrary
virtual std::vector<HistoryPtr> history() const;
virtual std::vector<MediaPtr> searchAlbumTracks( const std::string& title ) const override;
virtual std::vector<PlaylistPtr> searchPlaylists( const std::string& name ) const override;
virtual void discover( const std::string& entryPoint ) override;
bool banFolder( const std::string& path ) override;
......
......@@ -128,9 +128,13 @@ bool Playlist::createTable( DBConnection dbConn )
"FOREIGN KEY(playlist_id) REFERENCES " + policy::PlaylistTable::Name + "("
+ policy::PlaylistTable::PrimaryKeyColumn + ") ON DELETE CASCADE"
")";
static const std::string vtableReq = "CREATE VIRTUAL TABLE " + policy::PlaylistTable::Name + "Fts USING FTS3("
"name"
")";
//FIXME Enforce (playlist_id,position) uniqueness
return sqlite::Tools::executeRequest( dbConn, req ) &&
sqlite::Tools::executeRequest( dbConn, relTableReq );
sqlite::Tools::executeRequest( dbConn, relTableReq ) &&
sqlite::Tools::executeRequest( dbConn, vtableReq );
}
bool Playlist::createTriggers( DBConnection dbConn )
......@@ -161,7 +165,32 @@ bool Playlist::createTriggers( DBConnection dbConn )
" AND position = new.position"
" AND media_id != new.media_id;"
" END";
static const std::string vtriggerInsert = "CREATE TRIGGER IF NOT EXISTS insert_playlist_fts AFTER INSERT ON "
+ policy::PlaylistTable::Name +
" BEGIN"
" INSERT INTO " + policy::PlaylistTable::Name + "Fts(rowid, name) VALUES(new.id_playlist, new.name);"
" END";
static const std::string vtriggerUpdate = "CREATE TRIGGER IF NOT EXISTS update_playlist_fts AFTER UPDATE OF name"
" ON " + policy::PlaylistTable::Name +
" BEGIN"
" UPDATE " + policy::PlaylistTable::Name + "Fts SET name = new.name WHERE rowid = new.id_playlist;"
" END";
static const std::string vtriggerDelete = "CREATE TRIGGER IF NOT EXISTS delete_playlist_fts BEFORE DELETE ON "
+ policy::PlaylistTable::Name +
" BEGIN"
" DELETE FROM " + policy::PlaylistTable::Name + "Fts WHERE rowid = old.id_playlist;"
" END";
return sqlite::Tools::executeRequest( dbConn, req ) &&
sqlite::Tools::executeRequest( dbConn, autoAppendReq ) &&
sqlite::Tools::executeRequest( dbConn, autoShiftPosReq );
sqlite::Tools::executeRequest( dbConn, autoShiftPosReq ) &&
sqlite::Tools::executeRequest( dbConn, vtriggerInsert ) &&
sqlite::Tools::executeRequest( dbConn, vtriggerUpdate ) &&
sqlite::Tools::executeRequest( dbConn, vtriggerDelete );
}
std::vector<PlaylistPtr> Playlist::search( DBConnection dbConnection, const std::string& name )
{
static const std::string req = "SELECT * FROM " + policy::PlaylistTable::Name + " WHERE id_playlist IN "
"(SELECT rowid FROM " + policy::PlaylistTable::Name + "Fts WHERE name MATCH ?)";
return fetchAll<IPlaylist>( dbConnection, req, name + "*" );
}
......@@ -59,6 +59,7 @@ public:
static bool createTable( DBConnection dbConn );
static bool createTriggers( DBConnection dbConn );
static std::vector<PlaylistPtr> search( DBConnection dbConnection, const std::string& name );
private:
DBConnection m_dbConnection;
......
......@@ -240,3 +240,38 @@ TEST_F( Playlists, DeleteFile )
ASSERT_NE( nullptr, pl );
}
TEST_F( Playlists, Search )
{
ml->createPlaylist( "playlist 2" );
ml->createPlaylist( "laylist 3" );
auto playlists = ml->searchPlaylists( "play" );
ASSERT_EQ( 2u, playlists.size() );
}
TEST_F( Playlists, SearchAfterDelete )
{
auto pl = ml->createPlaylist( "sea otters greatest hits" );
auto pls = ml->searchPlaylists( "sea otters" );
ASSERT_EQ( 1u, pls.size() );
ml->deletePlaylist( pl->id() );
pls = ml->searchPlaylists( "sea otters" );
ASSERT_EQ( 0u, pls.size() );
}
TEST_F( Playlists, SearchAfterUpdate )
{
auto pl = ml->createPlaylist( "sea otters greatest hits" );
auto pls = ml->searchPlaylists( "sea otters" );
ASSERT_EQ( 1u, pls.size() );
pl->setName( "pangolins are cool too" );
pls = ml->searchPlaylists( "sea otters" );
ASSERT_EQ( 0u, pls.size() );
pls = ml->searchPlaylists( "pangolins" );
ASSERT_EQ( 1u, pls.size() );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment