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

Rework File/Label API to make it more natural

parent 090bb277
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include "IMediaLibrary.h"
#include "ITrackInformation.h" #include "ITrackInformation.h"
class IAlbumTrack; class IAlbumTrack;
class ILabel;
class IShowEpisode; class IShowEpisode;
class ITrackInformation; class ITrackInformation;
...@@ -21,9 +22,9 @@ class IFile ...@@ -21,9 +22,9 @@ class IFile
virtual std::shared_ptr<IShowEpisode> showEpisode() = 0; virtual std::shared_ptr<IShowEpisode> showEpisode() = 0;
virtual int playCount() = 0; virtual int playCount() = 0;
virtual const std::string& mrl() = 0; virtual const std::string& mrl() = 0;
virtual std::shared_ptr<ILabel> addLabel( const std::string& label ) = 0; virtual bool addLabel( LabelPtr label ) = 0;
virtual bool removeLabel( const std::shared_ptr<ILabel>& label ) = 0; virtual bool removeLabel( LabelPtr label ) = 0;
virtual const std::vector<std::shared_ptr<ILabel>>& labels() = 0; virtual std::vector<std::shared_ptr<ILabel> > labels() = 0;
}; };
#endif // IFILE_H #endif // IFILE_H
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
class IFile; #include "IMediaLibrary.h"
class ILabel class ILabel
{ {
...@@ -13,9 +13,7 @@ class ILabel ...@@ -13,9 +13,7 @@ class ILabel
virtual unsigned int id() const = 0; virtual unsigned int id() const = 0;
virtual const std::string& name() = 0; virtual const std::string& name() = 0;
virtual std::vector<std::shared_ptr<IFile>>& files() = 0; virtual std::vector<FilePtr>& files() = 0;
virtual bool link( IFile* file ) = 0;
virtual bool unlink( IFile* file ) const = 0;
}; };
#endif // ILABEL_H #endif // ILABEL_H
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#include <memory> #include <memory>
class IFile; class IFile;
class ILabel;
typedef std::shared_ptr<IFile> FilePtr; typedef std::shared_ptr<IFile> FilePtr;
typedef std::shared_ptr<ILabel> LabelPtr;
class IMediaLibrary class IMediaLibrary
{ {
...@@ -16,6 +18,7 @@ class IMediaLibrary ...@@ -16,6 +18,7 @@ class IMediaLibrary
virtual bool initialize( const std::string& dbPath ) = 0; virtual bool initialize( const std::string& dbPath ) = 0;
virtual FilePtr addFile( const std::string& path ) = 0; virtual FilePtr addFile( const std::string& path ) = 0;
virtual FilePtr file( const std::string& path ) = 0; virtual FilePtr file( const std::string& path ) = 0;
virtual LabelPtr createLabel( const std::string& label ) = 0;
virtual bool files( std::vector<FilePtr>& res ) = 0; virtual bool files( std::vector<FilePtr>& res ) = 0;
}; };
......
...@@ -14,7 +14,6 @@ const std::string policy::FileTable::CacheColumn = "mrl"; ...@@ -14,7 +14,6 @@ const std::string policy::FileTable::CacheColumn = "mrl";
File::File( sqlite3* dbConnection, sqlite3_stmt* stmt ) File::File( sqlite3* dbConnection, sqlite3_stmt* stmt )
: m_dbConnection( dbConnection ) : m_dbConnection( dbConnection )
, m_labels( nullptr )
{ {
m_id = sqlite3_column_int( stmt, 0 ); m_id = sqlite3_column_int( stmt, 0 );
m_type = (Type)sqlite3_column_int( stmt, 1 ); m_type = (Type)sqlite3_column_int( stmt, 1 );
...@@ -34,7 +33,6 @@ File::File( const std::string& mrl ) ...@@ -34,7 +33,6 @@ File::File( const std::string& mrl )
, m_playCount( 0 ) , m_playCount( 0 )
, m_showEpisodeId( 0 ) , m_showEpisodeId( 0 )
, m_mrl( mrl ) , m_mrl( mrl )
, m_labels( nullptr )
{ {
} }
...@@ -87,17 +85,14 @@ std::shared_ptr<IShowEpisode> File::showEpisode() ...@@ -87,17 +85,14 @@ std::shared_ptr<IShowEpisode> File::showEpisode()
return m_showEpisode; return m_showEpisode;
} }
const std::vector<std::shared_ptr<ILabel>>& File::labels() std::vector<std::shared_ptr<ILabel> > File::labels()
{ {
if ( m_labels == nullptr ) std::vector<std::shared_ptr<ILabel> > labels;
{ const char* req = "SELECT l.* FROM Label l "
m_labels = new std::vector<std::shared_ptr<ILabel>>; "LEFT JOIN LabelFileRelation lfr ON lfr.id_label = l.id_label "
const char* req = "SELECT l.* FROM Label l " "WHERE lfr.id_file = ?";
"LEFT JOIN LabelFileRelation lfr ON lfr.id_label = l.id_label " SqliteTools::fetchAll<Label>( m_dbConnection, req, m_id, labels );
"WHERE lfr.id_file = ?"; return labels;
SqliteTools::fetchAll<Label>( m_dbConnection, req, m_id, *m_labels );
}
return *m_labels;
} }
int File::playCount() int File::playCount()
...@@ -110,36 +105,6 @@ const std::string& File::mrl() ...@@ -110,36 +105,6 @@ const std::string& File::mrl()
return m_mrl; return m_mrl;
} }
std::shared_ptr<ILabel> File::addLabel(const std::string& label)
{
auto l = Label::create( label );
if ( l->insert( m_dbConnection ) == false )
{
return nullptr;
}
l->link( this );
return l;
}
bool File::removeLabel( const std::shared_ptr<ILabel>& label )
{
if ( m_labels != false )
{
auto it = m_labels->begin();
auto ite = m_labels->end();
while ( it != ite )
{
if ( (*it)->id() == label->id() )
break;
++it;
}
if ( it == ite )
return false;
m_labels->erase( it );
}
return label->unlink( this );
}
unsigned int File::id() const unsigned int File::id() const
{ {
return m_id; return m_id;
...@@ -160,6 +125,47 @@ bool File::createTable(sqlite3* connection) ...@@ -160,6 +125,47 @@ bool File::createTable(sqlite3* connection)
return SqliteTools::createTable( connection, req ); return SqliteTools::createTable( connection, req );
} }
bool File::addLabel( LabelPtr label )
{
if ( m_dbConnection == nullptr || m_id == 0 || label->id() == 0)
{
std::cerr << "Both file & label need to be inserted in database before being linked together" << std::endl;
return false;
}
const char* req = "INSERT INTO LabelFileRelation VALUES(?, ?)";
sqlite3_stmt* stmt;
if ( sqlite3_prepare_v2( m_dbConnection, req, -1, &stmt, NULL ) != SQLITE_OK )
{
std::cerr << "Failed to insert record: " << sqlite3_errmsg( m_dbConnection ) << std::endl;
return false;
}
sqlite3_bind_int( stmt, 1, label->id() );
sqlite3_bind_int( stmt, 2, m_id );
bool res = sqlite3_step( stmt ) == SQLITE_DONE;
sqlite3_finalize( stmt );
return res;
}
bool File::removeLabel( LabelPtr label )
{
if ( m_dbConnection == nullptr || m_id == 0 || label->id() == 0 )
{
std::cerr << "Can't unlink a label/file not inserted in database" << std::endl;
return false;
}
const char* req = "DELETE FROM LabelFileRelation WHERE id_label = ? AND id_file = ?";
sqlite3_stmt* stmt;
if ( sqlite3_prepare_v2( m_dbConnection, req, -1, &stmt, NULL ) != SQLITE_OK )
{
std::cerr << "Failed to remove record: " << sqlite3_errmsg( m_dbConnection ) << std::endl;
return false;
}
sqlite3_bind_int( stmt, 1, label->id() );
sqlite3_bind_int( stmt, 2, m_id );
sqlite3_step( stmt );
sqlite3_finalize( stmt );
return sqlite3_changes( m_dbConnection ) > 0;
}
const std::string& policy::FileCache::key(const std::shared_ptr<File> self ) const std::string& policy::FileCache::key(const std::shared_ptr<File> self )
{ {
......
...@@ -56,11 +56,11 @@ class File : public IFile, public Cache<File, IFile, policy::FileTable, policy:: ...@@ -56,11 +56,11 @@ class File : public IFile, public Cache<File, IFile, policy::FileTable, policy::
virtual std::shared_ptr<IAlbumTrack> albumTrack(); virtual std::shared_ptr<IAlbumTrack> albumTrack();
virtual unsigned int duration(); virtual unsigned int duration();
virtual std::shared_ptr<IShowEpisode> showEpisode(); virtual std::shared_ptr<IShowEpisode> showEpisode();
virtual const std::vector<std::shared_ptr<ILabel>>& labels(); virtual bool addLabel( LabelPtr label );
virtual bool removeLabel( LabelPtr label );
virtual std::vector<std::shared_ptr<ILabel> > labels();
virtual int playCount(); virtual int playCount();
virtual const std::string& mrl(); virtual const std::string& mrl();
virtual std::shared_ptr<ILabel> addLabel( const std::string &label );
virtual bool removeLabel(const std::shared_ptr<ILabel>& label );
private: private:
sqlite3* m_dbConnection; sqlite3* m_dbConnection;
...@@ -78,7 +78,6 @@ class File : public IFile, public Cache<File, IFile, policy::FileTable, policy:: ...@@ -78,7 +78,6 @@ class File : public IFile, public Cache<File, IFile, policy::FileTable, policy::
Album* m_album; Album* m_album;
std::shared_ptr<AlbumTrack> m_albumTrack; std::shared_ptr<AlbumTrack> m_albumTrack;
std::shared_ptr<ShowEpisode> m_showEpisode; std::shared_ptr<ShowEpisode> m_showEpisode;
std::vector<std::shared_ptr<ILabel>>* m_labels;
friend class Cache<File, IFile, policy::FileTable, policy::FileCache>; friend class Cache<File, IFile, policy::FileTable, policy::FileCache>;
}; };
......
...@@ -36,7 +36,7 @@ const std::string& Label::name() ...@@ -36,7 +36,7 @@ const std::string& Label::name()
return m_name; return m_name;
} }
std::vector<std::shared_ptr<IFile>>& Label::files() std::vector<FilePtr>& Label::files()
{ {
if ( m_files == nullptr ) if ( m_files == nullptr )
{ {
...@@ -86,44 +86,3 @@ bool Label::createTable(sqlite3* dbConnection) ...@@ -86,44 +86,3 @@ bool Label::createTable(sqlite3* dbConnection)
return SqliteTools::createTable( dbConnection, req ); return SqliteTools::createTable( dbConnection, req );
} }
bool Label::link( IFile* file )
{
if ( m_dbConnection == nullptr || m_id == 0 )
{
std::cerr << "A label needs to be inserted in database before being linked to a file" << std::endl;
return false;
}
const char* req = "INSERT INTO LabelFileRelation VALUES(?, ?)";
sqlite3_stmt* stmt;
if ( sqlite3_prepare_v2( m_dbConnection, req, -1, &stmt, NULL ) != SQLITE_OK )
{
std::cerr << "Failed to insert record: " << sqlite3_errmsg( m_dbConnection ) << std::endl;
return false;
}
sqlite3_bind_int( stmt, 1, m_id );
sqlite3_bind_int( stmt, 2, file->id() );
bool res = sqlite3_step( stmt ) == SQLITE_DONE;
sqlite3_finalize( stmt );
return res;
}
bool Label::unlink( IFile* file ) const
{
if ( m_dbConnection == nullptr || m_id == 0 )
{
std::cerr << "Can't unlink a label not inserted in database" << std::endl;
return false;
}
const char* req = "DELETE FROM LabelFileRelation WHERE id_label = ? AND id_file = ?";
sqlite3_stmt* stmt;
if ( sqlite3_prepare_v2( m_dbConnection, req, -1, &stmt, NULL ) != SQLITE_OK )
{
std::cerr << "Failed to remove record: " << sqlite3_errmsg( m_dbConnection ) << std::endl;
return false;
}
sqlite3_bind_int( stmt, 1, m_id );
sqlite3_bind_int( stmt, 2, file->id() );
bool res = sqlite3_step( stmt ) == SQLITE_DONE;
sqlite3_finalize( stmt );
return res;
}
...@@ -28,12 +28,10 @@ class Label : public ILabel, public Cache<Label, ILabel, policy::LabelTable> ...@@ -28,12 +28,10 @@ class Label : public ILabel, public Cache<Label, ILabel, policy::LabelTable>
public: public:
virtual unsigned int id() const; virtual unsigned int id() const;
virtual const std::string& name(); virtual const std::string& name();
virtual std::vector<std::shared_ptr<IFile>>& files(); virtual std::vector<FilePtr>& files();
bool insert( sqlite3* dbConnection ); bool insert( sqlite3* dbConnection );
static bool createTable( sqlite3* dbConnection ); static bool createTable( sqlite3* dbConnection );
bool link( IFile* file );
bool unlink( IFile* file ) const;
private: private:
sqlite3* m_dbConnection; sqlite3* m_dbConnection;
unsigned int m_id; unsigned int m_id;
......
...@@ -50,3 +50,13 @@ FilePtr MediaLibrary::addFile( const std::string& path ) ...@@ -50,3 +50,13 @@ FilePtr MediaLibrary::addFile( const std::string& path )
} }
return f; return f;
} }
LabelPtr MediaLibrary::createLabel( const std::string& label )
{
auto l = Label::create( label );
if ( l->insert( m_dbConnection ) == false )
{
return nullptr;
}
return l;
}
...@@ -13,9 +13,9 @@ class MediaLibrary : public IMediaLibrary ...@@ -13,9 +13,9 @@ class MediaLibrary : public IMediaLibrary
virtual bool files( std::vector<FilePtr>& res ); virtual bool files( std::vector<FilePtr>& res );
virtual FilePtr file( const std::string& path ); virtual FilePtr file( const std::string& path );
virtual FilePtr addFile( const std::string& path ); virtual FilePtr addFile( const std::string& path );
virtual LabelPtr createLabel(const std::string& label);
private: private:
sqlite3* m_dbConnection; sqlite3* m_dbConnection;
}; };
#endif // MEDIALIBRARY_H #endif // MEDIALIBRARY_H
...@@ -59,13 +59,20 @@ TEST_F( MLTest, FetchFile ) ...@@ -59,13 +59,20 @@ TEST_F( MLTest, FetchFile )
TEST_F( MLTest, AddLabel ) TEST_F( MLTest, AddLabel )
{ {
auto f = ml->addFile( "/dev/null" ); auto f = ml->addFile( "/dev/null" );
auto l1 = f->addLabel( "sea otter" ); auto l1 = ml->createLabel( "sea otter" );
auto l2 = f->addLabel( "cony the cone" ); auto l2 = ml->createLabel( "cony the cone" );
ASSERT_TRUE( l1 != NULL ); ASSERT_NE( l1, nullptr);
ASSERT_TRUE( l2 != NULL ); ASSERT_NE( l2, nullptr);
auto labels = f->labels(); auto labels = f->labels();
ASSERT_EQ( labels.size(), 0u );
f->addLabel( l1 );
f->addLabel( l2 );
labels = f->labels();
ASSERT_EQ( labels.size(), 2u ); ASSERT_EQ( labels.size(), 2u );
ASSERT_EQ( labels[0]->name(), "sea otter" ); ASSERT_EQ( labels[0]->name(), "sea otter" );
ASSERT_EQ( labels[1]->name(), "cony the cone" ); ASSERT_EQ( labels[1]->name(), "cony the cone" );
...@@ -74,8 +81,11 @@ TEST_F( MLTest, AddLabel ) ...@@ -74,8 +81,11 @@ TEST_F( MLTest, AddLabel )
TEST_F( MLTest, RemoveLabel ) TEST_F( MLTest, RemoveLabel )
{ {
auto f = ml->addFile( "/dev/null" ); auto f = ml->addFile( "/dev/null" );
auto l1 = f->addLabel( "sea otter" ); auto l1 = ml->createLabel( "sea otter" );
auto l2 = f->addLabel( "cony the cone" ); auto l2 = ml->createLabel( "cony the cone" );
f->addLabel( l1 );
f->addLabel( l2 );
auto labels = f->labels(); auto labels = f->labels();
ASSERT_EQ( labels.size(), 2u ); ASSERT_EQ( labels.size(), 2u );
...@@ -110,3 +120,5 @@ TEST_F( MLTest, RemoveLabel ) ...@@ -110,3 +120,5 @@ TEST_F( MLTest, RemoveLabel )
labels = f2->labels(); labels = f2->labels();
ASSERT_EQ( labels.size(), 0u ); ASSERT_EQ( labels.size(), 0u );
} }
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