summaryrefslogtreecommitdiffstats
path: root/src/Cepis/Faixa.cs
blob: e2477b6acb2f6b306572bf6a22bb89628b9d1385 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System.Text.Json.Serialization;

namespace Cepis;

/// <summary>
/// The municipality a CEP that does not exist would have belonged to.
/// </summary>
/// <remarks>
/// <para>
/// This is <b>context for an error, never an address</b>. It rides on the 404
/// of <see cref="CepisClient.LookupAsync(string, CancellationToken)"/>, hanging
/// off <see cref="CepNotFoundException.Faixa"/>. The CEP that was asked for
/// still does not exist, and nothing here says otherwise: filling a form from
/// these fields would be inventing an address.
/// </para>
/// <para>
/// It is worth having because a CEP that fails is rarely random — it is usually
/// someone who knows the city and guessed the number. The classic guess is the
/// <c>-000</c>, which 957 municipalities never received. Knowing where the
/// guess landed is what turns "CEP not found" into "did you mean a street in
/// Areal/RJ?".
/// </para>
/// <para>
/// <see cref="CepIni"/> and <see cref="CepFim"/> are the smallest and the
/// largest CEP that <b>actually exist</b> in that municipality, <i>not</i> the
/// bounds the Correios publish. For Areal the DNE's own range starts at
/// <c>25845000</c> — exactly the CEP that just failed — while
/// <see cref="CepIni"/> is <c>25845001</c>.
/// </para>
/// <para>
/// The range is <b>sparse</b>, and the pair is not a list of valid CEPs. Areal
/// has 118 of them (<see cref="Ceps"/>) spread across the ~4,900 numbers
/// between its two ends, so a number picked in between overwhelmingly does not
/// exist either. Never iterate the interval, and never show it as a set of
/// usable CEPs.
/// </para>
/// <para>
/// The property names are the API's own, in Portuguese, with only the casing
/// adapted — the same rule the rest of the data follows. On the wire they are
/// <c>localidade</c>, <c>uf</c>, <c>estado</c>, <c>regiao</c>, <c>ibge</c>,
/// <c>cep_ini</c>, <c>cep_fim</c> and <c>ceps</c>.
/// </para>
/// </remarks>
public sealed record Faixa
{
    /// <summary>The municipality. Wire name <c>localidade</c>.</summary>
    [JsonPropertyName("localidade")]
    public string Localidade { get; init; } = "";

    /// <summary>The two-letter state code. Wire name <c>uf</c>.</summary>
    [JsonPropertyName("uf")]
    public string UF { get; init; } = "";

    /// <summary>The state's name. Wire name <c>estado</c>.</summary>
    [JsonPropertyName("estado")]
    public string Estado { get; init; } = "";

    /// <summary>The region of the country. Wire name <c>regiao</c>.</summary>
    [JsonPropertyName("regiao")]
    public string Regiao { get; init; } = "";

    /// <summary>The IBGE municipality code. Wire name <c>ibge</c>.</summary>
    [JsonPropertyName("ibge")]
    public string Ibge { get; init; } = "";

    /// <summary>
    /// The smallest CEP that exists in that municipality, unmasked. Wire name
    /// <c>cep_ini</c>.
    /// </summary>
    /// <remarks>
    /// The smallest one <i>in the database</i>, not the start of the range the
    /// Correios publish — the published start may itself be a CEP that was never
    /// issued, which is often precisely the one the caller just tried.
    /// </remarks>
    [JsonPropertyName("cep_ini")]
    public string CepIni { get; init; } = "";

    /// <summary>
    /// The largest CEP that exists in that municipality, unmasked. Wire name
    /// <c>cep_fim</c>.
    /// </summary>
    /// <remarks>
    /// Together with <see cref="CepIni"/> it bounds the CEPs of the
    /// municipality; it does not enumerate them. See <see cref="Ceps"/>.
    /// </remarks>
    [JsonPropertyName("cep_fim")]
    public string CepFim { get; init; } = "";

    /// <summary>
    /// How many CEPs the municipality actually has. Wire name <c>ceps</c>.
    /// </summary>
    /// <remarks>
    /// This field exists to keep <see cref="CepIni"/> and <see cref="CepFim"/>
    /// from being read as a contiguous interval. Areal's 118 CEPs sit inside a
    /// span of about 4,900 numbers: the range is mostly empty.
    /// </remarks>
    [JsonPropertyName("ceps")]
    public int Ceps { get; init; }
}