diff --git a/src/api/ai_help.rs b/src/api/ai_help.rs index 71f46625..0c97975b 100644 --- a/src/api/ai_help.rs +++ b/src/api/ai_help.rs @@ -22,9 +22,9 @@ use crate::{ db::{ self, ai_help::{ - add_help_history, add_help_history_message, create_or_increment_total, - delete_full_help_history, delete_help_history, get_count, help_history, - help_history_get_message, list_help_history, update_help_history_label, AI_HELP_LIMIT, + add_help_history_message, create_or_increment_total, delete_full_help_history, + delete_help_history, get_count, help_history, help_history_get_message, + list_help_history, update_help_history_label, AI_HELP_LIMIT, }, model::{AIHelpHistoryMessage, AIHelpHistoryMessageInsert, Settings}, settings::get_settings, @@ -207,9 +207,7 @@ fn record_question( message_id, parent_id, } = help_ids; - if let Err(err) = add_help_history(&mut conn, user_id, chat_id) { - error!("AI Help log: {err}"); - } + let insert = AIHelpHistoryMessageInsert { user_id, chat_id, @@ -245,6 +243,7 @@ fn record_sources( message_id, parent_id, } = help_ids; + let insert = AIHelpHistoryMessageInsert { user_id, chat_id, diff --git a/src/db/ai_help.rs b/src/db/ai_help.rs index 448442fc..e0ca699d 100644 --- a/src/db/ai_help.rs +++ b/src/db/ai_help.rs @@ -132,31 +132,63 @@ pub fn add_help_history( .do_update() .set(ai_help_history::updated_at.eq(diesel::dsl::now)) .execute(conn)?; - Ok(()) } -pub fn add_help_history_message( +pub fn update_help_history( conn: &mut PgConnection, - mut message: AIHelpHistoryMessageInsert, -) -> Result { - let updated_at = update(ai_help_history::table) + user_id: i64, + chat_id: Uuid, +) -> Result<(), DbError> { + update(ai_help_history::table) .filter( ai_help_history::user_id - .eq(message.user_id) - .and(ai_help_history::chat_id.eq(message.chat_id)), + .eq(user_id) + .and(ai_help_history::chat_id.eq(chat_id)), ) .set(ai_help_history::updated_at.eq(diesel::dsl::now)) - .returning(ai_help_history::updated_at) - .get_result::(conn)?; - message.created_at = Some(updated_at); - insert_into(ai_help_history_messages::table) + .execute(conn)?; + Ok(()) +} + +pub fn add_help_history_message( + conn: &mut PgConnection, + message: AIHelpHistoryMessageInsert, +) -> Result { + // If a `parent_id` is present, we execute an update on the help history + // record because one of these are true: + // * We created a history record at the beginning of the conversation. + // * History was switched off, we did not create a record and the update + // will simply not match/change any record. + // + // With no `parent_id`, we create a new record because at this point, history + // _is_ enabled and we are at the start of a new conversation. + let res = if message.parent_id.is_some() { + update_help_history(conn, message.user_id, message.chat_id) + } else { + add_help_history(conn, message.user_id, message.chat_id) + }; + if let Err(err) = res { + error!("AI Help log: {err}"); + } + + let res = insert_into(ai_help_history_messages::table) .values(&message) .on_conflict(ai_help_history_messages::message_id) .do_update() .set(&message) - .execute(conn)?; - Ok(updated_at) + .returning(ai_help_history_messages::created_at) + .get_result::(conn); + match res { + Ok(created_at) => Ok(created_at), + // Ignore foreign key violations deliberately + // because of the edge cases described above + Err(diesel::result::Error::DatabaseError( + diesel::result::DatabaseErrorKind::ForeignKeyViolation, + _info, + )) => Ok(Utc::now().naive_utc()), + Err(e) => Err(e.into()), + } } pub fn help_history_get_message(