criterium 3.1.3

Lightweigt dynamic database queries for rusqlite.
Documentation
// SPDX-FileCopyrightText: 2025 Slatian
//
// SPDX-License-Identifier: LGPL-3.0-only

use crate::search::phrase::Phrase;

#[cfg(feature = "rusqlite")]
mod rusqlite;

pub mod builder;

/// This chain behaves similar to a regular [criterium chain][crate::chain::CriteriumChain], but is meant for full text search.
///
/// It directly be transformed into SQL building blocks
/// (if you enable the needed integrations).
///
/// **SQLite Note:** Due to how SQLite fts5 works make sure you have an `any` column
/// that always contains the word `any`.
///
/// No serde support here yet, Apologies. (Feel free to push a PR though)
#[derive(Clone, Debug)]
pub enum CriteriumSearchChain {
	/// All of the sub-chains must match for the query to match
	And(Vec<Self>),

	/// Any of the sub-chains can match for the query to match
	Or(Vec<Self>),

	/// If the sub-chain matches this chain will not match
	NotChain(Box<Self>),

	/// Multiple phrases that must follow each other like tokens within a phrase.
	///
	/// This is equivalent to the SQLite fts5 `+` operator or the postgres `<->` operator.
	PhraseChain(Vec<Phrase>),

	/// Represents literal tokens
	Phrase(Phrase),
}

impl CriteriumSearchChain {
	/// Negates the chain result.
	///
	/// Similar to a `not` or `!` in other languages.
	///
	/// This wraps the CriteriumSearchChain in a `CriteriumSearchChain::NotChain`
	/// or unwraps one layer if already wrapped in a `CriteriumSearchChain::NotChain`.
	pub fn invert(self) -> Self {
		if let CriteriumSearchChain::NotChain(chain) = self {
			return *chain;
		} else {
			return CriteriumSearchChain::NotChain(Box::new(self));
		}
	}

	/// Inverts the chain if `do_invert` is `true`,
	/// otherwise returns the chain unmodified.
	pub fn invert_if(self, do_invert: bool) -> Self {
		if do_invert {
			self.invert()
		} else {
			self
		}
	}
}