1use super::*;
2use crate::{
3 ColumnDefinition,
4 Constant,
5 PrimaryKey,
6 TerminatingList,
7};
8
9#[derive(ParseFromStr, Clone, Debug, TryInto, From, ToTokens, PartialEq)]
10#[parse_via(TaggedDataDefinitionStatement)]
11pub enum DataDefinitionStatement {
12 Use(UseStatement),
13 CreateKeyspace(CreateKeyspaceStatement),
14 AlterKeyspace(AlterKeyspaceStatement),
15 DropKeyspace(DropKeyspaceStatement),
16 CreateTable(CreateTableStatement),
17 AlterTable(AlterTableStatement),
18 DropTable(DropTableStatement),
19 Truncate(TruncateStatement),
20}
21
22impl TryFrom<TaggedDataDefinitionStatement> for DataDefinitionStatement {
23 type Error = anyhow::Error;
24 fn try_from(value: TaggedDataDefinitionStatement) -> Result<Self, Self::Error> {
25 Ok(match value {
26 TaggedDataDefinitionStatement::Use(value) => DataDefinitionStatement::Use(value.try_into()?),
27 TaggedDataDefinitionStatement::CreateKeyspace(value) => {
28 DataDefinitionStatement::CreateKeyspace(value.try_into()?)
29 }
30 TaggedDataDefinitionStatement::AlterKeyspace(value) => {
31 DataDefinitionStatement::AlterKeyspace(value.try_into()?)
32 }
33 TaggedDataDefinitionStatement::DropKeyspace(value) => {
34 DataDefinitionStatement::DropKeyspace(value.try_into()?)
35 }
36 TaggedDataDefinitionStatement::CreateTable(value) => {
37 DataDefinitionStatement::CreateTable(value.try_into()?)
38 }
39 TaggedDataDefinitionStatement::AlterTable(value) => DataDefinitionStatement::AlterTable(value.try_into()?),
40 TaggedDataDefinitionStatement::DropTable(value) => DataDefinitionStatement::DropTable(value.try_into()?),
41 TaggedDataDefinitionStatement::Truncate(value) => DataDefinitionStatement::Truncate(value.try_into()?),
42 })
43 }
44}
45
46#[derive(ParseFromStr, Clone, Debug, TryInto, From, ToTokens, PartialEq)]
47#[tokenize_as(DataDefinitionStatement)]
48pub enum TaggedDataDefinitionStatement {
49 Use(TaggedUseStatement),
50 CreateKeyspace(TaggedCreateKeyspaceStatement),
51 AlterKeyspace(TaggedAlterKeyspaceStatement),
52 DropKeyspace(TaggedDropKeyspaceStatement),
53 CreateTable(TaggedCreateTableStatement),
54 AlterTable(TaggedAlterTableStatement),
55 DropTable(TaggedDropTableStatement),
56 Truncate(TaggedTruncateStatement),
57}
58
59impl Parse for TaggedDataDefinitionStatement {
60 type Output = Self;
61 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
62 Ok(if let Some(keyword) = s.find::<ReservedKeyword>() {
63 match keyword {
64 ReservedKeyword::USE => Self::Use(s.parse()?),
65 ReservedKeyword::CREATE | ReservedKeyword::ALTER | ReservedKeyword::DROP => {
66 if let Some((_, keyword2)) = s.find::<(ReservedKeyword, ReservedKeyword)>() {
67 match (keyword, keyword2) {
68 (ReservedKeyword::CREATE, ReservedKeyword::KEYSPACE) => Self::CreateKeyspace(s.parse()?),
69 (ReservedKeyword::CREATE, ReservedKeyword::TABLE) => Self::CreateTable(s.parse()?),
70 (ReservedKeyword::ALTER, ReservedKeyword::KEYSPACE) => Self::AlterKeyspace(s.parse()?),
71 (ReservedKeyword::ALTER, ReservedKeyword::TABLE) => Self::AlterTable(s.parse()?),
72 (ReservedKeyword::DROP, ReservedKeyword::KEYSPACE) => Self::DropKeyspace(s.parse()?),
73 (ReservedKeyword::DROP, ReservedKeyword::TABLE) => Self::DropTable(s.parse()?),
74 _ => anyhow::bail!("Unexpected keyword following {}: {}", keyword, keyword2),
75 }
76 } else {
77 anyhow::bail!("Unexpected token following {}: {}", keyword, s.info())
78 }
79 }
80 ReservedKeyword::TRUNCATE => Self::Truncate(s.parse()?),
81 _ => anyhow::bail!("Expected a data definition statement, found {}", s.info()),
82 }
83 } else {
84 anyhow::bail!("Expected a data definition statement, found {}", s.info())
85 })
86 }
87}
88
89impl Display for DataDefinitionStatement {
90 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
91 match self {
92 Self::Use(s) => s.fmt(f),
93 Self::CreateKeyspace(s) => s.fmt(f),
94 Self::AlterKeyspace(s) => s.fmt(f),
95 Self::DropKeyspace(s) => s.fmt(f),
96 Self::CreateTable(s) => s.fmt(f),
97 Self::AlterTable(s) => s.fmt(f),
98 Self::DropTable(s) => s.fmt(f),
99 Self::Truncate(s) => s.fmt(f),
100 }
101 }
102}
103
104#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
105#[parse_via(TaggedUseStatement)]
106pub struct UseStatement {
107 pub keyspace: Name,
108}
109
110impl TryFrom<TaggedUseStatement> for UseStatement {
111 type Error = anyhow::Error;
112 fn try_from(value: TaggedUseStatement) -> Result<Self, Self::Error> {
113 Ok(Self {
114 keyspace: value.keyspace.into_value()?,
115 })
116 }
117}
118
119#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
120#[tokenize_as(UseStatement)]
121pub struct TaggedUseStatement {
122 pub keyspace: Tag<Name>,
123}
124
125impl Parse for TaggedUseStatement {
126 type Output = Self;
127 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
128 s.parse::<USE>()?;
129 let keyspace = s.parse()?;
130 s.parse::<Option<Semicolon>>()?;
131 Ok(Self { keyspace })
132 }
133}
134
135impl Display for UseStatement {
136 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
137 write!(f, "USE {}", self.keyspace)
138 }
139}
140
141impl<T: Into<Name>> From<T> for UseStatement {
142 fn from(name: T) -> Self {
143 Self { keyspace: name.into() }
144 }
145}
146
147#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq, Default)]
148#[parse_via(TaggedKeyspaceOpts)]
149pub struct KeyspaceOpts {
150 #[builder(setter(into))]
151 pub replication: Replication,
152 #[builder(setter(strip_option), default)]
153 pub durable_writes: Option<bool>,
154}
155
156impl TryFrom<TaggedKeyspaceOpts> for KeyspaceOpts {
157 type Error = anyhow::Error;
158 fn try_from(value: TaggedKeyspaceOpts) -> Result<Self, Self::Error> {
159 Ok(Self {
160 replication: value.replication.into_value()?.try_into()?,
161 durable_writes: value.durable_writes.map(|v| v.into_value()).transpose()?,
162 })
163 }
164}
165
166#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq, Default)]
167#[tokenize_as(KeyspaceOpts)]
168pub struct TaggedKeyspaceOpts {
169 pub replication: Tag<TaggedReplication>,
170 #[builder(setter(strip_option), default)]
171 pub durable_writes: Option<Tag<bool>>,
172}
173
174impl Parse for TaggedKeyspaceOpts {
175 type Output = Self;
176 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
177 let mut res = TaggedKeyspaceOptsBuilder::default();
178 for TaggedStatementOpt { name, value } in s.parse_from::<List<TaggedStatementOpt, AND>>()? {
179 let (Name::Quoted(n) | Name::Unquoted(n)) = &name;
180 match n.as_str() {
181 "replication" => {
182 if res.replication.is_some() {
183 anyhow::bail!("Duplicate replication option");
184 } else if let TaggedStatementOptValue::Map(m) = value {
185 res.replication(match m {
186 Tag::Tag(t) => Tag::Tag(t),
187 Tag::Value(m) => Tag::Value(TaggedReplication::try_from(m)?),
188 });
189 } else {
190 anyhow::bail!("Invalid replication value: {}", value);
191 }
192 }
193 "durable_writes" => {
194 if res.durable_writes.is_some() {
195 anyhow::bail!("Duplicate durable writes option");
196 } else if let TaggedStatementOptValue::Constant(b) = value {
197 res.durable_writes(match b {
198 Tag::Tag(t) => Tag::Tag(t),
199 Tag::Value(b) => {
200 if let Constant::Boolean(b) = b {
201 Tag::Value(b)
202 } else {
203 anyhow::bail!("Invalid durable writes value: {}", b);
204 }
205 }
206 });
207 } else {
208 anyhow::bail!("Invalid durable writes value: {}", value);
209 }
210 }
211 _ => anyhow::bail!("Invalid table option: {}", name),
212 }
213 }
214 Ok(res
215 .build()
216 .map_err(|e| anyhow::anyhow!("Invalid Keyspace Options: {}", e))?)
217 }
218}
219
220impl Display for KeyspaceOpts {
221 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
222 write!(f, "replication = {}", self.replication)?;
223 if let Some(d) = self.durable_writes {
224 write!(f, " AND durable_writes = {}", d)?;
225 }
226 Ok(())
227 }
228}
229
230#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
231#[parse_via(TaggedCreateKeyspaceStatement)]
232pub struct CreateKeyspaceStatement {
233 #[builder(setter(name = "set_if_not_exists"), default)]
234 pub if_not_exists: bool,
235 #[builder(setter(into))]
236 pub keyspace: Name,
237 pub options: KeyspaceOpts,
238}
239
240impl TryFrom<TaggedCreateKeyspaceStatement> for CreateKeyspaceStatement {
241 type Error = anyhow::Error;
242 fn try_from(value: TaggedCreateKeyspaceStatement) -> Result<Self, Self::Error> {
243 Ok(Self {
244 if_not_exists: value.if_not_exists,
245 keyspace: value.keyspace.into_value()?,
246 options: value.options.into_value()?.try_into()?,
247 })
248 }
249}
250
251#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
252#[tokenize_as(CreateKeyspaceStatement)]
253pub struct TaggedCreateKeyspaceStatement {
254 #[builder(setter(name = "set_if_not_exists"), default)]
255 pub if_not_exists: bool,
256 pub keyspace: Tag<Name>,
257 pub options: Tag<TaggedKeyspaceOpts>,
258}
259
260impl CreateKeyspaceStatementBuilder {
261 pub fn if_not_exists(&mut self) -> &mut Self {
264 self.if_not_exists.replace(true);
265 self
266 }
267}
268
269impl Parse for TaggedCreateKeyspaceStatement {
270 type Output = Self;
271 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
272 s.parse::<(CREATE, KEYSPACE)>()?;
273 let mut res = TaggedCreateKeyspaceStatementBuilder::default();
274 res.set_if_not_exists(s.parse::<Option<(IF, NOT, EXISTS)>>()?.is_some())
275 .keyspace(s.parse()?);
276 s.parse::<WITH>()?;
277 res.options(s.parse()?);
278 s.parse::<Option<Semicolon>>()?;
279 Ok(res
280 .build()
281 .map_err(|e| anyhow::anyhow!("Invalid CREATE KEYSPACE statement: {}", e))?)
282 }
283}
284
285impl Display for CreateKeyspaceStatement {
286 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
287 write!(
288 f,
289 "CREATE KEYSPACE{} {} WITH {}",
290 if self.if_not_exists { " IF NOT EXISTS" } else { "" },
291 self.keyspace,
292 self.options
293 )
294 }
295}
296
297impl KeyspaceOptionsExt for CreateKeyspaceStatement {
298 fn keyspace_opts(&self) -> &KeyspaceOpts {
299 &self.options
300 }
301
302 fn keyspace_opts_mut(&mut self) -> &mut KeyspaceOpts {
303 &mut self.options
304 }
305}
306
307#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
308#[parse_via(TaggedAlterKeyspaceStatement)]
309pub struct AlterKeyspaceStatement {
310 #[builder(setter(into))]
311 pub keyspace: Name,
312 pub options: KeyspaceOpts,
313}
314
315impl TryFrom<TaggedAlterKeyspaceStatement> for AlterKeyspaceStatement {
316 type Error = anyhow::Error;
317 fn try_from(value: TaggedAlterKeyspaceStatement) -> Result<Self, Self::Error> {
318 Ok(Self {
319 keyspace: value.keyspace.into_value()?,
320 options: value.options,
321 })
322 }
323}
324
325#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
326#[tokenize_as(AlterKeyspaceStatement)]
327pub struct TaggedAlterKeyspaceStatement {
328 pub keyspace: Tag<Name>,
329 pub options: KeyspaceOpts,
330}
331
332impl Parse for TaggedAlterKeyspaceStatement {
333 type Output = Self;
334 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
335 s.parse::<(ALTER, KEYSPACE)>()?;
336 let mut res = TaggedAlterKeyspaceStatementBuilder::default();
337 res.keyspace(s.parse()?);
338 s.parse::<WITH>()?;
339 res.options(s.parse()?);
340 s.parse::<Option<Semicolon>>()?;
341 Ok(res
342 .build()
343 .map_err(|e| anyhow::anyhow!("Invalid ALTER KEYSPACE statement: {}", e))?)
344 }
345}
346
347impl Display for AlterKeyspaceStatement {
348 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
349 write!(f, "ALTER KEYSPACE {} WITH {}", self.keyspace, self.options)
350 }
351}
352
353#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
354#[parse_via(TaggedDropKeyspaceStatement)]
355pub struct DropKeyspaceStatement {
356 #[builder(setter(name = "set_if_exists"), default)]
357 pub if_exists: bool,
358 #[builder(setter(into))]
359 pub keyspace: Name,
360}
361
362impl TryFrom<TaggedDropKeyspaceStatement> for DropKeyspaceStatement {
363 type Error = anyhow::Error;
364 fn try_from(value: TaggedDropKeyspaceStatement) -> Result<Self, Self::Error> {
365 Ok(Self {
366 if_exists: value.if_exists,
367 keyspace: value.keyspace.into_value()?,
368 })
369 }
370}
371
372#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
373#[tokenize_as(DropKeyspaceStatement)]
374pub struct TaggedDropKeyspaceStatement {
375 #[builder(setter(name = "set_if_exists"), default)]
376 pub if_exists: bool,
377 pub keyspace: Tag<Name>,
378}
379
380impl DropKeyspaceStatementBuilder {
381 pub fn if_exists(&mut self) -> &mut Self {
384 self.if_exists.replace(true);
385 self
386 }
387}
388
389impl Parse for TaggedDropKeyspaceStatement {
390 type Output = Self;
391 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
392 s.parse::<(DROP, KEYSPACE)>()?;
393 let mut res = TaggedDropKeyspaceStatementBuilder::default();
394 res.set_if_exists(s.parse::<Option<(IF, EXISTS)>>()?.is_some())
395 .keyspace(s.parse()?);
396 s.parse::<Option<Semicolon>>()?;
397 Ok(res
398 .build()
399 .map_err(|e| anyhow::anyhow!("Invalid DROP KEYSPACE statement: {}", e))?)
400 }
401}
402
403impl Display for DropKeyspaceStatement {
404 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
405 write!(
406 f,
407 "DROP KEYSPACE{} {}",
408 if self.if_exists { " IF EXISTS" } else { "" },
409 self.keyspace
410 )
411 }
412}
413
414impl<T: Into<Name>> From<T> for DropKeyspaceStatement {
415 fn from(name: T) -> Self {
416 Self {
417 if_exists: Default::default(),
418 keyspace: name.into(),
419 }
420 }
421}
422
423#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq)]
424#[builder(setter(strip_option), build_fn(validate = "Self::validate"))]
425#[parse_via(TaggedCreateTableStatement)]
426pub struct CreateTableStatement {
427 #[builder(setter(name = "set_if_not_exists"), default)]
428 pub if_not_exists: bool,
429 #[builder(setter(into))]
430 pub table: KeyspaceQualifiedName,
431 pub columns: Vec<ColumnDefinition>,
432 #[builder(setter(into), default)]
433 pub primary_key: Option<PrimaryKey>,
434 #[builder(default)]
435 pub options: Option<TableOpts>,
436}
437
438impl TryFrom<TaggedCreateTableStatement> for CreateTableStatement {
439 type Error = anyhow::Error;
440 fn try_from(value: TaggedCreateTableStatement) -> Result<Self, Self::Error> {
441 Ok(Self {
442 if_not_exists: value.if_not_exists,
443 table: value.table.try_into()?,
444 columns: value.columns,
445 primary_key: value.primary_key,
446 options: value.options.map(|v| v.into_value()).transpose()?,
447 })
448 }
449}
450
451#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq)]
452#[builder(setter(strip_option), build_fn(validate = "Self::validate"))]
453#[tokenize_as(CreateTableStatement)]
454pub struct TaggedCreateTableStatement {
455 #[builder(setter(name = "set_if_not_exists"), default)]
456 pub if_not_exists: bool,
457 pub table: TaggedKeyspaceQualifiedName,
458 pub columns: Vec<ColumnDefinition>,
459 #[builder(default)]
460 pub primary_key: Option<PrimaryKey>,
461 #[builder(default)]
462 pub options: Option<Tag<TableOpts>>,
463}
464
465impl CreateTableStatementBuilder {
466 pub fn if_not_exists(&mut self) -> &mut Self {
469 self.if_not_exists.replace(true);
470 self
471 }
472
473 fn validate(&self) -> Result<(), String> {
474 if self.columns.as_ref().map(|s| s.is_empty()).unwrap_or(false) {
475 return Err("Column definitions cannot be empty".to_string());
476 }
477 Ok(())
478 }
479}
480
481impl TaggedCreateTableStatementBuilder {
482 fn validate(&self) -> Result<(), String> {
483 if self.columns.as_ref().map(|s| s.is_empty()).unwrap_or(false) {
484 return Err("Column definitions cannot be empty".to_string());
485 }
486 Ok(())
487 }
488}
489
490impl Parse for TaggedCreateTableStatement {
491 type Output = Self;
492 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
493 s.parse::<(CREATE, TABLE)>()?;
494 let mut res = TaggedCreateTableStatementBuilder::default();
495 res.set_if_not_exists(s.parse::<Option<(IF, NOT, EXISTS)>>()?.is_some())
496 .table(s.parse()?);
497 s.parse::<LeftParen>()?;
498 res.columns(s.parse_from::<TerminatingList<ColumnDefinition, Comma, (PRIMARY, KEY)>>()?);
499 if let Some(p) = s.parse_from::<If<(PRIMARY, KEY), Parens<PrimaryKey>>>()? {
500 res.primary_key(p);
501 }
502 s.parse::<RightParen>()?;
503 if let Some(p) = s.parse_from::<If<WITH, Tag<TableOpts>>>()? {
504 res.options(p);
505 }
506 s.parse::<Option<Semicolon>>()?;
507 Ok(res
508 .build()
509 .map_err(|e| anyhow::anyhow!("Invalid CREATE TABLE statement: {}", e))?)
510 }
511}
512
513impl Display for CreateTableStatement {
514 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
515 write!(
516 f,
517 "CREATE TABLE{} {} ({}",
518 if self.if_not_exists { " IF NOT EXISTS" } else { "" },
519 self.table,
520 self.columns
521 .iter()
522 .map(|i| i.to_string())
523 .collect::<Vec<_>>()
524 .join(", "),
525 )?;
526 if let Some(ref pk) = self.primary_key {
527 write!(f, ", PRIMARY KEY ({})", pk)?;
528 }
529 write!(f, ")")?;
530 if let Some(ref options) = self.options {
531 write!(f, " WITH {}", options)?;
532 }
533 Ok(())
534 }
535}
536
537impl TableOptionsExt for CreateTableStatement {
538 fn table_opts(&self) -> &Option<TableOpts> {
539 &self.options
540 }
541
542 fn table_opts_mut(&mut self) -> &mut Option<TableOpts> {
543 &mut self.options
544 }
545}
546
547#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq)]
548#[parse_via(TaggedAlterTableStatement)]
549pub struct AlterTableStatement {
550 #[builder(setter(into))]
551 pub table: KeyspaceQualifiedName,
552 pub instruction: AlterTableInstruction,
553}
554
555impl TryFrom<TaggedAlterTableStatement> for AlterTableStatement {
556 type Error = anyhow::Error;
557 fn try_from(value: TaggedAlterTableStatement) -> Result<Self, Self::Error> {
558 Ok(Self {
559 table: value.table.try_into()?,
560 instruction: value.instruction,
561 })
562 }
563}
564
565#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq)]
566#[tokenize_as(AlterTableStatement)]
567pub struct TaggedAlterTableStatement {
568 pub table: TaggedKeyspaceQualifiedName,
569 pub instruction: AlterTableInstruction,
570}
571
572impl Parse for TaggedAlterTableStatement {
573 type Output = Self;
574 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
575 s.parse::<(ALTER, TABLE)>()?;
576 let mut res = TaggedAlterTableStatementBuilder::default();
577 res.table(s.parse()?).instruction(s.parse()?);
578 s.parse::<Option<Semicolon>>()?;
579 Ok(res
580 .build()
581 .map_err(|e| anyhow::anyhow!("Invalid ALTER TABLE statement: {}", e))?)
582 }
583}
584
585impl Display for AlterTableStatement {
586 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
587 write!(f, "ALTER TABLE {} {}", self.table, self.instruction)
588 }
589}
590
591#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq)]
592pub enum AlterTableInstruction {
593 Add(Vec<ColumnDefinition>),
594 Drop(Vec<Name>),
595 Alter(Name, CqlType),
596 With(TableOpts),
597}
598
599impl AlterTableInstruction {
600 pub fn add<T: Into<ColumnDefinition>>(defs: Vec<T>) -> anyhow::Result<Self> {
601 if defs.is_empty() {
602 anyhow::bail!("Column definitions cannot be empty");
603 }
604 Ok(AlterTableInstruction::Add(defs.into_iter().map(|i| i.into()).collect()))
605 }
606
607 pub fn drop<T: Into<Name>>(names: Vec<T>) -> anyhow::Result<Self> {
608 if names.is_empty() {
609 anyhow::bail!("Column names cannot be empty");
610 }
611 Ok(AlterTableInstruction::Drop(
612 names.into_iter().map(|i| i.into()).collect(),
613 ))
614 }
615
616 pub fn alter<N: Into<Name>, T: Into<CqlType>>(name: N, cql_type: T) -> Self {
617 AlterTableInstruction::Alter(name.into(), cql_type.into())
618 }
619
620 pub fn with(opts: TableOpts) -> Self {
621 AlterTableInstruction::With(opts)
622 }
623}
624
625impl Parse for AlterTableInstruction {
626 type Output = Self;
627 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
628 Ok(
629 if s.parse::<Option<ADD>>()?.is_some() || s.check::<ColumnDefinition>() {
630 Self::Add(s.parse_from::<List<ColumnDefinition, Comma>>()?)
631 } else if s.parse::<Option<DROP>>()?.is_some() {
632 if let Some(columns) = s.parse_from::<Option<Parens<List<Name, Comma>>>>()? {
633 Self::Drop(columns)
634 } else {
635 Self::Drop(vec![s.parse()?])
636 }
637 } else if s.parse::<Option<ALTER>>()?.is_some() {
638 let (col, _, ty) = s.parse::<(_, TYPE, _)>()?;
639 Self::Alter(col, ty)
640 } else if s.parse::<Option<WITH>>()?.is_some() {
641 Self::With(s.parse_from::<TableOpts>()?)
642 } else {
643 anyhow::bail!("Expected ALTER TABLE instruction, found {}", s.info());
644 },
645 )
646 }
647}
648
649impl Display for AlterTableInstruction {
650 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
651 match self {
652 Self::Add(cols) => write!(
653 f,
654 "ADD {}",
655 cols.iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
656 ),
657 Self::Drop(cols) => write!(
658 f,
659 "DROP ({})",
660 cols.iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
661 ),
662 Self::Alter(col, ty) => write!(f, "ALTER {} TYPE {}", col, ty),
663 Self::With(options) => write!(f, "WITH {}", options),
664 }
665 }
666}
667
668#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
669#[parse_via(TaggedDropTableStatement)]
670pub struct DropTableStatement {
671 #[builder(setter(name = "set_if_exists"), default)]
672 pub if_exists: bool,
673 #[builder(setter(into))]
674 pub table: KeyspaceQualifiedName,
675}
676
677impl TryFrom<TaggedDropTableStatement> for DropTableStatement {
678 type Error = anyhow::Error;
679 fn try_from(value: TaggedDropTableStatement) -> Result<Self, Self::Error> {
680 Ok(Self {
681 if_exists: value.if_exists,
682 table: value.table.try_into()?,
683 })
684 }
685}
686
687#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
688#[tokenize_as(DropTableStatement)]
689pub struct TaggedDropTableStatement {
690 #[builder(setter(name = "set_if_exists"), default)]
691 pub if_exists: bool,
692 pub table: TaggedKeyspaceQualifiedName,
693}
694
695impl DropTableStatementBuilder {
696 pub fn if_exists(&mut self) -> &mut Self {
699 self.if_exists.replace(true);
700 self
701 }
702}
703
704impl Parse for TaggedDropTableStatement {
705 type Output = Self;
706 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
707 s.parse::<(DROP, TABLE)>()?;
708 let mut res = TaggedDropTableStatementBuilder::default();
709 res.set_if_exists(s.parse::<Option<(IF, EXISTS)>>()?.is_some())
710 .table(s.parse()?);
711 s.parse::<Option<Semicolon>>()?;
712 Ok(res
713 .build()
714 .map_err(|e| anyhow::anyhow!("Invalid DROP TABLE statement: {}", e))?)
715 }
716}
717
718impl Display for DropTableStatement {
719 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
720 write!(
721 f,
722 "DROP TABLE{} {}",
723 if self.if_exists { " IF EXISTS" } else { "" },
724 self.table,
725 )
726 }
727}
728
729impl<T: Into<KeyspaceQualifiedName>> From<T> for DropTableStatement {
730 fn from(name: T) -> Self {
731 Self {
732 if_exists: Default::default(),
733 table: name.into(),
734 }
735 }
736}
737
738#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
739#[parse_via(TaggedTruncateStatement)]
740pub struct TruncateStatement {
741 #[builder(setter(into))]
742 pub table: KeyspaceQualifiedName,
743}
744
745impl TryFrom<TaggedTruncateStatement> for TruncateStatement {
746 type Error = anyhow::Error;
747 fn try_from(value: TaggedTruncateStatement) -> Result<Self, Self::Error> {
748 Ok(Self {
749 table: value.table.try_into()?,
750 })
751 }
752}
753
754#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
755#[tokenize_as(TruncateStatement)]
756pub struct TaggedTruncateStatement {
757 pub table: TaggedKeyspaceQualifiedName,
758}
759
760impl Parse for TaggedTruncateStatement {
761 type Output = Self;
762 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
763 s.parse::<TRUNCATE>()?;
764 let mut res = TaggedTruncateStatementBuilder::default();
765 res.table(s.parse()?);
766 s.parse::<Option<Semicolon>>()?;
767 Ok(res
768 .build()
769 .map_err(|e| anyhow::anyhow!("Invalid TRUNCATE statement: {}", e))?)
770 }
771}
772
773impl Display for TruncateStatement {
774 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
775 write!(f, "TRUNCATE {}", self.table)
776 }
777}
778
779impl<T: Into<KeyspaceQualifiedName>> From<T> for TruncateStatement {
780 fn from(name: T) -> Self {
781 Self { table: name.into() }
782 }
783}
784
785#[cfg(test)]
786mod test {
787 use super::*;
788 use crate::{
789 Compaction,
790 Compression,
791 JavaTimeUnit,
792 KeyspaceQualifyExt,
793 NativeType,
794 Order,
795 SpeculativeRetry,
796 };
797
798 #[test]
799 fn test_parse_create_table() {
800 let mut builder = CreateTableStatementBuilder::default();
801 assert!(builder.build().is_err());
802 builder.table("test");
803 assert!(builder.build().is_err());
804 builder.columns(vec![
805 ("ascii", NativeType::Ascii).into(),
806 ("bigint", NativeType::Bigint).into(),
807 ("blob", NativeType::Blob).into(),
808 ("boolean", NativeType::Boolean).into(),
809 ("counter", NativeType::Counter).into(),
810 ("decimal", NativeType::Decimal).into(),
811 ("double", NativeType::Double).into(),
812 ("duration", NativeType::Duration).into(),
813 ("float", NativeType::Float).into(),
814 ("inet", NativeType::Inet).into(),
815 ("int", NativeType::Int).into(),
816 ("smallint", NativeType::Smallint).into(),
817 ("text", NativeType::Text).into(),
818 ("time", NativeType::Time).into(),
819 ("timestamp", NativeType::Timestamp).into(),
820 ("timeuuid", NativeType::Timeuuid).into(),
821 ("tinyint", NativeType::Tinyint).into(),
822 ("uuid", NativeType::Uuid).into(),
823 ("varchar", NativeType::Varchar).into(),
824 ("varint", NativeType::Varint).into(),
825 ]);
826 let statement = builder.build().unwrap().to_string();
827 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
828 builder.table("test".dot("test"));
829 let statement = builder.build().unwrap().to_string();
830 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
831 builder.primary_key(vec!["tinyint", "int", "bigint"]);
832 let statement = builder.build().unwrap().to_string();
833 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
834 builder.if_not_exists();
835 let statement = builder.build().unwrap().to_string();
836 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
837 let mut opts_builder = crate::TableOptsBuilder::default();
838 assert!(opts_builder.build().is_err());
839 opts_builder.clustering_order(vec![
840 ("tinyint", Order::Ascending).into(),
841 ("int", Order::Descending).into(),
842 ("bigint", Order::Ascending).into(),
843 ]);
844 builder.options(opts_builder.build().unwrap());
845 let statement = builder.build().unwrap().to_string();
846 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
847 opts_builder.comment("test");
848 builder.options(opts_builder.build().unwrap());
849 let statement = builder.build().unwrap().to_string();
850 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
851 opts_builder.compaction(Compaction::size_tiered().enabled(false).build().unwrap().into());
852 builder.options(opts_builder.build().unwrap());
853 let statement = builder.build().unwrap().to_string();
854 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
855 opts_builder.compression(Compression::build().class("LZ4Compressor").build().unwrap());
856 builder.options(opts_builder.build().unwrap());
857 let statement = builder.build().unwrap().to_string();
858 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
859 opts_builder.default_time_to_live(0);
860 builder.options(opts_builder.build().unwrap());
861 let statement = builder.build().unwrap().to_string();
862 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
863 opts_builder.gc_grace_seconds(99999);
864 builder.options(opts_builder.build().unwrap());
865 let statement = builder.build().unwrap().to_string();
866 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
867 opts_builder.memtable_flush_period_in_ms(100);
868 builder.options(opts_builder.build().unwrap());
869 let statement = builder.build().unwrap().to_string();
870 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
871 opts_builder.read_repair(true);
872 builder.options(opts_builder.build().unwrap());
873 let statement = builder.build().unwrap().to_string();
874 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
875 opts_builder.read_repair(false);
876 builder.options(opts_builder.build().unwrap());
877 let statement = builder.build().unwrap().to_string();
878 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
879 opts_builder.speculative_retry(SpeculativeRetry::Percentile(99.0));
880 builder.options(opts_builder.build().unwrap());
881 let statement = builder.build().unwrap().to_string();
882 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
883 }
884
885 #[test]
886 fn test_parse_alter_table() {
887 let mut builder = AlterTableStatementBuilder::default();
888 builder.table("test");
889 assert!(builder.build().is_err());
890 builder.instruction(
891 AlterTableInstruction::add(vec![
892 ("ascii", NativeType::Ascii),
893 ("bigint", NativeType::Bigint),
894 ("blob", NativeType::Blob),
895 ("boolean", NativeType::Boolean),
896 ("counter", NativeType::Counter),
897 ("decimal", NativeType::Decimal),
898 ("double", NativeType::Double),
899 ("duration", NativeType::Duration),
900 ("float", NativeType::Float),
901 ("inet", NativeType::Inet),
902 ("int", NativeType::Int),
903 ("smallint", NativeType::Smallint),
904 ("text", NativeType::Text),
905 ("time", NativeType::Time),
906 ("timestamp", NativeType::Timestamp),
907 ("timeuuid", NativeType::Timeuuid),
908 ("tinyint", NativeType::Tinyint),
909 ("uuid", NativeType::Uuid),
910 ("varchar", NativeType::Varchar),
911 ("varint", NativeType::Varint),
912 ])
913 .unwrap(),
914 );
915 let statement = builder.build().unwrap().to_string();
916 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
917 builder.table("test".dot("test"));
918 let statement = builder.build().unwrap().to_string();
919 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
920 builder.instruction(AlterTableInstruction::alter("ascii", NativeType::Blob));
921 let statement = builder.build().unwrap().to_string();
922 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
923 builder.instruction(AlterTableInstruction::drop(vec!["ascii", "timestamp", "varint"]).unwrap());
924 let statement = builder.build().unwrap().to_string();
925 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
926 let mut opts_builder = crate::TableOptsBuilder::default();
927 assert!(opts_builder.build().is_err());
928 opts_builder
929 .compaction(
930 Compaction::leveled()
931 .enabled(false)
932 .tombstone_threshold(0.99)
933 .tombstone_compaction_interval(10)
934 .sstable_size_in_mb(2)
935 .fanout_size(4)
936 .log_all(true)
937 .unchecked_tombstone_compaction(false)
938 .only_purge_repaired_tombstone(true)
939 .min_threshold(1)
940 .max_threshold(10)
941 .build()
942 .unwrap()
943 .into(),
944 )
945 .compression(
946 Compression::build()
947 .class("java.org.something.MyCompressorClass")
948 .chunk_length_in_kb(10)
949 .crc_check_chance(0.5)
950 .compression_level(1)
951 .enabled(true)
952 .build()
953 .unwrap(),
954 )
955 .default_time_to_live(0)
956 .gc_grace_seconds(99999)
957 .memtable_flush_period_in_ms(100)
958 .read_repair(true)
959 .speculative_retry(SpeculativeRetry::custom("3h30m"));
960 builder.instruction(AlterTableInstruction::with(opts_builder.build().unwrap()));
961 let statement = builder.build().unwrap().to_string();
962 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
963 opts_builder
964 .compaction(
965 Compaction::time_window()
966 .enabled(true)
967 .tombstone_threshold(0.05)
968 .tombstone_compaction_interval(2)
969 .compaction_window_unit(JavaTimeUnit::Days)
970 .compaction_window_size(2)
971 .unsafe_aggressive_sstable_expiration(true)
972 .log_all(false)
973 .unchecked_tombstone_compaction(true)
974 .only_purge_repaired_tombstone(false)
975 .min_threshold(1)
976 .max_threshold(10)
977 .build()
978 .unwrap()
979 .into(),
980 )
981 .read_repair(false)
982 .speculative_retry(SpeculativeRetry::Always);
983 builder.instruction(AlterTableInstruction::with(opts_builder.build().unwrap()));
984 let statement = builder.build().unwrap().to_string();
985 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
986 }
987
988 #[test]
989 fn test_parse_drop_table() {
990 let mut builder = DropTableStatementBuilder::default();
991 builder.table("test");
992 let statement = builder.build().unwrap().to_string();
993 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
994 builder.if_exists().table("test".dot("test"));
995 let statement = builder.build().unwrap().to_string();
996 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
997 }
998
999 #[test]
1000 fn test_parse_create_keyspace() {
1001 let mut builder = CreateKeyspaceStatementBuilder::default();
1002 builder.keyspace("test");
1003 assert!(builder.build().is_err());
1004 builder.if_not_exists();
1005 assert!(builder.build().is_err());
1006 builder.options(
1007 KeyspaceOptsBuilder::default()
1008 .replication(1)
1009 .durable_writes(true)
1010 .build()
1011 .unwrap(),
1012 );
1013 let statement = builder.build().unwrap().to_string();
1014 println!("{}", statement);
1015 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
1016 builder.options(
1017 KeyspaceOptsBuilder::default()
1018 .replication(Replication::network_topology(maplit::btreemap! {
1019 "dc1" => 1,
1020 "dc2" => 2,
1021 }))
1022 .durable_writes(false)
1023 .build()
1024 .unwrap(),
1025 );
1026 let statement = builder.build().unwrap().to_string();
1027 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
1028 }
1029
1030 #[test]
1031 fn test_parse_alter_keyspace() {
1032 let mut builder = AlterKeyspaceStatementBuilder::default();
1033 builder.keyspace("test whitespace");
1034 assert!(builder.build().is_err());
1035 builder.options(KeyspaceOptsBuilder::default().replication(2).build().unwrap());
1036 let statement = builder.build().unwrap().to_string();
1037 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
1038 builder.options(
1039 KeyspaceOptsBuilder::default()
1040 .replication(Replication::network_topology(maplit::btreemap! {
1041 "dc1" => 1,
1042 "dc2" => 2,
1043 }))
1044 .durable_writes(true)
1045 .build()
1046 .unwrap(),
1047 );
1048 let statement = builder.build().unwrap().to_string();
1049 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
1050 }
1051
1052 #[test]
1053 fn test_parse_drop_keyspace() {
1054 let mut builder = DropKeyspaceStatementBuilder::default();
1055 builder.keyspace("test");
1056 let statement = builder.build().unwrap().to_string();
1057 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
1058 builder.if_exists();
1059 let statement = builder.build().unwrap().to_string();
1060 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
1061 }
1062}