fast-fantoir/src/main.rs

77 lines
2.6 KiB
Rust

use std::fs::File;
use std::io::{BufReader, BufRead};
use rusqlite::{Connection, Result, Statement, params};
/// Create a new SQLite DB and sets the appropriate pragmas.
///
/// This is a one time batch import. We don't care about atomicity
/// here. If the batch fails, then we'll start it over from scratch.
/// Disabling the rollback journal speeds up quite a lot the inserts.
///
///
fn conn_db (path: &str) -> Result<Connection> {
let db = Connection::open(path)?;
db.pragma_update(None,"journal_mode","OFF")?;
db.pragma_update(None,"synchronous","OFF")?;
db.execute(
"CREATE TABLE fantoir (
id INTEGER PRIMARY KEY,
rivoli TEXT NOT NULL,
insee TEXT NOT NULL,
libelle TEXT NOT NULL
)", []
)?;
Ok(db)
}
/// Parsing a FANTOIR file. This is where all the business logic lives.
///
/// # Parsing logic
///
/// For each line, we try to figure out what kind of record type we're
/// looking at. We're using some of the FANTOIR specificities to do so.
///
/// 1. If the 3rd char is empty, we can assume it's a "Département"
/// record.
/// 2. If the 3rd & 6th char are empty, it's a "Commune".
/// 3. All the other record will be street records. In that case, we
/// can extract the insee code, the rivoli code (with the key) and
/// the street name (aka libelle).
#[inline]
fn parse_fantoir_lines(reader: BufReader<File>, mut stmt: Statement) -> () {
for line in reader.lines() {
let l = line.unwrap();
if l.chars().nth(3) == Some(' ') {
// Enregistrement Département
} else if l.chars().nth(6) == Some(' ') {
// Enregistrement Commune
} else {
let mut full_insee = String::from(l.get(0..2).unwrap());
full_insee.push_str(l.get(3..6).unwrap());
let rivoli_with_key = l.get(6..11).unwrap();
let libelle = l.get(15..41).unwrap().trim();
stmt.execute(params! [rivoli_with_key, full_insee, libelle]).unwrap();
}
};
}
fn main() -> std::io::Result<()> {
let db = match conn_db("./fantoir.sqlite") {
Err(err) => panic!("Cannot close DB: {}", err),
Ok(conn) => conn
};
let stmt = db.prepare(
"INSERT INTO fantoir (rivoli, insee, libelle) VALUES (?1, ?2, ?3)"
).unwrap();
let fantoir_path = std::env::args().nth(1).unwrap();
let file = match File::open(&fantoir_path) {
Err(err) => panic!("Cannot read file {}: {}", fantoir_path, err),
Ok(file) => file,
};
let reader = BufReader::new(file);
parse_fantoir_lines(reader, stmt);
db.close();
Ok(())
}