geolite 0.0.15

open source geocode solution
use rusqlite::Connection;

use super::entity::admin_level;
use super::rules::extraction_rules;
use super::scale::level;
use super::{place_ways, relations, streets};
use crate::progress_report;

pub struct extract_opts<'a> {
  pub threads: usize,
  pub name_priority: &'a [&'a str],
  pub rules: &'a [extraction_rules],
}

pub(super) const CHUNK_SIZE: usize = 500;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum source {
  relations,
  place_ways,
  streets,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct stage {
  pub level: level,
  pub source: source,
  pub ordinal: usize,
  pub of: usize,
}

pub struct extract_event {
  pub stage: stage,
  pub step: extract_step,
}

pub enum extract_step {
  started,
  candidates { found: u64, pending: u64 },
  progress(progress_report),
  finished,
}

impl admin_level {
  pub fn stages_of(level: level) -> Vec<stage> {
    let sources: &[source] = match level {
      level::neighborhood => &[source::relations, source::place_ways],
      level::street => &[source::streets],
      _ => &[source::relations],
    };
    sources
      .iter()
      .enumerate()
      .map(|(i, &source)| stage {
        level,
        source,
        ordinal: i + 1,
        of: sources.len(),
      })
      .collect()
  }

  pub fn extract(
    conn: &Connection,
    level: level,
    opts: &extract_opts,
    mut on_event: impl FnMut(extract_event),
  ) {
    for stage in Self::stages_of(level) {
      let mut emit = |step: extract_step| on_event(extract_event { stage, step });
      emit(extract_step::started);
      match stage.source {
        source::relations => {
          let found =
            crate::osm_relation::repository::all_ids_by_admin_level(conn, level).len() as u64;
          let pending =
            crate::osm_relation::repository::remaining_ids_by_admin_level(conn, level);
          emit(extract_step::candidates {
            found,
            pending: pending.len() as u64,
          });
          relations::run_with_ids(
            conn,
            pending,
            level,
            opts.threads,
            opts.name_priority,
            |report| emit(extract_step::progress(report)),
          );
        }
        source::place_ways => place_ways::run(conn, opts.rules, opts.name_priority, |report| {
          emit(extract_step::progress(report))
        }),
        source::streets => streets::run(conn, opts.rules, opts.name_priority, |report| {
          emit(extract_step::progress(report))
        }),
      }
      emit(extract_step::finished);
    }
  }
}