Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: added activity_log_retrieval #9

Merged
merged 15 commits into from
Dec 1, 2024
2 changes: 1 addition & 1 deletion src/api_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl IntoResponse for ApiError {
ApiError::DatabaseError(ref err) => format!("{}", err),
ApiError::InternalError(ref err) => format!("{}", err),
};
error!("{}", error_to_log);
error!("ERROR -------> {}", error_to_log);

Abeeujah marked this conversation as resolved.
Show resolved Hide resolved
// Error message to be sent to the API client.
let resp = ApiErrorResp {
Expand Down
75 changes: 75 additions & 0 deletions src/http/activity_log_retrieval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::AppState;
use axum::extract::{Query, State};
use axum::Json;
use serde_json::{json, Value};

use super::types::{ActivityLogData, ActivityLogGetRequest, ActivityLogGetResponse};
use crate::api_error::ApiError;
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;

pub async fn log_retrieval(
State(app_state): State<AppState>,
Query(query_params): Query<ActivityLogGetRequest>,
) -> Result<Json<Value>, ApiError> {
// println!("\nLog Retrieval: {:?}\n", query_params);

// Add default date if no cursor is provided
let cursor = match query_params.cursor {
Some(cursor1) => cursor1,

None => {
let now = OffsetDateTime::now_utc();
now.format(&Rfc3339).unwrap()
}
};

let limit = query_params.limit.unwrap_or(10);

let rows: Vec<ActivityLogData> = sqlx::query_as::<_, ActivityLogData>(
r#"
SELECT
wallet_address,
from_token,
to_token,
amount_from,
percentage,
amount_to,
TO_CHAR(created_at, 'YYYY-MM-DD"T"HH24:MI:SSZ') AS created_at
FROM transactions_log
WHERE created_at < $1::TIMESTAMPTZ
ORDER BY created_at DESC
LIMIT $2
"#,
)
.bind(cursor)
.bind(limit)
.fetch_all(&app_state.db.pool)
.await
.map_err(ApiError::DatabaseError)?;

// Map results to the response data structure
let mut response_data: ActivityLogGetResponse = ActivityLogGetResponse {
transactions: rows
.into_iter()
.map(|row| ActivityLogData {
wallet_address: row.wallet_address,
from_token: row.from_token,
to_token: row.to_token,
percentage: row.percentage,
amount_from: row.amount_from,
amount_to: row.amount_to,
created_at: row.created_at,
})
.collect(),
next_cursor: None,
};

// Check if there are more transactions
if response_data.transactions.len() == limit as usize {
let last_transaction = response_data.transactions.last().unwrap();
response_data.next_cursor = Some(last_transaction.created_at.clone());
}

Ok(Json(json!(response_data)))
}
5 changes: 4 additions & 1 deletion src/http/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use axum::{routing::get, Router};
mod activity_log_retrieval;
mod health_check;
mod types;

Expand All @@ -7,5 +8,7 @@ use crate::AppState;
// Application router.
// All routes should be merged here.
pub fn router() -> Router<AppState> {
Router::new().route("/health_check", get(health_check::health_check))
Router::new()
.route("/health_check", get(health_check::health_check))
.route("/log_retrieval", get(activity_log_retrieval::log_retrieval))
}
24 changes: 24 additions & 0 deletions src/http/types.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
use serde::de::Visitor;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use sqlx::FromRow;
use std::fmt::Formatter;
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;

#[derive(Debug, Deserialize)]
pub struct ActivityLogGetRequest {
pub cursor: Option<String>,
pub limit: Option<i32>,
}

#[derive(FromRow, Debug, Serialize)]
pub struct ActivityLogData {
pub wallet_address: String,
pub from_token: String,
pub to_token: String,
pub percentage: i16,
pub amount_from: i64,
pub amount_to: i64,
pub created_at: String,
}

#[derive(Debug, Serialize)]
pub struct ActivityLogGetResponse {
pub transactions: Vec<ActivityLogData>,
pub next_cursor: Option<String>,
}

#[derive(sqlx::Type)]
pub struct TimeStamptz(pub OffsetDateTime);

Expand Down
31 changes: 31 additions & 0 deletions tests/api/activity_log_retrieval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use axum::{
body::Body,
extract::Query,
http::{Request, StatusCode},
};

use crate::helpers::*;

use serde::Deserialize;

#[derive(Deserialize)]
struct Pagination {
page: usize,
per_page: usize,
}

#[tokio::test]
async fn test_log_retrieval() {
let app = TestApp::new().await; // 2024-11-24T10:30:00Z
let req = Request::get("/log_retrieval?cursor=2024-11-28T12:02:49Z&limit=10")
.body(Body::empty())
.unwrap();
let resp = app.request(req).await;
let headers = resp.headers().clone();
println!("{:#?}", resp.body());

assert_eq!(resp.status(), StatusCode::OK);
assert!(headers.get("x-request-id").is_some());
assert_eq!(headers.get("access-control-allow-origin").unwrap(), "*");
assert!(headers.get("vary").is_some());
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also could you include test cases that check for errors and edge cases eg empty transactions log

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_home_abee_Desktop_OdHack_autoswappr-backend_tarpaulin-report html
Here's the result of your current test coverage...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

1 change: 1 addition & 0 deletions tests/api/main.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mod activity_log_retrieval;
mod health_check;
mod helpers;
Loading