pub mod models;
pub mod schemas;
use sqlx::MySql;
use sqlx::Pool;
use sqlx::QueryBuilder;
use sqlx::Row;
use sqlx_mysql::MySqlRow;
pub use models::*;
pub use schemas::*;
use crate::core::error2::Error;
use crate::core::error2::Result;
pub fn filter_db_record(note: &NoteModel) -> NoteModelResponse {
NoteModelResponse {
id: note.id.to_owned(),
title: note.title.to_owned(),
content: note.content.to_owned(),
category: note.category.to_owned(),
published: note.published != 0,
createdAt: note.created_at.unwrap(),
updatedAt: note.updated_at.unwrap(),
}
}
pub fn filter_db_record2(r: &MySqlRow) -> NoteModelResponse {
let id: String = r.get("id");
let title: String = r.get("title");
let content: String = r.get("content");
let category: Option<String> = r.get("category");
let published: i8 = r.get("published");
let created_at: chrono::DateTime<chrono::Utc> = r.get("createdAt");
let updated_at: chrono::DateTime<chrono::Utc> = r.get("updatedAt");
NoteModelResponse {
id,
title,
content,
category,
published: published != 0,
createdAt: created_at,
updatedAt: updated_at,
}
}
pub async fn select_nodes(
limit: usize,
offset: usize,
pool: &Pool<MySql>,
) -> Result<Vec<NoteModelResponse>> {
let mut query_builder: QueryBuilder<MySql> =
QueryBuilder::new("SELECT * FROM t_notes ORDER by id");
query_builder.push(" LIMIT ");
query_builder.push_bind(limit as i32);
query_builder.push(" OFFSET ");
query_builder.push_bind(offset as i32);
let rows = query_builder.build().fetch_all(pool).await.map_err(|e| {
Error::throw(
"Failed to acquire a mysql connection from the pool",
Some(e),
)
})?;
Ok(rows
.into_iter()
.map(|note| filter_db_record2(¬e))
.collect::<Vec<NoteModelResponse>>())
}
pub async fn select_by_id(note_id: &str, pool: &Pool<MySql>) -> Result<Option<NoteModelResponse>> {
let mut query_builder: QueryBuilder<MySql> =
QueryBuilder::new("SELECT * FROM t_notes WHERE 1=1");
query_builder.push(" id = ");
query_builder.push_bind(note_id);
let query_result = query_builder.build().fetch_one(pool).await;
match query_result {
Ok(note) => Ok(Some(filter_db_record2(¬e))),
Err(sqlx::Error::RowNotFound) => Ok(None),
Err(e) => Err(Error::UnexpectedError(anyhow::anyhow!(e))),
}
}
pub async fn save_note(record: &CreateNoteSchema, pool: &Pool<MySql>) -> Result<String> {
let user_id = uuid::Uuid::now_v7().to_string();
let insert_result =
sqlx::query(r#"INSERT INTO t_notes (id,title,content,category) VALUES (?, ?, ?, ?)"#)
.bind(user_id.clone())
.bind(record.title.to_string())
.bind(record.content.to_string())
.bind(record.category.to_owned())
.execute(pool)
.await
.map_err(|err: sqlx::Error| err.to_string());
if let Err(err) = insert_result {
if err.contains("Duplicate entry") {
return Err(Error::UnexpectedError(anyhow::anyhow!(
"Note with that title already exists"
)));
}
return Err(Error::UnexpectedError(anyhow::anyhow!(err)));
}
Ok(user_id)
}
pub async fn note_update(
note_id: &str,
data: &UpdateNoteSchema,
pool: &Pool<MySql>,
) -> Result<bool> {
let note = select_by_id(note_id, pool).await?;
let note = if let Some(s) = note {
s
} else {
return Ok(false);
};
let published = data.published.unwrap_or(note.published);
let i8_publised = published as i8;
let update_result = sqlx::query(
r#"UPDATE t_notes SET title = ?, content = ?, category = ?, published = ? WHERE id = ?"#,
)
.bind(data.title.to_owned().unwrap_or_else(|| note.title.clone()))
.bind(
data.content
.to_owned()
.unwrap_or_else(|| note.content.clone()),
)
.bind(if let Some(s) = data.category.to_owned() {
Some(s)
} else {
note.category
})
.bind(i8_publised)
.bind(note_id.to_owned())
.execute(pool)
.await;
match update_result {
Ok(result) => {
if result.rows_affected() == 0 {
Ok(false)
} else {
Ok(true)
}
}
Err(e) => {
log::error!("update-note-failed: error={:?}", e);
Ok(false)
}
}
}
pub async fn delete_note_by_id(note_id: &str, pool: &Pool<MySql>) -> Result<bool> {
let mut query_builder: QueryBuilder<MySql> =
QueryBuilder::new(r#""DELETE FROM t_notes WHERE 1=1"#);
query_builder.push(" and id = ");
query_builder.push_bind(note_id);
let query_result = query_builder.build().execute(pool).await;
match query_result {
Ok(result) => {
if result.rows_affected() == 0 {
Ok(false)
} else {
Ok(true)
}
}
Err(e) => {
log::error!("delete-note-failed: error={:?}", e);
Err(Error::throw("delete-note-failed", Some(e)))
}
}
}