1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use std::mem::take;

use ahash::AHashMap;

use crate::cli::formatters::OutputStreamFormatter;
use crate::core::config::FluffConfig;
use crate::core::dialects::init::dialect_selector;
use crate::core::errors::{SQLBaseError, SQLFluffUserError};
use crate::core::linter::linter::Linter;
use crate::core::rules::base::ErasedRule;

pub fn get_simple_config(
    dialect: Option<String>,
    rules: Option<Vec<String>>,
    exclude_rules: Option<Vec<String>>,
    config_path: Option<String>,
) -> Result<FluffConfig, SQLFluffUserError> {
    let mut overrides = AHashMap::new();
    if let Some(dialect) = dialect {
        let selected = dialect_selector(&dialect);
        if selected.is_none() {
            return Err(SQLFluffUserError::new(format!(
                "Error loading dialect '{}': {}",
                dialect, "Dialect not found"
            )));
        }
        overrides.insert("dialect".to_owned(), dialect);
    }
    if let Some(rules) = rules {
        overrides.insert("rules".to_owned(), rules.join(","));
    }
    if let Some(exclude_rules) = exclude_rules {
        overrides.insert("exclude_rules".to_owned(), exclude_rules.join(","));
    }

    FluffConfig::from_root(config_path, true, Some(overrides))
        .map_err(|err| SQLFluffUserError::new(format!("Error loading config: {:?}", err)))
}

pub fn lint(
    sql: String,
    dialect: String,
    rules: Vec<ErasedRule>,
    exclude_rules: Option<Vec<String>>,
    config_path: Option<String>,
) -> Result<Vec<SQLBaseError>, SQLFluffUserError> {
    lint_with_formatter(&sql, dialect, rules, exclude_rules, config_path, None)
}

/// Lint a SQL string.
pub fn lint_with_formatter(
    sql: &str,
    dialect: String,
    rules: Vec<ErasedRule>,
    exclude_rules: Option<Vec<String>>,
    config_path: Option<String>,
    formatter: Option<OutputStreamFormatter>,
) -> Result<Vec<SQLBaseError>, SQLFluffUserError> {
    let cfg = get_simple_config(dialect.into(), None, exclude_rules, config_path)?;

    let mut linter = Linter::new(cfg, None, None);
    linter.formatter = formatter;

    let mut result = linter.lint_string_wrapped(sql, None, None, rules);

    Ok(take(&mut result.paths[0].files[0].violations))
}

pub fn fix(sql: &str, rules: Vec<ErasedRule>) -> String {
    let cfg = get_simple_config(Some("ansi".into()), None, None, None).unwrap();
    let mut linter = Linter::new(cfg, None, None);
    let mut result = linter.lint_string_wrapped(sql, None, Some(true), rules);
    take(&mut result.paths[0].files[0]).fix_string()
}