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.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user