atter 0.1.1

common components for atters and atterc
Documentation
// Copyright (c) 2018 atter developers
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! Data Access Layer for the sqlite database.
use chrono::{DateTime, TimeZone, Utc};
use config::{Config, Field};
use error::Result;
use rusqlite::Connection;
use std::path::Path;

/// Initialize the `atter` sqlite database.
pub fn initialize<P: AsRef<Path>>(config: &Config, path: P) -> Result<Connection> {
    let indices = config.index();
    let conn = Connection::open(path)?;

    for index in indices {
        let idx = index.idx_prefix();
        let fields = index.fields();

        let mut create_table = String::from("CREATE TABLE IF NOT EXISTS ");
        create_table.push_str(&idx.to_string().replace("-", "_"));
        create_table.push_str(" (");

        for field in fields {
            create_table.push_str(field.name());
            create_table.push(' ');
            create_table.push_str(&field.data_type().to_string());

            if let Some(pk) = field.primary_key() {
                if *pk {
                    create_table.push_str(" PRIMARY KEY");
                }
            }

            if let Some(nn) = field.not_null() {
                if *nn {
                    create_table.push_str(" NOT NULL");
                }
            }
            create_table.push(',');
        }

        let uniques: Vec<String> = fields.iter().filter_map(unique_name).collect();

        if uniques.is_empty() {
            create_table = String::from(create_table.trim_right_matches(','));
        } else {
            let uniques_str = uniques.join(",");
            create_table.push_str(&format!("UNIQUE({}) ON CONFLICT REPLACE", uniques_str));
        }
        create_table.push(')');
        conn.execute(&create_table, &[])?;
    }
    Ok(conn)
}

fn unique_name(field: &Field) -> Option<String> {
    if let Some(unique) = field.unique() {
        if *unique {
            Some(field.name().clone())
        } else {
            None
        }
    } else {
        None
    }
}

/// Find the largest timestamp value (i.e. most recent)
pub fn find_most_recent(conn: &Connection) -> Result<DateTime<Utc>> {
    let mut stmt =
        conn.prepare("SELECT MAX(DISTINCT timestamp) FROM mobile_service_layer_checkout")?;
    let max_timestamp: i64 = stmt.query_row(&[], |row| row.get(0))?;
    let date_time: DateTime<Utc> = Utc.timestamp(max_timestamp / 1000, 0);
    Ok(date_time)
}