geolite 0.0.14

open source geocode solution
use geo::Point;
use rusqlite::Connection;
use std::collections::HashMap;

use super::entity::{house_number_match, query_house_number};
use crate::house_number::repository::numbers_by_street;
use crate::house_number::{
  house_number, house_number_policy, house_number_resolution, resolution, token,
};

pub(super) struct resolved_number {
  number: house_number,
  resolution: house_number_resolution,
}

impl resolved_number {
  pub(super) fn placed(&self) -> Option<(&str, Point<f64>)> {
    match self.resolution {
      house_number_resolution::exact(point) | house_number_resolution::interpolated(point) => {
        Some((self.number.stored_form(), point))
      }
      house_number_resolution::absent => None,
    }
  }

  pub(super) fn reported(&self) -> query_house_number {
    query_house_number {
      number: self.number.stored_form().to_string(),
      kind: match self.resolution {
        house_number_resolution::exact(_) => house_number_match::exact,
        house_number_resolution::interpolated(_) => house_number_match::interpolated,
        house_number_resolution::absent => house_number_match::absent,
      },
    }
  }
}

pub(super) fn from_query(
  conn: &Connection,
  query: &str,
  streets: &[(i64, &str)],
  policy: &house_number_policy,
) -> HashMap<i64, resolved_number> {
  if streets.is_empty() || !token::has_house_number(query, policy) {
    return HashMap::new();
  }
  let street_ids: Vec<i64> = streets.iter().map(|(id, _)| *id).collect();
  let by_street = numbers_by_street(conn, &street_ids);
  let no_numbers: Vec<(house_number, Point<f64>)> = Vec::new();

  streets
    .iter()
    .filter_map(|&(id, name)| {
      let number = token::first_house_number(query, name, policy)?;
      let known = by_street.get(&id).unwrap_or(&no_numbers);
      let resolution = resolution::resolve(&number, known);
      Some((id, resolved_number { number, resolution }))
    })
    .collect()
}

pub(super) fn nearest_to(
  conn: &Connection,
  input_pt: Point<f64>,
  street_ids: &[i64],
) -> HashMap<i64, house_number> {
  numbers_by_street(conn, street_ids)
    .into_iter()
    .filter_map(|(id, known)| {
      resolution::nearest(input_pt, &known)
        .cloned()
        .map(|number| (id, number))
    })
    .collect()
}