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

Artist: Add search

parent 681a7a98
......@@ -119,6 +119,7 @@ class IMediaLibrary
virtual std::vector<PlaylistPtr> searchPlaylists( const std::string& name ) const = 0;
virtual std::vector<AlbumPtr> searchAlbums( const std::string& pattern ) const = 0;
virtual std::vector<GenrePtr> searchGenre( const std::string& genre ) const = 0;
virtual std::vector<ArtistPtr> searchArtists( const std::string& name ) const = 0;
/**
* @brief discover Launch a discovery on the provided entry point.
......
......@@ -190,8 +190,13 @@ bool Artist::createTable( DBConnection dbConnection )
"FOREIGN KEY(artist_id) REFERENCES " + policy::ArtistTable::Name + "("
+ policy::ArtistTable::PrimaryKeyColumn + ") ON DELETE CASCADE"
")";
static const std::string reqFts = "CREATE VIRTUAL TABLE IF NOT EXISTS " +
policy::ArtistTable::Name + "Fts USING FTS3("
"name"
")";
return sqlite::Tools::executeRequest( dbConnection, req ) &&
sqlite::Tools::executeRequest( dbConnection, reqRel );
sqlite::Tools::executeRequest( dbConnection, reqRel ) &&
sqlite::Tools::executeRequest( dbConnection, reqFts );
}
bool Artist::createTriggers(DBConnection dbConnection)
......@@ -203,7 +208,19 @@ bool Artist::createTriggers(DBConnection dbConnection)
"(SELECT COUNT(id_album) FROM " + policy::AlbumTable::Name + " WHERE artist_id=new.artist_id AND is_present=1) "
"WHERE id_artist=new.artist_id;"
" END";
return sqlite::Tools::executeRequest( dbConnection, triggerReq );
static const std::string ftsInsertTrigger = "CREATE TRIGGER IF NOT EXISTS insert_artist_fts"
" AFTER INSERT ON " + policy::ArtistTable::Name +
" BEGIN"
" INSERT INTO " + policy::ArtistTable::Name + "Fts(rowid,name) VALUES(new.id_artist, new.name);"
" END";
static const std::string ftsDeleteTrigger = "CREATE TRIGGER IF NOT EXISTS delete_artist_fts"
" BEFORE DELETE ON " + policy::ArtistTable::Name +
" BEGIN"
" DELETE FROM " + policy::ArtistTable::Name + "Fts WHERE rowid=old.id_artist;"
" END";
return sqlite::Tools::executeRequest( dbConnection, triggerReq ) &&
sqlite::Tools::executeRequest( dbConnection, ftsInsertTrigger ) &&
sqlite::Tools::executeRequest( dbConnection, ftsDeleteTrigger );
}
bool Artist::createDefaultArtists( DBConnection dbConnection )
......@@ -230,3 +247,11 @@ std::shared_ptr<Artist> Artist::create( DBConnection dbConnection, const std::st
return artist;
}
std::vector<ArtistPtr> Artist::search( DBConnection dbConnection, const std::string& name )
{
static const std::string req = "SELECT * FROM " + policy::ArtistTable::Name + " WHERE id_artist IN "
"(SELECT rowid FROM " + policy::ArtistTable::Name + "Fts WHERE name MATCH ?)"
"AND is_present != 0";
return fetchAll<IArtist>( dbConnection, req, name + "*" );
}
......@@ -64,6 +64,7 @@ public:
static bool createTriggers( DBConnection dbConnection );
static bool createDefaultArtists( DBConnection dbConnection );
static std::shared_ptr<Artist> create( DBConnection dbConnection, const std::string& name );
static std::vector<ArtistPtr> search( DBConnection dbConnection, const std::string& name );
private:
DBConnection m_dbConnection;
......
......@@ -433,6 +433,13 @@ std::vector<GenrePtr> MediaLibrary::searchGenre( const std::string& genre ) cons
return Genre::search( m_dbConnection.get(), genre );
}
std::vector<ArtistPtr> MediaLibrary::searchArtists(const std::string& name ) const
{
if ( validateSearchPattern( name ) == false )
return {};
return Artist::search( m_dbConnection.get(), name );
}
void MediaLibrary::startParser()
{
m_parser.reset( new Parser( m_dbConnection.get(), this, m_callback ) );
......
......@@ -93,6 +93,7 @@ class MediaLibrary : public IMediaLibrary
virtual std::vector<PlaylistPtr> searchPlaylists( const std::string& name ) const override;
virtual std::vector<AlbumPtr> searchAlbums( const std::string& pattern ) const override;
virtual std::vector<GenrePtr> searchGenre( const std::string& genre ) const override;
virtual std::vector<ArtistPtr> searchArtists( const std::string& name ) const override;
virtual void discover( const std::string& entryPoint ) override;
bool banFolder( const std::string& path ) override;
......
......@@ -190,3 +190,28 @@ TEST_F( Artists, MusicBrainzId )
ASSERT_NE( a2, nullptr );
ASSERT_EQ( a2->musicBrainzId(), mbId );
}
TEST_F( Artists, Search )
{
ml->createArtist( "artist 1" );
ml->createArtist( "artist 2" );
ml->createArtist( "dream seaotter" );
auto artists = ml->searchArtists( "artist" );
ASSERT_EQ( 2u, artists.size() );
}
TEST_F( Artists, SearchAfterDelete )
{
auto a = ml->createArtist( "artist 1" );
ml->createArtist( "artist 2" );
ml->createArtist( "dream seaotter" );
auto artists = ml->searchArtists( "artist" );
ASSERT_EQ( 2u, artists.size() );
ml->deleteArtist( a->id() );
artists = ml->searchArtists( "artist" );
ASSERT_EQ( 1u, artists.size() );
}
......@@ -25,6 +25,7 @@
#include <memory>
#include "Album.h"
#include "Artist.h"
#include "File.h"
#include "filesystem/IFile.h"
#include "filesystem/IDirectory.h"
......@@ -141,3 +142,8 @@ void MediaLibraryTester::deleteGenre( unsigned int genreId )
{
Genre::destroy( m_dbConnection.get(), genreId );
}
void MediaLibraryTester::deleteArtist( unsigned int artistId )
{
Artist::destroy( m_dbConnection.get(), artistId );
}
......@@ -40,6 +40,7 @@ public:
void deleteAlbum( unsigned int albumId );
std::shared_ptr<Genre> createGenre( const std::string& name );
void deleteGenre( unsigned int genreId );
void deleteArtist( unsigned int artistId );
private:
std::unique_ptr<fs::IDirectory> dummyDirectory;
......
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