# `locus`
[🔗](https://github.com/g-andrade/locus/blob/2.3.15/src/locus.erl#L24)

The main API.

# `custom_fetcher`

```erlang
-type custom_fetcher() :: {custom_fetcher, module(), Args :: term()}.
```

# `database_edition`

```erlang
-type database_edition() :: maxmind_database_edition().
```

# `database_entry`

```erlang
-type database_entry() :: locus_mmdb_data:value().
```

# `database_error`

```erlang
-type database_error() :: database_unknown | database_not_loaded.
```

# `database_info`

```erlang
-type database_info() ::
          #{metadata := database_metadata(), source := database_source(), version := database_version()}.
```

# `database_metadata`

```erlang
-type database_metadata() :: locus_mmdb_metadata:t().
```

# `database_source`

```erlang
-type database_source() :: locus_loader:source().
```

# `database_url`

```erlang
-type database_url() :: unicode:chardata().
```

# `database_version`

```erlang
-type database_version() :: calendar:datetime().
```

# `ip_address_prefix`

```erlang
-type ip_address_prefix() :: locus_mmdb_tree:ip_address_prefix().
```

# `legacy_maxmind_database_edition`

```erlang
-type legacy_maxmind_database_edition() :: atom().
```

# `maxmind_database_edition`

```erlang
-type maxmind_database_edition() ::
          {maxmind, atom() | unicode:chardata()} | legacy_maxmind_database_edition().
```

# `await_loader`

```erlang
-spec await_loader(DatabaseId) -> {ok, LoadedVersion} | {error, Reason}
                      when
                          DatabaseId :: atom(),
                          LoadedVersion :: database_version(),
                          Reason ::
                              database_unknown |
                              {database_stopped, term()} |
                              {timeout, LoadAttemptFailures},
                          LoadAttemptFailures :: [term()].
```

Like `await_loader/2` but with a default timeout of 30 seconds.

- `DatabaseId` must be an atom and refer to a database loader.

Returns:

- `{ok, LoadedVersion}` when the database is ready to use.
- `{error, database_unknown}` if the database loader for `DatabaseId` hasn't been started.
- `{error, {database_stopped, _}}` if the database loader for `DatabaseId` stopped while we waited.
- `{error, {timeout, [_]}}` if all the load attempts performed before timing out have failed.

See also: `await_loader/2`.

# `await_loader`

```erlang
-spec await_loader(DatabaseId, Timeout) -> {ok, LoadedVersion} | {error, Reason}
                      when
                          DatabaseId :: atom(),
                          Timeout :: timeout(),
                          LoadedVersion :: database_version(),
                          Reason ::
                              database_unknown |
                              {database_stopped, term()} |
                              {timeout, LoadAttemptFailures},
                          LoadAttemptFailures :: [term()].
```

Blocks caller execution until either readiness is achieved or the given timeout is triggered.

- `DatabaseId` must be an atom and refer to a database loader.
- `Timeout` must be either a non-negative integer (milliseconds) or `infinity`.

Returns:

- `{ok, LoadedVersion}` when the database is ready to use.
- `{error, database_unknown}` if the database loader for `DatabaseId` hasn't been started.
- `{error, {database_stopped, _}}` if the database loader for `DatabaseId` stopped while we waited.
- `{error, {timeout, [_]}}` if all the load attempts performed before timing out have failed.

See also: `await_loader/1`, `await_loaders/2`.

# `await_loaders`

```erlang
-spec await_loaders(DatabaseIds, Timeout) ->
                       {ok, Successes} | {error, {ErrorPerDatabase, PartialSuccesses}}
                       when
                           DatabaseIds :: [DatabaseId],
                           Timeout :: timeout(),
                           Successes :: LoadedVersionPerDatabase,
                           PartialSuccesses :: LoadedVersionPerDatabase,
                           LoadedVersionPerDatabase :: #{DatabaseId => LoadedVersion},
                           LoadedVersion :: database_version(),
                           ErrorPerDatabase :: #{DatabaseId := Reason},
                           Reason ::
                               database_unknown |
                               {database_stopped, term()} |
                               {timeout, LoadAttemptFailures},
                           LoadAttemptFailures :: [term()].
```

Like `await_loader/2` but concurrently awaits status from more than one database.

- `DatabaseIds` must be a list of atoms referring to database loaders.
- `Timeout` must be either a non-negative integer (milliseconds) or `infinity`.

Returns:

- `{ok, #{DatabaseId => LoadedVersion}}` when all the databases are ready to use.
- `{error, {#{DatabaseId => ErrorReason}, _}}` in case of errors.

See also: `await_loader/2`.

# `check`

```erlang
-spec check(DatabaseId) ->
               ok |
               {error, Error} |
               {validation_warnings, [ValidationWarning, ...]} |
               {validation_errors, [ValidationError, ...], [ValidationWarning]}
               when
                   DatabaseId :: atom(),
                   Error :: database_unknown | database_not_loaded,
                   ValidationWarning :: locus_mmdb_check:warning(),
                   ValidationError :: locus_mmdb_check:error().
```

Analyzes a loaded database for corruption or incompatibility.

- `DatabaseId` must be an atom and refer to a database loader.

Returns:

- `ok` if the database is wholesome.
- `{error, database_unknown}` if the database loader for `DatabaseId` hasn't been started.
- `{error, database_not_loaded}` if the database hasn't yet been loaded.
- `{validation_warnings, [CheckWarning, ...]}` in case something smells within the database
  (check the definitions in `m:locus_mmdb_check`).
- `{validation_errors, [CheckError], [...]}` in case of corruption or incompatibility
  (check the definitions in `m:locus_mmdb_check`).

# `get_info`

```erlang
-spec get_info(DatabaseId) -> {ok, Info} | {error, Error}
                  when
                      DatabaseId :: atom(),
                      Info :: database_info(),
                      Error :: database_unknown | database_not_loaded.
```

Returns the properties of a currently loaded database.

- `DatabaseId` must be an atom and refer to a database loader.

Returns:

- `{ok, t:database_info/0}` in case of success.
- `{error, database_unknown}` if the database loader for `DatabaseId` hasn't been started.
- `{error, database_not_loaded}` if the database hasn't yet been loaded.

See also: `get_info/2`.

# `get_info`

```erlang
-spec get_info(DatabaseId, Property) -> {ok, Value} | {error, Error}
                  when
                      DatabaseId :: atom(),
                      Property :: metadata | source | version,
                      Value :: database_metadata() | database_source() | database_version(),
                      Error :: database_unknown | database_not_loaded.
```

Returns a specific property of a currently loaded database.

- `DatabaseId` must be an atom and refer to a database loader.
- `Property` must be either `metadata`, `source` or `version`.

Returns:

- `{ok, Value}` in case of success.
- `{error, database_unknown}` if the database loader for `DatabaseId` hasn't been started.
- `{error, database_not_loaded}` if the database hasn't yet been loaded.

See also: `get_info/1`.

# `loader_child_spec`

```erlang
-spec loader_child_spec(DatabaseId, LoadFrom) -> ChildSpec | no_return()
                           when
                               DatabaseId :: atom(),
                               LoadFrom :: DatabaseEdition | DatabaseURL | CustomFetcher,
                               DatabaseEdition :: database_edition(),
                               DatabaseURL :: database_url(),
                               CustomFetcher :: custom_fetcher(),
                               ChildSpec :: locus_database:static_child_spec().
```

Like `loader_child_spec/3` but with default options.

- `DatabaseId` must be an atom.
- `LoadFrom` must be either:
  - a `t:database_edition/0` tuple, or
  - a `DatabaseURL` containing either a string or binary representation
    of a HTTP(s) URL or local path, or
  - a `{custom_fetcher, Module, Args}` tuple, with `Module` implementing
    the `m:locus_custom_fetcher` behaviour

Returns:

- A `t:supervisor:child_spec/0`.

See also: `loader_child_spec/3`, `await_loader/1`, `await_loader/2`, `start_loader/2`.

# `loader_child_spec`

```erlang
-spec loader_child_spec(DatabaseId, LoadFrom, Opts) -> ChildSpec | no_return()
                           when
                               DatabaseId :: atom(),
                               LoadFrom :: DatabaseEdition | DatabaseURL | CustomFetcher,
                               DatabaseEdition :: database_edition(),
                               DatabaseURL :: database_url(),
                               CustomFetcher :: custom_fetcher(),
                               Opts :: [locus_database:opt()],
                               ChildSpec :: locus_database:static_child_spec().
```

Like `loader_child_spec/4` but with default child id.

- `DatabaseId` must be an atom.
- `LoadFrom` must be either:
  - a `t:database_edition/0` tuple, or
  - a `DatabaseURL` containing either a string or binary representation
    of a HTTP(s) URL or local path, or
  - a `{custom_fetcher, Module, Args}` tuple, with `Module` implementing
    the `m:locus_custom_fetcher` behaviour
- `Opts` must be a list of `t:locus_database:opt/0` values

Returns:

- A `t:supervisor:child_spec/0`.

See also: `loader_child_spec/2`, `loader_child_spec/4`, `await_loader/1`,
`await_loader/2`, `start_loader/3`.

# `loader_child_spec`

```erlang
-spec loader_child_spec(ChildId, DatabaseId, LoadFrom, Opts) -> ChildSpec | no_return()
                           when
                               ChildId :: term(),
                               DatabaseId :: atom(),
                               LoadFrom :: DatabaseEdition | DatabaseURL | CustomFetcher,
                               DatabaseEdition :: database_edition(),
                               DatabaseURL :: database_url(),
                               CustomFetcher :: custom_fetcher(),
                               Opts :: [locus_database:opt()],
                               ChildSpec :: locus_database:static_child_spec().
```

Returns a supervisor child spec for a database loader under id `DatabaseId` with options `Opts`.

- `DatabaseId` must be an atom.
- `LoadFrom` must be either:
  - a `t:database_edition/0` tuple, or
  - a `DatabaseURL` containing either a string or binary representation
    of a HTTP(s) URL or local path, or
  - a `{custom_fetcher, Module, Args}` tuple, with `Module` implementing
    the `m:locus_custom_fetcher` behaviour
- `Opts` must be a list of `t:locus_database:opt/0` values

Returns:

- A `t:supervisor:child_spec/0`.

See also: `loader_child_spec/3`, `await_loader/1`, `await_loader/2`, `start_loader/3`.

# `lookup`

```erlang
-spec lookup(DatabaseId, Address) -> {ok, Entry} | not_found | {error, Error}
                when
                    DatabaseId :: atom(),
                    Address :: inet:ip_address() | string() | binary(),
                    Entry :: database_entry(),
                    Error ::
                        database_unknown | database_not_loaded |
                        {invalid_address, Address} |
                        ipv4_database.
```

Looks up info on IPv4 and IPv6 addresses.

- `DatabaseId` must be an atom and refer to a database loader.
- `Address` must be either a `t:inet:ip_address/0` tuple, or a string/binary
  containing a valid representation of the address.

Returns:

- `{ok, Entry}` in case of success.
- `not_found` if no data was found for this `Address`.
- `{error, invalid_address}` if `Address` is not either a `t:inet:ip_address/0`
  tuple or a valid textual representation of an IP address.
- `{error, database_unknown}` if the database loader for `DatabaseId` hasn't been started.
- `{error, database_not_loaded}` if the database hasn't yet been loaded.
- `{error, ipv4_database}` if `Address` represents an IPv6 address and the database
  only supports IPv4 addresses.

# `start_loader`

```erlang
-spec start_loader(DatabaseId, LoadFrom) -> ok | {error, Error}
                      when
                          DatabaseId :: atom(),
                          LoadFrom :: DatabaseEdition | DatabaseURL | CustomFetcher,
                          DatabaseEdition :: database_edition(),
                          DatabaseURL :: database_url(),
                          CustomFetcher :: custom_fetcher(),
                          Error :: invalid_url | already_started | application_not_running.
```

Like `start_loader/3` but with default options.

- `DatabaseId` must be an atom.
- `LoadFrom` must be either:
  - a `t:database_edition/0` tuple, or
  - a `DatabaseURL` containing either a string or binary representation
    of a HTTP(s) URL or local path, or
  - a `{custom_fetcher, Module, Args}` tuple, with `Module` implementing
    the `m:locus_custom_fetcher` behaviour

Returns:

- `ok` in case of success.
- `{error, invalid_url}` if the source is invalid.
- `{error, already_started}` if the loader under `DatabaseId` has already been started.

See also: `await_loader/1`, `await_loader/2`, `start_loader/3`.

# `start_loader`

```erlang
-spec start_loader(DatabaseId, LoadFrom, Opts) -> ok | {error, Error}
                      when
                          DatabaseId :: atom(),
                          LoadFrom :: DatabaseEdition | DatabaseURL | CustomFetcher,
                          DatabaseEdition :: database_edition(),
                          DatabaseURL :: database_url(),
                          CustomFetcher :: custom_fetcher(),
                          Opts :: [locus_database:opt()],
                          Error ::
                              invalid_url | already_started |
                              {invalid_opt, term()} |
                              application_not_running.
```

Starts a database loader under id `DatabaseId` with options `Opts`.

- `DatabaseId` must be an atom.
- `LoadFrom` must be either:
  - a `t:database_edition/0` tuple, or
  - a `DatabaseURL` containing either a string or binary representation
    of a HTTP(s) URL or local path, or
  - a `{custom_fetcher, Module, Args}` tuple, with `Module` implementing
    the `m:locus_custom_fetcher` behaviour
- `Opts` must be a list of `t:locus_database:opt/0` values

Returns:

- `ok` in case of success.
- `{error, invalid_url}` if the source is invalid.
- `{error, already_started}` if the loader under `DatabaseId` has already been started.

See also: `await_loader/1`, `await_loader/2`, `start_loader/2`.

# `stop_loader`

```erlang
-spec stop_loader(DatabaseId) -> ok | {error, Error} when DatabaseId :: atom(), Error :: not_found.
```

Stops the database loader under id `DatabaseId`.

- `DatabaseId` must be an atom and refer to a database loader.

Returns `ok` in case of success, `{error, not_found}` otherwise.

---

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