unobtanium 3.0.0

Opinioated Web search engine library with crawler and viewer companion.
Documentation
use criterium::CriteriumChain;
use criterium::rusqlite::AssembleRusqliteQuery;
use criterium::sql::Prefix;
use log::trace;
use rusqlite::OptionalExtension;
use uuid::Uuid;

use crate::criterium::EntityCriterium;
use crate::database::id::EntityGenerationId;
use crate::database::DatabaseError;
use crate::database::EntityComponentTable;
use crate::database::fields::*;
use crate::database::Page;
use crate::database::summary::structs::SummaryDatabase;
use crate::database::summary::structs::SummaryDatabaseTransaction;
use crate::summary::TextPile;

impl SummaryDatabase {
	pub fn get_text_pile(
		&self, entity_generation_id: EntityGenerationId
	) -> Result<TextPile, DatabaseError> {
		trace!("summary_db.get_text_pile()");
		self.connection().query_row(
			"SELECT
				text,
				secondary_text,
				big_headlines,
				small_headlines,
				code_text,
				quote_text
			FROM entity_generation
			INNER JOIN text_pile
				ON text_pile.text_pile_id = entity_generation.text_pile_id
			WHERE entity_generation_id = ?
			", (entity_generation_id,),
			|row| Ok(TextPile {
				text: row.get(0)?,
				secondary_text: row.get(1)?,
				big_headlines: row.get(2)?,
				small_headlines: row.get(3)?,
				code_text: row.get(4)?,
				quote_text: row.get(5)?,
			})
		).map_err(Into::into)

	}

	pub fn get_text_pile_by_uuid(
		&self, entity_generation_uuid: Uuid
	) -> Result<TextPile, DatabaseError> {
		trace!("summary_db.get_text_pile()");
		self.connection().query_row(
			"SELECT
				text,
				secondary_text,
				big_headlines,
				small_headlines,
				code_text,
				quote_text
			FROM entity_generation
			INNER JOIN text_pile
				ON text_pile.text_pile_id = entity_generation.text_pile_id
			WHERE entity_generation_uuid = ?
			", (entity_generation_uuid,),
			|row| Ok(TextPile {
				text: row.get(0)?,
				secondary_text: row.get(1)?,
				big_headlines: row.get(2)?,
				small_headlines: row.get(3)?,
				code_text: row.get(4)?,
				quote_text: row.get(5)?,
			})
		).map_err(Into::into)

	}

	pub fn get_text_piles(
		&self,
		page: &Page,
		criterium_chain: CriteriumChain<EntityCriterium>,
	) -> Result<Vec<TextPile>, DatabaseError> {
		trace!("summary_db.get_text_piles()");
		let mut query = criterium_chain.assemble_rusqlite_query_for_db(
			&EntityComponentTable::EntityGeneration
		);
		query = query
			.inner_join(
				// This is the name that is generated by the Entity::TextPile criterium
				// Usually save a join
				Some("text_pile_text_pile"), 
				TextPileField::TextPileId.into(),
				Some(&Prefix::empty()),
				EntityGenerationField::TextPileId.into(),
			);
		trace!("SQL where: {}", query.sql_where_clause);
		trace!("SQL where values: {:?}", query.where_values);
		trace!("SQL joins: {}", query.joins_to_sql());
		let mut get_text_piles_statement = self.connection().prepare(
			format!("
			SELECT
				text_pile_text_pile.text,
				text_pile_text_pile.secondary_text,
				text_pile_text_pile.big_headlines,
				text_pile_text_pile.small_headlines,
				text_pile_text_pile.code_text,
				text_pile_text_pile.quote_text
			FROM entity_generation
			{}
			WHERE {}
			LIMIT ?
			OFFSET ?",
				query.joins_to_sql(),
				query.sql_where_clause,
			).as_str(),
		)?;
		query.where_values.push(page.limit().into());
		query.where_values.push(page.offset().into());

		return get_text_piles_statement.query_map(
			query.where_values_as_params(),
			|row| Ok(TextPile {
				text: row.get(0)?,
				secondary_text: row.get(1)?,
				big_headlines: row.get(2)?,
				small_headlines: row.get(3)?,
				code_text: row.get(4)?,
				quote_text: row.get(5)?,
			})
		)?.map(|r| r.map_err(Into::into)).collect();

	}

}

impl SummaryDatabaseTransaction<'_> {
	pub fn store_text_pile(
		&mut self,
		entity_generation_uuid: Uuid,
		pile: TextPile
	) -> Result<(), DatabaseError> {
		trace!("summary_db_transaction.store_text_pile()");
		let entity_generation_id = self.get_entity_generation_id(entity_generation_uuid)?;
		let text_pile_digest = pile.calculate_blake2b512_digest();
		let existing_text_pile_id = self.connection().query_row(
			"SELECT text_pile_id
			FROM text_pile
			WHERE blake2b512_digest = ?
			",(&text_pile_digest,),
			|row| row.get(0)
		).optional()?;
		let text_pile_id: i64;
		if let Some(existing_text_pile_id) = existing_text_pile_id {
			text_pile_id = existing_text_pile_id;
		} else {
			self.connection().execute(
				"INSERT INTO text_pile (
					blake2b512_digest,
					text,
					secondary_text,
					big_headlines,
					small_headlines,
					code_text,
					quote_text
				) VALUES (
					?,?,?,?,?,?,?
				)", (
					text_pile_digest,
					pile.text,
					pile.secondary_text,
					pile.big_headlines,
					pile.small_headlines,
					pile.code_text,
					pile.quote_text
				)
			)?;
			text_pile_id = self.connection().last_insert_rowid();
		}
		self.connection().execute(
			"UPDATE entity_generation
			SET text_pile_id = ?
			WHERE entity_generation_id = ?
			", (
				text_pile_id,
				entity_generation_id,
			)
		)?;
		Ok(())
	}

}