Add phần create map by upload
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-06-19 11:52:21 +07:00
parent 098e1b2b69
commit a6cf06d7eb
27 changed files with 4960 additions and 129 deletions

View File

@@ -11,6 +11,11 @@ namespace lm {
namespace {
constexpr const char* kMapSelect =
"SELECT id, name, description, site_id, created_by, width, height, resolution, "
"origin_x, origin_y, origin_yaw, image_file, yaml_file, zones_json, created_at, updated_at "
"FROM maps";
nlohmann::json rowToJson(sqlite3_stmt* stmt)
{
auto textOrNull = [&](int col) -> nlohmann::json {
@@ -25,11 +30,11 @@ nlohmann::json rowToJson(sqlite3_stmt* stmt)
};
nlohmann::json zones = nlohmann::json::array();
if (sqlite3_column_type(stmt, 11) != SQLITE_NULL)
if (sqlite3_column_type(stmt, 13) != SQLITE_NULL)
{
try
{
zones = nlohmann::json::parse(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 11)));
zones = nlohmann::json::parse(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 13)));
}
catch (...)
{
@@ -40,17 +45,19 @@ nlohmann::json rowToJson(sqlite3_stmt* stmt)
return {{"id", textOrNull(0)},
{"name", textOrNull(1)},
{"description", textOrNull(2)},
{"width", realOrNull(3)},
{"height", realOrNull(4)},
{"resolution", realOrNull(5)},
{"origin_x", realOrNull(6)},
{"origin_y", realOrNull(7)},
{"origin_yaw", realOrNull(8)},
{"image_file", textOrNull(9)},
{"yaml_file", textOrNull(10)},
{"site_id", textOrNull(3)},
{"created_by", textOrNull(4)},
{"width", realOrNull(5)},
{"height", realOrNull(6)},
{"resolution", realOrNull(7)},
{"origin_x", realOrNull(8)},
{"origin_y", realOrNull(9)},
{"origin_yaw", realOrNull(10)},
{"image_file", textOrNull(11)},
{"yaml_file", textOrNull(12)},
{"zones", zones},
{"created_at", textOrNull(12)},
{"updated_at", textOrNull(13)}};
{"created_at", textOrNull(14)},
{"updated_at", textOrNull(15)}};
}
} // namespace
@@ -66,14 +73,9 @@ nlohmann::json MapStore::list() const
{
std::lock_guard<std::mutex> lock(mu_);
nlohmann::json maps = nlohmann::json::array();
std::string sql = std::string(kMapSelect) + " ORDER BY name";
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db_.handle(),
"SELECT id, name, description, width, height, resolution, "
"origin_x, origin_y, origin_yaw, image_file, yaml_file, zones_json, "
"created_at, updated_at FROM maps ORDER BY name",
-1,
&stmt,
nullptr) != SQLITE_OK)
if (sqlite3_prepare_v2(db_.handle(), sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return maps;
while (sqlite3_step(stmt) == SQLITE_ROW)
maps.push_back(rowToJson(stmt));
@@ -84,14 +86,9 @@ nlohmann::json MapStore::list() const
std::optional<nlohmann::json> MapStore::find(const std::string& id) const
{
std::lock_guard<std::mutex> lock(mu_);
std::string sql = std::string(kMapSelect) + " WHERE id = ?1";
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db_.handle(),
"SELECT id, name, description, width, height, resolution, "
"origin_x, origin_y, origin_yaw, image_file, yaml_file, zones_json, "
"created_at, updated_at FROM maps WHERE id = ?1",
-1,
&stmt,
nullptr) != SQLITE_OK)
if (sqlite3_prepare_v2(db_.handle(), sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return std::nullopt;
sqlite3_bind_text(stmt, 1, id.c_str(), -1, SQLITE_TRANSIENT);
std::optional<nlohmann::json> out;
@@ -118,6 +115,8 @@ std::optional<nlohmann::json> MapStore::create(const nlohmann::json& payload, st
const std::string id = payload.value("id", IdUtil::newId());
const std::string now = IdUtil::nowIso8601();
const std::string description = payload.value("description", "");
const std::string site_id = payload.value("site_id", "");
const std::string created_by = payload.value("created_by", "");
const auto zones = payload.contains("zones") ? payload["zones"] : nlohmann::json::array();
std::error_code ec;
@@ -131,10 +130,10 @@ std::optional<nlohmann::json> MapStore::create(const nlohmann::json& payload, st
std::lock_guard<std::mutex> lock(mu_);
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db_.handle(),
"INSERT INTO maps(id, name, description, width, height, resolution, "
"INSERT INTO maps(id, name, description, site_id, created_by, width, height, resolution, "
"origin_x, origin_y, origin_yaw, image_file, yaml_file, zones_json, "
"created_at, updated_at) "
"VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14)",
"VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16)",
-1,
&stmt,
nullptr) != SQLITE_OK)
@@ -146,27 +145,32 @@ std::optional<nlohmann::json> MapStore::create(const nlohmann::json& payload, st
sqlite3_bind_text(stmt, 1, id.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, name.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, description.c_str(), -1, SQLITE_TRANSIENT);
if (payload.contains("width") && payload["width"].is_number())
sqlite3_bind_double(stmt, 4, payload["width"].get<double>());
else
if (site_id.empty())
sqlite3_bind_null(stmt, 4);
if (payload.contains("height") && payload["height"].is_number())
sqlite3_bind_double(stmt, 5, payload["height"].get<double>());
else
sqlite3_bind_null(stmt, 5);
if (payload.contains("resolution") && payload["resolution"].is_number())
sqlite3_bind_double(stmt, 6, payload["resolution"].get<double>());
sqlite3_bind_text(stmt, 4, site_id.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, created_by.c_str(), -1, SQLITE_TRANSIENT);
if (payload.contains("width") && payload["width"].is_number())
sqlite3_bind_double(stmt, 6, payload["width"].get<double>());
else
sqlite3_bind_null(stmt, 6);
sqlite3_bind_double(stmt, 7, payload.value("origin_x", 0.0));
sqlite3_bind_double(stmt, 8, payload.value("origin_y", 0.0));
sqlite3_bind_double(stmt, 9, payload.value("origin_yaw", 0.0));
sqlite3_bind_null(stmt, 10);
sqlite3_bind_null(stmt, 11);
if (payload.contains("height") && payload["height"].is_number())
sqlite3_bind_double(stmt, 7, payload["height"].get<double>());
else
sqlite3_bind_null(stmt, 7);
if (payload.contains("resolution") && payload["resolution"].is_number())
sqlite3_bind_double(stmt, 8, payload["resolution"].get<double>());
else
sqlite3_bind_null(stmt, 8);
sqlite3_bind_double(stmt, 9, payload.value("origin_x", 0.0));
sqlite3_bind_double(stmt, 10, payload.value("origin_y", 0.0));
sqlite3_bind_double(stmt, 11, payload.value("origin_yaw", 0.0));
sqlite3_bind_null(stmt, 12);
sqlite3_bind_null(stmt, 13);
const std::string zones_str = zones.dump();
sqlite3_bind_text(stmt, 12, zones_str.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 13, now.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 14, now.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 14, zones_str.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 15, now.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 16, now.c_str(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) != SQLITE_DONE)
{
@@ -180,6 +184,8 @@ std::optional<nlohmann::json> MapStore::create(const nlohmann::json& payload, st
created["id"] = id;
created["name"] = name;
created["description"] = description;
created["site_id"] = site_id.empty() ? nullptr : nlohmann::json(site_id);
created["created_by"] = created_by;
if (payload.contains("width") && payload["width"].is_number())
created["width"] = payload["width"];
if (payload.contains("height") && payload["height"].is_number())
@@ -207,7 +213,8 @@ bool MapStore::update(const std::string& id, const nlohmann::json& payload, std:
}
nlohmann::json merged = *existing;
for (const char* key : {"name", "description", "width", "height", "resolution", "origin_x", "origin_y", "origin_yaw"})
for (const char* key :
{"name", "description", "site_id", "created_by", "width", "height", "resolution", "origin_x", "origin_y", "origin_yaw"})
{
if (payload.contains(key))
merged[key] = payload[key];
@@ -221,8 +228,9 @@ bool MapStore::update(const std::string& id, const nlohmann::json& payload, std:
std::lock_guard<std::mutex> lock(mu_);
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db_.handle(),
"UPDATE maps SET name=?2, description=?3, width=?4, height=?5, resolution=?6, "
"origin_x=?7, origin_y=?8, origin_yaw=?9, zones_json=?10, updated_at=?11 WHERE id=?1",
"UPDATE maps SET name=?2, description=?3, site_id=?4, created_by=?5, width=?6, height=?7, "
"resolution=?8, origin_x=?9, origin_y=?10, origin_yaw=?11, zones_json=?12, updated_at=?13 "
"WHERE id=?1",
-1,
&stmt,
nullptr) != SQLITE_OK)
@@ -234,23 +242,29 @@ bool MapStore::update(const std::string& id, const nlohmann::json& payload, std:
sqlite3_bind_text(stmt, 1, id.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, merged.value("name", "").c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, merged.value("description", "").c_str(), -1, SQLITE_TRANSIENT);
if (merged["width"].is_number())
sqlite3_bind_double(stmt, 4, merged["width"].get<double>());
else
const std::string site_id = merged.value("site_id", "");
if (site_id.empty())
sqlite3_bind_null(stmt, 4);
if (merged["height"].is_number())
sqlite3_bind_double(stmt, 5, merged["height"].get<double>());
else
sqlite3_bind_null(stmt, 5);
if (merged["resolution"].is_number())
sqlite3_bind_double(stmt, 6, merged["resolution"].get<double>());
sqlite3_bind_text(stmt, 4, site_id.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, merged.value("created_by", "").c_str(), -1, SQLITE_TRANSIENT);
if (merged["width"].is_number())
sqlite3_bind_double(stmt, 6, merged["width"].get<double>());
else
sqlite3_bind_null(stmt, 6);
sqlite3_bind_double(stmt, 7, merged.value("origin_x", 0.0));
sqlite3_bind_double(stmt, 8, merged.value("origin_y", 0.0));
sqlite3_bind_double(stmt, 9, merged.value("origin_yaw", 0.0));
sqlite3_bind_text(stmt, 10, zones_str.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 11, now.c_str(), -1, SQLITE_TRANSIENT);
if (merged["height"].is_number())
sqlite3_bind_double(stmt, 7, merged["height"].get<double>());
else
sqlite3_bind_null(stmt, 7);
if (merged["resolution"].is_number())
sqlite3_bind_double(stmt, 8, merged["resolution"].get<double>());
else
sqlite3_bind_null(stmt, 8);
sqlite3_bind_double(stmt, 9, merged.value("origin_x", 0.0));
sqlite3_bind_double(stmt, 10, merged.value("origin_y", 0.0));
sqlite3_bind_double(stmt, 11, merged.value("origin_yaw", 0.0));
sqlite3_bind_text(stmt, 12, zones_str.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 13, now.c_str(), -1, SQLITE_TRANSIENT);
const bool ok = sqlite3_step(stmt) == SQLITE_DONE;
if (!ok)