diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-26 12:28:10 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-26 12:28:10 -0300 |
| commit | b71faa6e95a0736f1ff171e006b171467b65db90 (patch) | |
| tree | 7580c3ab515e8f50726dc68dbc240995ff4a1a4c /src/models.cpp | |
| download | cpp-b71faa6e95a0736f1ff171e006b171467b65db90.tar.gz | |
Initial importv0.1.0
Diffstat (limited to 'src/models.cpp')
| -rw-r--r-- | src/models.cpp | 137 |
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 |