ocarina/design/database.txt

170 lines
5.0 KiB
Plaintext

== Files ==
ocarina/include/
database.h
database.hpp
ocarina/lib/
database.cpp
== Depends ==
file
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.
- DatabaseEntry:
class DatabaseEntry { /* let database modify valid flag */
public:
const std::string primary_key;
bool valid;
DatabaseEntry(const std::string &);
virtual void write(File &) = 0;
virtual void read(File &) = 0;
virtual void print() = 0;
};
File << <CHILD_CLASS_DATA>
- IndexEntry:
class IndexEntry : public DatabaseEntry {
public:
set<unsigned int> values;
void write(File &);
void read(File &);
void print();
void insert(unsigned int);
void remove(unsigned int);
};
File << key << endl;
File << values.size() << values[0] << .. << values[N] << endl;
- Database:
template <class T>
class Database {
private:
vector<T> db;
map<std::string, unsigned int> keys;
unsigned int _size; /* Number of valid rows */
File file;
public:
Database::Database(filename, flags);
void load();
void save();
void clear();
void print();
void print_keys();
unsigned int insert(T);
void remove(unsigned int);
unsigned int size();
unsigned int num_rows();
unsigned int first();
unsigned int last();
unsigned int next(unsigned int &);
bool has_key(const std :: string &);
unsigned int find_index(const std::string &);
T &find(const std::string &);
T &operator[](unsigned int);
};
File << db.size() << endl
File << INDEX_0 << db[INDEX_0].valid << db[INDEX_0] << endl;
File << INDEX_1 << db[INDEX_1].valid << db[INDEX_1] << endl;
...
- API:
Database :: Database(filename, flags);
Initializes database to use ~/.ocarina{-debug}/filename.
Set up flags.
void Database :: load();
Reads a saved database from disk.
void Database :: save();
Saves the database to disk.
void Database :: clear();
This function exists only if CONFIG_TEST is enabled.
Clear the database contents in-memory, but do NOT write
to disk.
void Database :: print();
This function exists only If CONFIG_TEST is enabled.
Following a similar format for writing to disk, print the
database to the console in a human-readable format.
void Database :: print_keys();
This function exists only if CONFIG_TEST is enabled.
Print out the collected primary keys in the database.
template <class T>
unsigned int Database :: insert(T &);
Adds a new item to the db and marks it as valid. A reverse
mapping is also created into the keys map to map the primary
key back to the id of the newly added item.
void Database :: remove(unsigned int index);
Mark db[index] as invalid (quick deletion).
unsigned int Database :: size();
Returns number of valid rows in the database.
unsigned int Database :: num_rows();
Return db.size().
unsigned int Database :: first();
Return the id to the first valid row. Return db.size() if
there are no valid rows.
unsigned int Database :: last();
Return the id of the last valid row. Return db.size() if
there are no valid rows.
unsigned int Database :: next(unsigned int &id);
Return the id of the next valid row or return db.size() if
there are no valid rows.
bool Database :: has_key(const std::string &key);
Return true if an item with primary key "key" exists in the
database, and false otherwise.
unsigned int Database :: find_index(const std::string key);
If the key exists in the database, return the index of the
database item with that key. Throw -EEXIST if the key is not
in the database.
template <class T>
T &Database :: find(const std::string &key);
Search for primary key "key" in the database. The reverse
mapping should be used to make this operation faster.
Throw -EEXIST if the key is not found in the mapping.
Throw -EINVAL if the key points to an invalid entry.
template <class T>
T &Database :: operator[](unsigned int index);
Return a reference to db[index].
Throw -EEXIST if index is out of range.
Throw -EINVAL if index is invalid.