summaryrefslogtreecommitdiffstats
path: root/src/models.cpp
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 12:28:10 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 12:28:10 -0300
commitb71faa6e95a0736f1ff171e006b171467b65db90 (patch)
tree7580c3ab515e8f50726dc68dbc240995ff4a1a4c /src/models.cpp
downloadcpp-b71faa6e95a0736f1ff171e006b171467b65db90.tar.gz
Initial importv0.1.0
Diffstat (limited to 'src/models.cpp')
-rw-r--r--src/models.cpp137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/models.cpp b/src/models.cpp
new file mode 100644
index 0000000..84e03f9
--- /dev/null
+++ b/src/models.cpp
@@ -0,0 +1,137 @@
+#include "cepis/models.hpp"
+
+#include <cerrno>
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+#include <optional>
+#include <string>
+
+namespace cepis {
+namespace {
+
+std::string as_field(const Json* value) {
+ if (value == nullptr) {
+ return {};
+ }
+ switch (value->kind()) {
+ case Json::Kind::String:
+ return value->as_string();
+ case Json::Kind::Number: {
+ const double number = value->as_number();
+ if (number == std::trunc(number) && std::fabs(number) < 9.0e15) {
+ return std::to_string(static_cast<std::int64_t>(number));
+ }
+ return Json::number(number).dump();
+ }
+ case Json::Kind::Bool:
+ return value->as_bool() ? "true" : "false";
+ default:
+ return {};
+ }
+}
+
+std::optional<double> as_double(const Json* value) {
+ if (value == nullptr) {
+ return std::nullopt;
+ }
+ if (value->is_number()) {
+ return value->as_number();
+ }
+ if (!value->is_string()) {
+ return std::nullopt;
+ }
+ const std::string& text = value->as_string();
+ if (text.empty()) {
+ return std::nullopt;
+ }
+ errno = 0;
+ char* end = nullptr;
+ const double parsed = std::strtod(text.c_str(), &end);
+ if (errno != 0 || end != text.c_str() + text.size() || !std::isfinite(parsed)) {
+ return std::nullopt;
+ }
+ return parsed;
+}
+
+std::optional<std::int64_t> as_integer(const Json* value) {
+ if (value == nullptr) {
+ return std::nullopt;
+ }
+ if (value->is_number()) {
+ const double number = value->as_number();
+ if (!std::isfinite(number) || std::fabs(number) >= 9.0e18) {
+ return std::nullopt;
+ }
+ return static_cast<std::int64_t>(std::trunc(number));
+ }
+ if (!value->is_string()) {
+ return std::nullopt;
+ }
+ const std::string& text = value->as_string();
+ if (text.empty()) {
+ return std::nullopt;
+ }
+ errno = 0;
+ char* end = nullptr;
+ const long long parsed = std::strtoll(text.c_str(), &end, 10);
+ if (errno != 0 || end != text.c_str() + text.size()) {
+ return std::nullopt;
+ }
+ return static_cast<std::int64_t>(parsed);
+}
+
+std::optional<Geo> geo_from_json(const Json* block) {
+ if (block == nullptr || !block->is_object()) {
+ return std::nullopt;
+ }
+ const std::optional<double> lat = as_double(block->find("lat"));
+ const std::optional<double> lon = as_double(block->find("lon"));
+ const std::optional<std::int64_t> raio_m = as_integer(block->find("raio_m"));
+ const Json* precisao = block->find("precisao");
+ if (!lat || !lon || !raio_m || precisao == nullptr || !precisao->is_string()) {
+ return std::nullopt;
+ }
+ return Geo{*lat, *lon, *raio_m, precisao->as_string()};
+}
+
+} // namespace
+
+std::string Address::formatted_cep() const {
+ if (cep.size() != 8) {
+ return cep;
+ }
+ return cep.substr(0, 5) + "-" + cep.substr(5);
+}
+
+Address Address::from_json(const Json& data) {
+ Address address;
+ address.cep = as_field(data.find("cep"));
+ address.logradouro = as_field(data.find("logradouro"));
+ address.complemento = as_field(data.find("complemento"));
+ address.unidade = as_field(data.find("unidade"));
+ address.bairro = as_field(data.find("bairro"));
+ address.localidade = as_field(data.find("localidade"));
+ address.uf = as_field(data.find("uf"));
+ address.estado = as_field(data.find("estado"));
+ address.regiao = as_field(data.find("regiao"));
+ address.ibge = as_field(data.find("ibge"));
+ address.gia = as_field(data.find("gia"));
+ address.ddd = as_field(data.find("ddd"));
+ address.siafi = as_field(data.find("siafi"));
+ address.geo = geo_from_json(data.find("geo"));
+ address.raw = data;
+ return address;
+}
+
+Health Health::from_json(const Json& data) {
+ Health health;
+ health.status = as_field(data.find("status"));
+ health.dne = as_field(data.find("dne"));
+ health.ceps = as_integer(data.find("ceps")).value_or(0);
+ health.geo = as_integer(data.find("geo")).value_or(0);
+ health.base_gerada_em = as_field(data.find("base_gerada_em"));
+ return health;
+}
+
+} // namespace cepis