Skip to content

Commit

Permalink
elseif support in IfElseStatement
Browse files Browse the repository at this point in the history
  • Loading branch information
gronke committed Oct 14, 2024
1 parent 55ada32 commit 59f612d
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/backend/mysql/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ impl QueryBuilder for MysqlQueryBuilder {
fn insert_default_keyword(&self) -> &str {
"()"
}

/// Prefix of the ELSEIF (MySQL)
fn elseif_keyword_prefix(&self) -> &str {
"ELSE"
}

}

impl MysqlQueryBuilder {
Expand Down
5 changes: 5 additions & 0 deletions src/backend/postgres/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ impl QueryBuilder for PostgresQueryBuilder {
fn if_null_function(&self) -> &str {
"COALESCE"
}

/// Prefix of the ELSIF (Postgres)
fn elseif_keyword_prefix(&self) -> &str {
"ELS"
}
}

fn is_pg_comparison(b: &BinOper) -> bool {
Expand Down
20 changes: 16 additions & 4 deletions src/backend/query_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,16 +393,28 @@ pub trait QueryBuilder:
}
}

/// Prefix of the ELSEIF (MySQL) vs ELSIF (Postgres) keyword
fn elseif_keyword_prefix(&self) -> &str {
panic!("ELSEIF/ELSIF keyword prefix not implemented for this backend");
}

fn prepare_if_else_statement(&self, val: &Box<IfElseStatement>, sql: &mut dyn SqlWriter) {
write!(sql, "IF ").unwrap();
self.prepare_simple_expr(&val.when, sql);
write!(sql, " THEN\n").unwrap();
self.prepare_simple_expr(&val.then, sql);
if let Some(otherwise) = &val.otherwise {
write!(sql, "\nELSE\n").unwrap();
self.prepare_simple_expr(otherwise, sql);
match &val.otherwise {
Some(SimpleExpr::IfElse(value)) => {
write!(sql, "\n{}", self.elseif_keyword_prefix()).unwrap();
self.prepare_if_else_statement(value, sql);
},
Some(otherwise) => {
write!(sql, "\nELSE\n").unwrap();
self.prepare_simple_expr(otherwise, sql);
write!(sql, "\nEND IF").unwrap();
},
None => write!(sql, "\nEND IF").unwrap()
};
write!(sql, "\nEND IF").unwrap();
}

/// Translate [`CaseStatement`] into SQL statement.
Expand Down
4 changes: 4 additions & 0 deletions src/backend/sqlite/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,8 @@ impl QueryBuilder for SqliteQueryBuilder {
// SQLite doesn't support inserting multiple rows with default values
write!(sql, "DEFAULT VALUES").unwrap()
}

fn prepare_if_else_statement(&self, _val: &Box<IfElseStatement>, _sql: &mut dyn SqlWriter) {
panic!("Sqlite doesn't support if-else statements")
}
}
52 changes: 52 additions & 0 deletions tests/mysql/if_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,55 @@ fn if_with_else() {
].join("\n")
)
}

#[test]
fn if_with_elseif() {
let query = Query::select().column(Asterisk).from(Glyph::Table).take();
let then = SimpleExpr::SubQuery(None, Box::new(query.into_sub_query_statement()));
let if_statement = IfElseStatement::new(
Expr::col(Glyph::Id).eq(1),
then,
Some(SimpleExpr::IfElse(Box::new(IfElseStatement::new(
Expr::col(Glyph::Id).eq(2),
Expr::val("42").into(),
None
))))
);
assert_eq!(
if_statement.to_string(MysqlQueryBuilder),
[
"IF `id` = 1 THEN",
"(SELECT * FROM `glyph`)",
"ELSEIF `id` = 2 THEN",
"'42'",
"END IF"
].join("\n")
)
}

#[test]
fn if_with_elseif_and_else() {
let query = Query::select().column(Asterisk).from(Glyph::Table).take();
let then = SimpleExpr::SubQuery(None, Box::new(query.into_sub_query_statement()));
let if_statement = IfElseStatement::new(
Expr::col(Glyph::Id).eq(1),
then,
Some(SimpleExpr::IfElse(Box::new(IfElseStatement::new(
Expr::col(Glyph::Id).eq(2),
Expr::val("42").into(),
Some(Expr::val("9000").into())
))))
);
assert_eq!(
if_statement.to_string(MysqlQueryBuilder),
[
"IF `id` = 1 THEN",
"(SELECT * FROM `glyph`)",
"ELSEIF `id` = 2 THEN",
"'42'",
"ELSE",
"'9000'",
"END IF"
].join("\n")
);
}
67 changes: 67 additions & 0 deletions tests/postgres/if_else.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use super::*;
use pretty_assertions::assert_eq;

#[test]
fn if_without_else() {
let query = Query::select().column(Asterisk).from(Glyph::Table).take();
let then = SimpleExpr::SubQuery(None, Box::new(query.into_sub_query_statement()));
let if_statement = IfElseStatement::new(
Expr::col(Glyph::Id).eq(1),
then,
None
);
assert_eq!(
if_statement.to_string(MysqlQueryBuilder),
[
"IF `id` = 1 THEN",
"(SELECT * FROM `glyph`)",
"END IF"
].join("\n")
)
}

#[test]
fn if_with_else() {
let query = Query::select().column(Asterisk).from(Glyph::Table).take();
let then = SimpleExpr::SubQuery(None, Box::new(query.into_sub_query_statement()));
let if_statement = IfElseStatement::new(
Expr::col(Glyph::Id).eq(1),
then,
Some(Expr::val("23").into())
);
assert_eq!(
if_statement.to_string(PostgresQueryBuilder),
[
"IF \"id\" = 1 THEN",
"(SELECT * FROM \"glyph\")",
"ELSE",
"'23'",
"END IF"
].join("\n")
)
}

#[test]
fn if_with_elseif() {
let query = Query::select().column(Asterisk).from(Glyph::Table).take();
let then = SimpleExpr::SubQuery(None, Box::new(query.into_sub_query_statement()));
let if_statement = IfElseStatement::new(
Expr::col(Glyph::Id).eq(1),
then,
Some(SimpleExpr::IfElse(Box::new(IfElseStatement::new(
Expr::col(Glyph::Id).eq(2),
Expr::val("123").into(),
None
))))
);
assert_eq!(
if_statement.to_string(PostgresQueryBuilder),
[
"IF \"id\" = 1 THEN",
"(SELECT * FROM \"glyph\")",
"ELSIF \"id\" = 2 THEN",
"'123'",
"END IF"
].join("\n")
)
}
1 change: 1 addition & 0 deletions tests/postgres/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod index;
mod query;
mod table;
mod types;
mod if_else;

#[path = "../common.rs"]
mod common;
Expand Down
1 change: 1 addition & 0 deletions tests/sqlite/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod foreign_key;
mod index;
mod query;
mod table;
mod unsupported;

#[path = "../common.rs"]
mod common;
Expand Down
12 changes: 12 additions & 0 deletions tests/sqlite/unsupported.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use super::*;

#[test]
#[should_panic]
fn if_else_statement_is_unsupported() {
let if_statement = IfElseStatement::new(
Expr::col(Glyph::Id).eq(1),
Expr::val("23").into(),
None
);
if_statement.to_string(SqliteQueryBuilder);
}

0 comments on commit 59f612d

Please sign in to comment.