unobtanium 3.0.0

Opinioated Web search engine library with crawler and viewer companion.
Documentation

//! Rusqlite specific helpers to avoid duplicated code.

use mediatype::MediaTypeBuf;
use mediatype::Name as MimeName;
use rusqlite::Error;
use rusqlite::Row;
use url::Url;

use crate::content::LocationSignature;
use crate::database::Database;
use crate::database::DatabaseError;
use crate::database::id::UrlId;
use crate::summary::HttpSummary;

// Re-export these as they are needed all across the database.
pub use crate::time::from_unix_timestamp_opt;
pub use crate::time::from_unix_timestamp_or_epoch;
pub use crate::time::to_unix_timestamp_opt;


pub fn url_with_fragment_from_row_opt(
	db: &Database,
	row: &Row,
	url_id_column: usize,
	fragment_column: usize,
) -> Result<Option<Url>,Error> {
	if let Some(id) = row.get::<usize,Option<UrlId>>(url_id_column)? {
		if let Ok(url) = db.get_url_by_id(id) {
			return Ok(Some(url.with_fragment_string(
				row.get::<usize,Option<String>>(fragment_column)?
			)));
		}
	}
	return Ok(None);
}

pub fn url_with_fragment_from_row(
	db: &Database,
	row: &Row,
	url_id_column: usize,
	fragment_column: usize,
) -> Result<Url, DatabaseError> {
	let id: UrlId = row.get(url_id_column)?;
	let url = db.get_url_by_id(id)?
		.with_fragment_string(row.get(fragment_column)?);
	return Ok(url);
}

pub fn mediatypebuf_from_row(
	row: &Row,
	type_column: usize,
	subtype_column: usize,
	suffix_column: usize,
) -> Result<MediaTypeBuf,Error> {
	let ty_string = row.get::<usize,String>(type_column)?;
	let sty_string = row.get::<usize,String>(subtype_column)?;
	let suffix_string_opt = row.get::<usize,Option<String>>(suffix_column)?;
	let suffix_name = if let Some(s) = &suffix_string_opt {
		MimeName::new(s.as_str())
	} else {
		None
	};
	let mediatype = MediaTypeBuf::from_parts(
		MimeName::new(ty_string.as_str())
			.unwrap_or(MimeName::new("application").expect("Static MimeName 'application' fallback.")),
		MimeName::new(sty_string.as_str())
			.unwrap_or(MimeName::new("unknown").expect("Static MimeName 'unknown' fallback.")),
		suffix_name,
		&[],
	);
	return Ok(mediatype);
}

pub fn mediatypebuf_from_row_opt(
	row: &Row,
	type_column: usize,
	subtype_column: usize,
	suffix_column: usize,
) -> Result<Option<MediaTypeBuf>,Error> {
	let ty_string = row.get::<usize,Option<String>>(type_column)?;
	let sty_string = row.get::<usize,Option<String>>(subtype_column)?;
	let suffix_string_opt = row.get::<usize,Option<String>>(suffix_column)?;
	let suffix_name = if let Some(s) = &suffix_string_opt {
		MimeName::new(s.as_str())
	} else {
		None
	};
	if let Some(ty_string) = ty_string {
		if let Some(sty_string) = sty_string {
			let mediatype = MediaTypeBuf::from_parts(
				MimeName::new(ty_string.as_str())
					.unwrap_or(MimeName::new("application").expect("Static MimeName 'application' fallback.")),
				MimeName::new(sty_string.as_str())
					.unwrap_or(MimeName::new("unknown").expect("Static MimeName 'unknown' fallback.")),
				suffix_name,
				&[],
			);
			return Ok(Some(mediatype));
		}
	}

	return Ok(None);
}


/// This function fetches a location signature from the database.
///
/// It requires 12 columns in order, the `start` column being the first:
/// * in_header
/// * in_footer
/// * in_aside
/// * in_nav
/// * in_form
/// * in_main
/// * in_article
/// * in_section
/// * in_table
/// * in_figure
/// * in_address
/// * in_code
/// * in_code
/// * in_headline
/// * in_list
/// * in_paragraph
///
/// Note that the function name contains how many columns are required
/// to make it obvious which version is used
/// in case the location signature gets an update.
pub fn location_signature_from_row_and_15_columns(
	row: &Row,
	start: usize
) -> Result<LocationSignature,Error> {
	return Ok(LocationSignature {
		in_header:    row.get(start)?,
		in_footer:    row.get(start+1)?,
		in_aside:     row.get(start+2)?,
		in_nav:       row.get(start+3)?,
		in_form:      row.get(start+4)?,
		in_main:      row.get(start+5)?,
		in_article:   row.get(start+6)?,
		in_section:   row.get(start+7)?,
		in_table:     row.get(start+8)?,
		in_figure:    row.get(start+9)?,
		in_address:   row.get(start+10)?,
		in_code:      row.get(start+11)?,
		in_headline:  row.get(start+12)?,
		in_list:      row.get(start+13)?,
		in_paragraph: row.get(start+14)?,
	});

}

pub fn http_summary_from_row(
	row: &Row,
	status_col: usize,
	etag_col: usize,
) -> Result<Option<HttpSummary>,Error> {
	let http_status_code: Option<u16> = row.get(status_col)?;
	if let Some(http_status_code) = http_status_code {
		return Ok(Some(HttpSummary {
			status_code: http_status_code,
			etag: row.get(etag_col)?,
		}))
	} else {
		return Ok(None);
	}
}