This commit is contained in:
@@ -42,10 +42,19 @@ CREATE TABLE IF NOT EXISTS layout_profiles (
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sites (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS maps (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
site_id TEXT,
|
||||
created_by TEXT NOT NULL DEFAULT '',
|
||||
width REAL,
|
||||
height REAL,
|
||||
resolution REAL,
|
||||
@@ -56,7 +65,8 @@ CREATE TABLE IF NOT EXISTS maps (
|
||||
yaml_file TEXT,
|
||||
zones_json TEXT NOT NULL DEFAULT '[]',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
updated_at TEXT NOT NULL,
|
||||
FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sounds (
|
||||
@@ -188,6 +198,86 @@ bool Database::applySchema(std::string& err)
|
||||
return execSql(db_, kSchemaSql, err);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool tableHasColumn(sqlite3* db, const char* table, const char* column)
|
||||
{
|
||||
std::string sql = "PRAGMA table_info(";
|
||||
sql += table;
|
||||
sql += ")";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
|
||||
return false;
|
||||
bool found = false;
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW)
|
||||
{
|
||||
const char* name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||
if (name && column == std::string(name))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
return found;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Database::applySchemaMigrations(std::string& err)
|
||||
{
|
||||
const std::string ver = getMeta("schema_version").value_or("1");
|
||||
|
||||
if (ver == "1")
|
||||
{
|
||||
if (!execSql(db_,
|
||||
"CREATE TABLE IF NOT EXISTS sites ("
|
||||
"id TEXT PRIMARY KEY, name TEXT NOT NULL, "
|
||||
"created_at TEXT NOT NULL, updated_at TEXT NOT NULL)",
|
||||
err))
|
||||
return false;
|
||||
|
||||
if (!tableHasColumn(db_, "maps", "site_id"))
|
||||
{
|
||||
if (!execSql(db_, "ALTER TABLE maps ADD COLUMN site_id TEXT", err))
|
||||
return false;
|
||||
}
|
||||
if (!tableHasColumn(db_, "maps", "created_by"))
|
||||
{
|
||||
if (!execSql(db_, "ALTER TABLE maps ADD COLUMN created_by TEXT NOT NULL DEFAULT ''", err))
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string now = IdUtil::nowIso8601();
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
if (sqlite3_prepare_v2(db_,
|
||||
"INSERT OR IGNORE INTO sites(id, name, created_at, updated_at) "
|
||||
"VALUES('site_configuration', 'ConfigurationSite', ?1, ?1)",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr) == SQLITE_OK)
|
||||
{
|
||||
sqlite3_bind_text(stmt, 1, now.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
if (sqlite3_prepare_v2(db_,
|
||||
"UPDATE maps SET site_id = 'site_configuration' WHERE site_id IS NULL OR site_id = ''",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr) == SQLITE_OK)
|
||||
{
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
setMeta("schema_version", "2");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<std::string> Database::getMeta(const std::string& key) const
|
||||
{
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
@@ -400,6 +490,8 @@ bool Database::init(std::string& err)
|
||||
return false;
|
||||
if (!applySchema(err))
|
||||
return false;
|
||||
if (!applySchemaMigrations(err))
|
||||
return false;
|
||||
if (!ensureDataDirs(err))
|
||||
return false;
|
||||
if (!migrateFromJsonIfNeeded(err))
|
||||
|
||||
Reference in New Issue
Block a user