unobtanium 3.0.0

Opinioated Web search engine library with crawler and viewer companion.
Documentation
# SQLite unobtanium Database Cookbook

## URLs

URLs are handled by the base databse.

Storing:
```rust
self.get_url_id(&file_summary.url, true)?,
```

Retrieving:
```rust
self.get_url_by_id(row.get(/*n*/)?)
```

Magic lines for setting the fragment from a `Option<String>`:
```rust
let mut url = self.get_url_by_id(url_id)?;
if let Some(fragmet) = row.get<usize,Option<String>>(/*n*/)? {
	url.set_fragment(Some(fragmet.as_str()));
}
```

## Timestamps

Timestamps in the databse are UNIX timestamps in the UTC timezone, where no advanced tomestamp processing is needed, timestamps are stored as `std::time::SystemTime`.

Use the `unix_to_systime` and `systime_to_unix` helpers for them.

Include them with:
```rust
use crate::database::helper::*;
```

## Durations

In the Databse dureations are stored as integers in milliseconds, usually nullable as a missing duration isn't critical in almost all cases.

Storing (nullable):
```rust
file_summary.request_duration.map(|d| d.as_millis() as u64),
```

Retrieving:
```rust
row.get::<usize,Option<u64>>(/*n*/)?.map(|t| Duration::from_millis(t)),
```

## Mimetypes

Mimtypes are usually split up into their components `type`, `subtype` and `suffix` fo the databse and are passed as a `mediatype::MimeType` in code.

Storing:
```rust
file.mime.as_ref().map(|m| m.ty().to_string()),
file.mime.as_ref().map(|m| m.subty().to_string()),
file.mime.as_ref().map(|m| m.suffix().map(|s| s.to_string())),
```