Skip to content

Commit 7efcf12

Browse files
committed
feat: interval query param
1 parent 66d186f commit 7efcf12

File tree

3 files changed

+89
-9
lines changed

3 files changed

+89
-9
lines changed

pragma-node/src/handlers/entries/get_entry.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use axum::extract::State;
1+
use axum::extract::{Query, State};
22
use axum::Json;
33
use bigdecimal::num_bigint::ToBigInt;
44

@@ -9,6 +9,7 @@ use crate::AppState;
99
use pragma_entities::{error::InfraError, EntryError};
1010

1111
use super::utils::currency_pair_to_pair_id;
12+
use super::GetEntryParams;
1213

1314
#[utoipa::path(
1415
get,
@@ -24,11 +25,17 @@ use super::utils::currency_pair_to_pair_id;
2425
pub async fn get_entry(
2526
State(state): State<AppState>,
2627
PathExtractor(pair): PathExtractor<(String, String)>,
28+
Query(params): Query<GetEntryParams>,
2729
) -> Result<Json<GetEntryResponse>, EntryError> {
2830
tracing::info!("Received get entry request for pair {:?}", pair);
2931
// Construct pair id
3032
let pair_id = currency_pair_to_pair_id(&pair.1, &pair.0);
3133

34+
// Validate given timestamp
35+
if params.timestamp > chrono::Utc::now().naive_utc() {
36+
return Err(EntryError::InvalidTimestamp);
37+
}
38+
3239
// Mock strk/eth pair
3340
if pair_id == "STRK/ETH" {
3441
return Ok(Json(GetEntryResponse {
@@ -41,13 +48,9 @@ pub async fn get_entry(
4148
}
4249

4350
// Get entries from database with given pair id (only the latest one grouped by publisher)
44-
let entry = entry_repository::get_median_price(&state.pool, pair_id.clone())
51+
let entry = entry_repository::get_median_price(&state.pool, pair_id.clone(), params.interval)
4552
.await
46-
.map_err(|db_error| match db_error {
47-
InfraError::InternalServerError => EntryError::InternalServerError,
48-
InfraError::NotFound => EntryError::NotFound(pair_id.clone()),
49-
InfraError::InvalidTimeStamp => EntryError::InvalidTimestamp,
50-
})?;
53+
.map_err(|db_error| to_entry_error(db_error, pair_id.clone()))?;
5154

5255
let decimals = entry_repository::get_decimals(&state.pool, &pair_id)
5356
.await
@@ -82,3 +85,11 @@ fn adapt_entry_to_entry_response(
8285
decimals,
8386
}
8487
}
88+
89+
fn to_entry_error(error: InfraError, pair_id: String) -> EntryError {
90+
match error {
91+
InfraError::InternalServerError => EntryError::InternalServerError,
92+
InfraError::NotFound => EntryError::NotFound(pair_id.to_string()),
93+
InfraError::InvalidTimeStamp => EntryError::InvalidTimestamp,
94+
}
95+
}

pragma-node/src/handlers/entries/mod.rs

+30
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use chrono::NaiveDateTime;
12
use serde::{Deserialize, Serialize};
23

34
use starknet::core::types::FieldElement;
@@ -54,3 +55,32 @@ pub struct GetVolatilityResponse {
5455
volatility: f64,
5556
decimals: u32,
5657
}
58+
59+
/// Query parameters structs
60+
61+
// Define an enum for the allowed intervals
62+
#[derive(Default, Debug, Deserialize)]
63+
pub enum Interval {
64+
#[serde(rename = "1min")]
65+
#[default]
66+
OneMinute,
67+
#[serde(rename = "15min")]
68+
FifteenMinutes,
69+
#[serde(rename = "1h")]
70+
OneHour,
71+
}
72+
73+
#[derive(Debug, Deserialize)]
74+
pub struct GetEntryParams {
75+
pub timestamp: NaiveDateTime,
76+
pub interval: Interval,
77+
}
78+
79+
impl Default for GetEntryParams {
80+
fn default() -> Self {
81+
Self {
82+
timestamp: chrono::Utc::now().naive_utc(),
83+
interval: Interval::default(),
84+
}
85+
}
86+
}

pragma-node/src/infra/repositories/entry_repository.rs

+41-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use pragma_entities::{
1111
Entry, NewEntry,
1212
};
1313

14+
use crate::handlers::entries::Interval;
15+
1416
#[derive(Deserialize)]
1517
#[allow(unused)]
1618
pub struct EntriesFilter {
@@ -82,10 +84,13 @@ pub struct MedianEntryRaw {
8284
pub async fn get_median_price(
8385
pool: &deadpool_diesel::postgres::Pool,
8486
pair_id: String,
87+
interval: Interval,
8588
) -> Result<MedianEntry, InfraError> {
8689
let conn = pool.get().await.map_err(adapt_infra_error)?;
8790

88-
let raw_sql = r#"
91+
let raw_sql = match interval {
92+
Interval::OneMinute => {
93+
r#"
8994
-- query the materialized realtime view
9095
SELECT
9196
bucket AS time,
@@ -98,7 +103,41 @@ pub async fn get_median_price(
98103
ORDER BY
99104
time DESC
100105
LIMIT 1;
101-
"#;
106+
"#
107+
}
108+
Interval::FifteenMinutes => {
109+
r#"
110+
-- query the materialized realtime view
111+
SELECT
112+
bucket AS time,
113+
median_price,
114+
num_sources
115+
FROM
116+
price_15_min_agg
117+
WHERE
118+
pair_id = $1
119+
ORDER BY
120+
time DESC
121+
LIMIT 1;
122+
"#
123+
}
124+
Interval::OneHour => {
125+
r#"
126+
-- query the materialized realtime view
127+
SELECT
128+
bucket AS time,
129+
median_price,
130+
num_sources
131+
FROM
132+
price_1_hour_agg
133+
WHERE
134+
pair_id = $1
135+
ORDER BY
136+
time DESC
137+
LIMIT 1;
138+
"#
139+
}
140+
};
102141

103142
let raw_entry = conn
104143
.interact(move |conn| {

0 commit comments

Comments
 (0)