mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 13:16:38 +00:00
* chore(labrinth): bump to redis 1.4.1 * feat(labrinth): redis cluster * chore: cleanup * feat(labrinth): cache locking * fix(labrinth): clippy * chore(labrinth): cleanup env, remove postcard support * chore(ci): fix test env for labrinth * chore(labrinth): bump all key versions * chore(labrinth): improve redis key identities handling * chore(labrinth): simplify deadline handling * chore(labrinth): remove unused lease tracking * chore(labrinth): remove distributed cache locking for now * chore(labrinth): improve redis backend init error * feat(labrinth): expose redis read replica strategy * chore(ci): remove other connection mode tests * chore: split xredis crate * feat(xredis): primaries routing * chore: tombi fmt * chore: clippy * chore: update query cache
130 lines
3.4 KiB
Rust
130 lines
3.4 KiB
Rust
use chrono::{DateTime, Utc};
|
|
use futures::{StreamExt, TryStreamExt};
|
|
use sqlx::types::Json;
|
|
use xredis::RedisPool;
|
|
|
|
use crate::{
|
|
database::models::{DBAnalyticsEventId, DatabaseError},
|
|
models::v3::analytics_event::AnalyticsEventMeta,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
const ANALYTICS_EVENTS_NAMESPACE: &str = "analytics_events:v3";
|
|
const ANALYTICS_EVENTS_ALL_KEY: &str = "all";
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct DBAnalyticsEvent {
|
|
pub id: DBAnalyticsEventId,
|
|
pub meta: AnalyticsEventMeta,
|
|
pub starts: DateTime<Utc>,
|
|
pub ends: DateTime<Utc>,
|
|
}
|
|
|
|
impl DBAnalyticsEvent {
|
|
pub async fn insert(
|
|
&self,
|
|
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
|
) -> Result<(), DatabaseError> {
|
|
sqlx::query!(
|
|
"
|
|
INSERT INTO analytics_events (id, meta, starts, ends)
|
|
VALUES ($1, $2, $3, $4)
|
|
",
|
|
self.id as DBAnalyticsEventId,
|
|
sqlx::types::Json(&self.meta) as Json<&AnalyticsEventMeta>,
|
|
self.starts,
|
|
self.ends,
|
|
)
|
|
.execute(exec)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn update(
|
|
&self,
|
|
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
|
) -> Result<bool, DatabaseError> {
|
|
let result = sqlx::query!(
|
|
"
|
|
UPDATE analytics_events
|
|
SET meta = $2, starts = $3, ends = $4
|
|
WHERE id = $1
|
|
",
|
|
self.id as DBAnalyticsEventId,
|
|
sqlx::types::Json(&self.meta) as Json<&AnalyticsEventMeta>,
|
|
self.starts,
|
|
self.ends,
|
|
)
|
|
.execute(exec)
|
|
.await?;
|
|
|
|
Ok(result.rows_affected() > 0)
|
|
}
|
|
|
|
pub async fn remove(
|
|
id: DBAnalyticsEventId,
|
|
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
|
) -> Result<bool, DatabaseError> {
|
|
let result = sqlx::query!(
|
|
"
|
|
DELETE FROM analytics_events
|
|
WHERE id = $1
|
|
",
|
|
id as DBAnalyticsEventId,
|
|
)
|
|
.execute(exec)
|
|
.await?;
|
|
|
|
Ok(result.rows_affected() > 0)
|
|
}
|
|
|
|
pub async fn get_all(
|
|
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
|
redis: &RedisPool,
|
|
) -> Result<Vec<DBAnalyticsEvent>, DatabaseError> {
|
|
let mut redis = redis.connect().await?;
|
|
let key = redis
|
|
.key()
|
|
.metadata(ANALYTICS_EVENTS_NAMESPACE, ANALYTICS_EVENTS_ALL_KEY);
|
|
|
|
if let Some(events) = redis.get_deserialized(&key).await? {
|
|
return Ok(events);
|
|
}
|
|
|
|
let events = sqlx::query!(
|
|
r#"
|
|
SELECT id, meta AS "meta: Json<AnalyticsEventMeta>", starts, ends
|
|
FROM analytics_events
|
|
ORDER BY starts DESC
|
|
"#
|
|
)
|
|
.fetch(exec)
|
|
.map(|record| {
|
|
let record = record?;
|
|
|
|
Ok::<_, DatabaseError>(DBAnalyticsEvent {
|
|
id: DBAnalyticsEventId(record.id),
|
|
meta: record.meta.0,
|
|
starts: record.starts,
|
|
ends: record.ends,
|
|
})
|
|
})
|
|
.try_collect::<Vec<_>>()
|
|
.await?;
|
|
|
|
redis.set_serialized(&key, &events, None).await?;
|
|
|
|
Ok(events)
|
|
}
|
|
|
|
pub async fn clear_cache(redis: &RedisPool) -> Result<(), DatabaseError> {
|
|
let mut redis = redis.connect().await?;
|
|
let key = redis
|
|
.key()
|
|
.metadata(ANALYTICS_EVENTS_NAMESPACE, ANALYTICS_EVENTS_ALL_KEY);
|
|
redis.delete(&key).await?;
|
|
Ok(())
|
|
}
|
|
}
|