use sqlx::query! macro

This commit is contained in:
Greg Shuflin 2025-02-05 02:40:23 -08:00
parent c89ee29d4d
commit 3cb122306a
4 changed files with 106 additions and 62 deletions

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "DELETE FROM users WHERE id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a"
}

View File

@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "\n SELECT COUNT(*) as \"count!: i32\"\n FROM users\n ",
"describe": {
"columns": [
{
"name": "count!: i32",
"ordinal": 0,
"type_info": "Int"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false
]
},
"hash": "b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin) \n VALUES (?, ?, ?, ?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 7
},
"nullable": []
},
"hash": "bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8"
}

View File

@ -45,19 +45,22 @@ impl User {
where
E: sqlx::Executor<'a, Database = sqlx::Sqlite>,
{
sqlx::query(
let id_str = self.id.to_string();
let created_at_str = self.created_at.to_rfc3339();
sqlx::query!(
r#"
INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
VALUES (?, ?, ?, ?, ?, ?, ?)
"#,
id_str,
self.username,
self.password_hash,
self.email,
self.display_name,
created_at_str,
self.admin
)
.bind(self.id.to_string())
.bind(self.username.clone())
.bind(self.password_hash.clone())
.bind(self.email.clone())
.bind(self.display_name.clone())
.bind(self.created_at.to_rfc3339())
.bind(self.admin)
.execute(executor)
.await?;
@ -173,12 +176,15 @@ pub async fn delete_user(mut db: Connection<Db>, user_id: &str) -> Status {
Err(_) => return Status::BadRequest,
};
let query = sqlx::query("DELETE FROM users WHERE id = ?")
.bind(uuid.to_string())
.execute(&mut **db)
.await;
let id_str = uuid.to_string();
let result = sqlx::query!(
"DELETE FROM users WHERE id = ?",
id_str
)
.execute(&mut **db)
.await;
match query {
match result {
Ok(result) => {
if result.rows_affected() > 0 {
Status::NoContent
@ -201,6 +207,7 @@ pub async fn login(
sessions: &State<SessionStore>,
) -> Result<Json<LoginResponse>, Status> {
let creds = credentials.into_inner();
let username = creds.username.clone();
// Find user by username
let user = sqlx::query!(
@ -212,7 +219,7 @@ pub async fn login(
FROM users
WHERE username = ?
"#,
creds.username
username
)
.fetch_optional(&mut **db)
.await
@ -300,19 +307,21 @@ impl<'r> rocket::request::FromRequest<'r> for AuthenticatedUser {
#[get("/setup")]
pub async fn setup_page(mut db: Connection<Db>) -> Result<Template, Status> {
// Check if any users exist
let count = sqlx::query!("SELECT COUNT(*) as count FROM users")
.fetch_one(&mut **db)
.await
.map_err(|_| Status::InternalServerError)?
.count;
let count = sqlx::query!(
r#"
SELECT COUNT(*) as "count!: i32"
FROM users
"#
)
.fetch_one(&mut **db)
.await
.map_err(|_| Status::InternalServerError)?;
if count > 0 {
// If users exist, redirect to login
Err(Status::SeeOther)
} else {
// Show setup page
Ok(Template::render("setup", context! {}))
if count.count > 0 {
return Err(Status::Forbidden);
}
Ok(Template::render("setup", context! {}))
}
#[post("/setup", data = "<new_user>")]
@ -320,33 +329,33 @@ pub async fn setup(
mut db: Connection<Db>,
new_user: Json<NewUser>,
) -> Result<Status, Json<SetupError>> {
let new_user = new_user.into_inner();
// Check if any users exist
let count = sqlx::query!("SELECT COUNT(*) as count FROM users")
.fetch_one(&mut **db)
.await
.map_err(|e| {
eprintln!("Database error: {}", e);
Json(SetupError {
error: "Internal server error".to_string(),
})
})?
.count;
let count = sqlx::query!(
r#"
SELECT COUNT(*) as "count!: i32"
FROM users
"#
)
.fetch_one(&mut **db)
.await
.map_err(|_| {
Json(SetupError {
error: "Database error".to_string(),
})
})?;
if count > 0 {
if count.count > 0 {
return Err(Json(SetupError {
error: "Setup has already been completed".to_string(),
error: "Setup already completed".to_string(),
}));
}
let password = new_user.password.as_bytes();
let new_user = new_user.into_inner();
// Hash the password
let password_hash = bcrypt::hash(password, bcrypt::DEFAULT_COST).map_err(|e| {
eprintln!("Password hashing error: {}", e);
// Hash the password - we'll use bcrypt
let password_hash = bcrypt::hash(new_user.password.as_bytes(), bcrypt::DEFAULT_COST).map_err(|_| {
Json(SetupError {
error: "Failed to process password".to_string(),
error: "Failed to hash password".to_string(),
})
})?;
@ -356,22 +365,13 @@ pub async fn setup(
new_user.email,
new_user.display_name,
);
user.admin = true; // This is an admin user
user.admin = true;
match user.write_to_database(&mut **db).await {
Ok(_) => Ok(Status::Created),
Err(e) => {
error!("Database error: {}", e);
match e {
sqlx::Error::Database(db_err) if db_err.is_unique_violation() => {
Err(Json(SetupError {
error: "Username already exists".to_string(),
}))
}
_ => Err(Json(SetupError {
error: "Failed to create user".to_string(),
})),
}
}
}
user.write_to_database(&mut **db)
.await
.map_err(|_| Json(SetupError {
error: "Failed to create user".to_string(),
}))?;
Ok(Status::Created)
}