use serde::{Deserialize, Serialize};
use super::explain::{ExplainFormat, ExplainMode};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ExplainOptions {
pub analyze: bool,
pub verbose: bool,
pub format: ExplainFormatOption,
pub costs: bool,
pub buffers: bool,
pub timing: bool,
pub summary: bool,
pub storage: bool,
pub ai: bool,
pub why_not: bool,
pub indexes: bool,
pub statistics: bool,
}
impl Default for ExplainOptions {
fn default() -> Self {
Self {
analyze: false,
verbose: false,
format: ExplainFormatOption::Text,
costs: true, buffers: false,
timing: true, summary: false,
storage: false,
ai: false,
why_not: false,
indexes: false,
statistics: false,
}
}
}
impl ExplainOptions {
pub fn new() -> Self {
Self::default()
}
pub fn standard() -> Self {
Self::default()
}
pub fn analyze() -> Self {
Self {
analyze: true,
timing: true,
summary: true,
..Self::default()
}
}
pub fn verbose() -> Self {
Self {
verbose: true,
..Self::default()
}
}
pub fn full() -> Self {
Self {
analyze: true,
verbose: true,
costs: true,
buffers: true,
timing: true,
summary: true,
storage: true,
ai: false, why_not: true,
indexes: true,
statistics: true,
..Self::default()
}
}
pub fn with_analyze(mut self) -> Self {
self.analyze = true;
self
}
pub fn with_verbose(mut self) -> Self {
self.verbose = true;
self
}
pub fn with_format(mut self, format: ExplainFormatOption) -> Self {
self.format = format;
self
}
pub fn with_storage(mut self) -> Self {
self.storage = true;
self
}
pub fn with_ai(mut self) -> Self {
self.ai = true;
self
}
pub fn with_why_not(mut self) -> Self {
self.why_not = true;
self
}
pub fn with_indexes(mut self) -> Self {
self.indexes = true;
self
}
pub fn with_statistics(mut self) -> Self {
self.statistics = true;
self
}
pub fn to_explain_mode(&self) -> ExplainMode {
if self.ai {
ExplainMode::AI
} else if self.analyze && self.why_not {
ExplainMode::Analyze
} else if self.verbose {
ExplainMode::Verbose
} else if self.analyze {
ExplainMode::Verbose
} else {
ExplainMode::Standard
}
}
pub fn to_explain_format(&self) -> ExplainFormat {
match self.format {
ExplainFormatOption::Text => ExplainFormat::Text,
ExplainFormatOption::Json => ExplainFormat::JSON,
ExplainFormatOption::Yaml => ExplainFormat::YAML,
ExplainFormatOption::Tree => ExplainFormat::Tree,
}
}
pub fn has_extended_features(&self) -> bool {
self.storage || self.ai || self.why_not || self.indexes || self.statistics
}
pub fn requires_execution(&self) -> bool {
self.analyze || self.buffers
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum ExplainFormatOption {
#[default]
Text,
Json,
Yaml,
Tree,
}
impl ExplainFormatOption {
pub fn from_str(s: &str) -> Self {
match s.to_uppercase().as_str() {
"JSON" => Self::Json,
"YAML" => Self::Yaml,
"TREE" => Self::Tree,
"XML" => Self::Text, _ => Self::Text,
}
}
pub fn name(&self) -> &'static str {
match self {
Self::Text => "TEXT",
Self::Json => "JSON",
Self::Yaml => "YAML",
Self::Tree => "TREE",
}
}
}
impl std::fmt::Display for ExplainFormatOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_options() {
let opts = ExplainOptions::default();
assert!(!opts.analyze);
assert!(!opts.verbose);
assert!(opts.costs);
assert!(!opts.storage);
assert_eq!(opts.format, ExplainFormatOption::Text);
}
#[test]
fn test_analyze_options() {
let opts = ExplainOptions::analyze();
assert!(opts.analyze);
assert!(opts.timing);
assert!(opts.summary);
}
#[test]
fn test_builder_pattern() {
let opts = ExplainOptions::new()
.with_analyze()
.with_storage()
.with_format(ExplainFormatOption::Json);
assert!(opts.analyze);
assert!(opts.storage);
assert_eq!(opts.format, ExplainFormatOption::Json);
}
#[test]
fn test_to_explain_mode() {
assert_eq!(ExplainOptions::standard().to_explain_mode(), ExplainMode::Standard);
assert_eq!(ExplainOptions::verbose().to_explain_mode(), ExplainMode::Verbose);
let ai_opts = ExplainOptions::new().with_ai();
assert_eq!(ai_opts.to_explain_mode(), ExplainMode::AI);
let analyze_why_not = ExplainOptions::new().with_analyze().with_why_not();
assert_eq!(analyze_why_not.to_explain_mode(), ExplainMode::Analyze);
}
#[test]
fn test_format_from_str() {
assert_eq!(ExplainFormatOption::from_str("json"), ExplainFormatOption::Json);
assert_eq!(ExplainFormatOption::from_str("JSON"), ExplainFormatOption::Json);
assert_eq!(ExplainFormatOption::from_str("yaml"), ExplainFormatOption::Yaml);
assert_eq!(ExplainFormatOption::from_str("tree"), ExplainFormatOption::Tree);
assert_eq!(ExplainFormatOption::from_str("unknown"), ExplainFormatOption::Text);
}
}