use serde_json::Value;
use surrealdb::types::RecordId;
pub struct QueryKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Order {
Asc,
Desc,
}
impl QueryKind {
pub fn range(_table: &str, _start: i64, _end: i64) -> String {
"SELECT * FROM type::record($table, $start)..=type::record($table, $end);".to_owned()
}
pub fn replace(_id: RecordId, _data: Value) -> String {
"UPDATE $id REPLACE $data;".to_owned()
}
pub fn pagin(
_table: &str,
_count: i64,
has_cursor: bool,
order: Order,
order_key: &str,
) -> String {
let (than, order_str) = match order {
Order::Asc => (">", "ASC"),
Order::Desc => ("<", "DESC"),
};
if has_cursor {
format!(
"LET $rows = (SELECT *, id AS __page_record, record::id(id) AS __page_public_id FROM $table); SELECT *, __page_public_id AS id FROM $rows WHERE ({page_order_key} {than} $cursor_value OR ({page_order_key} = $cursor_value AND __page_record {than} $cursor_record)) ORDER BY {page_order_key} {order_str}, __page_record {order_str} LIMIT $count;",
page_order_key = order_key
)
} else {
format!(
"LET $rows = (SELECT *, id AS __page_record, record::id(id) AS __page_public_id FROM $table); SELECT *, __page_public_id AS id FROM $rows ORDER BY {page_order_key} {order_str}, __page_record {order_str} LIMIT $count;",
page_order_key = order_key
)
}
}
pub fn rel_pagin(
_in_id: &RecordId,
_table: &str,
_count: i64,
cursor: Option<String>,
order: Order,
_order_key: &str,
) -> String {
let (than, order_str) = match order {
Order::Asc => (">", "ASC"),
Order::Desc => ("<", "DESC"),
};
match cursor {
Some(_) => format!(
"SELECT * FROM $table WHERE [$order_key] {than} $cursor AND in = $in ORDER BY [$order_key] {order_str} LIMIT $count;"
),
None => format!(
"SELECT * FROM $table WHERE in = $in ORDER BY [$order_key] {order_str} LIMIT $count;"
),
}
}
pub fn all_by_order(_table: &str, order: Order, _key: &str) -> String {
match order {
Order::Asc => "SELECT * FROM $table ORDER BY [$key] ASC;".to_owned(),
Order::Desc => "SELECT * FROM $table ORDER BY [$key] DESC;".to_owned(),
}
}
pub fn limit(_table: &str, _count: i64) -> String {
"SELECT * FROM $table LIMIT $count;".to_owned()
}
pub fn insert(_table: &str) -> String {
"INSERT IGNORE INTO $table $data;".to_owned()
}
pub fn insert_or_replace(_table: &str, keys: Vec<String>) -> String {
let mut sql = String::from("INSERT INTO $table $data ON DUPLICATE KEY UPDATE ");
for (idx, key) in keys.iter().enumerate() {
if idx > 0 {
sql.push(',');
}
sql.push_str(key);
sql.push_str("=$input.");
sql.push_str(key);
}
sql.push(';');
sql
}
pub fn upsert_set(id: &str, key: &str, _value: &str) -> String {
let _ = (id, key);
"UPDATE $id SET [$key] = $value;".to_owned()
}
pub fn select_id_single(_table: &str) -> String {
"RETURN (SELECT id FROM ONLY $table WHERE [$k] = $v LIMIT 1).id;".to_owned()
}
pub fn select_id_by_fields(fields: &[String]) -> String {
let where_clause = fields
.iter()
.enumerate()
.map(|(idx, _)| format!("type::field($field_{idx}) = $value_{idx}"))
.collect::<Vec<_>>()
.join(" AND ");
format!("SELECT VALUE id FROM $table WHERE {where_clause} LIMIT 2;")
}
pub fn all_id(_table: &str) -> String {
"RETURN (SELECT id FROM $table).id;".to_owned()
}
pub fn table_has_rows(_table: &str) -> String {
"RETURN count((SELECT VALUE id FROM $table LIMIT 1)) > 0;".to_owned()
}
pub fn single_field(_table: &str, _k: &str) -> String {
"RETURN (SELECT VALUE [$k] FROM $table);".to_owned()
}
pub fn single_field_by_ids(_ids: Vec<RecordId>, _k: &str) -> String {
"RETURN (SELECT VALUE [$k] FROM $ids);".to_owned()
}
pub fn relate(_self_id: &RecordId, _target_id: &RecordId, _rel: &str) -> String {
"INSERT RELATION INTO $rel [{ in: $in, out: $out, created_at: time::now() }] RETURN NONE;"
.to_owned()
}
pub fn unrelate(_self_id: &RecordId, _target_id: &RecordId, _rel: &str) -> String {
"DELETE $rel WHERE in = $in AND out = $out RETURN NONE;".to_owned()
}
pub fn unrelate_all(_self_id: &RecordId, _rel: &str) -> String {
"DELETE $rel WHERE in = $in RETURN NONE;".to_owned()
}
pub fn select_out_ids(_in_id: &RecordId, _rel: &str, _out_table: &str) -> String {
"RETURN (SELECT VALUE out FROM $rel WHERE in = $in AND record::tb(out) = $out_table);"
.to_owned()
}
pub fn select_all_out_ids(_in_id: &RecordId, _rel: &str) -> String {
"RETURN (SELECT VALUE out FROM $rel WHERE in = $in);".to_owned()
}
pub fn select_outgoing_rows(_in_id: &RecordId, _rel: &str, _out_table: &str) -> String {
"LET $ids = (SELECT VALUE out FROM $rel WHERE in = $in AND record::tb(out) = $out_table); SELECT *, record::id(id) AS id FROM $ids;".to_owned()
}
pub fn count_all_outgoing(_in_id: &RecordId, _rel: &str) -> String {
"RETURN count((SELECT VALUE out FROM $rel WHERE in = $in));".to_owned()
}
pub fn count_outgoing_in_table(_in_id: &RecordId, _rel: &str, _out_table: &str) -> String {
"RETURN count((SELECT VALUE out FROM $rel WHERE in = $in AND record::tb(out) = $out_table));"
.to_owned()
}
pub fn select_out_edges(_in_id: &RecordId, _rel: &str) -> String {
"SELECT `in` AS source, out, position FROM $rel WHERE in = $in ORDER BY position ASC;"
.to_owned()
}
pub fn select_in_ids(_out_id: &RecordId, _rel: &str, _in_table: &str) -> String {
"RETURN (SELECT VALUE in FROM $rel WHERE out = $out AND record::tb(in) = $in_table);"
.to_owned()
}
pub fn select_in_edges(_out_id: &RecordId, _rel: &str) -> String {
"SELECT `in` AS source, out, position FROM $rel WHERE out = $out ORDER BY position ASC;"
.to_owned()
}
pub fn select_all_in_ids(_out_id: &RecordId, _rel: &str) -> String {
"RETURN (SELECT VALUE in FROM $rel WHERE out = $out);".to_owned()
}
pub fn select_incoming_rows(_out_id: &RecordId, _rel: &str, _in_table: &str) -> String {
"LET $ids = (SELECT VALUE in FROM $rel WHERE out = $out AND record::tb(in) = $in_table); SELECT *, record::id(id) AS id FROM $ids;".to_owned()
}
pub fn count_all_incoming(_out_id: &RecordId, _rel: &str) -> String {
"RETURN count((SELECT VALUE in FROM $rel WHERE out = $out));".to_owned()
}
pub fn count_incoming_in_table(_out_id: &RecordId, _rel: &str, _in_table: &str) -> String {
"RETURN count((SELECT VALUE in FROM $rel WHERE out = $out AND record::tb(in) = $in_table));"
.to_owned()
}
pub fn rel_id(_self_id: &RecordId, _rel: &str, _target_id: &RecordId) -> String {
"RETURN (SELECT * FROM ONLY $rel WHERE in = $in AND out = $out LIMIT 1).id;".to_owned()
}
pub fn create_return_id(_table: &str) -> String {
"RETURN (CREATE ONLY $table CONTENT $data).id;".to_owned()
}
pub fn delete_record() -> String {
"DELETE $record RETURN NONE;".to_owned()
}
pub fn delete_table() -> String {
"DELETE $table RETURN NONE;".to_owned()
}
pub fn select_by_id() -> String {
"RETURN (SELECT *, record::id(id) AS id FROM ONLY $record);".to_owned()
}
pub fn select_all_with_id() -> String {
"SELECT *, record::id(id) AS id FROM $table;".to_owned()
}
pub fn select_limit_with_id() -> String {
"SELECT *, record::id(id) AS id FROM $table LIMIT $count;".to_owned()
}
}
#[cfg(test)]
#[path = "builder_tests.rs"]
mod tests;