Skip to content

Commit

Permalink
feat: changing activity_preference functionality, fixing user upsert,…
Browse files Browse the repository at this point in the history
… modifying influence add
  • Loading branch information
112batuhan committed Nov 26, 2024
1 parent d163473 commit 910dd73
Show file tree
Hide file tree
Showing 16 changed files with 213 additions and 145 deletions.
2 changes: 1 addition & 1 deletion migrations/migrations/definitions/_initial.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"schemas":"DEFINE TABLE OVERWRITE activity_preference SCHEMAFULL;\n\nDEFINE FIELD OVERWRITE login ON activity_preference TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE add_influence ON activity_preference TYPE bool DEFAULT true;\nDEFINE FIELD OVERWRITE remove_influence ON activity_preference TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE add_user_beatmap ON activity_preference TYPE bool DEFAULT true;\nDEFINE FIELD OVERWRITE remove_user_beatmap ON activity_preference TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE add_influence_beatmap ON activity_preference TYPE bool DEFAULT true;\nDEFINE FIELD OVERWRITE remove_influence_beatmap ON activity_preference TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE edit_influence_description ON activity_preference TYPE bool DEFAULT true;\nDEFINE FIELD OVERWRITE edit_influence_type ON activity_preference TYPE bool DEFAULT true;\nDEFINE FIELD OVERWRITE edit_bio ON activity_preference TYPE bool DEFAULT true;\n\nDEFINE FUNCTION OVERWRITE fn::id_or_null($value: any) -> any {\n IF $value.is_none() {\n RETURN NONE;\n }\n ELSE {\n RETURN meta::id($value);\n };\n} PERMISSIONS FULL;\n\nDEFINE FUNCTION OVERWRITE fn::add_possible_nulls($var1: any, $var2: any) -> any {\n IF type::is::none($var1) AND type::is::none($var2) {\n RETURN NONE;\n }\n ELSE {\n RETURN $var1 + $var2;\n };\n} PERMISSIONS FULL;\n\nDEFINE TABLE OVERWRITE influenced_by SCHEMAFULL TYPE RELATION IN user OUT user ENFORCED;\n\nDEFINE FIELD OVERWRITE influence_type on influenced_by TYPE int DEFAULT 1;\nDEFINE FIELD OVERWRITE description ON influenced_by TYPE string DEFAULT \"\";\nDEFINE FIELD OVERWRITE beatmaps ON influenced_by TYPE set<int> DEFAULT [];\nDEFINE FIELD OVERWRITE updated_at ON influenced_by type datetime VALUE time::now();\nDEFINE FIELD OVERWRITE created_at ON influenced_by type datetime VALUE time::now() READONLY;\n\n// COUNTLESS HOURS LOST BECAUSE I USED VALUE INSTEAD OF DEFAULT\nDEFINE FIELD OVERWRITE order on influenced_by TYPE int \nDEFAULT (UPSERT increment:order SET increment+=1 RETURN increment).at(0).values().at(0);\n\nDEFINE INDEX OVERWRITE unique_in_out ON TABLE influenced_by COLUMNS in, out UNIQUE;\n\nDEFINE TABLE OVERWRITE script_migration SCHEMAFULL\n PERMISSIONS\n FOR select FULL\n FOR create, update, delete NONE;\n\nDEFINE FIELD OVERWRITE script_name ON script_migration TYPE string;\nDEFINE FIELD OVERWRITE executed_at ON script_migration TYPE datetime VALUE time::now() READONLY;\nDEFINE TABLE OVERWRITE user SCHEMAFULL;\n\nDEFINE FIELD OVERWRITE username ON user TYPE string;\nDEFINE FIELD OVERWRITE avatar_url ON user TYPE string;\nDEFINE FIELD OVERWRITE bio ON user TYPE string DEFAULT \"\";\nDEFINE FIELD OVERWRITE ranked_mapper ON user TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE authenticated ON user TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE beatmaps ON user TYPE set<int> DEFAULT [];\nDEFINE FIELD OVERWRITE updated_at ON user type datetime VALUE time::now();\nDEFINE FIELD OVERWRITE created_at ON user type datetime VALUE time::now() READONLY;\nDEFINE FIELD OVERWRITE country_name ON user TYPE string;\nDEFINE FIELD OVERWRITE country_code ON user TYPE string;\nDEFINE FIELD OVERWRITE groups ON user FLEXIBLE TYPE array<object>;\nDEFINE FIELD OVERWRITE previous_usernames ON user TYPE array<string>;\nDEFINE FIELD OVERWRITE ranked_and_approved_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE ranked_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE nominated_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE guest_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE loved_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE graveyard_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE pending_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE activity_preference ON user TYPE option<record<activity_preference>>;\n\nDEFINE INDEX OVERWRITE country_name_index ON TABLE user COLUMNS country_name;\n","events":"DEFINE EVENT OVERWRITE add_influence ON TABLE influenced_by\nWHEN \n $session.tk.ID == \"backend\" AND $event == \"CREATE\"\nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(),\n event_type = \"ADD_INFLUENCE\", \n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE add_influence_beatmap ON TABLE influenced_by\nWHEN\n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND array::len($after.beatmaps) > array::len($before.beatmaps)\nTHEN (\n CREATE activity \n SET user = $after.in,\n created_at = time::now(),\n event_type = \"ADD_INFLUENCE_BEATMAP\", \n beatmap = array::complement($after.beatmaps, $before.beatmaps).at(0),\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE add_user_beatmap ON TABLE user \nWHEN \n $session.tk.ID == \"backend\" \n AND $event == \"UPDATE\" \n AND array::len($after.beatmaps) > array::len($before.beatmaps) \nTHEN (\n CREATE activity \n SET user = $after.id,\n created_at = time::now(),\n event_type = \"ADD_USER_BEATMAP\", \n beatmap = array::complement($after.beatmaps, $before.beatmaps).at(0)\n);\n\n// edit_bio logs when creating user, so added before != null\nDEFINE EVENT OVERWRITE edit_bio ON TABLE user \nWHEN \n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND $before.bio != $after.bio\nTHEN (\n CREATE activity \n SET user = $after.id, \n created_at = time::now(), \n event_type = \"EDIT_BIO\", \n bio = $after.bio\n);\n\nDEFINE EVENT OVERWRITE edit_influence_description ON TABLE influenced_by\nWHEN\n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND $before.description != $after.description\nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(), \n event_type = \"EDIT_INFLUENCE_DESC\", \n description = $after.description,\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE edit_influence_type ON TABLE influenced_by \nWHEN \n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND $before.influence_type != $after.influence_type \nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(), \n event_type = \"EDIT_INFLUENCE_TYPE\", \n influence_type= $after.influence_type,\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE remove_influence ON TABLE influenced_by\nWHEN \n $session.tk.ID == \"backend\" AND $event == \"DELETE\"\nTHEN (\n CREATE activity \n SET user = $before.in, \n created_at = time::now(),\n event_type = \"REMOVE_INFLUENCE\", \n influence = $before\n);\n\nDEFINE EVENT OVERWRITE remove_influence_beatmap ON TABLE influenced_by\nWHEN\n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND array::len($before.beatmaps) > array::len($after.beatmaps)\nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(),\n event_type = \"REMOVE_INFLUENCE_BEATMAP\", \n beatmap = array::complement($before.beatmaps, $after.beatmaps).at(0),\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE remove_user_beatmap ON TABLE user \nWHEN \n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND array::len($before.beatmaps) > array::len($after.beatmaps)\nTHEN (\n CREATE activity \n SET user = $after.id, \n created_at = time::now(),\n event_type = \"REMOVE_USER_BEATMAP\", \n beatmap = array::complement($before.beatmaps, $after.beatmaps).at(0)\n);\n"}
{"schemas":"DEFINE FUNCTION OVERWRITE fn::id_or_null($value: any) -> any {\n IF $value.is_none() {\n RETURN NONE;\n }\n ELSE {\n RETURN meta::id($value);\n };\n} PERMISSIONS FULL;\n\nDEFINE FUNCTION OVERWRITE fn::add_possible_nulls($var1: any, $var2: any) -> any {\n IF type::is::none($var1) AND type::is::none($var2) {\n RETURN NONE;\n }\n ELSE {\n RETURN $var1 + $var2;\n };\n} PERMISSIONS FULL;\n\nDEFINE TABLE OVERWRITE influenced_by SCHEMAFULL TYPE RELATION IN user OUT user ENFORCED;\n\nDEFINE FIELD OVERWRITE influence_type on influenced_by TYPE int DEFAULT 1;\nDEFINE FIELD OVERWRITE description ON influenced_by TYPE string DEFAULT \"\";\nDEFINE FIELD OVERWRITE beatmaps ON influenced_by TYPE set<int> DEFAULT [];\nDEFINE FIELD OVERWRITE updated_at ON influenced_by type datetime VALUE time::now();\nDEFINE FIELD OVERWRITE created_at ON influenced_by type datetime VALUE time::now() READONLY;\n\n// COUNTLESS HOURS LOST BECAUSE I USED VALUE INSTEAD OF DEFAULT\nDEFINE FIELD OVERWRITE order on influenced_by TYPE int \nDEFAULT (UPSERT increment:order SET increment+=1 RETURN increment).at(0).values().at(0);\n\nDEFINE INDEX OVERWRITE unique_in_out ON TABLE influenced_by COLUMNS in, out UNIQUE;\n\nDEFINE TABLE OVERWRITE script_migration SCHEMAFULL\n PERMISSIONS\n FOR select FULL\n FOR create, update, delete NONE;\n\nDEFINE FIELD OVERWRITE script_name ON script_migration TYPE string;\nDEFINE FIELD OVERWRITE executed_at ON script_migration TYPE datetime VALUE time::now() READONLY;\nDEFINE TABLE OVERWRITE user SCHEMAFULL;\n\nDEFINE FIELD OVERWRITE username ON user TYPE string;\nDEFINE FIELD OVERWRITE avatar_url ON user TYPE string;\nDEFINE FIELD OVERWRITE bio ON user TYPE string DEFAULT \"\";\nDEFINE FIELD OVERWRITE ranked_mapper ON user TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE authenticated ON user TYPE bool DEFAULT false;\nDEFINE FIELD OVERWRITE beatmaps ON user TYPE set<int> DEFAULT [];\nDEFINE FIELD OVERWRITE updated_at ON user type datetime VALUE time::now();\nDEFINE FIELD OVERWRITE created_at ON user type datetime VALUE time::now() READONLY;\nDEFINE FIELD OVERWRITE country_name ON user TYPE string;\nDEFINE FIELD OVERWRITE country_code ON user TYPE string;\nDEFINE FIELD OVERWRITE groups ON user FLEXIBLE TYPE array<object>;\nDEFINE FIELD OVERWRITE previous_usernames ON user TYPE array<string>;\nDEFINE FIELD OVERWRITE ranked_and_approved_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE ranked_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE nominated_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE guest_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE loved_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE graveyard_beatmapset_count ON user TYPE int;\nDEFINE FIELD OVERWRITE pending_beatmapset_count ON user TYPE int;\n\nDEFINE FIELD OVERWRITE activity_preferences ON user FLEXIBLE TYPE object \nDEFAULT{\n add_influence: true,\n add_influence_beatmap: true,\n add_user_beatmap: true,\n edit_bio: true,\n edit_influence_description: true,\n edit_influence_type: true,\n login: false,\n remove_influence: false,\n remove_influence_beatmap: false,\n remove_user_beatmap: false,\n};\n","events":"DEFINE EVENT OVERWRITE add_influence ON TABLE influenced_by\nWHEN \n $session.tk.ID == \"backend\" AND $event == \"CREATE\"\nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(),\n event_type = \"ADD_INFLUENCE\", \n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE add_influence_beatmap ON TABLE influenced_by\nWHEN\n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND array::len($after.beatmaps) > array::len($before.beatmaps)\nTHEN (\n CREATE activity \n SET user = $after.in,\n created_at = time::now(),\n event_type = \"ADD_INFLUENCE_BEATMAP\", \n beatmap = array::complement($after.beatmaps, $before.beatmaps).at(0),\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE add_user_beatmap ON TABLE user \nWHEN \n $session.tk.ID == \"backend\" \n AND $event == \"UPDATE\" \n AND array::len($after.beatmaps) > array::len($before.beatmaps) \nTHEN (\n CREATE activity \n SET user = $after.id,\n created_at = time::now(),\n event_type = \"ADD_USER_BEATMAP\", \n beatmap = array::complement($after.beatmaps, $before.beatmaps).at(0)\n);\n\n// edit_bio logs when creating user, so added before != null\nDEFINE EVENT OVERWRITE edit_bio ON TABLE user \nWHEN \n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND $before.bio != $after.bio\nTHEN (\n CREATE activity \n SET user = $after.id, \n created_at = time::now(), \n event_type = \"EDIT_BIO\", \n bio = $after.bio\n);\n\nDEFINE EVENT OVERWRITE edit_influence_description ON TABLE influenced_by\nWHEN\n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND $before.description != $after.description\nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(), \n event_type = \"EDIT_INFLUENCE_DESC\", \n description = $after.description,\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE edit_influence_type ON TABLE influenced_by \nWHEN \n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND $before.influence_type != $after.influence_type \nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(), \n event_type = \"EDIT_INFLUENCE_TYPE\", \n influence_type= $after.influence_type,\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE remove_influence ON TABLE influenced_by\nWHEN \n $session.tk.ID == \"backend\" AND $event == \"DELETE\"\nTHEN (\n CREATE activity \n SET user = $before.in, \n created_at = time::now(),\n event_type = \"REMOVE_INFLUENCE\", \n influence = $before\n);\n\nDEFINE EVENT OVERWRITE remove_influence_beatmap ON TABLE influenced_by\nWHEN\n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND array::len($before.beatmaps) > array::len($after.beatmaps)\nTHEN (\n CREATE activity \n SET user = $after.in, \n created_at = time::now(),\n event_type = \"REMOVE_INFLUENCE_BEATMAP\", \n beatmap = array::complement($before.beatmaps, $after.beatmaps).at(0),\n influence = {\n id: $after.id,\n out: $after.out,\n }\n);\n\nDEFINE EVENT OVERWRITE remove_user_beatmap ON TABLE user \nWHEN \n $session.tk.ID == \"backend\"\n AND $event == \"UPDATE\"\n AND array::len($before.beatmaps) > array::len($after.beatmaps)\nTHEN (\n CREATE activity \n SET user = $after.id, \n created_at = time::now(),\n event_type = \"REMOVE_USER_BEATMAP\", \n beatmap = array::complement($before.beatmaps, $after.beatmaps).at(0)\n);\n"}
12 changes: 0 additions & 12 deletions migrations/schemas/activity_preference.surql

This file was deleted.

15 changes: 13 additions & 2 deletions migrations/schemas/user.surql
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ DEFINE FIELD OVERWRITE guest_beatmapset_count ON user TYPE int;
DEFINE FIELD OVERWRITE loved_beatmapset_count ON user TYPE int;
DEFINE FIELD OVERWRITE graveyard_beatmapset_count ON user TYPE int;
DEFINE FIELD OVERWRITE pending_beatmapset_count ON user TYPE int;
DEFINE FIELD OVERWRITE activity_preference ON user TYPE option<record<activity_preference>>;

DEFINE INDEX OVERWRITE country_name_index ON TABLE user COLUMNS country_name;
DEFINE FIELD OVERWRITE activity_preferences ON user FLEXIBLE TYPE object
DEFAULT{
add_influence: true,
add_influence_beatmap: true,
add_user_beatmap: true,
edit_bio: true,
edit_influence_description: true,
edit_influence_type: true,
login: false,
remove_influence: false,
remove_influence_beatmap: false,
remove_user_beatmap: false,
};
54 changes: 54 additions & 0 deletions src/daily_update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::{sync::Arc, time::Duration};

use crate::{
database::DatabaseClient, osu_api::credentials_grant::CredentialsGrantClient, retry::Retryable,
};

pub async fn update_once(
client: Arc<CredentialsGrantClient>,
database: Arc<DatabaseClient>,
users_to_update: Vec<u32>,
wait_duration: Duration,
) {
let mut interval = tokio::time::interval(wait_duration);
for user_id in users_to_update {
interval.tick().await;
let Ok(user) = client.get_user_osu(user_id).await else {
tracing::error!(
"Failed to request {} from osu! API for daily update",
user_id
);
continue;
};
let Ok(_) = database.upsert_user(user).await else {
tracing::error!(
"Failed to insert user {} to database for daily update",
user_id
);
continue;
};
tracing::debug!("Requested and inserted user {} for daily update", user_id);
}
}

pub async fn update_routine(
client: Arc<CredentialsGrantClient>,
mut database: Arc<DatabaseClient>,
initial_sleep_time: Duration,
) {
tokio::time::sleep(initial_sleep_time).await;
let mut interval = tokio::time::interval(Duration::from_secs(60 * 60 * 24));
loop {
interval.tick().await;
let users_to_update: Vec<u32> = database
.retry_until_success(60, "Failed to fetch users for daily update")
.await;
update_once(
client.clone(),
database.clone(),
users_to_update,
Duration::from_secs(15),
)
.await;
}
}
7 changes: 4 additions & 3 deletions src/database/activity.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::sync::Arc;

use async_trait::async_trait;

use surrealdb::{method::QueryStream, Notification};

use crate::{error::AppError, handlers::activity::Activity, retry::Retryable};
Expand Down Expand Up @@ -83,9 +85,8 @@ impl DatabaseClient {
}
}

impl Retryable for Arc<DatabaseClient> {
type Value = QueryStream<Notification<Activity>>;
type Err = AppError;
#[async_trait]
impl Retryable<QueryStream<Notification<Activity>>, AppError> for Arc<DatabaseClient> {
async fn retry(&mut self) -> Result<QueryStream<Notification<Activity>>, AppError> {
self.start_activity_stream().await
}
Expand Down
3 changes: 2 additions & 1 deletion src/database/graph_vizualizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct GraphUser {
pub struct GraphInfluence {
source: u32,
target: u32,
influence_type: u8,
}

impl DatabaseClient {
Expand All @@ -41,7 +42,7 @@ impl DatabaseClient {
pub async fn get_influences_for_graph(&self) -> Result<Vec<GraphInfluence>, AppError> {
let graph_influences: Vec<GraphInfluence> = self
.db
.query("SELECT meta::id(in) AS source, meta::id(out) AS target FROM influenced_by;")
.query("SELECT meta::id(in) AS source, meta::id(out), influence_type AS target FROM influenced_by;")
.await?
.take(0)?;
Ok(graph_influences)
Expand Down
Loading

0 comments on commit 910dd73

Please sign in to comment.