feat: add analytics metric granularity query
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use serde_json::Value;
|
||||
use shared_kernel::{offset_datetime_to_unix_micros, parse_rfc3339};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::domain::*;
|
||||
use crate::errors::RuntimeProfileFieldError;
|
||||
@@ -502,6 +503,81 @@ pub fn build_runtime_tracking_daily_stat_id(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn aggregate_runtime_tracking_daily_stats(
|
||||
stats: Vec<RuntimeAnalyticsDailyStatSnapshot>,
|
||||
event_key: &str,
|
||||
scope_kind: RuntimeTrackingScopeKind,
|
||||
scope_id: &str,
|
||||
granularity: AnalyticsGranularity,
|
||||
) -> Vec<AnalyticsBucketMetric> {
|
||||
let mut buckets: BTreeMap<(String, i64, i64), u64> = BTreeMap::new();
|
||||
let event_key = event_key.trim();
|
||||
let scope_id = scope_id.trim();
|
||||
|
||||
for stat in stats {
|
||||
if stat.event_key.trim() != event_key
|
||||
|| stat.scope_kind != scope_kind
|
||||
|| stat.scope_id.trim() != scope_id
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let dimension = build_analytics_date_dimension_from_date_key(stat.day_key);
|
||||
let (bucket_key, bucket_start_date_key, bucket_end_date_key) =
|
||||
analytics_bucket_for_dimension(&dimension, granularity);
|
||||
*buckets
|
||||
.entry((bucket_key, bucket_start_date_key, bucket_end_date_key))
|
||||
.or_insert(0) += u64::from(stat.count);
|
||||
}
|
||||
|
||||
buckets
|
||||
.into_iter()
|
||||
.map(
|
||||
|((bucket_key, bucket_start_date_key, bucket_end_date_key), value)| {
|
||||
AnalyticsBucketMetric {
|
||||
bucket_key,
|
||||
bucket_start_date_key,
|
||||
bucket_end_date_key,
|
||||
value,
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn analytics_bucket_for_dimension(
|
||||
dimension: &AnalyticsDateDimensionSnapshot,
|
||||
granularity: AnalyticsGranularity,
|
||||
) -> (String, i64, i64) {
|
||||
match granularity {
|
||||
AnalyticsGranularity::Day => (
|
||||
dimension.calendar_date.clone(),
|
||||
dimension.date_key,
|
||||
dimension.date_key,
|
||||
),
|
||||
AnalyticsGranularity::Week => (
|
||||
dimension.iso_week_key.to_string(),
|
||||
dimension.week_start_date_key,
|
||||
dimension.week_end_date_key,
|
||||
),
|
||||
AnalyticsGranularity::Month => (
|
||||
dimension.month_key.to_string(),
|
||||
dimension.month_start_date_key,
|
||||
dimension.month_end_date_key,
|
||||
),
|
||||
AnalyticsGranularity::Quarter => (
|
||||
dimension.quarter_key.to_string(),
|
||||
dimension.quarter_start_date_key,
|
||||
dimension.quarter_end_date_key,
|
||||
),
|
||||
AnalyticsGranularity::Year => (
|
||||
dimension.year_key.to_string(),
|
||||
dimension.year_start_date_key,
|
||||
dimension.year_end_date_key,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_runtime_profile_task_config_record(
|
||||
snapshot: RuntimeProfileTaskConfigSnapshot,
|
||||
) -> RuntimeProfileTaskConfigRecord {
|
||||
|
||||
@@ -116,6 +116,24 @@ pub fn build_runtime_profile_task_center_get_input(
|
||||
Ok(RuntimeProfileTaskCenterGetInput { user_id })
|
||||
}
|
||||
|
||||
pub fn build_analytics_metric_query_input(
|
||||
event_key: String,
|
||||
scope_kind: RuntimeTrackingScopeKind,
|
||||
scope_id: String,
|
||||
granularity: AnalyticsGranularity,
|
||||
) -> Result<AnalyticsMetricQueryInput, RuntimeProfileFieldError> {
|
||||
let event_key = normalize_required_string(event_key)
|
||||
.ok_or(RuntimeProfileFieldError::MissingTaskEventKey)?;
|
||||
let scope_id = normalize_required_string(scope_id)
|
||||
.ok_or(RuntimeProfileFieldError::MissingTrackingScopeId)?;
|
||||
Ok(AnalyticsMetricQueryInput {
|
||||
event_key,
|
||||
scope_kind,
|
||||
scope_id,
|
||||
granularity,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn build_runtime_profile_task_claim_input(
|
||||
user_id: String,
|
||||
task_id: String,
|
||||
|
||||
@@ -58,6 +58,78 @@ pub struct AnalyticsDateDimensionSnapshot {
|
||||
pub year_end_date_key: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AnalyticsGranularity {
|
||||
Day,
|
||||
Week,
|
||||
Month,
|
||||
Quarter,
|
||||
Year,
|
||||
}
|
||||
|
||||
impl AnalyticsGranularity {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Day => "day",
|
||||
Self::Week => "week",
|
||||
Self::Month => "month",
|
||||
Self::Quarter => "quarter",
|
||||
Self::Year => "year",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_client_str(value: &str) -> Option<Self> {
|
||||
match value.trim().to_ascii_lowercase().as_str() {
|
||||
"day" => Some(Self::Day),
|
||||
"week" => Some(Self::Week),
|
||||
"month" => Some(Self::Month),
|
||||
"quarter" => Some(Self::Quarter),
|
||||
"year" => Some(Self::Year),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct RuntimeAnalyticsDailyStatSnapshot {
|
||||
pub event_key: String,
|
||||
pub scope_kind: RuntimeTrackingScopeKind,
|
||||
pub scope_id: String,
|
||||
pub day_key: i64,
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AnalyticsBucketMetric {
|
||||
pub bucket_key: String,
|
||||
pub bucket_start_date_key: i64,
|
||||
pub bucket_end_date_key: i64,
|
||||
pub value: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct AnalyticsMetricQueryRequest {
|
||||
pub event_key: String,
|
||||
pub scope_kind: RuntimeTrackingScopeKind,
|
||||
pub scope_id: String,
|
||||
pub granularity: AnalyticsGranularity,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct AnalyticsMetricQueryResponse {
|
||||
pub buckets: Vec<AnalyticsBucketMetric>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AnalyticsMetricQueryProcedureResult {
|
||||
pub ok: bool,
|
||||
pub buckets: Vec<AnalyticsBucketMetric>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
/// 运行时平台主题。
|
||||
///
|
||||
/// 当前只冻结 light/dark 两种主题,避免各层散落字符串字面量。
|
||||
@@ -552,6 +624,15 @@ pub struct RuntimeProfileTaskCenterGetInput {
|
||||
pub user_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AnalyticsMetricQueryInput {
|
||||
pub event_key: String,
|
||||
pub scope_kind: RuntimeTrackingScopeKind,
|
||||
pub scope_id: String,
|
||||
pub granularity: AnalyticsGranularity,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RuntimeProfileTaskClaimInput {
|
||||
|
||||
Reference in New Issue
Block a user