unobtanium 3.0.0

Opinioated Web search engine library with crawler and viewer companion.
Documentation
//! Integrate the origin datatype with Criterium

use criterium::sql::Field;
use criterium::CriteriumChainBuilder;
use serde::{Serialize,Deserialize};
use url::Url;

use criterium::DirectMatch;
use criterium::NumberCriterium;
use criterium::rusqlite::assembler::*;
use criterium::StringCriterium;

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

#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="snake_case")]
pub enum OriginCriterium {

	/// Matches the URL scheme, the scheme is never None.
	Scheme(StringCriterium),

	/// Matches the URL Host, non-ascii hsotnames are punycode encoded.
	Host(StringCriterium),

	/// Matches the Url port, extracted using [Url::port_or_known_default].
	Port(NumberCriterium<u16>),

	/// Matches equality to the given origin
	Equals(Origin),
}

impl OriginCriterium {
	/// Adds some smarts to the hostname.
	///
	/// A dot on any end indicates that the name
	/// is supposed to continue in that direction
	/// turnung the name into a equals, prefix, suffix or
	/// contains match as appropriate.
	pub fn parse_host(host: String) -> Self {
		let start_dot = host.starts_with(".");
		return OriginCriterium::Host(
			if host.ends_with(".") {
				if start_dot {
					StringCriterium::Contains(host)
				} else {
					StringCriterium::HasPrefix(host)
				}
			} else if start_dot {
				StringCriterium::HasSuffix(host)
			} else {
				StringCriterium::Equals(host)
			}
		);
	}
}

impl<F: Field + From<OriginField>> AssembleRusqliteQuery<F ,()> for OriginCriterium {
	fn assemble_rusqlite_query(
		&self,
		assembly_context: &AssemblyContext,
		_context: &()
	) -> InvertableRusqliteQuery<F> {
		match self {
			Self::Scheme(c) => c.assemble_query(assembly_context, &OriginField::Scheme.into()),
			Self::Host(c) =>   c.assemble_query(assembly_context, &OriginField::Host.into()),
			Self::Port(c) =>   c.assemble_query(assembly_context, &OriginField::Port.into()),
			Self::Equals(origin) => {
				let mut builder = CriteriumChainBuilder::and(false) ;
				builder.add_criterium(Self::Scheme(origin.scheme.clone().into())); 
				builder.add_criterium(Self::Host(origin.host.clone().into())); 
				builder.add_criterium(Self::Port(origin.port.into())); 
				builder.to_chain().assemble_rusqlite_query(assembly_context, &())
			}
		}
	}
}

impl DirectMatch<Origin> for OriginCriterium {

	type Output =  bool;
	
	fn criterium_match(&self, data: &Origin) -> bool {
		match self {
			Self::Scheme(c) => c.criterium_match(&data.scheme),
			Self::Host(c) =>   c.criterium_match(&data.host.as_ref()),
			Self::Port(c) =>   c.criterium_match(&data.port),
			Self::Equals(origin) => origin == data, 
		}
	}
}

impl DirectMatch<Url> for OriginCriterium {

	type Output =  bool;
	
	fn criterium_match(&self, data: &Url) -> bool {
		match self {
			Self::Scheme(c) => c.criterium_match(data.scheme()),
			Self::Host(c) =>   c.criterium_match(&data.host_str()),
			Self::Port(c) =>   c.criterium_match(&data.port_or_known_default()),
			Self::Equals(origin) =>
				origin.host.as_deref() == data.host_str() &&
				origin.port == data.port() &&
				origin.scheme == data.scheme(),
		}
	}
}