Files
retoor 3c4334cec9 feat: implement MoloApp plans 01-15 with integration
Full C++23 framework tree: runtime, observability, security,
data, app, realtime, supervisor, clients, CLI, example plus
enterprise tenancy, audit, operability, governance,
supplychain. Postgres via docker compose for tests.
2026-10-23 18:20:04 +02:00

142 lines
5.5 KiB
C++

#include "App.hpp"
#include "../fw/Http.hpp"
#include "../fw/Router.hpp"
#include "../fw/Validate.hpp"
namespace molo::example::app {
namespace {
fw::OrmDb* pick_db(Services& services, const fw::Request& req) {
if (fw::parse_backend(req.query_or("backend", "sqlite")) ==
fw::OrmBackend::Postgres)
return services.postgres.get();
return services.sqlite.get();
}
std::string rows_json(const std::vector<fw::OrmRow>& rows) {
std::string out = "[";
bool first = true;
for (const auto& r : rows) {
if (!first) out += ",";
first = false;
out += "{";
bool fc = true;
for (const auto& [k, v] : r.columns) {
if (!fc) out += ",";
fc = false;
out += "\"" + fw::json_escape(k) + "\":\"" + fw::json_escape(v) + "\"";
}
out += "}";
}
return out + "]";
}
} // namespace
void register_data_demo(fw::Router& router, Services& services) {
fw::OrmDb* sqlite = services.sqlite.get();
fw::OrmDb* postgres = services.postgres.get();
fw::KvStore* kv = services.kv.get();
fw::Cache* cache = services.cache.get();
fw::Pubsub* pubsub = services.pubsub.get();
router.get("/orm/users", "orm-users", [sqlite, postgres](fw::Request req) {
fw::OrmDb* db = req.query_or("backend", "sqlite") == "postgres" ? postgres
: sqlite;
fw::OrmResult res = db->select_all("users");
std::string body = "{\"backend\":\"" + fw::backend_name(db->backend()) +
"\",\"healed\":" + (res.healed ? "true" : "false") +
",\"note\":\"" + fw::json_escape(res.healed_note) +
"\",\"rows\":" + rows_json(res.rows) + "}";
return fw::JsonResponse(body, 200);
});
router.post("/orm/users", "orm-users-post",
[sqlite, postgres](fw::Request req) {
fw::OrmDb* db = req.query_or("backend", "sqlite") == "postgres"
? postgres
: sqlite;
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
fw::OrmResult res = db->insert("users", input);
if (!res.ok)
return fw::JsonResponse("{\"error\":\"store full\"}", 500);
std::string body =
"{\"backend\":\"" + fw::backend_name(db->backend()) +
"\",\"healed\":" + (res.healed ? "true" : "false") +
",\"note\":\"" + fw::json_escape(res.healed_note) +
"\",\"rows\":" + rows_json(res.rows) + "}";
return fw::JsonResponse(body, 201);
});
router.get("/kv/items", "kv-get", [kv](fw::Request req) {
std::string key = req.query_or("key", "");
if (key.empty()) return fw::JsonResponse("{\"error\":\"key required\"}", 400);
std::string value;
if (!kv->get(key, value))
return fw::JsonResponse("{\"error\":\"not found\"}", 404);
return fw::JsonResponse("{\"key\":\"" + fw::json_escape(key) +
"\",\"value\":\"" + fw::json_escape(value) +
"\"}",
200);
});
router.post("/kv/items", "kv-set", [kv](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
if (!input.count("key") || !input.count("value"))
return fw::JsonResponse("{\"error\":\"key and value required\"}", 400);
if (!kv->set(input["key"], input["value"]))
return fw::JsonResponse("{\"error\":\"store full\"}", 500);
return fw::JsonResponse("{\"stored\":\"" + fw::json_escape(input["key"]) +
"\"}",
201);
});
router.get("/cache/lookup", "cache", [cache](fw::Request req) {
std::string key = req.query_or("key", "demo");
std::string value;
bool hit = cache->lookup(key, value, 1000);
if (!hit) {
value = "computed-for-" + key;
cache->put(key, value, 60, 1000);
return fw::JsonResponse(
"{\"key\":\"" + fw::json_escape(key) + "\",\"hit\":false,\"value\":\"" +
fw::json_escape(value) + "\"}",
200);
}
return fw::JsonResponse(
"{\"key\":\"" + fw::json_escape(key) + "\",\"hit\":true,\"value\":\"" +
fw::json_escape(value) + "\"}",
200);
});
router.post("/pubsub/publish", "pubsub", [pubsub](fw::Request req) {
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
std::string topic = input.count("topic") ? input["topic"] : "news";
std::string message = input.count("message") ? input["message"] : "hello";
std::size_t delivered = pubsub->publish(topic, message);
return fw::JsonResponse("{\"topic\":\"" + fw::json_escape(topic) +
"\",\"delivered\":" +
std::to_string(delivered) + "}",
200);
});
router.get("/pubsub/publish", "pubsub-history", [pubsub](fw::Request req) {
std::string topic = req.query_or("topic", "news");
auto hist = pubsub->history(topic);
std::string body = "{\"topic\":\"" + fw::json_escape(topic) +
"\",\"history\":[";
bool first = true;
for (const auto& m : hist) {
if (!first) body += ",";
first = false;
body += "\"" + fw::json_escape(m) + "\"";
}
return fw::JsonResponse(body + "]}", 200);
});
(void)pick_db;
}
} // namespace molo::example::app