Compare commits
3 commits
54889bdf89
...
eb3445d64c
Author | SHA1 | Date | |
---|---|---|---|
eb3445d64c | |||
221a740c96 | |||
f74d2c3905 |
25 changed files with 578 additions and 47 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
@ -105,13 +105,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.83"
|
||||
version = "0.1.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -237,9 +237,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.6"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
|
||||
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
@ -390,7 +390,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version 0.4.1",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -412,7 +412,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -552,7 +552,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -885,7 +885,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1215,9 +1215,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
|||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -1584,7 +1584,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1789,9 +1789,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.93"
|
||||
version = "2.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
|
||||
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1812,7 +1812,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1865,7 +1865,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1949,7 +1949,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2013,7 +2013,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2253,7 +2253,7 @@ dependencies = [
|
|||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2288,7 +2288,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -2583,7 +2583,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
@ -2618,7 +2618,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2638,7 +2638,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
@ -2661,5 +2661,9 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zou"
|
||||
version = "0.1.0"
|
||||
|
|
28
Cargo.toml
28
Cargo.toml
|
@ -1,24 +1,8 @@
|
|||
[package]
|
||||
name = "yorokobot"
|
||||
description = "Discord bot implementing a topic management system"
|
||||
version = "0.2.1"
|
||||
authors = [ "Victor Mignot <dala@dalaran.fr>" ]
|
||||
license = "EUPL-1.2"
|
||||
readme = "README.md"
|
||||
repository = "https://git.dalaran.fr/dala/yorokobot"
|
||||
edition = "2021"
|
||||
[workspace]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
serenity = { version="0.11", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "collector" ] }
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||
mongodb = { version = "2.3.0", default-features = false, features = ["tokio-runtime"] }
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
log = "0.4.17"
|
||||
futures = "0.3.25"
|
||||
env_logger = "0.11.6"
|
||||
|
||||
[lints.rust]
|
||||
unsafe_code= "forbid"
|
||||
missing_docs = "forbid"
|
||||
members = [
|
||||
"yorokobot",
|
||||
"zou"
|
||||
]
|
||||
|
|
24
yorokobot/Cargo.toml
Normal file
24
yorokobot/Cargo.toml
Normal file
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "yorokobot"
|
||||
description = "Discord bot implementing a topic management system"
|
||||
version = "0.2.1"
|
||||
authors = [ "Victor Mignot <dala@dalaran.fr>" ]
|
||||
license = "EUPL-1.2"
|
||||
readme = "README.md"
|
||||
repository = "https://git.dalaran.fr/dala/yorokobot"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serenity = { version="0.11", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "collector" ] }
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||
mongodb = { version = "2.3.0", default-features = false, features = ["tokio-runtime"] }
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
log = "0.4.17"
|
||||
futures = "0.3.25"
|
||||
env_logger = "0.11.6"
|
||||
|
||||
[lints.rust]
|
||||
unsafe_code= "forbid"
|
||||
missing_docs = "forbid"
|
|
@ -8,7 +8,7 @@ pub fn get_env_variable(var_name: &str) -> String {
|
|||
match env::var(var_name) {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
error!(target: "bot_warn_errors", "Failed to fetch the {} environment variable.", var_name);
|
||||
error!("Failed to fetch the {} environment variable.", var_name);
|
||||
panic!("Exiting...");
|
||||
}
|
||||
}
|
6
zou/Cargo.toml
Normal file
6
zou/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "zou"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
513
zou/src/lib.rs
Normal file
513
zou/src/lib.rs
Normal file
|
@ -0,0 +1,513 @@
|
|||
pub trait ObjectModel: Sized {
|
||||
fn table_name() -> &'static str;
|
||||
}
|
||||
|
||||
enum QueryOperation {
|
||||
Select,
|
||||
}
|
||||
|
||||
impl QueryOperation {
|
||||
fn format(&self) -> &'static str {
|
||||
match self {
|
||||
QueryOperation::Select => "SELECT $f FROM $t $j $w $o;",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Operand = String;
|
||||
|
||||
enum Filter {
|
||||
Equal {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
Greater {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
Less {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
GreaterOrEqual {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
LessOrEqual {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
NotEqual {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
And {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
Or {
|
||||
op1: Operand,
|
||||
op2: Operand,
|
||||
},
|
||||
In {
|
||||
value: Operand,
|
||||
valid_range: Vec<Operand>,
|
||||
},
|
||||
Between {
|
||||
value: Operand,
|
||||
lower: Operand,
|
||||
upper: Operand,
|
||||
},
|
||||
Like {
|
||||
value: Operand,
|
||||
pattern: Operand,
|
||||
},
|
||||
IsNull {
|
||||
value: Operand,
|
||||
},
|
||||
IsNotNull {
|
||||
value: Operand,
|
||||
},
|
||||
Not {
|
||||
op: Operand,
|
||||
},
|
||||
}
|
||||
|
||||
impl ToString for Filter {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Filter::Equal { op1, op2 } => format!("{} = {}", op1.to_string(), op2.to_string()),
|
||||
Filter::Greater { op1, op2 } => format!("{} > {}", op1.to_string(), op2.to_string()),
|
||||
Filter::Less { op1, op2 } => format!("{} < {}", op1.to_string(), op2.to_string()),
|
||||
Filter::GreaterOrEqual { op1, op2 } => {
|
||||
format!("{} >= {}", op1.to_string(), op2.to_string())
|
||||
}
|
||||
Filter::LessOrEqual { op1, op2 } => {
|
||||
format!("{} <= {}", op1.to_string(), op2.to_string())
|
||||
}
|
||||
Filter::NotEqual { op1, op2 } => format!("{} != {}", op1.to_string(), op2.to_string()),
|
||||
Filter::And { op1, op2 } => format!("{} AND {}", op1.to_string(), op2.to_string()),
|
||||
Filter::Or { op1, op2 } => format!("{} OR {}", op1.to_string(), op2.to_string()),
|
||||
Filter::In { value, valid_range } => {
|
||||
let mut formatted_range: String = "(".to_string();
|
||||
|
||||
for element in valid_range {
|
||||
formatted_range.push_str(&element.to_string());
|
||||
formatted_range.push(',');
|
||||
}
|
||||
|
||||
formatted_range.pop();
|
||||
formatted_range.push(')');
|
||||
format!("{} in {formatted_range}", value.to_string())
|
||||
}
|
||||
Filter::Between {
|
||||
value,
|
||||
lower,
|
||||
upper,
|
||||
} => format!(
|
||||
"{} BETWEEN {} AND {}",
|
||||
value.to_string(),
|
||||
lower.to_string(),
|
||||
upper.to_string()
|
||||
),
|
||||
Filter::Like { value, pattern } => {
|
||||
format!("{} LIKE {}", value.to_string(), pattern.to_string())
|
||||
}
|
||||
Filter::IsNull { value } => format!("{} IS NULL", value.to_string()),
|
||||
Filter::IsNotNull { value } => format!("{} IS NOT NULL", value.to_string()),
|
||||
Filter::Not { op } => format!("NOT {}", op.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FilterData(Option<Filter>);
|
||||
impl FilterData {
|
||||
fn new() -> Self {
|
||||
FilterData(None)
|
||||
}
|
||||
|
||||
pub fn equal<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::Equal {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn greater<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::Greater {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn less<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::Less {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn greater_or_equal<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::GreaterOrEqual {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn less_or_equal<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::LessOrEqual {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn not_equal<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::NotEqual {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn and<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::And {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn or<T: ToString>(mut self, op1: T, op2: T) -> Self {
|
||||
self.0 = Some(Filter::Or {
|
||||
op1: op1.to_string(),
|
||||
op2: op2.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn in_values<T: ToString>(mut self, value: T, valid_values: Vec<T>) -> Self {
|
||||
self.0 = Some(Filter::In {
|
||||
value: value.to_string(),
|
||||
valid_range: valid_values.iter().map(|v| v.to_string()).collect(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn between<T: ToString>(mut self, value: T, lower: T, upper: T) -> Self {
|
||||
self.0 = Some(Filter::Between {
|
||||
value: value.to_string(),
|
||||
lower: lower.to_string(),
|
||||
upper: upper.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn like<T: ToString>(mut self, value: T, pattern: String) -> Self {
|
||||
self.0 = Some(Filter::Like {
|
||||
value: value.to_string(),
|
||||
pattern,
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_null<T: ToString>(mut self, value: T) -> Self {
|
||||
self.0 = Some(Filter::IsNull {
|
||||
value: value.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_not_null<T: ToString>(mut self, value: T) -> Self {
|
||||
self.0 = Some(Filter::IsNotNull {
|
||||
value: value.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn not<T: ToString>(mut self, value: T) -> Self {
|
||||
self.0 = Some(Filter::IsNotNull {
|
||||
value: value.to_string(),
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
enum Order {
|
||||
Asc,
|
||||
Desc,
|
||||
}
|
||||
|
||||
impl ToString for Order {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Order::Asc => "ASC",
|
||||
Order::Desc => "DESC",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
struct OrderingClause {
|
||||
field: String,
|
||||
order: Order,
|
||||
}
|
||||
|
||||
impl ToString for OrderingClause {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{} {}", self.field, self.order.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
enum JoinKind {
|
||||
Inner,
|
||||
Left,
|
||||
Right,
|
||||
Full,
|
||||
}
|
||||
|
||||
impl ToString for JoinKind {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
JoinKind::Inner => "INNER JOIN",
|
||||
JoinKind::Left => "LEFT JOIN",
|
||||
JoinKind::Right => "RIGHT JOIN",
|
||||
JoinKind::Full => "FULL JOIN",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
struct Join {
|
||||
kind: JoinKind,
|
||||
dest_table: String,
|
||||
join_columns: (String, String),
|
||||
}
|
||||
|
||||
impl ToString for Join {
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
" {} {} ON {} = {}",
|
||||
self.kind.to_string(),
|
||||
self.dest_table,
|
||||
self.join_columns.0,
|
||||
self.join_columns.1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct Query {
|
||||
operation: QueryOperation,
|
||||
table: String,
|
||||
filter: Option<Filter>,
|
||||
ordering: Vec<OrderingClause>,
|
||||
join: Option<Join>,
|
||||
}
|
||||
|
||||
impl Query {
|
||||
pub fn new<T: ObjectModel>(operation: QueryOperation) -> Self {
|
||||
Query {
|
||||
operation,
|
||||
table: T::table_name().to_string(),
|
||||
filter: None,
|
||||
ordering: vec![],
|
||||
join: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filter<F: FnOnce(FilterData) -> FilterData>(mut self, filter_data_callback: F) -> Self {
|
||||
let filter_data = FilterData::new();
|
||||
self.filter = filter_data_callback(filter_data).0;
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn order(mut self, field: String, order: Order) -> Self {
|
||||
self.ordering.push(OrderingClause { field, order });
|
||||
self
|
||||
}
|
||||
|
||||
pub fn join(
|
||||
mut self,
|
||||
kind: JoinKind,
|
||||
dest_table: String,
|
||||
join_columns: (String, String),
|
||||
) -> Self {
|
||||
self.join = Some(Join {
|
||||
kind,
|
||||
dest_table,
|
||||
join_columns,
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> String {
|
||||
let where_clause = if let Some(f) = self.filter {
|
||||
format!("WHERE {}", f.to_string())
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let order_clause = if self.ordering.len() != 0 {
|
||||
let mut clause_str = String::from(" ORDER BY ");
|
||||
|
||||
for o in self.ordering {
|
||||
clause_str.push_str(&o.to_string());
|
||||
clause_str.push(',');
|
||||
clause_str.push(' ');
|
||||
}
|
||||
|
||||
clause_str.pop();
|
||||
clause_str.pop();
|
||||
|
||||
clause_str
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let join_clause = if let Some(j) = self.join {
|
||||
j.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
self.operation
|
||||
.format()
|
||||
.replace("$f", "*")
|
||||
.replace("$t", &self.table)
|
||||
.replace(" $j", &join_clause)
|
||||
.replace(" $w", &where_clause)
|
||||
.replace(" $o", &order_clause)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ObjectModel;
|
||||
|
||||
use super::Query;
|
||||
|
||||
struct TestModel;
|
||||
impl ObjectModel for TestModel {
|
||||
fn table_name() -> &'static str {
|
||||
"test_objects"
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_all() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select).build();
|
||||
|
||||
assert_eq!(query, "SELECT * FROM test_objects;")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_join_inner() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select)
|
||||
.join(
|
||||
crate::JoinKind::Inner,
|
||||
"test_join".to_owned(),
|
||||
("a".to_owned(), "b".to_owned()),
|
||||
)
|
||||
.build();
|
||||
|
||||
assert_eq!(
|
||||
query,
|
||||
"SELECT * FROM test_objects INNER JOIN test_join ON a = b;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_join_left() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select)
|
||||
.join(
|
||||
crate::JoinKind::Left,
|
||||
"test_join".to_owned(),
|
||||
("a".to_owned(), "b".to_owned()),
|
||||
)
|
||||
.build();
|
||||
|
||||
assert_eq!(
|
||||
query,
|
||||
"SELECT * FROM test_objects LEFT JOIN test_join ON a = b;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_join_right() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select)
|
||||
.join(
|
||||
crate::JoinKind::Right,
|
||||
"test_join".to_owned(),
|
||||
("a".to_owned(), "b".to_owned()),
|
||||
)
|
||||
.build();
|
||||
|
||||
assert_eq!(
|
||||
query,
|
||||
"SELECT * FROM test_objects RIGHT JOIN test_join ON a = b;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_join_full() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select)
|
||||
.join(
|
||||
crate::JoinKind::Full,
|
||||
"test_join".to_owned(),
|
||||
("a".to_owned(), "b".to_owned()),
|
||||
)
|
||||
.build();
|
||||
|
||||
assert_eq!(
|
||||
query,
|
||||
"SELECT * FROM test_objects FULL JOIN test_join ON a = b;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_ordering_single_asc() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select)
|
||||
.order("a".to_owned(), crate::Order::Asc)
|
||||
.build();
|
||||
|
||||
assert_eq!(query, "SELECT * FROM test_objects ORDER BY a ASC;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_ordering_single_desc() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select)
|
||||
.order("a".to_owned(), crate::Order::Desc)
|
||||
.build();
|
||||
|
||||
assert_eq!(query, "SELECT * FROM test_objects ORDER BY a DESC;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_ordering_multiple() {
|
||||
let query = Query::new::<TestModel>(super::QueryOperation::Select)
|
||||
.order("a".to_owned(), crate::Order::Desc)
|
||||
.order("b".to_owned(), crate::Order::Asc)
|
||||
.build();
|
||||
|
||||
assert_eq!(query, "SELECT * FROM test_objects ORDER BY a DESC, b ASC;");
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue