-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(webserver): support filter by users for userEvents api (#1956)
* feat(webserver): support filter by users for userEvents api * add indexing * add unit test
- Loading branch information
Showing
9 changed files
with
106 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
DROP INDEX idx_user_events_user_id; | ||
DROP INDEX idx_user_events_created_at; | ||
DROP TABLE user_events; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
use async_trait::async_trait; | ||
use chrono::{DateTime, Utc}; | ||
use juniper::ID; | ||
use tabby_db::DbConn; | ||
use tracing::warn; | ||
|
||
use super::graphql_pagination_to_filter; | ||
use super::{graphql_pagination_to_filter, AsRowid}; | ||
use crate::schema::{ | ||
user_event::{UserEvent, UserEventService}, | ||
Result, | ||
|
@@ -24,17 +26,90 @@ impl UserEventService for UserEventServiceImpl { | |
before: Option<String>, | ||
first: Option<usize>, | ||
last: Option<usize>, | ||
users: Vec<ID>, | ||
start: DateTime<Utc>, | ||
end: DateTime<Utc>, | ||
) -> Result<Vec<UserEvent>> { | ||
let users = convert_ids(users); | ||
let (limit, skip_id, backwards) = graphql_pagination_to_filter(after, before, first, last)?; | ||
let events = self | ||
.db | ||
.list_user_events(limit, skip_id, backwards, start.into(), end.into()) | ||
.list_user_events(limit, skip_id, backwards, users, start.into(), end.into()) | ||
.await?; | ||
Ok(events | ||
.into_iter() | ||
.map(UserEvent::try_from) | ||
.collect::<Result<_, _>>()?) | ||
} | ||
} | ||
|
||
fn convert_ids(ids: Vec<ID>) -> Vec<i64> { | ||
ids.into_iter() | ||
.filter_map(|id| match id.as_rowid() { | ||
Ok(rowid) => Some(rowid), | ||
Err(_) => { | ||
warn!("Ignoring invalid ID: {}", id); | ||
None | ||
} | ||
}) | ||
.collect() | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use assert_matches::assert_matches; | ||
use chrono::{Days, Duration}; | ||
|
||
use super::*; | ||
use crate::{schema::user_event::EventKind, service::AsID}; | ||
|
||
fn timestamp() -> u128 { | ||
use std::time::{SystemTime, UNIX_EPOCH}; | ||
let start = SystemTime::now(); | ||
start | ||
.duration_since(UNIX_EPOCH) | ||
.expect("Time went backwards") | ||
.as_millis() | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_list_user_events() { | ||
let db = DbConn::new_in_memory().await.unwrap(); | ||
let user1 = db | ||
.create_user("[email protected]".into(), Some("pass".into()), true) | ||
.await | ||
.unwrap(); | ||
|
||
db.create_user_event(user1, "view".into(), timestamp(), "".into()) | ||
.await | ||
.unwrap(); | ||
|
||
let user2 = db | ||
.create_user("[email protected]".into(), Some("pass".into()), true) | ||
.await | ||
.unwrap(); | ||
|
||
db.create_user_event(user2, "select".into(), timestamp(), "".into()) | ||
.await | ||
.unwrap(); | ||
|
||
let svc = create(db); | ||
let end = Utc::now() + Duration::days(1); | ||
let start = end.checked_sub_days(Days::new(100)).unwrap(); | ||
|
||
// List without users should return all events | ||
let events = svc | ||
.list(None, None, None, None, vec![], start, end) | ||
.await | ||
.unwrap(); | ||
assert_eq!(events.len(), 2); | ||
|
||
// Filter with user should return only events for that user | ||
let events = svc | ||
.list(None, None, None, None, vec![user1.as_id()], start, end) | ||
.await | ||
.unwrap(); | ||
assert_eq!(events.len(), 1); | ||
assert_matches!(events[0].kind, EventKind::View); | ||
} | ||
} |