use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool};
use ts_rs_forge::TS;
use uuid::Uuid;
#[derive(Debug, Clone, FromRow, Serialize, Deserialize, TS)]
pub struct ExecutorSession {
pub id: Uuid,
pub task_attempt_id: Option<Uuid>, pub execution_process_id: Uuid,
pub session_id: Option<String>, pub prompt: Option<String>, pub summary: Option<String>, pub commit_message: Option<String>, pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize, TS)]
pub struct CreateExecutorSession {
pub task_attempt_id: Option<Uuid>, pub execution_process_id: Uuid,
pub prompt: Option<String>,
}
#[derive(Debug, Deserialize, TS)]
#[allow(dead_code)]
pub struct UpdateExecutorSession {
pub session_id: Option<String>,
pub prompt: Option<String>,
pub summary: Option<String>,
pub commit_message: Option<String>,
}
impl ExecutorSession {
#[allow(dead_code)]
pub async fn find_by_id(pool: &SqlitePool, id: Uuid) -> Result<Option<Self>, sqlx::Error> {
sqlx::query_as!(
ExecutorSession,
r#"SELECT
id as "id!: Uuid",
task_attempt_id as "task_attempt_id: Uuid",
execution_process_id as "execution_process_id!: Uuid",
session_id,
prompt,
summary,
commit_message,
created_at as "created_at!: DateTime<Utc>",
updated_at as "updated_at!: DateTime<Utc>"
FROM executor_sessions
WHERE id = $1"#,
id
)
.fetch_optional(pool)
.await
}
pub async fn find_by_execution_process_id(
pool: &SqlitePool,
execution_process_id: Uuid,
) -> Result<Option<Self>, sqlx::Error> {
sqlx::query_as!(
ExecutorSession,
r#"SELECT
id as "id!: Uuid",
task_attempt_id as "task_attempt_id: Uuid",
execution_process_id as "execution_process_id!: Uuid",
session_id,
prompt,
summary,
commit_message,
created_at as "created_at!: DateTime<Utc>",
updated_at as "updated_at!: DateTime<Utc>"
FROM executor_sessions
WHERE execution_process_id = $1"#,
execution_process_id
)
.fetch_optional(pool)
.await
}
#[allow(dead_code)]
pub async fn find_by_task_attempt_id(
pool: &SqlitePool,
task_attempt_id: Uuid,
) -> Result<Vec<Self>, sqlx::Error> {
sqlx::query_as!(
ExecutorSession,
r#"SELECT
id as "id!: Uuid",
task_attempt_id as "task_attempt_id: Uuid",
execution_process_id as "execution_process_id!: Uuid",
session_id,
prompt,
summary,
commit_message,
created_at as "created_at!: DateTime<Utc>",
updated_at as "updated_at!: DateTime<Utc>"
FROM executor_sessions
WHERE task_attempt_id = $1
ORDER BY created_at ASC"#,
task_attempt_id
)
.fetch_all(pool)
.await
}
pub async fn find_by_session_id(
pool: &SqlitePool,
session_id: &str,
) -> Result<Option<Self>, sqlx::Error> {
sqlx::query_as!(
ExecutorSession,
r#"SELECT
id as "id!: Uuid",
task_attempt_id as "task_attempt_id: Uuid",
execution_process_id as "execution_process_id!: Uuid",
session_id,
prompt,
summary,
commit_message,
created_at as "created_at!: DateTime<Utc>",
updated_at as "updated_at!: DateTime<Utc>"
FROM executor_sessions
WHERE session_id = ?
ORDER BY updated_at DESC
LIMIT 1"#,
session_id
)
.fetch_optional(pool)
.await
}
pub async fn create(
pool: &SqlitePool,
data: &CreateExecutorSession,
session_id: Uuid,
) -> Result<Self, sqlx::Error> {
let now = Utc::now();
tracing::debug!(
"Creating executor session: id={}, task_attempt_id={:?}, execution_process_id={}, external_session_id=None (will be set later)",
session_id,
data.task_attempt_id,
data.execution_process_id
);
sqlx::query_as!(
ExecutorSession,
r#"INSERT INTO executor_sessions (
id, task_attempt_id, execution_process_id, session_id, prompt, summary, commit_message,
created_at, updated_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING
id as "id!: Uuid",
task_attempt_id as "task_attempt_id: Uuid",
execution_process_id as "execution_process_id!: Uuid",
session_id,
prompt,
summary,
commit_message,
created_at as "created_at!: DateTime<Utc>",
updated_at as "updated_at!: DateTime<Utc>""#,
session_id,
data.task_attempt_id,
data.execution_process_id,
None::<String>, data.prompt,
None::<String>, None::<String>, now, now )
.fetch_one(pool)
.await
}
pub async fn update_session_id(
pool: &SqlitePool,
execution_process_id: Uuid,
external_session_id: &str,
) -> Result<(), sqlx::Error> {
let now = Utc::now();
sqlx::query!(
r#"UPDATE executor_sessions
SET session_id = $1, updated_at = $2
WHERE execution_process_id = $3"#,
external_session_id,
now,
execution_process_id
)
.execute(pool)
.await?;
Ok(())
}
#[allow(dead_code)]
pub async fn update_prompt(
pool: &SqlitePool,
id: Uuid,
prompt: &str,
) -> Result<(), sqlx::Error> {
let now = Utc::now();
sqlx::query!(
r#"UPDATE executor_sessions
SET prompt = $1, updated_at = $2
WHERE id = $3"#,
prompt,
now,
id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn update_summary(
pool: &SqlitePool,
execution_process_id: Uuid,
summary: &str,
) -> Result<(), sqlx::Error> {
let now = Utc::now();
sqlx::query!(
r#"UPDATE executor_sessions
SET summary = $1, updated_at = $2
WHERE execution_process_id = $3"#,
summary,
now,
execution_process_id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn update_commit_message(
pool: &SqlitePool,
execution_process_id: Uuid,
commit_message: &str,
) -> Result<(), sqlx::Error> {
let now = Utc::now();
sqlx::query!(
r#"UPDATE executor_sessions
SET commit_message = $1, updated_at = $2
WHERE execution_process_id = $3"#,
commit_message,
now,
execution_process_id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn delete_by_task_attempt_id(
pool: &SqlitePool,
task_attempt_id: Uuid,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"DELETE FROM executor_sessions WHERE task_attempt_id = $1",
task_attempt_id
)
.execute(pool)
.await?;
Ok(())
}
}