summaryrefslogtreecommitdiffstats
path: root/R/models.R
diff options
context:
space:
mode:
Diffstat (limited to 'R/models.R')
-rw-r--r--R/models.R102
1 files changed, 96 insertions, 6 deletions
diff --git a/R/models.R b/R/models.R
index 076db48..5d90898 100644
--- a/R/models.R
+++ b/R/models.R
@@ -62,6 +62,53 @@ NULL
#' @name cepis_geo
NULL
+#' The municipality a CEP that does not exist would have belonged to
+#'
+#' @description
+#' The `faixa` field of a [cepis_not_found][cepis_conditions] condition, a
+#' plain list of class `cepis_faixa`. It is **context for an error, not an
+#' address**: the CEP asked for does not exist, and nothing here says
+#' otherwise. What it does say is which municipality owns the band of numbers
+#' the CEP fell into.
+#'
+#' It exists because a CEP that fails is rarely random — it is usually
+#' someone who knows the city and guessed the number, and the classic guess is
+#' the `-000` that 957 municipalities never received.
+#'
+#' @section Fields:
+#' \describe{
+#' \item{`localidade`, `uf`, `estado`, `regiao`}{municipality, state code,
+#' state name, region — the same names, and the same meaning, as in a
+#' [cepis_address].}
+#' \item{`ibge`}{the municipality's IBGE code, so the answer can be joined
+#' to other data without matching on the name.}
+#' \item{`cep_ini`, `cep_fim`}{the smallest and the largest CEP that
+#' **actually exists** in that municipality. Not the range the Correios
+#' publish: the DNE's own start for Areal/RJ is `25845000`, which is
+#' precisely the CEP that just failed.}
+#' \item{`ceps`}{how many CEPs the municipality really has.}
+#' }
+#'
+#' @section The range is sparse:
+#' Areal's 118 CEPs are scattered over the ~4900 numbers between `25845001`
+#' and `25849899`. `cep_ini` and `cep_fim` are two endpoints that exist, not a
+#' promise about anything in between — never present the pair as a list of
+#' valid CEPs, and never iterate from one to the other. `ceps` is there so the
+#' emptiness of the interval is visible: 118 out of 4899.
+#'
+#' @section When there is no faixa:
+#' `NULL`, and not a list of empty strings, when the CEP falls in a band no
+#' municipality owns. The API **omits** the field rather than sending null,
+#' and this package keeps that distinction intact: `is.null(x$faixa)` means
+#' the number is close to nothing, not that the fields came back blank.
+#'
+#' Only [cep_lookup()] reports it. In [cep_lookup_many()] a CEP that does not
+#' exist is still `NULL` at its position: the endpoint behind a batch is CSV
+#' and says nothing about ranges.
+#'
+#' @name cepis_faixa
+NULL
+
#' The answer of `GET /health`
#'
#' @description
@@ -96,6 +143,15 @@ text_field <- function(data, name) {
as.character(value)
}
+count_field <- function(data, name) {
+ value <- data[[name]]
+ if (!is.numeric(value) && !is.character(value)) {
+ return(0L)
+ }
+ value <- suppressWarnings(as.numeric(value))
+ if (length(value) != 1L || is.na(value)) 0L else as.integer(value)
+}
+
new_geo <- function(block) {
lat <- suppressWarnings(as.numeric(block[["lat"]]))
lon <- suppressWarnings(as.numeric(block[["lon"]]))
@@ -121,6 +177,35 @@ new_geo <- function(block) {
)
}
+# Never signals. A faixa is decoration on a 404, and a malformed one must not
+# turn a clean "this CEP does not exist" into a parse failure: anything that
+# is not an object naming a municipality is simply no faixa at all.
+new_faixa <- function(block) {
+ if (!is.list(block) || is.null(names(block))) {
+ return(NULL)
+ }
+
+ localidade <- text_field(block, "localidade")
+ uf <- text_field(block, "uf")
+ if (!nzchar(localidade) || !nzchar(uf)) {
+ return(NULL)
+ }
+
+ structure(
+ list(
+ localidade = localidade,
+ uf = uf,
+ estado = text_field(block, "estado"),
+ regiao = text_field(block, "regiao"),
+ ibge = text_field(block, "ibge"),
+ cep_ini = text_field(block, "cep_ini"),
+ cep_fim = text_field(block, "cep_fim"),
+ ceps = count_field(block, "ceps")
+ ),
+ class = "cepis_faixa"
+ )
+}
+
new_address <- function(data) {
geo <- NULL
block <- data[["geo"]]
@@ -135,10 +220,6 @@ new_address <- function(data) {
}
new_health <- function(data) {
- count <- function(name) {
- value <- suppressWarnings(as.numeric(data[[name]]))
- if (length(value) != 1L || is.na(value)) 0L else as.integer(value)
- }
status <- text_field(data, "status")
structure(
@@ -146,8 +227,8 @@ new_health <- function(data) {
status = status,
ok = identical(status, "ok"),
dne = text_field(data, "dne"),
- ceps = count("ceps"),
- geo = count("geo"),
+ ceps = count_field(data, "ceps"),
+ geo = count_field(data, "geo"),
base_gerada_em = text_field(data, "base_gerada_em")
),
class = "cepis_health"
@@ -204,6 +285,15 @@ print.cepis_geo <- function(x, ...) {
}
#' @export
+print.cepis_faixa <- function(x, ...) {
+ cat("<cepis_faixa> ", x$localidade, "/", x$uf, " (IBGE ", x$ibge, ")\n",
+ sep = "")
+ cat(" ", x$ceps, " CEP(s), the first ", formatted_cep(x$cep_ini),
+ " and the last ", formatted_cep(x$cep_fim), "\n", sep = "")
+ invisible(x)
+}
+
+#' @export
print.cepis_health <- function(x, ...) {
cat("<cepis_health> ", x$status, "\n", sep = "")
cat(" dne: ", x$dne, " (generated ", x$base_gerada_em, ")\n", sep = "")