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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use super::super::super::{
	comment::shouldbespace,
	ending,
	error::expected,
	literal::{filters, ident, strand, tokenizer::tokenizers},
	IResult,
};
use crate::sql::Ident;
use crate::sql::{filter::Filter, statements::DefineAnalyzerStatement, Strand, Tokenizer};
use nom::{branch::alt, bytes::complete::tag_no_case, combinator::cut, multi::many0};
use nom::{bytes::complete::tag, combinator::opt, sequence::tuple};

pub fn analyzer(i: &str) -> IResult<&str, DefineAnalyzerStatement> {
	let (i, _) = tag_no_case("ANALYZER")(i)?;
	let (i, if_not_exists) = opt(tuple((
		shouldbespace,
		tag_no_case("IF"),
		shouldbespace,
		tag_no_case("NOT"),
		shouldbespace,
		cut(tag_no_case("EXISTS")),
	)))(i)?;
	let (i, _) = shouldbespace(i)?;
	let (i, name) = cut(ident)(i)?;
	let (i, opts) = many0(analyzer_opts)(i)?;
	let (i, _) = expected("one of FUNCTION, FILTERS, TOKENIZERS, or COMMENT", ending::query)(i)?;
	// Create the base statement
	let mut res = DefineAnalyzerStatement {
		name,
		if_not_exists: if_not_exists.is_some(),
		..Default::default()
	};
	// Assign any defined options
	for opt in opts {
		match opt {
			DefineAnalyzerOption::Function(i) => {
				res.function = Some(i);
			}
			DefineAnalyzerOption::Comment(v) => {
				res.comment = Some(v);
			}
			DefineAnalyzerOption::Filters(v) => {
				res.filters = Some(v);
			}
			DefineAnalyzerOption::Tokenizers(v) => {
				res.tokenizers = Some(v);
			}
		}
	}
	// Return the statement
	Ok((i, res))
}

enum DefineAnalyzerOption {
	Function(Ident),
	Comment(Strand),
	Filters(Vec<Filter>),
	Tokenizers(Vec<Tokenizer>),
}

fn analyzer_opts(i: &str) -> IResult<&str, DefineAnalyzerOption> {
	alt((analyzer_function, analyzer_comment, analyzer_filters, analyzer_tokenizers))(i)
}

fn analyzer_function(i: &str) -> IResult<&str, DefineAnalyzerOption> {
	let (i, _) = shouldbespace(i)?;
	let (i, _) = tag_no_case("FUNCTION")(i)?;
	let (i, _) = shouldbespace(i)?;
	let (i, _) = tag("fn::")(i)?;
	let (i, name) = ident(i)?;
	Ok((i, DefineAnalyzerOption::Function(name)))
}

fn analyzer_comment(i: &str) -> IResult<&str, DefineAnalyzerOption> {
	let (i, _) = shouldbespace(i)?;
	let (i, _) = tag_no_case("COMMENT")(i)?;
	let (i, _) = shouldbespace(i)?;
	let (i, v) = cut(strand)(i)?;
	Ok((i, DefineAnalyzerOption::Comment(v)))
}

fn analyzer_filters(i: &str) -> IResult<&str, DefineAnalyzerOption> {
	let (i, _) = shouldbespace(i)?;
	let (i, _) = tag_no_case("FILTERS")(i)?;
	let (i, _) = shouldbespace(i)?;
	let (i, v) = cut(filters)(i)?;
	Ok((i, DefineAnalyzerOption::Filters(v)))
}

fn analyzer_tokenizers(i: &str) -> IResult<&str, DefineAnalyzerOption> {
	let (i, _) = shouldbespace(i)?;
	let (i, _) = tag_no_case("TOKENIZERS")(i)?;
	let (i, _) = shouldbespace(i)?;
	let (i, v) = cut(tokenizers)(i)?;
	Ok((i, DefineAnalyzerOption::Tokenizers(v)))
}