summaryrefslogtreecommitdiff
path: root/mg_db.h
diff options
context:
space:
mode:
Diffstat (limited to 'mg_db.h')
-rw-r--r--mg_db.h642
1 files changed, 81 insertions, 561 deletions
diff --git a/mg_db.h b/mg_db.h
index 40e3308..2ba02df 100644
--- a/mg_db.h
+++ b/mg_db.h
@@ -9,8 +9,8 @@
*
*/
-#ifndef _DB_H
-#define _DB_H
+#ifndef _MG_DB_H
+#define _MG_DB_H
#include <stdlib.h>
#include <mysql/mysql.h>
#include <string>
@@ -25,443 +25,29 @@
using namespace std;
#include "mg_tools.h"
+#include "mg_valmap.h"
+#include "mg_order.h"
typedef vector<string> strvector;
-//! \brief a map for reading / writing configuration data.
-class mgValmap : public map<string,string> {
- private:
- const char *m_key;
- public:
- /*! \brief constructor
- * \param key all names will be prefixed with key.
- */
- mgValmap(const char *key);
- //! \brief read from file
- void Read(FILE *f);
- //! \brief write to file
- void Write(FILE *f);
- //! \brief enter a string value
- void put(const char*name, string value);
- //! \brief enter a C string value
- void put(const char*name, const char* value);
- //! \brief enter a long value
- void put(const char*name, long value);
- //! \brief enter a int value
- void put(const char*name, int value);
- //! \brief enter a unsigned int value
- void put(const char*name, unsigned int value);
- //! \brief enter a bool value
- void put(const char*name, bool value);
- //! \brief return a string
- string getstr(const char* name) {
- return (*this)[name];
- }
- //! \brief return a C string
- bool getbool(const char* name) {
- return (getstr(name)=="true");
- }
- //! \brief return a long
- long getlong(const char* name) {
- return atol(getstr(name).c_str());
- }
- //! \brief return an unsigned int
- unsigned int getuint(const char* name) {
- return (unsigned long)getlong(name);
- }
-};
-
-static const string EMPTY = "XNICHTGESETZTX";
class mgSelection;
-//! \brief a generic keyfield
-class keyfield
-{
- public:
- //! \brief set the owning selection.
- void setOwner(mgSelection *owner) { selection = owner; }
-
- //! \brief default constructor
- keyfield ()
- {
- };
-
- /*! \brief constructs a simple key field which only needs info from
- * the tracks table.
- * \param choice the internationalized name of this key field, e.g. "Jahr"
- */
- keyfield (const string choice);
-
- //! \brief default destructor
- virtual ~ keyfield ()
- {
- };
-
-/*! \brief assigns a new id and value to the key field.
- * This also invalidates the cache of the owning mgSelection.
- * \param id used for lookups in the data base
- * \param value used for display
- */
- void set (const string id, const string value);
-
-//! \brief helper function for streaming debug info
- void writeAt (ostream &) const;
-
-//! \brief adds lookup data to a WHERE SQL statement
- string restrict (string & result) const;
-
-//! \brief returns the internationalized name of this key field
- string choice () const
- {
- return m_choice;
- }
-
-/*! \brief returns the id of this key field. This is the string used
- * for lookups in the data base, not for display
- */
- string id () const
- {
- return m_id;
- }
-
-/*! \brief returns the filter for this key field.
- * \todo filters are not yet implemented but we already dump them in DumpState
- */
- string filter () const
- {
- return m_filter;
- }
-
-/*! \brief returns the value of this key field. This is the string used
- * for the display.
- */
- string value () const
- {
- return m_value;
- }
-
- virtual string order() const
- {
- return valuefield ();
- }
-
-//! \brief returns the name of the corresponding field in the tracks table
- virtual string basefield () const { return ""; }
-
-//! \brief returns the name of the field to be shown in the selection list
- virtual string valuefield () const
- {
- return basefield ();
- }
-
-//! \brief returns the name of the identification field
- virtual string idfield () const
- {
- return basefield ();
- }
-
-/*! \brief returns the name of the field needed to count how many
- * different values for this key field exist
- */
- virtual string countfield () const
- {
- return basefield ();
- }
-
-/*! \brief returns a join clause needed for the composition of
- * a WHERE statement
- */
- virtual string join () const;
-
-/*! \brief returns a join clause needed for the composition of
- * a WHERE statement especially for counting the number of items
- */
- virtual string countjoin () const
- {
- return join ();
- }
-
-/*! \brief if true, the WHERE clause should also return values from
- * join tables
- */
- bool lookup;
-
-//! \brief returns a SQL query command for counting different key
-//values
- string KeyCountquery ();
-
- protected:
-//! \brief the owning selection.
- mgSelection* selection;
- //! \brief the english name for this key field
- string m_choice;
- //! \brief used for lookup in the data base
- string m_id;
- //! \brief used for OSD display
- string m_value;
- //! \brief an SQL restriction like 'tracks.year=1982'
- string m_filter;
- /*! \brief should be defined as true if we need to join another
- * table for getting user friendly values (like the name of a genre)
- */
- virtual bool need_join () const;
- //! \brief escape the string as needed for calls to mysql
- string sql_string(const string s) const;
-};
-
-
-//! \brief orders by collection
-class collectionkeyfield:public keyfield
-{
- public:
- collectionkeyfield ():keyfield ("Collection")
- {
- }
- string basefield () const
- {
- return "playlist.id";
- }
- string valuefield () const
- {
- return "playlist.title";
- }
-/* this join() would ensure that empty collections be suppressed. But we
- * want them all. so we don't need the join
- */
- string join () const
- {
- return "";
- }
-};
-
-//! \brief orders by position in collection
-class collectionitemkeyfield:public keyfield
-{
- public:
- collectionitemkeyfield ():keyfield ("Collection item")
- {
- }
- string basefield () const
- {
- return "playlistitem.tracknumber";
- }
- string valuefield () const
- {
- return "tracks.title";
- }
- string order () const
- {
- return basefield ();
- }
- string join () const
- {
- return
- "tracks.id=playlistitem.trackid and playlist.id=playlistitem.playlist";
- }
-};
-
-//! \brief orders by album.title
-class albumkeyfield:public keyfield
-{
- public:
- albumkeyfield ():keyfield ("Album")
- {
- }
- string basefield () const
- {
- return "tracks.sourceid";
- }
- string valuefield () const
- {
- return "album.title";
- }
- string idfield () const
- {
- return "album.title";
- }
- string countfield () const
- {
- return "album.title";
- }
- string join () const
- {
- return "tracks.sourceid=album.cddbid";
- }
- protected:
- //!brief we always need to join table album
- bool need_join () const
- {
- return true;
- };
-};
-
-//! \brief orders by genre1
-class genre1keyfield:public keyfield
-{
- public:
- genre1keyfield ():keyfield ("Genre 1")
- {
- }
- string basefield () const
- {
- return "tracks.genre1";
- }
- string valuefield () const
- {
- return "genre.genre";
- }
- string idfield () const
- {
- return "genre.id";
- }
-};
-
-//! \brief orders by genre2
-class genre2keyfield:public keyfield
-{
- public:
- genre2keyfield ():keyfield ("Genre 2")
- {
- }
- string basefield () const
- {
- return "tracks.genre2";
- }
- string valuefield () const
- {
- return "genre.genre";
- }
- string idfield () const
- {
- return "genre.id";
- }
-};
-
-//! \brief orders by language
-class langkeyfield:public keyfield
-{
- public:
- langkeyfield ():keyfield ("Language")
- {
- }
- string basefield () const
- {
- return "tracks.lang";
- }
- string valuefield () const
- {
- return "language.language";
- }
- string idfield () const
- {
- return "language.id";
- }
-};
-
-//! \brief orders by tracks.artist
-class artistkeyfield:public keyfield
-{
- public:
- artistkeyfield ():keyfield ("Artist")
- {
- }
- string basefield () const
- {
- return "tracks.artist";
- }
-};
-
-//! \brief orders by tracks.rating
-class ratingkeyfield:public keyfield
-{
- public:
- ratingkeyfield ():keyfield ("Rating")
- {
- }
- string basefield () const
- {
- return "tracks.rating";
- }
-};
-
-//! \brief orders by tracks.year
-class yearkeyfield:public keyfield
-{
- public:
- yearkeyfield ():keyfield ("Year")
- {
- }
- string basefield () const
- {
- return "tracks.year";
- }
-};
-
-//! \brief orders by tracks.title
-class titlekeyfield:public keyfield
-{
- public:
- titlekeyfield ():keyfield ("Title")
- {
- }
- string basefield () const
- {
- return "tracks.title";
- }
-};
-
-//! \brief orders by tracks.tracknb and tracks.title
-class trackkeyfield:public keyfield
-{
- public:
- trackkeyfield ():keyfield ("Track")
- {
- }
- string basefield () const
- {
- return "tracks.tracknb";
- }
- string valuefield () const
- {
- return
- "concat("
- "if(tracks.tracknb>0,"
- "concat("
- "if(tracks.tracknb<10,' ',''),"
- "tracks.tracknb,"
- "' '"
- "),''"
- "),"
- "tracks.title)";
- }
-};
-
-//! \brief orders by decade (deduced from tracks.year)
-class decadekeyfield:public keyfield
-{
- public:
- decadekeyfield ():keyfield ("Decade")
- {
- }
- string basefield () const
- {
- return "substring(convert(10 * floor(tracks.year/10), char),3)";
- }
-};
-
-//! \brief represents a content item like an mp3 file
+//! \brief represents a content item like an mp3 file.
class mgContentItem
{
public:
mgContentItem ()
{
}
+
+ string getKeyValue(mgKeyTypes kt);
+
//! \brief copy constructor
mgContentItem(const mgContentItem* c);
//! \brief construct an item from an SQL row
- mgContentItem (const MYSQL_ROW row, const string ToplevelDir);
+ mgContentItem (const mgSelection* sel, const MYSQL_ROW row);
//! \brief returns track id
long getId () const
{
@@ -487,58 +73,38 @@ class mgContentItem
}
//! \brief returns the name of the album
- string getAlbum ();
+ string getAlbum () const;
//! \brief returns the name of genre 1
- string getGenre1 ();
+ string getGenre1 () const;
//! \brief returns the name of genre 2
- string getGenre2 ();
+ string getGenre2 () const;
//! \brief returns the name of genre 1
- string getGenre ()
- {
- return getGenre1 ();
- }
+ string getGenre () const;
//! \brief returns the bitrate
- string getBitrate () const
- {
- return m_bitrate;
- }
+ string getBitrate () const;
//! \brief returns the file name of the album image
- string getImageFile ();
+ string getImageFile () const;
//! \brief returns year
- int getYear () const
- {
- return m_year;
- }
+ int getYear () const;
//! \brief returns rating
- int getRating () const
- {
- return m_rating;
- }
+ int getRating () const;
//! \brief returns duration
- int getDuration () const
- {
- return m_duration;
- }
+ int getDuration () const;
//! \brief returns samplerate
- int getSampleRate () const
- {
- return m_samplerate;
- }
+ int getSampleRate () const;
//! \brief returns # of channels
- int getChannels () const
- {
- return m_channels;
- }
+ int getChannels () const;
+
private:
long m_id;
string m_title;
@@ -557,6 +123,10 @@ class mgContentItem
/*!
* \brief the only interface to the database.
+ * Some member functions are declared const although they can modify the inner state of mgSelection.
+ * But they only modify variables used for caching. With const, we want to express
+ * the logical constness. E.g. the selected tracks can change without breaking constness:
+ * The selection never defines concrete tracks but only how to choose them.
*/
class mgSelection
{
@@ -577,6 +147,13 @@ class mgSelection
/*! \brief define various ways to play music in random order
* \todo Party mode is not implemented, does same as SM_NORMAL
*/
+/*! \brief defines a field to be used as key for selection
+ *
+ * \param level 0 is the top level
+ * \param kt type of the key field. For possible values see mg_order.h
+ */
+ void setKey (const unsigned int level, const mgKeyTypes kt);
+
enum ShuffleMode
{
SM_NONE, //!< \brief play normal sequence
@@ -636,54 +213,32 @@ class mgSelection
//! \brief the normal destructor
~mgSelection ();
- //! \brief sets the top level directory where content is stored
- void setToplevelDir(string ToplevelDir) { m_ToplevelDir = ToplevelDir; }
-
/*! \brief represents all values for the current level. The result
* is cached in values, subsequent accesses to values only incur a
* small overhead for building the SQL WHERE command. The values will
* be reloaded when the SQL command changes
- * \todo we should do more caching. The last 5 result sets should be cached.
*/
- mgSelStrings values;
+ mutable mgSelStrings values;
-/*! \brief defines a field to be used as key for selection
- *
- * \param level 0 is the top level
- * \param name of the key field, internationalized. Possible values
- * are defined by keychoice()
+/*! \brief returns the name of a key
*/
- void setKey (const unsigned int level, const string name);
+ mgKeyTypes getKeyType (const unsigned int level) const;
-/*! \brief returns the name of a key
+//! \brief return the current value of this key
+ string getKeyValue (const unsigned int level) const;
+
+/*! \brief returns the current item from the value() list
*/
- string getKeyChoice (const unsigned int level)
- {
- return keys[level]->choice ();
- }
- //! \brief return the current value of this key
- string getKeyValue (const unsigned int level)
- {
- return keys[level]->value ();
- }
+ string getCurrentValue();
//! \brief returns a map (new allocated) for all used key fields and their values
- map<string,string> * UsedKeyValues();
-
-//! \brief helper function for << operator (dumps debug info)
- void writeAt (ostream &);
+ map<mgKeyTypes,string> * UsedKeyValues();
-/*! \brief returns FROM and WHERE clauses for the current state
- * of the selection.
- * \param want_trackinfo work in progress, should disappear I hope
- */
- string where (bool want_trackinfo = false);
+//! \brief the number of key fields used for the query
+ unsigned int ordersize ();
//! \brief the number of music items currently selected
- unsigned int count ();
-
-//! \brief the number of key fields used for the query
- unsigned int size ();
+ unsigned int count () const;
//! \brief the current position in the current level
unsigned int gotoPosition ()
@@ -692,12 +247,13 @@ class mgSelection
}
//! \brief the current position
- unsigned int getPosition (unsigned int level) const;
+ unsigned int getPosition (unsigned int level)const;
//! \brief go to the current position. If it does not exist,
// go to the nearest.
unsigned int gotoPosition (unsigned int level);
+
//! \brief the current position in the tracks list
unsigned int getTrackPosition () const;
@@ -779,28 +335,17 @@ class mgSelection
return m_level;
}
-/*! \brief the possible choices for a keyfield in this level.
- * keyfields already used in upper levels are no possible
- * choices, neither are most keyfields if their usage would
- * allow less than 2 choices.
- */
- const strvector &keychoice (const unsigned int level);
-
-/*! \brief returns the current item from the value() list
- */
- string getCurrentValue();
-
//! \brief true if the selection holds no items
bool empty();
-/*! \brief returns detailled info about all selected tracks.
+/*! \brief returns detailed info about all selected tracks.
* The ordering is done only by the keyfield of the current level.
* This might have to be changed - suborder by keyfields of detail
* levels. This list is cached so several consequent calls mean no
* loss of performance. See value(), the same warning applies.
* \todo call this more seldom. See getNumTracks()
*/
- const vector < mgContentItem > &tracks ();
+ const vector < mgContentItem > &tracks () const;
/*! \brief returns an item from the tracks() list
* \param position the position in the tracks() list
@@ -899,7 +444,7 @@ class mgSelection
* last existing position
* \return only if no position exists, false will be returned
*/
- void setTrack (unsigned int position);
+ void setTrackPosition (unsigned int position);
/*! \brief skip some tracks in the track list
* \return false if new position does not exist
@@ -928,7 +473,7 @@ class mgSelection
/*! \brief returns the sum of the durations of completed tracks
* those are tracks before the current track position
*/
- unsigned long getCompletedLength ();
+ unsigned long getCompletedLength () const;
/*! returns the number of tracks in the track list
* \todo should not call tracks () which loads all track info.
@@ -949,19 +494,19 @@ class mgSelection
/*! returns the name of the current play list. If no play list is active,
* the name is built from the name of the key fields.
*/
- string getListname ();
+ string getListname () const;
/*! \brief true if this selection currently selects a list of collections
*/
- bool isCollectionlist ();
+ bool isCollectionlist () const;
//! \brief true if we have entered a collection
- bool inCollection(const string Name="");
+ bool inCollection(const string Name="") const;
/*! \brief dumps the entire state of this selection into a map,
* \param nv the values will be entered into this map
*/
- void DumpState(mgValmap& nv);
+ void DumpState(mgValmap& nv) const;
/*! \brief creates a new selection using saved definitions
* \param nv this map contains the saved definitions
@@ -969,60 +514,49 @@ class mgSelection
mgSelection(mgValmap& nv);
//! \brief clear the cache, next access will reload from data base
- void clearCache();
+ void clearCache() const;
- //! \todo soll sql_values() nur noch bei Bedarf bauen, also muessen
- // alle Aenderungen, die Einfluss darauf haben, clearCache machen
- void refreshValues();
+ void refreshValues() const;
//! \brief true if values and tracks need to be reloaded
- bool cacheIsEmpty()
+ bool cacheIsEmpty() const
{
return (m_current_values=="" && m_current_tracks=="");
}
+ string value(mgKeyTypes kt, string id) const;
+ string value(mgKey* k, string id) const;
+ string value(mgKey* k) const;
+ string id(mgKeyTypes kt, string val) const;
+ string id(mgKey* k, string val) const;
+ string id(mgKey* k) const;
+
private:
- void AddOrder(const string sql,list<string>& orderlist, const string item);
- list < string > m_fromtables; //!< \brief part result from previous where()
- string m_from; //!< \brief part result from previous where()
- string m_where; //!< \brief part result from previous where()
+ mutable map <mgKeyTypes, map<string,string> > map_values;
+ mutable map <mgKeyTypes, map<string,string> > map_ids;
+ mutable string m_current_values;
+ mutable string m_current_tracks;
+//! \brief be careful when accessing this, see mgSelection::tracks()
+ mutable vector < mgContentItem > m_tracks;
+ mutable strvector m_ids;
+ //! \brief initializes maps for id/value mapping in both direction
+ bool loadvalues (mgKeyTypes kt) const;
bool m_fall_through;
vector < unsigned int >m_position;
- unsigned int m_tracks_position;
+ mutable unsigned int m_tracks_position;
ShuffleMode m_shuffle_mode;
LoopMode m_loop_mode;
MYSQL *m_db;
+ void setDB(MYSQL *db);
string m_Host;
string m_User;
string m_Password;
- string m_ToplevelDir;
unsigned int m_level;
long m_trackid;
- string m_current_values;
- string m_current_tracks;
-//! \brief be careful when accessing this, see mgSelection::tracks()
- vector < mgContentItem > m_tracks;
- strvector m_ids;
- strvector m_keychoice;
- artistkeyfield kartist;
- ratingkeyfield krating;
- yearkeyfield kyear;
- decadekeyfield kdecade;
- albumkeyfield kalbum;
- collectionkeyfield kcollection;
- collectionitemkeyfield kcollectionitem;
- genre1keyfield kgenre1;
- genre2keyfield kgenre2;
- langkeyfield klanguage;
- titlekeyfield ktitle;
- trackkeyfield ktrack;
- map < string, keyfield * >all_keys;
- map < string, keyfield * >trall_keys;
- vector < keyfield * >keys;
- bool UsedBefore (keyfield const *k, unsigned int level);
+ mgOrder order;
+ bool UsedBefore (const mgKeyTypes kt, unsigned int level) const;
void InitSelection ();
void InitDatabase ();
- void initkey (keyfield & f);
/*! \brief returns the SQL command for getting all values.
* For the leaf level, all values are returned. For upper
* levels, every distinct value is returned only once.
@@ -1031,13 +565,12 @@ class mgSelection
* entries and the wrong tracks might be played.
*/
string sql_values ();
- //! \todo das nach mgSelStrings verlagern
unsigned int valindex (const string val,const bool second_try=false);
string ListFilename ();
string m_Directory;
void loadgenres ();
- MYSQL_RES *exec_sql (string query);
- string get_col0 (string query);
+ MYSQL_RES * exec_sql(string query) const;
+ string get_col0 (string query) const;
void InitFrom(const mgSelection* s);
@@ -1046,25 +579,12 @@ class mgSelection
* returning only one row.
* \param query the SQL query to be executed
*/
- unsigned long mgSelection::exec_count (string query);
+ unsigned long mgSelection::exec_count (string query) const;
- keyfield* findKey (const string name);
- map < string, unsigned int > keycounts;
-};
-//! \brief streams debug info about a selection
-ostream & operator<< (ostream &, mgSelection & s);
-
-//! \brief convert the shuffle mode into a string
-// \return strings "SM_NONE" etc.
-string toString (mgSelection::ShuffleMode);
-
-//! \brief same as toString but returns a C string
-const char *toCString (mgSelection::ShuffleMode);
+};
-//string toString(long int l);
-string itos (int i);
unsigned int randrange (const unsigned int high);