summaryrefslogtreecommitdiffstats
path: root/cepis/models.lua
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:33:25 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:33:25 -0300
commit58dbe934a90c1eda8e76cd218a413f01a4d9b11d (patch)
treedeaee88adad3791c8f010db7f7161a95318ed67e /cepis/models.lua
parent7fd555fcaf4304cb0dff3e8f5661565c3618299e (diff)
downloadlua-58dbe934a90c1eda8e76cd218a413f01a4d9b11d.tar.gz
Carry the municipality of a missing CEP on not_foundHEADv0.2.0main
A CEP that fails is rarely a random number: it is someone who knows the city and guessed the digits, and the classic guess is the -000 that 957 municipalities never received. The API now answers that 404 with an optional faixa block naming where the CEP would have been, so a caller can turn "CEP does not exist" into something the user can act on. It hangs off the error, never off an address: the lookup still failed. Parsing gives up quietly at every step — no block, a block that is not an object, one without a municipality to name — because a broken piece of context must not turn a clean not-found into a parse failure. cep_ini and cep_fim are the CEPs that exist, not the range the Correios publish, and the interval between them is sparse; ceps is what keeps the pair from being read as a list of valid CEPs.
Diffstat (limited to 'cepis/models.lua')
-rw-r--r--cepis/models.lua86
1 files changed, 86 insertions, 0 deletions
diff --git a/cepis/models.lua b/cepis/models.lua
index 61ad678..a433369 100644
--- a/cepis/models.lua
+++ b/cepis/models.lua
@@ -185,6 +185,92 @@ function M.new_address(data)
return address
end
+--- The municipality a CEP that does not exist would have belonged to.
+--
+-- This is **context for an error, never an address**. It arrives on the 404 of
+-- `Client:lookup` and hangs off the `not_found` error as `err.faixa`; the
+-- lookup still failed, and nothing here says otherwise. The CEP asked for does
+-- not exist. What the API is saying is only *where it would have been*.
+--
+-- It exists because a CEP that fails is rarely a random number: it is usually
+-- someone who knows the city and guessed the digits, and the classic guess is
+-- the `-000` that 957 municipalities never received. Knowing the guess landed
+-- on Areal/RJ turns "CEP does not exist" into a message the user can act on.
+--
+-- **`cep_ini` and `cep_fim` are the smallest and the largest CEP that actually
+-- exist in that municipality — not the bounds the Correios publish.** For
+-- Areal the DNE's own range starts at `25845000`, which is precisely the CEP
+-- that just failed; the range reported here starts at `25845001`, the first
+-- one really in the base.
+--
+-- **The range is sparse.** Areal's 118 CEPs are spread over the roughly 4,900
+-- numbers between `25845001` and `25849899`. That is what `ceps` is for: the
+-- pair is an interval, never a list of valid CEPs, and picking a number
+-- between them has about one chance in forty of existing.
+--
+-- @type Faixa
+-- @field localidade string the municipality
+-- @field uf string
+-- @field estado string
+-- @field regiao string
+-- @field ibge string
+-- @field cep_ini string smallest CEP that exists there, 8 digits
+-- @field cep_fim string largest CEP that exists there, 8 digits
+-- @field ceps number how many exist between the two — far fewer than the span
+local Faixa = {}
+Faixa.__index = Faixa
+Faixa.__name = "cepis.Faixa"
+
+--- The municipality and its UF: `Areal/RJ`.
+--
+-- The one-line form for a message shown to a person, so it does not become a
+-- repeated concatenation in every project that uses this.
+-- @treturn string
+function Faixa:label()
+ if self.uf == "" then
+ return self.localidade
+ end
+ return self.localidade .. "/" .. self.uf
+end
+
+M.Faixa = Faixa
+
+--- Build a `Faixa` from the `faixa` block of a 404 body, or return `nil`.
+--
+-- The API **omits** the block, never sends it as null, when the CEP falls in a
+-- band no municipality owns. So `nil` here is the ordinary case, not a
+-- failure.
+--
+-- Anything unusable — absent, not an object, without a municipality to name —
+-- is also `nil`. That is deliberate and it is the whole point of this
+-- function: the caller is already holding a not-found, and a malformed piece
+-- of context must never be allowed to turn that clean answer into a parse
+-- error.
+--
+-- @tparam[opt] table block the decoded `faixa` object
+-- @treturn Faixa|nil
+function M.new_faixa(block)
+ if type(block) ~= "table" then
+ return nil
+ end
+
+ local localidade = text(block.localidade)
+ if localidade == "" then
+ return nil
+ end
+
+ return setmetatable({
+ localidade = localidade,
+ uf = text(block.uf),
+ estado = text(block.estado),
+ regiao = text(block.regiao),
+ ibge = text(block.ibge),
+ cep_ini = text(block.cep_ini),
+ cep_fim = text(block.cep_fim),
+ ceps = integer(block.ceps),
+ }, Faixa)
+end
+
--- The response of `GET /health`.
--
-- Good for two things: checking that the API answers, and knowing **which