unobtanium 3.0.0

Opinioated Web search engine library with crawler and viewer companion.
Documentation
use criterium::BooleanJoiner;
use criterium::DirectMatch;
use criterium::rusqlite::assembler::*;
use criterium::StringCriterium;
use criterium::sql::Field;
use mediatype::MediaTypeBuf;
use mediatype::Name;
use mediatype::ReadParams;
use serde::{Serialize,Deserialize};

use crate::database::fields::*;

/// Matches MimeTypes in the default table
#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="snake_case")]
pub enum MimeCriterium {
	MimeType(StringCriterium),
	MimeSubtype(StringCriterium),
	MimeSuffix(StringCriterium),
	MimeHasParameter(String, StringCriterium),
	IsNone,
}

impl MimeCriterium {

	/// Join the `mimetype` table under the current prefix,
	/// May spawn an additional table as `mimetype_param_*`.
	pub fn assemble_rusqlite_query<F: Field + From<MimetypeField> + From<MimeParameterField>> (
		&self,
		assembly_context: &AssemblyContext,
		dock_prefix: &Prefix,
		mimetype_id_field: &F,
	) -> InvertableRusqliteQuery<F> {
		match self {
			Self::MimeType(c) =>
				c.assemble_query(
					assembly_context,
					&MimetypeField::MimeType.into()
				),
			Self::MimeSubtype(c) =>
				c.assemble_query(
					assembly_context,
					&MimetypeField::MimeSubtype.into()
				),
			Self::MimeSuffix(c) =>
				c.assemble_query(
					assembly_context,
					&MimetypeField::MimeSuffix.into()
				),
			Self::MimeHasParameter(p,c) =>  {
				let p = p.to_ascii_lowercase();
				if p == "charset" {
					c.assemble_query(
						assembly_context,
						&MimetypeField::Charset.into()
					)
				} else {
					//TODO: handle cases of multiple of these anded together
					let param_assembly_context = assembly_context.prefix_with_unique_reason(
						"mimetype_param_",
						Some(BooleanJoiner::Or)
					);
					let value_query = c.assemble_query(
						&param_assembly_context.in_and_block(),
						&MimeParameterField::Value.into(),
					).get_corrected_query();
					let kc = StringCriterium::Equals(p.clone());
					let key_query = kc.assemble_query(
						&param_assembly_context.in_and_block(),
						&MimeParameterField::Key.into(),
					).get_corrected_query();
					value_query
						.and(key_query)
						.parenthesise_where_clause()
						.left_join( //Left join because of `IsNone` checks
							None,
							MimeParameterField::MimetypeId.into(),
							Some(assembly_context.prefix()),
							MimetypeField::MimetypeId.into()
						).as_invertable()
				}
			},
			Self::IsNone => {
				return RusqliteQuery::test_if_null(
					dock_prefix,
					mimetype_id_field,
					false
				).as_invertable();
			}
		}.inner_join(
			None,
			MimetypeField::MimetypeId.into(),
			Some(dock_prefix),
			mimetype_id_field.clone()
		)
	}

}

impl DirectMatch<MediaTypeBuf> for MimeCriterium {

	type Output =  bool;
	
	fn criterium_match(&self, data: &MediaTypeBuf) -> bool {
	    match self {
		    Self::MimeType(c) => c.criterium_match(data.ty().as_str()),
		    Self::MimeSubtype(c) => c.criterium_match(data.subty().as_str()),
		    Self::MimeSuffix(c) => c.criterium_match(&data.suffix().map(|s| s.as_str())),
		    Self::MimeHasParameter(key, c) => {
				if let Some(key) = Name::new(key) {
					return c.criterium_match(&data.get_param(key).map(|v| v.as_str()));
				}
				return false;
		    },
		    Self::IsNone => false,
	    }
	}
}

impl DirectMatch<Option<MediaTypeBuf>> for MimeCriterium {

	type Output =  bool;
	
	fn criterium_match(&self, data: &Option<MediaTypeBuf>) -> bool {
	    match (self,data) {
		    (Self::IsNone,data) => data.is_none(),
		    (c, Some(d)) => c.criterium_match(d),
		    (_, None) => false,
	    }
	}
}