#include "storage.h" #include "config.h" #include #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_stmt_create = std::make_shared(m_db, "CREATE TABLE IF NOT EXISTS documents (id VARCHAR(16) PRIMARY KEY, value BLOB, rev INTEGER, cursorpos INTEGER, timestamp BIGINT)"); m_stmt_create->exec(); m_stmt_getNumberOfDocuments = std::make_shared(m_db, "SELECT COUNT(*) FROM documents"); m_stmt_cleanup = std::make_shared(m_db, "DELETE FROM documents WHERE timestamp + " + std::to_string(static_cast(m_maxage)) + " < unixepoch()"); m_stmt_exists = std::make_shared(m_db, "SELECT id FROM documents WHERE id = ?"); m_stmt_getDocument = std::make_shared(m_db, "SELECT value FROM documents WHERE id = ?"); m_stmt_getRevision = std::make_shared(m_db, "SELECT rev FROM documents WHERE id = ?"); m_stmt_getCursorPos = std::make_shared(m_db, "SELECT cursorpos FROM documents WHERE id = ?"); m_stmt_getRow = std::make_shared(m_db, "SELECT value, rev, cursorpos FROM documents WHERE id = ?"); m_stmt_setDocument = std::make_shared(m_db, "UPDATE documents SET value = ? WHERE id = ?"); m_stmt_setDocument_new = std::make_shared(m_db, "INSERT INTO documents (id, value, rev, cursorpos, timestamp) values (?, ?, ?, ?, unixepoch())"); m_stmt_setRevision = std::make_shared(m_db, "UPDATE documents SET rev = ? WHERE id = ?"); m_stmt_setCursorPos = std::make_shared(m_db, "UPDATE documents SET cursorpos = ? WHERE id = ?"); m_stmt_setRow = std::make_shared(m_db, "INSERT OR REPLACE INTO documents (id, value, rev, cursorpos, timestamp) values (?, ?, ?, ?, unixepoch())"); } Storage::~Storage() { } uint64_t Storage::getNumberOfDocuments() { m_stmt_getNumberOfDocuments->reset(); if (!m_stmt_getNumberOfDocuments->executeStep()) throw std::runtime_error("Count not possible"); return static_cast(m_stmt_getNumberOfDocuments->getColumn(0)); } void Storage::cleanup() { if (m_maxage == 0) return; m_stmt_cleanup->reset(); m_stmt_cleanup->exec(); } bool Storage::exists(const std::string& id) { m_stmt_exists->reset(); m_stmt_exists->bind(1, id); return m_stmt_exists->executeStep(); } std::string Storage::getDocument(const std::string& id) { m_stmt_getDocument->reset(); m_stmt_getDocument->bind(1, id); if (!m_stmt_getDocument->executeStep()) throw std::runtime_error("id "s + id + " not found"s); return m_stmt_getDocument->getColumn(0); } int Storage::getRevision(const std::string& id) { m_stmt_getRevision->reset(); m_stmt_getRevision->bind(1, id); if (!m_stmt_getRevision->executeStep()) throw std::runtime_error("id "s + id + " not found"s); return m_stmt_getRevision->getColumn(0); } int Storage::getCursorPos(const std::string& id) { m_stmt_getCursorPos->reset(); m_stmt_getCursorPos->bind(1, id); if (!m_stmt_getCursorPos->executeStep()) throw std::runtime_error("id "s + id + " not found"s); return m_stmt_getCursorPos->getColumn(0); } std::tuple Storage::getRow(const std::string& id) { m_stmt_getRow->reset(); m_stmt_getRow->bind(1, id); if (!m_stmt_getRow->executeStep()) throw std::runtime_error("id "s + id + " not found"s); return {m_stmt_getRow->getColumn(0), m_stmt_getRow->getColumn(1), m_stmt_getRow->getColumn(2)}; } void Storage::setDocument(const std::string& id, const std::string& document) { m_stmt_setDocument->reset(); m_stmt_setDocument->bind(1, document); m_stmt_setDocument->bind(2, id); if (!m_stmt_setDocument->exec()) { m_stmt_setDocument_new->reset(); m_stmt_setDocument_new->bind(1, id); m_stmt_setDocument_new->bind(2, document); m_stmt_setDocument_new->bind(3, 0); m_stmt_setDocument_new->bind(4, 0); m_stmt_setDocument_new->exec(); } } void Storage::setRevision(const std::string& id, int rev) { m_stmt_setRevision->reset(); m_stmt_setRevision->bind(1, rev); m_stmt_setRevision->bind(2, id); if (!m_stmt_setRevision->exec()) throw std::runtime_error("Unable to insert row with id "s + id); } void Storage::setCursorPos(const std::string& id, int cursorPos) { m_stmt_setCursorPos->reset(); m_stmt_setCursorPos->bind(1, cursorPos); m_stmt_setCursorPos->bind(2, id); if (!m_stmt_setCursorPos->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) { m_stmt_setRow->reset(); m_stmt_setRow->bind(1, id); m_stmt_setRow->bind(2, document); m_stmt_setRow->bind(3, rev); m_stmt_setRow->bind(4, cursorPos); if (!m_stmt_setRow->exec()) throw std::runtime_error("Unable to insert row with id "s + id); }