# `PostalAddress`

A postal address in any country.

Use it for where to send a parcel or a letter. It fits every country, since locality, region and postal code are only there when the country uses them. A point on a map is a [`Point`](/docs/types/type-point.md), and a property's own number in Great Britain is a [`Uprn`](/docs/types/type-uprn.md). It is personal data with no `personal:` on the field: it counts as `PersonalData.contact`.

## Shape

| Field | Type | Required? |
|---|---|---|
| `lines` | `List<Text>` | Yes |
| `locality` | `Text` | No |
| `region` | `Text` | No |
| `postal_code` | [`PostalCode`](/docs/types/type-postal-code.md) | No |
| `country` | [`Country`](/docs/types/type-country.md) | Yes |

Write every field when you build one, and give a field that isn't required as `none`.

Its parts keep these rules, and a value that breaks one fails with the rule's name:

- `postal_code_of_country`: postal_code is in the form of its country's postal codes

## Example

```jadpo
PostalAddress {
    lines: ["Buckingham Palace"]
    locality: "London"
    region: none
    postal_code: "SW1A 1AA"
    country: Country.gb
}
```

## Good to know

- `text.format` writes it the way its country lays out an address, and leaves the country line out for a reader in the same country.
- The postal code is checked against the country's own form, so a value with a French code and `Country.gb` is refused.
- `==` tells you whether two are the same. `<` and `list.sort_by` don't take it, so sort by one of its parts instead.
- A field that holds one counts as personal data (`contact`), so you don't mark it yourself.

## In JSON

An object of its parts, in a request, a response or `json.write`:

```json
{"lines":["Buckingham Palace"],"locality":"London","region":null,"postal_code":"SW1A 1AA","country":"GB"}
{"lines":["2-7-2 Marunouchi"],"locality":"Chiyoda-ku","region":"Tokyo","postal_code":"100-8994","country":"JP"}
```

When you read one, a field that isn't required may be left out, or sent as `null`.

## Details

<details>
<summary>Text form, storage, how it is shown, and operations</summary>

`PostalAddress` is in the group People and contact, and has been in Jadpo since 0.1.0.

### Text form

It has no single text form, so `text.from` and `text.parse` don't take it.

### How it is stored

It is stored in 5 columns, each named for the field, `_` and its suffix. This is `{"lines":["2-7-2 Marunouchi"],"locality":"Chiyoda-ku","region":"Tokyo","postal_code":"100-8994","country":"JP"}`:

| Column | Type | Holds |
|---|---|---|
| `<field>_lines` | `text[]` | `ARRAY['2-7-2 Marunouchi']::text[]` |
| `<field>_locality` | `text` | `'Chiyoda-ku'` |
| `<field>_region` | `text` | `'Tokyo'` |
| `<field>_postal_code` | `text` | `'100-8994'` |
| `<field>_country` | `text` | `'JP'` |

### How it is shown to people

`text.format(value, locale:)` shows it to people in their locale.

With `locale: Locale.en_gb`:

| Value | Shown |
|---|---|
| `{"lines":["Buckingham Palace"],"locality":"London","region":null,"postal_code":"SW1A 1AA","country":"GB"}` | `"Buckingham Palace\nLondon\nSW1A 1AA"` |
| `{"lines":["2-7-2 Marunouchi"],"locality":"Chiyoda-ku","region":"Tokyo","postal_code":"100-8994","country":"JP"}` | `"2-7-2 Marunouchi\nChiyoda-ku, Tokyo\n100-8994\nJapan"` |

### Operations

It also takes `text.format`, `json.read`, `json.write` and `==`. [How every standard type behaves](/docs/every-standard-type-meets-one-contract.md) says how they work.

</details>
