use categories;
use chrono::prelude::*;
use failure::*;
use heck::KebabCase;
use rich_crate::CrateVersionSourceData;
use rich_crate::CrateOwner;
use rich_crate::Derived;
use rich_crate::Manifest;
use rich_crate::ManifestExt;
use rich_crate::Markup;
use rich_crate::Origin;
use rich_crate::Readme;
use rich_crate::Repo;
use rich_crate::RichCrate;
use rusqlite::types::ToSql;
use rusqlite::NO_PARAMS;
use rusqlite::*;
use std::borrow::Cow;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt::Write;
use std::fs;
use std::path::Path;
use thread_local::ThreadLocal;
use tokio::sync::{Mutex, RwLock};
type FResult<T> = std::result::Result<T, failure::Error>;
pub mod builddb;
mod schema;
mod stopwords;
use crate::stopwords::{COND_STOPWORDS, STOPWORDS};
pub struct CrateDb {
url: String,
// Sqlite is awful with "database table is locked"
concurrency_control: RwLock<()>,
conn: ThreadLocal<std::result::Result<RefCell<Connection>, rusqlite::Error>>,
exclusive_conn: Mutex<Option<Connection>>,
tag_synonyms: HashMap<Box<str>, (Box<str>, u8)>,
}
pub struct CrateVersionData<'a> {
pub origin: &'a Origin,
pub derived: &'a CrateVersionSourceData,
pub manifest: &'a Manifest,
pub deps_stats: &'a [(&'a str, f32)],
pub is_build: bool,
pub is_dev: bool,
pub authors: &'a [rich_crate::Author],
pub category_slugs: &'a [Cow<'a, str>],
pub repository: Option<&'a Repo>,
pub extracted_auto_keywords: Vec<(f32, String)>,
}
impl CrateDb {
/// Path to sqlite db file to create/update
pub fn new(path: impl AsRef<Path>) -> FResult<Self> {
let path = path.as_ref();
Self::new_with_synonyms(path, &path.with_file_name("tag-synonyms.csv"))
}
pub fn new_with_synonyms(path: &Path, synonyms: &Path) -> FResult<Self> {
let tag_synonyms = fs::read_to_string(synonyms)?;
let tag_synonyms = tag_synonyms.lines()
.filter(|l| !l.starts_with('#'))
.map(|l| {
let mut cols = l.splitn(3, ',');
let score: u8 = cols.next().unwrap().parse().unwrap();
let find = cols.next().unwrap();
let replace = cols.next().unwrap();
(find.into(), (