Skip to content

Commit bf190c0

Browse files
authored
Merge pull request #6 from fmguerreiro/feat/text-search
feat: parse CREATE TEXT SEARCH CONFIGURATION/DICTIONARY/PARSER/TEMPLATE
2 parents a736c67 + 7688828 commit bf190c0

6 files changed

Lines changed: 343 additions & 1 deletion

File tree

src/ast/ddl.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5757,3 +5757,127 @@ impl From<AlterPolicy> for crate::ast::Statement {
57575757
crate::ast::Statement::AlterPolicy(v)
57585758
}
57595759
}
5760+
5761+
/// `CREATE TEXT SEARCH CONFIGURATION` statement.
5762+
///
5763+
/// Note: this is a PostgreSQL-specific statement.
5764+
/// <https://www.postgresql.org/docs/current/sql-createtsconfig.html>
5765+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5766+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5767+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5768+
pub struct CreateTextSearchConfiguration {
5769+
/// Name of the text search configuration being created.
5770+
pub name: ObjectName,
5771+
/// Options list — must include `PARSER = parser_name`.
5772+
pub options: Vec<SqlOption>,
5773+
}
5774+
5775+
impl fmt::Display for CreateTextSearchConfiguration {
5776+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5777+
write!(
5778+
f,
5779+
"CREATE TEXT SEARCH CONFIGURATION {name} ({options})",
5780+
name = self.name,
5781+
options = display_comma_separated(&self.options),
5782+
)
5783+
}
5784+
}
5785+
5786+
impl From<CreateTextSearchConfiguration> for crate::ast::Statement {
5787+
fn from(v: CreateTextSearchConfiguration) -> Self {
5788+
crate::ast::Statement::CreateTextSearchConfiguration(v)
5789+
}
5790+
}
5791+
5792+
/// `CREATE TEXT SEARCH DICTIONARY` statement.
5793+
///
5794+
/// Note: this is a PostgreSQL-specific statement.
5795+
/// <https://www.postgresql.org/docs/current/sql-createtsdictionary.html>
5796+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5797+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5798+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5799+
pub struct CreateTextSearchDictionary {
5800+
/// Name of the text search dictionary being created.
5801+
pub name: ObjectName,
5802+
/// Options list — must include `TEMPLATE = template_name`.
5803+
pub options: Vec<SqlOption>,
5804+
}
5805+
5806+
impl fmt::Display for CreateTextSearchDictionary {
5807+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5808+
write!(
5809+
f,
5810+
"CREATE TEXT SEARCH DICTIONARY {name} ({options})",
5811+
name = self.name,
5812+
options = display_comma_separated(&self.options),
5813+
)
5814+
}
5815+
}
5816+
5817+
impl From<CreateTextSearchDictionary> for crate::ast::Statement {
5818+
fn from(v: CreateTextSearchDictionary) -> Self {
5819+
crate::ast::Statement::CreateTextSearchDictionary(v)
5820+
}
5821+
}
5822+
5823+
/// `CREATE TEXT SEARCH PARSER` statement.
5824+
///
5825+
/// Note: this is a PostgreSQL-specific statement.
5826+
/// <https://www.postgresql.org/docs/current/sql-createtsparser.html>
5827+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5828+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5829+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5830+
pub struct CreateTextSearchParser {
5831+
/// Name of the text search parser being created.
5832+
pub name: ObjectName,
5833+
/// Options list — must include `START`, `GETTOKEN`, `END`, `LEXTYPES` (and optionally `HEADLINE`).
5834+
pub options: Vec<SqlOption>,
5835+
}
5836+
5837+
impl fmt::Display for CreateTextSearchParser {
5838+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5839+
write!(
5840+
f,
5841+
"CREATE TEXT SEARCH PARSER {name} ({options})",
5842+
name = self.name,
5843+
options = display_comma_separated(&self.options),
5844+
)
5845+
}
5846+
}
5847+
5848+
impl From<CreateTextSearchParser> for crate::ast::Statement {
5849+
fn from(v: CreateTextSearchParser) -> Self {
5850+
crate::ast::Statement::CreateTextSearchParser(v)
5851+
}
5852+
}
5853+
5854+
/// `CREATE TEXT SEARCH TEMPLATE` statement.
5855+
///
5856+
/// Note: this is a PostgreSQL-specific statement.
5857+
/// <https://www.postgresql.org/docs/current/sql-createtstemplate.html>
5858+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5859+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5860+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5861+
pub struct CreateTextSearchTemplate {
5862+
/// Name of the text search template being created.
5863+
pub name: ObjectName,
5864+
/// Options list — must include `LEXIZE` (and optionally `INIT`).
5865+
pub options: Vec<SqlOption>,
5866+
}
5867+
5868+
impl fmt::Display for CreateTextSearchTemplate {
5869+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5870+
write!(
5871+
f,
5872+
"CREATE TEXT SEARCH TEMPLATE {name} ({options})",
5873+
name = self.name,
5874+
options = display_comma_separated(&self.options),
5875+
)
5876+
}
5877+
}
5878+
5879+
impl From<CreateTextSearchTemplate> for crate::ast::Statement {
5880+
fn from(v: CreateTextSearchTemplate) -> Self {
5881+
crate::ast::Statement::CreateTextSearchTemplate(v)
5882+
}
5883+
}

src/ast/mod.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ pub use self::ddl::{
7171
ColumnPolicyProperty, ConstraintCharacteristics, CreateCollation, CreateCollationDefinition,
7272
CreateConnector, CreateDomain, CreateExtension, CreateFunction, CreateIndex, CreateOperator,
7373
CreateOperatorClass, CreateOperatorFamily, CreatePolicy, CreatePolicyCommand, CreatePolicyType,
74-
CreateTable, CreateTrigger, CreateView, Deduplicate, DeferrableInitial, DistStyle,
74+
CreateTable, CreateTextSearchConfiguration, CreateTextSearchDictionary, CreateTextSearchParser,
75+
CreateTextSearchTemplate, CreateTrigger, CreateView, Deduplicate, DeferrableInitial, DistStyle,
7576
DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorClass, DropOperatorFamily,
7677
DropOperatorSignature, DropPolicy, DropTrigger, ForValues, FunctionReturnType, GeneratedAs,
7778
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
@@ -3975,6 +3976,30 @@ pub enum Statement {
39753976
/// <https://www.postgresql.org/docs/current/sql-createcollation.html>
39763977
CreateCollation(CreateCollation),
39773978
/// ```sql
3979+
/// CREATE TEXT SEARCH CONFIGURATION name ( PARSER = parser_name )
3980+
/// ```
3981+
/// Note: this is a PostgreSQL-specific statement.
3982+
/// <https://www.postgresql.org/docs/current/sql-createtsconfig.html>
3983+
CreateTextSearchConfiguration(CreateTextSearchConfiguration),
3984+
/// ```sql
3985+
/// CREATE TEXT SEARCH DICTIONARY name ( TEMPLATE = template_name [, option = value, ...] )
3986+
/// ```
3987+
/// Note: this is a PostgreSQL-specific statement.
3988+
/// <https://www.postgresql.org/docs/current/sql-createtsdictionary.html>
3989+
CreateTextSearchDictionary(CreateTextSearchDictionary),
3990+
/// ```sql
3991+
/// CREATE TEXT SEARCH PARSER name ( START = start_fn, GETTOKEN = gettoken_fn, END = end_fn, LEXTYPES = lextypes_fn [, HEADLINE = headline_fn] )
3992+
/// ```
3993+
/// Note: this is a PostgreSQL-specific statement.
3994+
/// <https://www.postgresql.org/docs/current/sql-createtsparser.html>
3995+
CreateTextSearchParser(CreateTextSearchParser),
3996+
/// ```sql
3997+
/// CREATE TEXT SEARCH TEMPLATE name ( [INIT = init_fn,] LEXIZE = lexize_fn )
3998+
/// ```
3999+
/// Note: this is a PostgreSQL-specific statement.
4000+
/// <https://www.postgresql.org/docs/current/sql-createtstemplate.html>
4001+
CreateTextSearchTemplate(CreateTextSearchTemplate),
4002+
/// ```sql
39784003
/// DROP EXTENSION [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]
39794004
/// ```
39804005
/// Note: this is a PostgreSQL-specific statement.
@@ -5457,6 +5482,10 @@ impl fmt::Display for Statement {
54575482
Statement::CreateIndex(create_index) => create_index.fmt(f),
54585483
Statement::CreateExtension(create_extension) => write!(f, "{create_extension}"),
54595484
Statement::CreateCollation(create_collation) => write!(f, "{create_collation}"),
5485+
Statement::CreateTextSearchConfiguration(v) => write!(f, "{v}"),
5486+
Statement::CreateTextSearchDictionary(v) => write!(f, "{v}"),
5487+
Statement::CreateTextSearchParser(v) => write!(f, "{v}"),
5488+
Statement::CreateTextSearchTemplate(v) => write!(f, "{v}"),
54605489
Statement::DropExtension(drop_extension) => write!(f, "{drop_extension}"),
54615490
Statement::DropOperator(drop_operator) => write!(f, "{drop_operator}"),
54625491
Statement::DropOperatorFamily(drop_operator_family) => {

src/ast/spans.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ impl Spanned for Values {
265265
/// - [Statement::Declare]
266266
/// - [Statement::CreateExtension]
267267
/// - [Statement::CreateCollation]
268+
/// - [Statement::CreateTextSearchConfiguration]
269+
/// - [Statement::CreateTextSearchDictionary]
270+
/// - [Statement::CreateTextSearchParser]
271+
/// - [Statement::CreateTextSearchTemplate]
268272
/// - [Statement::AlterCollation]
269273
/// - [Statement::Fetch]
270274
/// - [Statement::Flush]
@@ -380,6 +384,10 @@ impl Spanned for Statement {
380384
Statement::CreateRole(create_role) => create_role.span(),
381385
Statement::CreateExtension(create_extension) => create_extension.span(),
382386
Statement::CreateCollation(create_collation) => create_collation.span(),
387+
Statement::CreateTextSearchConfiguration(_) => Span::empty(),
388+
Statement::CreateTextSearchDictionary(_) => Span::empty(),
389+
Statement::CreateTextSearchParser(_) => Span::empty(),
390+
Statement::CreateTextSearchTemplate(_) => Span::empty(),
383391
Statement::DropExtension(drop_extension) => drop_extension.span(),
384392
Statement::DropOperator(drop_operator) => drop_operator.span(),
385393
Statement::DropOperatorFamily(drop_operator_family) => drop_operator_family.span(),

src/keywords.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ define_keywords!(
244244
COMPRESSION,
245245
COMPUPDATE,
246246
COMPUTE,
247+
CONFIGURATION,
247248
CONCURRENTLY,
248249
CONDITION,
249250
CONFLICT,
@@ -333,6 +334,7 @@ define_keywords!(
333334
DETACH,
334335
DETAIL,
335336
DETERMINISTIC,
337+
DICTIONARY,
336338
DIMENSIONS,
337339
DIRECTORY,
338340
DISABLE,
@@ -765,6 +767,7 @@ define_keywords!(
765767
PARALLEL,
766768
PARAMETER,
767769
PARQUET,
770+
PARSER,
768771
PART,
769772
PARTIAL,
770773
PARTITION,
@@ -1035,6 +1038,7 @@ define_keywords!(
10351038
TASK,
10361039
TBLPROPERTIES,
10371040
TEMP,
1041+
TEMPLATE,
10381042
TEMPORARY,
10391043
TEMPTABLE,
10401044
TERMINATED,

src/parser/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5213,6 +5213,8 @@ impl<'a> Parser<'a> {
52135213
}
52145214
} else if self.parse_keyword(Keyword::SERVER) {
52155215
self.parse_pg_create_server()
5216+
} else if self.parse_keywords(&[Keyword::TEXT, Keyword::SEARCH]) {
5217+
self.parse_create_text_search()
52165218
} else {
52175219
self.expected_ref("an object type after CREATE", self.peek_token_ref())
52185220
}
@@ -8177,6 +8179,49 @@ impl<'a> Parser<'a> {
81778179
})
81788180
}
81798181

8182+
/// Parse a PostgreSQL-specific `CREATE TEXT SEARCH CONFIGURATION | DICTIONARY | PARSER | TEMPLATE` statement.
8183+
pub fn parse_create_text_search(&mut self) -> Result<Statement, ParserError> {
8184+
if self.parse_keyword(Keyword::CONFIGURATION) {
8185+
let name = self.parse_object_name(false)?;
8186+
self.expect_token(&Token::LParen)?;
8187+
let options = self.parse_comma_separated(Parser::parse_sql_option)?;
8188+
self.expect_token(&Token::RParen)?;
8189+
Ok(Statement::CreateTextSearchConfiguration(
8190+
CreateTextSearchConfiguration { name, options },
8191+
))
8192+
} else if self.parse_keyword(Keyword::DICTIONARY) {
8193+
let name = self.parse_object_name(false)?;
8194+
self.expect_token(&Token::LParen)?;
8195+
let options = self.parse_comma_separated(Parser::parse_sql_option)?;
8196+
self.expect_token(&Token::RParen)?;
8197+
Ok(Statement::CreateTextSearchDictionary(
8198+
CreateTextSearchDictionary { name, options },
8199+
))
8200+
} else if self.parse_keyword(Keyword::PARSER) {
8201+
let name = self.parse_object_name(false)?;
8202+
self.expect_token(&Token::LParen)?;
8203+
let options = self.parse_comma_separated(Parser::parse_sql_option)?;
8204+
self.expect_token(&Token::RParen)?;
8205+
Ok(Statement::CreateTextSearchParser(CreateTextSearchParser {
8206+
name,
8207+
options,
8208+
}))
8209+
} else if self.parse_keyword(Keyword::TEMPLATE) {
8210+
let name = self.parse_object_name(false)?;
8211+
self.expect_token(&Token::LParen)?;
8212+
let options = self.parse_comma_separated(Parser::parse_sql_option)?;
8213+
self.expect_token(&Token::RParen)?;
8214+
Ok(Statement::CreateTextSearchTemplate(
8215+
CreateTextSearchTemplate { name, options },
8216+
))
8217+
} else {
8218+
self.expected_ref(
8219+
"CONFIGURATION, DICTIONARY, PARSER, or TEMPLATE after CREATE TEXT SEARCH",
8220+
self.peek_token_ref(),
8221+
)
8222+
}
8223+
}
8224+
81808225
/// Parse a PostgreSQL-specific [Statement::DropExtension] statement.
81818226
pub fn parse_drop_extension(&mut self) -> Result<Statement, ParserError> {
81828227
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);

0 commit comments

Comments
 (0)