unobtanium 3.0.0

Opinioated Web search engine library with crawler and viewer companion.
Documentation
use criterium::rusqlite::assembler::*;
use criterium::search::CriteriumSearchChain;
use criterium::TagCriterium;
use serde::{Serialize,Deserialize};

use crate::criterium::CrawlSummaryCriterium;
use crate::criterium::EntityGenerationCriterium;
use crate::criterium::FileSummaryCriterium;
use crate::database::EntityComponentTable;
use crate::database::SummarySchema;
use crate::database::fields::*;
use crate::database::SummaryTable;

use super::DuplicateSummaryCriterium;
use super::LinkSummaryCriterium;
use super::TextPileCriterium;
use super::TokenStatisticsCriterium;

#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="snake_case")]
pub enum EntityCriterium {
	Generation(EntityGenerationCriterium),
	File(FileSummaryCriterium),
	Crawl(CrawlSummaryCriterium),
	TextPile(TextPileCriterium),
	Links(TagCriterium<LinkSummaryCriterium>),
	/// Query duplicate summaries where this entity is the duplicate
	DuplicateSubject(TagCriterium<DuplicateSummaryCriterium>),
	/// Query duplicate summaries where this entity is the original
	DuplicatedBy(TagCriterium<DuplicateSummaryCriterium>),
	#[serde(skip)] //TODO: remove this once the search chain is serializable
	Search(CriteriumSearchChain),

	TokenStatistics(TagCriterium<TokenStatisticsCriterium>),

	// TODO: HasComponent
	// TODO: Redirect
	// TODO: LinkedFrom
}

impl AssembleRusqliteQuery<SummarySchema, EntityComponentTable> for EntityCriterium {
	/// Assemble the query, alredy joined to the indicated table.
	fn assemble_rusqlite_query(
		&self,
		assembly_context: &AssemblyContext,
		join_to_table: &EntityComponentTable,
	) -> InvertableRusqliteQuery<SummarySchema> {
		let mut query = match self {
			Self::Generation(c) =>
				c.assemble_rusqlite_query(assembly_context, &()),
			Self::File(FileSummaryCriterium::Description(c)) =>
				c.assemble_rusqlite_query(assembly_context, &()),
			Self::File(c) =>
				c.assemble_rusqlite_query(assembly_context, &()),
			Self::Crawl(c) =>
				c.assemble_rusqlite_query(assembly_context, &()),
			Self::TextPile(c) =>
				c.assemble_rusqlite_query(&assembly_context.prefix_with("text_pile_"), &())
				.inner_join(
					None,
					TextPileField::TextPileId.into(),
					Some(assembly_context.prefix()),
					EntityGenerationField::TextPileId.into()
				),
			Self::TokenStatistics(c) =>
				c.assemble_rusqlite_query(
					&assembly_context.prefix_with("token_statistics_"),
					&TokenStatisticsField::TextPileId.into(),
					assembly_context.prefix(),
					&EntityGenerationField::TextPileId.into(),
					&()
				),
			Self::Links(tc) => {
				return tc.assemble_rusqlite_query(
					&assembly_context.prefix_with("has_link_"),
					&LinkSummaryField::EntityGenerationId.into(),
					assembly_context.prefix(),
					&join_to_table.entity_generation_id_field(),
					&()
				)
			},
			Self::DuplicateSubject(tc) => {
				return tc.assemble_rusqlite_query(
					&assembly_context.prefix_with("duplicate_subject_"),
					&DuplicateSummaryField::SubjectEntityGenerationId.into(),
					assembly_context.prefix(),
					&join_to_table.entity_generation_id_field(),
					&()
				);
			},
			Self::DuplicatedBy(tc) => {
				return tc.assemble_rusqlite_query(
					&assembly_context.prefix_with("duplicated_by_"),
					&DuplicateSummaryField::DuplicateOfEntityGenerationId.into(),
					assembly_context.prefix(),
					&join_to_table.entity_generation_id_field(),
					&()
				);
			},
			Self::Search(c) =>
				c.to_rusqlite_query(
					&assembly_context.prefix().with("entity_"),
					SummaryTable::FullTextEntityIndex,
					&vec![
						&FullTextEntityIndexField::Title.into(),
						&FullTextEntityIndexField::Text.into(),
						&FullTextEntityIndexField::SecondaryText.into(),
						&FullTextEntityIndexField::BigHeadlines.into(),
						&FullTextEntityIndexField::SmallHeadlines.into(),
					],
				).inner_join(
					None,
					FullTextEntityIndexField::TextPileId.into(),
					Some(assembly_context.prefix()),
					EntityGenerationField::TextPileId.into(),
				).as_invertable()
		};

		let join_from_table = self.join_from();

		if &join_from_table != join_to_table {
			query = query.inner_join(
				None,
				join_from_table.entity_generation_id_field(),
				None,
				join_to_table.entity_generation_id_field()
			);
		}
		return query;
	}

}

impl EntityCriterium {
	/// Returns which table this would join from
	fn join_from(&self) -> EntityComponentTable {
		match self {
			Self::Generation(_) =>
				EntityComponentTable::EntityGeneration,
			Self::File(FileSummaryCriterium::Description(_)) =>
				EntityComponentTable::DocumentDescription,
			Self::File(_) =>
				EntityComponentTable::FileSummary,
			Self::Crawl(_) =>
				EntityComponentTable::CrawlSummary,
			// Everything addressed through a text pile id
			Self::TextPile(_) |
			Self::TokenStatistics(_) =>
				EntityComponentTable::EntityGeneration,
			Self::Links(_) =>
				EntityComponentTable::LinkSummary,
			Self::DuplicateSubject(_) =>
				EntityComponentTable::DuplicateSummarySubject,
			Self::DuplicatedBy(_) =>
				EntityComponentTable::DuplicateSummaryDuplicteOf,
			Self::Search(_) =>
				EntityComponentTable::EntityGeneration,
		}
	}
}

impl From<EntityGenerationCriterium> for EntityCriterium {
	fn from(c: EntityGenerationCriterium) -> Self {
		Self::Generation(c)
	}
}

impl From<FileSummaryCriterium> for EntityCriterium {
	fn from(c: FileSummaryCriterium) -> Self {
		Self::File(c)
	}
}

impl From<CrawlSummaryCriterium> for EntityCriterium {
	fn from(c: CrawlSummaryCriterium) -> Self {
		Self::Crawl(c)
	}
}