#include "storage.h" #include "config.h" #include #include using namespace std::string_literals; Storage::Storage(const Config& config): m_db(config.getDataPath() + "/whiteboard.db3", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE), m_maxage(config.getMaxage()) { m_db.exec("CREATE TABLE IF NOT EXISTS documents (id VARCHAR(16) PRIMARY KEY, value BLOB, rev INTEGER, cursorpos INTEGER, timestamp BIGINT)"); } uint64_t Storage::getNumberOfDocuments() { SQLite::Statement query(m_db, "SELECT COUNT(*) FROM documents"); if (!query.executeStep()) throw std::runtime_error("Count not possible"); return static_cast(query.getColumn(0)); } void Storage::cleanup() { if (m_maxage == 0) return; SQLite::Statement query(m_db, "DELETE FROM documents WHERE timestamp + ? < unixepoch()"); query.bind(1, static_cast(m_maxage)); query.exec(); } bool Storage::exists(const std::string& id) { SQLite::Statement query(m_db, "SELECT id FROM documents WHERE id = ?"); query.bind(1, id); return query.executeStep(); } std::string Storage::getDocument(const std::string& id) { SQLite::Statement query(m_db, "SELECT value FROM documents WHERE id = ?"); query.bind(1, id); if (!query.executeStep()) throw std::runtime_error("id "s + id + " not found"s); return query.getColumn(0); } int Storage::getRevision(const std::string& id) { SQLite::Statement query(m_db, "SELECT rev FROM documents WHERE id = ?"); query.bind(1, id); if (!query.executeStep()) throw std::runtime_error("id "s + id + " not found"s); return query.getColumn(0); } int Storage::getCursorPos(const std::string& id) { SQLite::Statement query(m_db, "SELECT cursorpos FROM documents WHERE id = ?"); query.bind(1, id); if (!query.executeStep()) throw std::runtime_error("id "s + id + " not found"s); return query.getColumn(0); } std::tuple Storage::getRow(const std::string& id) { SQLite::Statement query(m_db, "SELECT value, rev, cursorpos FROM documents WHERE id = ?"); query.bind(1, id); if (!query.executeStep()) throw std::runtime_error("id "s + id + " not found"s); return {query.getColumn(0), query.getColumn(1), query.getColumn(2)}; } void Storage::setDocument(const std::string& id, const std::string& document) { SQLite::Statement query(m_db, "UPDATE documents SET value = ? WHERE id = ?"); query.bind(1, document); query.bind(2, id); if (!query.exec()) { SQLite::Statement query(m_db, "INSERT INTO documents (id, value, rev, cursorpos, timestamp) values (?, ?, ?, ?, unixepoch())"); query.bind(1, id); query.bind(2, document); query.bind(3, 0); query.bind(4, 0); query.exec(); } } void Storage::setRevision(const std::string& id, int rev) { SQLite::Statement query(m_db, "UPDATE documents SET rev = ? WHERE id = ?"); query.bind(1, rev); query.bind(2, id); if (!query.exec()) throw std::runtime_error("Unable to insert row with id "s + id); } void Storage::setCursorPos(const std::string& id, int cursorPos) { SQLite::Statement query(m_db, "UPDATE documents SET cursorpos = ? WHERE id = ?"); query.bind(1, cursorPos); query.bind(2, id); if (!query.exec()) throw std::runtime_error("Unable to insert row with id "s + id); } void Storage::setRow(const std::string& id, const std::string& document, int rev, int cursorPos) { SQLite::Statement query(m_db, "INSERT OR REPLACE INTO documents (id, value, rev, cursorpos, timestamp) values (?, ?, ?, ?, unixepoch())"); query.bind(1, id); query.bind(2, document); query.bind(3, rev); query.bind(4, cursorPos); if (!query.exec()) throw std::runtime_error("Unable to insert row with id "s + id); }