Database design
I've decided to make my own "database" tailored for things I need to do. Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This commit is contained in:
parent
80e00dd914
commit
2ea1ea8d26
197
design.txt
197
design.txt
|
@ -17,92 +17,183 @@ Files:
|
|||
design.txt
|
||||
ocarina/gui/
|
||||
ocarina/include/
|
||||
database.h
|
||||
database.hpp
|
||||
group.h
|
||||
library.h
|
||||
playlist.h
|
||||
ocarina/lib/
|
||||
database.cpp
|
||||
group.cpp
|
||||
library.cpp
|
||||
playlist.cpp
|
||||
ocarina/tests/
|
||||
|
||||
$HOME/.ocarina{-debug}/
|
||||
library/global.db
|
||||
library/{0-X}
|
||||
album.db
|
||||
artist.db
|
||||
genre.db
|
||||
library.db
|
||||
track.db
|
||||
|
||||
|
||||
|
||||
Database: (ocarina.db)
|
||||
<Research FTS tables and inverted indexes for filtering>
|
||||
On-disk files:
|
||||
I use the disk to store data between sessions, this could include
|
||||
library state and user preferences. In theory, file formats do not
|
||||
change often so updating between file formats should be possible.
|
||||
Supporting all previous file formats can create a lot of clutter in
|
||||
the code, so I will ONLY support updating from the previous file-format
|
||||
version. Ocarina 5.x used two different numbers to represent the
|
||||
current file format (library = 2 and playlist = 3). I want to unify
|
||||
this into a single number shared across all files for simplicity, and
|
||||
then create a class to read and write data on disk.
|
||||
|
||||
|
||||
|
||||
Database: (lib/database.cpp)
|
||||
Ocarina 5.x created a different save file format for each type of
|
||||
data that needed to be stored (preferences, library paths, playlists).
|
||||
I intend to unify everything into a generic file format that can be
|
||||
accessed through a generic database interface. The database code will
|
||||
be in charge of printing the "valid" bit for each DatabaseEntry so that
|
||||
child classes do not need to call into the parent class. If valid ==
|
||||
true, the DatabaseEntry will be streamed out followed by a newline. If
|
||||
valid == false the database will print the next entry in the vector.
|
||||
|
||||
Modules should inherit from the DatabasEntry class and implement their
|
||||
own read() and write() functions. The "valid" field will be stored
|
||||
before these functions are called, and the entry will be skipped if
|
||||
valid is set to false.
|
||||
|
||||
The Database class is a templated class, so code could potentially
|
||||
get messy. Normal class declarations can still exist in the file
|
||||
include/database.h and member functions can be written in the file
|
||||
include/database.hpp, which will be included by database.h. Any
|
||||
function not relying on a template can be written in lib/database.cpp.
|
||||
|
||||
Structures and constants:
|
||||
#define FILE_VERSION 4
|
||||
|
||||
class DatabaseEntry { /* let database modify valid flag */
|
||||
private:
|
||||
bool valid;
|
||||
public:
|
||||
virtual istream &operator>>(istream &) = 0;
|
||||
virtual ostream &operator<<(ostream &) = 0;
|
||||
friend class Database;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Database {
|
||||
private:
|
||||
unsigned int _size; /* Number of valid rows */
|
||||
string filename;
|
||||
vector<T> db;
|
||||
public:
|
||||
Database::Database(filename);
|
||||
void load();
|
||||
void save();
|
||||
void insert(T);
|
||||
void delete(unsigned int);
|
||||
const unsigned int &size();
|
||||
const T &operator[](unsigned int);
|
||||
};
|
||||
|
||||
File formats:
|
||||
Database:
|
||||
FILE_VERSION db.size()
|
||||
INDEX db[INDEX].valid DatabaseEntry
|
||||
INDEX db[INDEX].valid DatabaseEntry
|
||||
...
|
||||
|
||||
DatabaseEntry:
|
||||
<CHILD_CLASS_DATA>
|
||||
|
||||
API:
|
||||
Database.Database(filename);
|
||||
Initializes database to use ~/.ocarina{-debug}/filename
|
||||
Database.load();
|
||||
Reads data from file. Call after static initialization of
|
||||
Ocarina to ensure idle tasks are configured.
|
||||
Database.save();
|
||||
Saves data to file.
|
||||
Database.insert(T &);
|
||||
Adds a new item to the db
|
||||
Database.delete(unsigned int index);
|
||||
Mark db[index] as invalid (quick deletion)
|
||||
Database.size();
|
||||
Returns number of valid rows in the database
|
||||
Database.operator[unsigned int index]
|
||||
Return a reference to db[index]
|
||||
|
||||
Tags index -
|
||||
<another FTS table>
|
||||
Tag Name -> song ids
|
||||
|
||||
User settings -
|
||||
create table if not exists config(
|
||||
name PRIMARY KEY,
|
||||
value INT,
|
||||
);
|
||||
|
||||
Library: (lib/library.cpp)
|
||||
|
||||
This file will manage and control access to the library.
|
||||
This file will manage and control access to the library. The library
|
||||
will be split into 5 database tables based on the content being stored,
|
||||
and should be initialized before access attempts.
|
||||
|
||||
Album and artist information tables will be saved to a file in
|
||||
library/global.db and can be shared across multiple library paths.
|
||||
|
||||
Internal:
|
||||
|
||||
struct Album {
|
||||
unsigned int id;
|
||||
class Album : public DatabaseEntry {
|
||||
string name;
|
||||
short year;
|
||||
};
|
||||
vector<Album>;
|
||||
|
||||
struct Artist {
|
||||
unsigned int id;
|
||||
class Artist : public DatabaseEntry {
|
||||
string name;
|
||||
};
|
||||
vector<Artist>
|
||||
|
||||
struct Genre {
|
||||
unsigned int id;
|
||||
class Genre : public DatabaseEntry {
|
||||
string name;
|
||||
};
|
||||
vector<Genre>
|
||||
|
||||
struct Track {
|
||||
unsigned int id;
|
||||
unsigned int artist_id;
|
||||
unsigned int album_id;
|
||||
unsigned int genre_id;
|
||||
bool valid;
|
||||
class Library : public DatabaseEntry {
|
||||
string base_path;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
string filepath;
|
||||
string title;
|
||||
string length_str;
|
||||
short track;
|
||||
short last_year;
|
||||
short last_month;
|
||||
short last_day;
|
||||
unsigned int play_count;
|
||||
unsigned int length;
|
||||
};
|
||||
class Track : public DatabaseEntry {
|
||||
unsigned int artist_id;
|
||||
unsigned int album_id;
|
||||
unsigned int genre_id;
|
||||
unsigned int library_id;
|
||||
|
||||
class Library {
|
||||
string base_path;
|
||||
bool enabled;
|
||||
bool valid;
|
||||
vector<struct Track>
|
||||
};
|
||||
short track;
|
||||
short last_year;
|
||||
short last_month;
|
||||
short last_day;
|
||||
unsigned int play_count;
|
||||
unsigned int length;
|
||||
string title;
|
||||
string length_str;
|
||||
string filepath;
|
||||
};
|
||||
|
||||
typedef struct trackid_t {
|
||||
unsigned int library_id;
|
||||
unsigned int track_id;
|
||||
};
|
||||
Database album_db;
|
||||
Database artist_db;
|
||||
Database genre_db;
|
||||
Database library_db;
|
||||
Database track_db;
|
||||
|
||||
File formats:
|
||||
Album:
|
||||
year name
|
||||
|
||||
Artist:
|
||||
name
|
||||
|
||||
Genre:
|
||||
name
|
||||
|
||||
Track:
|
||||
artist_id album_id genre_id library_id track last_year last_month last_day play_count length
|
||||
title
|
||||
length_str
|
||||
filepath
|
||||
|
||||
Library:
|
||||
enabled base_path;
|
||||
|
||||
|
||||
- API
|
||||
|
|
Loading…
Reference in New Issue