# `GeoGenius.Providers.ImpliedAreas`
[🔗](https://github.com/agoodway/geo_genius/blob/main/lib/geo_genius/providers/implied_areas.ex#L1)

Areas a source row implies through columns other than its own code.

A row that carries a grouping code -- a statistical grouping on an
administrative record, an administrative parent on a place record --
describes that grouping as well as itself. This module reads those columns
from a manifest option and returns both the implied areas and the edges
from each implied area to the row's own area.

An implied area carries no geometry and no centroid. A grouping a source
names only by code has no shape of its own in that source, and deriving one
from the row's geometry would claim the grouping's boundary is one member's
boundary.

The option is a list under `"implied_areas"`. Each entry names an
`"area_type"`, the column carrying the code, an optional `"names"` map from
code to display name, an optional `"authority"` override, and an optional
`"relation"` defaulting to `"contains"`. The column key is the calling
provider's own: `"code_property"` for `GeoGenius.Providers.GeoJSON`,
`"code_column"` for `GeoGenius.Providers.CSV`.

Argument order matches `GeoGenius.Providers.ManifestOptions`, this module's
sibling: payload first, option keys last.

# `entry`

```elixir
@type entry() :: %{
  area_type_key: String.t(),
  code_field: String.t(),
  names: %{optional(String.t()) =&gt; String.t()},
  relation: String.t(),
  authority_key: String.t() | nil
}
```

One parsed `implied_areas` entry.

# `areas`

```elixir
@spec areas(map(), [entry()], String.t()) ::
  {:ok, [GeoGenius.Provider.Area.t()]} | {:error, String.t()}
```

The areas `payload` implies, one per entry whose code column is populated.

A blank code implies no area and is not an error: a source whose grouping
column is populated for most rows and blank for a few is ordinary, and
failing the release over it would be wrong. A populated code with no entry
in `names` is an error, because keying an area with no name would publish
an unlabelled area.

`authority_key` is the row's own authority, used for any entry that
declares no `"authority"` of its own.

# `edges`

```elixir
@spec edges(map(), [entry()], String.t(), String.t()) :: [
  {String.t(), String.t(), String.t()}
]
```

The edges `payload` asserts, one per entry whose code column is populated,
each running from the implied area to the row's own area.

The parent end is composed through `GeoGenius.Provider.Area.key/1` rather
than by joining strings, and `child_area_key` must have been composed the
same way by the caller: an edge composed a second way can name a key
`normalize/2` never produced, and `GeoGenius.Catalog.put_relation_many/4`,
which is what the relating phase calls, refuses an area the release does not
carry.

Returns a bare list because `c:GeoGenius.Provider.asserted_relations/2`
does. An entry that cannot be parsed has already failed `normalize/2`,
which runs first.

# `parse`

```elixir
@spec parse(map(), String.t()) :: {:ok, [entry()]} | {:error, String.t()}
```

Parses the `implied_areas` option, reading each entry's code column under
`code_option_key`.

An absent option is not an error: most manifests imply nothing.

# `validate`

```elixir
@spec validate(map(), String.t()) :: :ok | {:error, String.t()}
```

`:ok` when every `implied_areas` entry parses under `code_option_key`, or the
first entry's error.

This is the shape `c:GeoGenius.Provider.validate_options/1` returns, so a
provider whose only manifest-wide check is its implied areas delegates here
rather than discarding `parse/2`'s entries at each call site.

# `with_implied`

```elixir
@spec with_implied(GeoGenius.Provider.Area.t(), map(), [entry()], String.t()) ::
  {:ok, GeoGenius.Provider.Area.t()}
  | {:ok, [GeoGenius.Provider.Area.t()]}
  | {:error, String.t()}
```

`area` alone when the manifest implies nothing, or `area` followed by every
area `payload` implies.

A provider whose manifest declares no `implied_areas` keeps returning a bare
`{:ok, %Area{}}` from `c:GeoGenius.Provider.normalize/2`, which is the shape
every existing manifest depends on. Only a manifest that actually implies
something sees the list form.

This lives here rather than in each provider because both generic providers
need exactly this, and the substance it wraps -- `areas/3` -- is already this
module's.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
