Move some DB stuff into separate files and create the DB if it's not there
This commit is contained in:
parent
d43bb02f72
commit
71654fe32e
|
@ -0,0 +1,101 @@
|
|||
#include "db.h"
|
||||
|
||||
sqlite3 *db = nullptr;
|
||||
|
||||
db_transaction::db_transaction()
|
||||
{
|
||||
sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
db_transaction::~db_transaction()
|
||||
{
|
||||
sqlite3_exec(db, "COMMIT TRANSACTION;", nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
std::string get_string(sqlite3_stmt *row, int col)
|
||||
{
|
||||
return std::string((char*)sqlite3_column_text(row, col));
|
||||
}
|
||||
|
||||
void db_check_schema() {
|
||||
bool settings_table_found = false;
|
||||
|
||||
sqlite3_stmt *query;
|
||||
SC(sqlite3_prepare_v2(db, "SELECT name FROM sqlite_master WHERE type='table';", -1, &query, nullptr));
|
||||
while(sqlite3_step(query) == SQLITE_ROW) {
|
||||
if(get_string(query, 0) == "settings")
|
||||
settings_table_found = true;
|
||||
}
|
||||
SC(sqlite3_finalize(query));
|
||||
|
||||
int schema_version = 0;
|
||||
if(settings_table_found) {
|
||||
const std::string schema_version_str = db_get_setting("schema_version");
|
||||
if(!schema_version_str.empty()) {
|
||||
schema_version = std::stoi(schema_version_str);
|
||||
}
|
||||
}
|
||||
if(schema_version < 1) {
|
||||
const std::string db_init_sql = R"(
|
||||
PRAGMA foreign_keys;
|
||||
PRAGMA synchronous = NORMAL;
|
||||
CREATE TABLE channels (
|
||||
channelId TEXT PRIMARY KEY,
|
||||
name TEXT
|
||||
);
|
||||
CREATE TABLE "settings" (
|
||||
key TEXT NOT NULL PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE videos (
|
||||
videoId TEXT PRIMARY KEY,
|
||||
channelId TEXT REFERENCES channels(channelId) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
title TEXT,
|
||||
description TEXT,
|
||||
flags INTEGER DEFAULT 0 NOT NULL,
|
||||
published TEXT
|
||||
);
|
||||
INSERT INTO settings(key, value) VALUES("schema_version", "1"); )";
|
||||
SC(sqlite3_exec(db, db_init_sql.c_str(), nullptr, nullptr, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
std::string db_get_setting(const std::string &key)
|
||||
{
|
||||
sqlite3_stmt *query;
|
||||
SC(sqlite3_prepare_v2(db, "SELECT value FROM settings WHERE key = ?1;", -1, &query, nullptr));
|
||||
SC(sqlite3_bind_text(query, 1, key.c_str(), -1, SQLITE_TRANSIENT));
|
||||
SC(sqlite3_step(query));
|
||||
const std::string value = get_string(query, 0);
|
||||
SC(sqlite3_finalize(query));
|
||||
return value;
|
||||
}
|
||||
|
||||
void db_set_setting(const std::string &key, const std::string &value)
|
||||
{
|
||||
sqlite3_stmt *query;
|
||||
SC(sqlite3_prepare_v2(db, "INSERT INTO settings(key, value) values(?1, ?2) ON CONFLICT(key) DO UPDATE SET value=excluded.value;", -1, &query, nullptr));
|
||||
SC(sqlite3_bind_text(query, 1, key.c_str(), -1, SQLITE_TRANSIENT));
|
||||
SC(sqlite3_bind_text(query, 2, value.c_str(), -1, SQLITE_TRANSIENT));
|
||||
SC(sqlite3_step(query));
|
||||
SC(sqlite3_finalize(query));
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> db_get_settings(const std::string &prefix)
|
||||
{
|
||||
std::map<std::string, std::string> result;
|
||||
|
||||
sqlite3_stmt *query;
|
||||
SC(sqlite3_prepare_v2(db, "SELECT key, value FROM settings WHERE key LIKE ?1;", -1, &query, nullptr));
|
||||
SC(sqlite3_bind_text(query, 1, (prefix + ":").c_str(), -1, SQLITE_TRANSIENT));
|
||||
while(sqlite3_step(query) == SQLITE_ROW) {
|
||||
const std::string key = get_string(query, 0);
|
||||
const std::string value = get_string(query, 1);
|
||||
size_t i = key.find(':');
|
||||
if(i != std::string::npos) {
|
||||
result.emplace(key.substr(i), value);
|
||||
}
|
||||
}
|
||||
SC(sqlite3_finalize(query));
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <sqlite3.h>
|
||||
#include <string>
|
||||
|
||||
extern sqlite3 *db;
|
||||
|
||||
extern void tui_abort(const char *fmt, ...);
|
||||
#define SC(x) { const int res = (x); if(res != SQLITE_OK && res != SQLITE_ROW && res != SQLITE_DONE) { tui_abort("Database error:\n%s failed: (%d) %s", #x, res, sqlite3_errstr(res)); }}
|
||||
|
||||
class db_transaction {
|
||||
public:
|
||||
db_transaction();
|
||||
~db_transaction();
|
||||
};
|
||||
std::string get_string(sqlite3_stmt *row, int col);
|
||||
|
||||
void db_check_schema();
|
||||
|
||||
std::string db_get_setting(const std::string &key);
|
||||
void db_set_setting(const std::string &key, const std::string &value);
|
||||
std::map<std::string, std::string> db_get_settings(const std::string &prefix);
|
||||
|
14
main.cpp
14
main.cpp
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "tui.h"
|
||||
#include "yt.h"
|
||||
#include "db.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
@ -15,7 +16,6 @@
|
|||
|
||||
#include <curl/curl.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <sqlite3.h>
|
||||
|
||||
static std::string user_home;
|
||||
|
||||
|
@ -30,8 +30,6 @@ size_t current_page_count = 0;
|
|||
size_t title_offset = 0;
|
||||
bool any_title_in_next_half = false;
|
||||
|
||||
#define SC(x) { const int res = (x); if(res != SQLITE_OK && res != SQLITE_ROW && res != SQLITE_DONE) { tui_abort("Database error:\n%s failed: (%d) %s", #x, res, sqlite3_errstr(res)); }}
|
||||
|
||||
static termpaint_attr* get_attr(const AttributeSetType type, const bool highlight=false)
|
||||
{
|
||||
return highlight ? attributes[type].highlight : attributes[type].normal;
|
||||
|
@ -132,8 +130,6 @@ void draw_no_channels_msg()
|
|||
}
|
||||
}
|
||||
|
||||
sqlite3 *db;
|
||||
|
||||
void load_videos_for_channel(const std::string &channelId, bool force=false)
|
||||
{
|
||||
if(videos.find(channelId) != videos.end() && !force)
|
||||
|
@ -415,6 +411,8 @@ bool save_json(const std::string &filename, const json &data) {
|
|||
}
|
||||
}
|
||||
|
||||
std::string database_filename = "yttool.sqlite";
|
||||
|
||||
int main()
|
||||
{
|
||||
user_home = std::string(std::getenv("HOME"));
|
||||
|
@ -448,9 +446,13 @@ int main()
|
|||
}
|
||||
}
|
||||
}
|
||||
if(config.contains("database") && config["database"].is_string()) {
|
||||
database_filename = config["database"];
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_open("yttool.sqlite", &db);
|
||||
SC(sqlite3_open(database_filename.c_str(), &db));
|
||||
db_check_schema();
|
||||
|
||||
sqlite3_stmt *query;
|
||||
sqlite3_prepare_v2(db, "SELECT * FROM channels;", -1, &query, nullptr);
|
||||
|
|
|
@ -11,11 +11,13 @@ DEPENDPATH += $$PWD/termpaint
|
|||
unix:!macx: PRE_TARGETDEPS += $$PWD/termpaint/libtermpaint.a
|
||||
|
||||
SOURCES += \
|
||||
db.cpp \
|
||||
main.cpp \
|
||||
tui.cpp \
|
||||
yt.cpp
|
||||
|
||||
HEADERS += \
|
||||
db.h \
|
||||
tui.h \
|
||||
yt.h
|
||||
|
||||
|
|
8
yt.cpp
8
yt.cpp
|
@ -5,17 +5,11 @@
|
|||
#include <curl/curl.h>
|
||||
|
||||
#include "tui.h"
|
||||
|
||||
#define SC(x) { const int res = (x); if(res != SQLITE_OK && res != SQLITE_ROW && res != SQLITE_DONE) { tui_abort("Database error:\n%s failed: (%d) %s", #x, res, sqlite3_errstr(res)); }}
|
||||
#include "db.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
struct yt_config yt_config;
|
||||
|
||||
static std::string get_string(sqlite3_stmt *row, int col)
|
||||
{
|
||||
return std::string((char*)sqlite3_column_text(row, col));
|
||||
}
|
||||
|
||||
static size_t curl_writecallback(void *data, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
size_t to_add = size * nmemb;
|
||||
|
|
Loading…
Reference in New Issue