// file: kb_lib/src/db/queries/db_runtime_event.rs //! Queries for `kb_db_runtime_events`. /// Inserts one runtime event row and returns its numeric id. pub async fn insert_db_runtime_event( database: &crate::KbDatabase, dto: &crate::KbDbRuntimeEventDto, ) -> Result { match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query( r#" INSERT INTO kb_db_runtime_events ( event_kind, level, source, message, created_at ) VALUES (?, ?, ?, ?, ?) "#, ) .bind(dto.event_kind.clone()) .bind(dto.level.to_i16()) .bind(dto.source.clone()) .bind(dto.message.clone()) .bind(dto.created_at.to_rfc3339()) .execute(pool) .await; let query_result = match query_result { Ok(query_result) => query_result, Err(error) => { return Err(crate::KbError::Db(format!( "cannot insert kb_db_runtime_events on sqlite: {}", error ))); } }; Ok(query_result.last_insert_rowid()) } } } /// Lists recent runtime events ordered from newest to oldest. pub async fn list_recent_db_runtime_events( database: &crate::KbDatabase, limit: u32, ) -> Result, crate::KbError> { if limit == 0 { return Ok(std::vec::Vec::new()); } match database.connection() { crate::KbDatabaseConnection::Sqlite(pool) => { let query_result = sqlx::query_as::( r#" SELECT id, event_kind, level, source, message, created_at FROM kb_db_runtime_events ORDER BY id DESC LIMIT ? "#, ) .bind(i64::from(limit)) .fetch_all(pool) .await; let entities = match query_result { Ok(entities) => entities, Err(error) => { return Err(crate::KbError::Db(format!( "cannot list runtime events on sqlite: {}", error ))); } }; let mut dtos = std::vec::Vec::new(); for entity in entities { let dto_result = crate::KbDbRuntimeEventDto::try_from(entity); let dto = match dto_result { Ok(dto) => dto, Err(error) => return Err(error), }; dtos.push(dto); } Ok(dtos) } } } #[cfg(test)] mod tests { #[tokio::test] async fn runtime_event_roundtrip_works() { let tempdir = tempfile::tempdir().expect("tempdir must succeed"); let database_path = tempdir.path().join("runtime_event.sqlite3"); let config = crate::KbDatabaseConfig { enabled: true, backend: crate::KbDatabaseBackend::Sqlite, sqlite: crate::KbSqliteDatabaseConfig { path: database_path.to_string_lossy().to_string(), create_if_missing: true, busy_timeout_ms: 5000, max_connections: 1, auto_initialize_schema: true, use_wal: true, }, }; let database = crate::KbDatabase::connect_and_initialize(&config) .await .expect("database init must succeed"); let dto = crate::KbDbRuntimeEventDto::new( "http_request".to_string(), crate::KbDbRuntimeEventLevel::Info, "demo_http".to_string(), "getHealth executed".to_string(), ); let inserted_id = crate::insert_db_runtime_event(&database, &dto) .await .expect("insert must succeed"); assert!(inserted_id > 0); let listed = crate::list_recent_db_runtime_events(&database, 10) .await .expect("list must succeed"); assert_eq!(listed.len(), 1); assert_eq!(listed[0].event_kind, "http_request"); assert_eq!(listed[0].level, crate::KbDbRuntimeEventLevel::Info); } }