Skip to content

Commit

Permalink
Support nested for loop
Browse files Browse the repository at this point in the history
  • Loading branch information
Oyelowo committed Oct 5, 2023
1 parent 7b97fd7 commit a95f11c
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 62 deletions.
144 changes: 111 additions & 33 deletions query-builder/src/statements/for_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,48 @@ impl From<&Param> for ForParam {
}
}

/// A helper function to create a for loop
/// ```
/// use surreal_query_builder as surreal_orm;
/// use surreal_orm::{*, statements::{for_, select, select_value}};
///
/// let ref person_table = Table::from("person");
/// let ref user_name = Field::from("user_name");
///
/// for_!((name in vec!["Oyelowo", "Oyedayo"]) {
/// select(All).from(person_table).where_(user_name.eq(name));
/// select(All).from(person_table).where_(user_name.eq(name));
///
/// for_!((name in select_value(user_name).from_only(person_table)) {
/// select(All).from(person_table).where_(user_name.eq(name));
/// select(All).from(person_table).where_(user_name.eq(name));
/// });
/// });
/// ```
#[macro_export]
macro_rules! for_loop {
(($param:ident in $iterable:expr) { $($stmt:expr;)+ }) => {{
let ref $param = $crate::Param::new(stringify!($param));
$crate::statements::for_($param).in_($iterable).block($crate::block! {
$($stmt;)+
})
}};
(($param:ident IN $iterable:expr) { $($stmt:expr;)+ }) => {{
let ref $param = $crate::Param::new(stringify!($param));
$crate::statements::for_($param).in_($iterable).block($crate::block! {
$($stmt;)+
})
}};
}
pub use for_loop as for_;

// #[macro_export]
// macro_rules! FOR {
// ($param:ident IN $iterable:expr { $($stmt:expr;)+ }) => {{
// macro_rules! for_ {
// ($param:ident in $iterable:expr; $block:block) => {{
// let ref $param = $crate::Param::new(stringify!($param));
// $crate::for_($param).in_($iterable).block($crate::block! {
// $($stmt;)+
// })
// $crate::statements::for_($param).in_($iterable).block($crate::block! { $block })
// }};
// }


/// A helper function to create a for loop
/// ```
/// use surreal_query_builder as surreal_orm;
Expand Down Expand Up @@ -145,7 +176,7 @@ impl Buildable for ForLoopStatement {
.join(", "),
);

query.push_str(" ");
query.push(' ');

match &self.0.flow_type {
FlowType::InIterableData(iterable) => {
Expand All @@ -157,10 +188,11 @@ impl Buildable for ForLoopStatement {
query.push_str(&iterable.build());
}
}
query.push_str(" ");
query.push(' ');
if let Some(block) = &self.0.block {
query.push_str(&block.build());
}
query.push(';');
query
}
}
Expand Down Expand Up @@ -212,9 +244,45 @@ impl fmt::Display for ForLoopStatement {
mod tests {
use super::*;
use crate::{statements::{if_, select::{select, select_value}}, *};

#[test]
fn test_for_macro() {
let ref person_table = Table::from("person");
let ref user_name = Field::from("user_name");

let for_loop = for_!((name in vec!["Oyelowo", "Oyedayo"]) {
select(All).from(person_table).where_(user_name.eq(name));
});

assert_eq!(
for_loop.fine_tune_params(),
"FOR $name IN $_param_00000001 {\nSELECT * FROM person WHERE user_name = $name;\n};"
);
assert_eq!(
for_loop.to_raw().build(),
"FOR $name IN ['Oyelowo', 'Oyedayo'] {\nSELECT * FROM person WHERE user_name = $name;\n};"
);
}

#[test]
fn test_for_in_blockx() {
fn test_for_macro_nested() {
let ref __name = Param::new("name");
let ref person_table = Table::from("person");
let ref user_name = Field::from("user_name");

let for_loop = for_!((__name in vec!["Oyelowo", "Oyedayo"]) {
select(All).from(person_table).where_(user_name.eq(__name));
for_!((__name in vec!["Oyelowo", "Oyedayo"]) {
select(All).from(person_table).where_(user_name.eq(__name));
});
});

insta::assert_snapshot!(for_loop.fine_tune_params());
insta::assert_snapshot!(for_loop.to_raw().build());
}

#[test]
fn test_for_macro_and_block_macro() {
let ref person_table = Table::from("person");
let ref user_name = Field::from("user_name");

Expand All @@ -223,6 +291,10 @@ mod tests {
select(All).from(person_table).where_(user_name.eq(__name));
select(All).from(person_table).where_(user_name.eq(__name));

for_!((__moniker IN select_value(user_name).from(person_table)) {
select(All).from(person_table).where_(user_name.eq(__moniker));
select(All).from(person_table).where_(user_name.eq(__name));
});

for_(__name).in_(vec!["Oyelowo", "Oyedayo"])
.block(block! {
Expand All @@ -243,28 +315,34 @@ mod tests {

if_(__name.eq("Oyelowo")).then(6).end();



};
// IF (__name.eq("Oyelowo")) THEN {
// select(All).from(person_table).where_(user_name.eq(__name));
// select(All).from(person_table).where_(user_name.eq(__name));
// } ELSE IF (__name.eq("Oyelowo")) THEN{
// select(All).from(person_table).where_(user_name.eq(__name));
// select(All).from(person_table).where_(user_name.eq(__name));
// };

for_!((__name in vec!["Oyelowo"]) {
select(All).from(person_table).where_(user_name.eq(__name));
select(All).from(person_table).where_(user_name.eq(__name));

assert_eq!(
for_loop.fine_tune_params(),
"FOR $name IN $_param_00000001 {\nSELECT * FROM person WHERE user_name = $name;\n}"
);
assert_eq!(
for_loop.to_raw().build(),
"FOR $name IN ['Oyelowo', 'Oyedayo'] {\nSELECT * FROM person WHERE user_name = $name;\n}"
);
for_!((__name in vec!["Oyelowo"]) {
select(All).from(person_table).where_(user_name.eq(__name));
select(All).from(person_table).where_(user_name.eq(__name));

for_!((__name in vec!["Oyelowo"]) {
select(All).from(person_table).where_(user_name.eq(__name));
select(All).from(person_table).where_(user_name.eq(__name));
});

for_!((__name in vec!["Oyelowo"]) {
select(All).from(person_table).where_(user_name.eq(__name));
select(All).from(person_table).where_(user_name.eq(__name));
});

});
});

insta::assert_snapshot!(for_loop.fine_tune_params());
insta::assert_snapshot!(for_loop.to_raw().build());
}


#[test]
fn test_for_in_block() {
let ref __name = Param::new("name");
Expand All @@ -277,11 +355,11 @@ mod tests {

assert_eq!(
for_loop.fine_tune_params(),
"FOR $name IN $_param_00000001 {\nSELECT * FROM person WHERE user_name = $name;\n}"
"FOR $name IN $_param_00000001 {\nSELECT * FROM person WHERE user_name = $name;\n};"
);
assert_eq!(
for_loop.to_raw().build(),
"FOR $name IN ['Oyelowo', 'Oyedayo'] {\nSELECT * FROM person WHERE user_name = $name;\n}"
"FOR $name IN ['Oyelowo', 'Oyedayo'] {\nSELECT * FROM person WHERE user_name = $name;\n};"
);
}

Expand All @@ -300,12 +378,12 @@ mod tests {

assert_eq!(
for_loop.fine_tune_params(),
"FOR $name IN $_param_00000001 {\nLET $nick_name = $_param_00000002;\n\nSELECT * FROM person WHERE user_name = $nick_name;\n}"
"FOR $name IN $_param_00000001 {\nLET $nick_name = $_param_00000002;\n\nSELECT * FROM person WHERE user_name = $nick_name;\n};"
);

assert_eq!(
for_loop.to_raw().build(),
"FOR $name IN ['Oyelowo', 'Oyedayo'] {\nLET $nick_name = (SELECT user_name FROM ONLY person WHERE user_name = $name);\n\nSELECT * FROM person WHERE user_name = $nick_name;\n}"
"FOR $name IN ['Oyelowo', 'Oyedayo'] {\nLET $nick_name = (SELECT user_name FROM ONLY person WHERE user_name = $name);\n\nSELECT * FROM person WHERE user_name = $nick_name;\n};"
);
}

Expand All @@ -329,12 +407,12 @@ mod tests {

assert_eq!(
for_loop.fine_tune_params(),
"FOR $name IN $_param_00000001 {\nLET $__nick_name = $_param_00000002;\n\nSELECT * FROM person WHERE user_name = $__nick_name;\n}"
"FOR $name IN $_param_00000001 {\nLET $__nick_name = $_param_00000002;\n\nSELECT * FROM person WHERE user_name = $__nick_name;\n};"
);

assert_eq!(
for_loop.to_raw().build(),
"FOR $name IN (SELECT VALUE user_name FROM person WHERE user_name = $name) {\nLET $__nick_name = (SELECT user_name FROM ONLY person WHERE user_name = $name);\n\nSELECT * FROM person WHERE user_name = $__nick_name;\n}"
"FOR $name IN (SELECT VALUE user_name FROM person WHERE user_name = $name) {\nLET $__nick_name = (SELECT user_name FROM ONLY person WHERE user_name = $name);\n\nSELECT * FROM person WHERE user_name = $__nick_name;\n};"
);
}
}
28 changes: 1 addition & 27 deletions query-builder/src/statements/ifelse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,34 +90,8 @@ pub fn if_(condition: impl Conditional) -> IfStatement {
IfStatement::new(condition)
}

#[macro_export]
macro_rules! if_block {
(if ($condition:expr) then { $($then_body:expr;)+ } $(else if ($elif_condition:expr) then { $($elif_body:expr;)+ })* $(else { $($else_body:expr;)+ })?) => {
{
let mut __statements: ::std::vec::Vec<$crate::statements::utils::Chainable> = ::std::vec::Vec::new();

let if_condition = $crate::statements::if_($condition);
let if_block = $crate::block! { $($then_body;)+ };
__statements.push(if_condition.then(if_block).into());

$(
let elif_condition = $crate::statements::if_($elif_condition);
let elif_block = $crate::block! { $($elif_body;)+ };
__statements.push(elif_condition.else_if(elif_block).into());
)*

$(
let else_block = $crate::block! { $($else_body;)+ };
__statements.push(else_block.into());
)?

$crate::statements::utils::QueryChain::from(__statements)
}
};
}

#[derive(Debug, Clone)]
pub struct IfElseExpression(Expression);
struct IfElseExpression(Expression);

impl From<Expression> for IfElseExpression {
fn from(value: Expression) -> Self {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
source: query-builder/src/statements/for_loop.rs
expression: for_loop.to_raw().build()
---
FOR $__name IN ['Oyelowo', 'Oyedayo'] {
SELECT * FROM person WHERE user_name = $__name;

SELECT * FROM person WHERE user_name = $__name;

FOR $__moniker IN (SELECT VALUE user_name FROM person) {
SELECT * FROM person WHERE user_name = $__moniker;

SELECT * FROM person WHERE user_name = $__name;
};

FOR $__name IN ['Oyelowo', 'Oyedayo'] {
SELECT * FROM person WHERE user_name = $__name;
};
};

FOR $__name IN ['Oyelowo', 'Oyedayo'] {
SELECT * FROM person WHERE user_name = $__name;

SELECT * FROM person WHERE user_name = $__name;
};

FOR $__name IN ['Oyelowo', 'Oyedayo'] {
SELECT * FROM person WHERE user_name = $__name;

SELECT * FROM person WHERE user_name = $__name;
};

IF $__name = 'Oyelowo' THEN
6
END
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
source: query-builder/src/statements/for_loop.rs
expression: for_loop.fine_tune_params()
---
FOR $__name IN $_param_00000001 {
SELECT * FROM person WHERE user_name = $__name;

SELECT * FROM person WHERE user_name = $__name;

FOR $__moniker IN $_param_00000002 {
SELECT * FROM person WHERE user_name = $__moniker;

SELECT * FROM person WHERE user_name = $__name;
};

FOR $__name IN $_param_00000003 {
SELECT * FROM person WHERE user_name = $__name;
};
};

FOR $__name IN $_param_00000004 {
SELECT * FROM person WHERE user_name = $__name;

SELECT * FROM person WHERE user_name = $__name;
};

FOR $__name IN $_param_00000005 {
SELECT * FROM person WHERE user_name = $__name;

SELECT * FROM person WHERE user_name = $__name;
};

IF $__name = $_param_00000006 THEN
$_param_00000007
END
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: query-builder/src/statements/for_loop.rs
expression: for_loop.to_raw().build()
---
FOR $__name IN ['Oyelowo', 'Oyedayo'] {
SELECT * FROM person WHERE user_name = $__name;

FOR $__name IN ['Oyelowo', 'Oyedayo'] {
SELECT * FROM person WHERE user_name = $__name;
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: query-builder/src/statements/for_loop.rs
expression: for_loop.fine_tune_params()
---
FOR $__name IN $_param_00000001 {
SELECT * FROM person WHERE user_name = $__name;

FOR $__name IN $_param_00000002 {
SELECT * FROM person WHERE user_name = $__name;
};
};
2 changes: 0 additions & 2 deletions query-builder/src/statements/utils_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,6 @@ macro_rules! block_inner {
let ref $param = $crate::Param::new(stringify!($param));
let for_loop = $crate::statements::for_($param).in_($iterable).block($crate::block! { $($stmt;)+ });

// let mut __statements: ::std::vec::Vec<$crate::statements::utils::Chainable> = ::std::vec::Vec::new();
$statements.push(for_loop.into());
$crate::block_inner!($statements; $($rest)*);
}};
Expand All @@ -416,7 +415,6 @@ macro_rules! block_inner {
let ref $param = $crate::Param::new(stringify!($param));
let for_loop = $crate::statements::for_($param).in_($iterable).block($crate::block! { $($stmt;)+ });

// let mut __statements: ::std::vec::Vec<$crate::statements::utils::Chainable> = ::std::vec::Vec::new();
$statements.push(for_loop.clone().into());
$crate::block_inner!($statements; $($rest)*);
}};
Expand Down

0 comments on commit a95f11c

Please sign in to comment.