Skip to content

Commit

Permalink
feat(webserver): implement AnalyticService (#1752)
Browse files Browse the repository at this point in the history
* init

* implement anual report

* update

* update

* update

* [autofix.ci] apply automated fixes

* Update ee/tabby-db/src/user_completions.rs

* add individual user stats

* rename

* [autofix.ci] apply automated fixes

* switch to query_as!

* fix check_analytic_access

* add warning on invalid rowids

* fix query

* fix build

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
wsxiaoys and autofix-ci[bot] authored Apr 7, 2024
1 parent 3a7009d commit 0c94dda
Show file tree
Hide file tree
Showing 6 changed files with 473 additions and 122 deletions.
72 changes: 71 additions & 1 deletion ee/tabby-db/src/user_completions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::time::Duration;

use anyhow::{Context, Result};
use chrono::DateTime;
use chrono::{DateTime, Utc};
use sqlx::{prelude::FromRow, query};

use crate::{DateTimeUtc, DbConn};
Expand All @@ -20,6 +20,12 @@ pub struct UserCompletionDAO {
pub updated_at: DateTimeUtc,
}

pub struct UserCompletionDailyStatsDAO {
pub start: DateTime<Utc>,
pub completions: i32,
pub selects: i32,
}

impl DbConn {
pub async fn create_user_completion(
&self,
Expand Down Expand Up @@ -61,6 +67,70 @@ impl DbConn {
Ok(())
}

// FIXME(boxbeam): index `created_at` in user_completions table.
pub async fn compute_daily_stats_in_past_year(
&self,
users: Vec<i32>,
) -> Result<Vec<UserCompletionDailyStatsDAO>> {
let users = users
.iter()
.map(|u| u.to_string())
.collect::<Vec<_>>()
.join(",");
Ok(sqlx::query_as!(
UserCompletionDailyStatsDAO,
r#"
SELECT CAST(STRFTIME('%s', DATE(created_at)) AS TIMESTAMP) as "start!: DateTime<Utc>",
SUM(1) as "completions!: i32",
SUM(selects) as "selects!: i32"
FROM user_completions
WHERE created_at >= DATE('now', '-1 year')
AND (?1 = '' OR user_id IN (?1))
GROUP BY 1
ORDER BY 1 ASC
"#,
users
)
.fetch_all(&self.pool)
.await?)
}

pub async fn compute_daily_stats(
&self,
start: DateTime<Utc>,
end: DateTime<Utc>,
users: Vec<i32>,
languages: Vec<String>,
) -> Result<Vec<UserCompletionDailyStatsDAO>> {
let users = users
.iter()
.map(|u| u.to_string())
.collect::<Vec<_>>()
.join(",");
let languages = languages.join(",");
let res = sqlx::query_as!(
UserCompletionDailyStatsDAO,
r#"
SELECT CAST(STRFTIME('%s', DATE(created_at)) AS TIMESTAMP) as "start!: DateTime<Utc>",
SUM(1) as "completions!: i32",
SUM(selects) as "selects!: i32"
FROM user_completions
WHERE created_at >= ?1 AND created_at < ?2
AND (?3 = '' OR user_id IN (?3))
AND (?4 = '' OR language IN (?4))
GROUP BY 1
ORDER BY 1 ASC
"#,
start,
end,
users,
languages
)
.fetch_all(&self.pool)
.await?;
Ok(res)
}

#[cfg(any(test, feature = "testutils"))]
pub async fn fetch_one_user_completion(&self) -> Result<Option<UserCompletionDAO>> {
Ok(
Expand Down
Loading

0 comments on commit 0c94dda

Please sign in to comment.