ocarina/design/database.txt

154 lines
4.4 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:
bool valid;
virtual const std::string &primary_key() = 0;
virtual void write(File &) = 0;
virtual void read(File &) = 0;
virtual void print() = 0;
};
File << <CHILD_CLASS_DATA>
- IndexEntry:
class IndexEntry : public DatabaseEntry {
public:
string key;
set<unsigned int> values;
const std::string &primary_key();
void write(File &);
void read(File &);
void print();
};
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 delete(unsigned int);
unsigned int size();
unsigned int num_rows();
unsigned int first();
unsigned int last();
unsigned int next(unsigned int &);
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_DEBUG is enabled.
Clear the database contents in-memory, but do NOT write
to disk.
void Database :: print()
This function exists only If CONFIG_DEBUG 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_DEBUG 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 :: delete(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.
unsigned int Database :: last();
Return the id of the last valid row.
unsigned int Database :: next(unsigned int &id)
Return the id of the next valid row or return db.size()
if there are no remaining valid rows.
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
an empty exception if the key is not found in the mapping.
template <class T>
T &Database :: operator[unsigned int index]
Return a reference to db[index]. If index is out of range,
throw an empty exception.