Add command for writing cell edits over time

This commit is contained in:
2023-11-15 16:59:28 -05:00
parent 9fcac0ce39
commit c931eeca86
7 changed files with 466 additions and 159 deletions

View File

@@ -0,0 +1,47 @@
use crate::models::cell::{self, CellFileEditCount};
use anyhow::Result;
use chrono::{Duration, NaiveDateTime};
use std::collections::HashMap;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use tracing::{debug, info};
pub async fn dump_cell_edit_counts_over_time(
pool: &sqlx::Pool<sqlx::Postgres>,
start_date: NaiveDateTime,
end_date: NaiveDateTime,
path: &str,
) -> Result<()> {
let mut current_date = start_date;
while current_date <= end_date {
let next_date = current_date + Duration::weeks(1);
let mut cell_file_edit_counts = HashMap::new();
let counts =
cell::count_file_edits_in_time_range(pool, "Skyrim.esm", 1, current_date, next_date)
.await?;
for x in -77..75 {
for y in -50..44 {
let count: Option<&CellFileEditCount> = counts.iter().find(|c| c.x.unwrap() == x && c.y.unwrap() == y);
let count = count.map(|c| c.count).unwrap_or(Some(0)).unwrap();
debug!(x = x, y = y, count = count, "read cell edit count");
cell_file_edit_counts.insert(format!("{},{}", x, y), count);
}
}
let file_name = format!(
"{}/cell_edits_{}.json",
path,
current_date.format("%Y-%m-%d")
);
info!(
"writing {} cell edit counts to {}",
cell_file_edit_counts.values().sum::<i64>(),
file_name
);
let mut file = File::create(&file_name).await?;
file.write_all(serde_json::to_string(&cell_file_edit_counts)?.as_bytes()).await?;
current_date = next_date;
}
Ok(())
}

View File

@@ -2,6 +2,7 @@ pub mod backfills;
pub mod download_tiles;
pub mod dump_cell_data;
pub mod dump_cell_edit_counts;
pub mod dump_cell_edit_counts_over_time;
pub mod dump_file_data;
pub mod dump_games;
pub mod dump_mod_cell_counts;
@@ -13,6 +14,7 @@ pub mod update;
pub use download_tiles::download_tiles;
pub use dump_cell_data::dump_cell_data;
pub use dump_cell_edit_counts::dump_cell_edit_counts;
pub use dump_cell_edit_counts_over_time::dump_cell_edit_counts_over_time;
pub use dump_file_data::dump_file_data;
pub use dump_games::dump_games;
pub use dump_mod_cell_counts::dump_mod_cell_counts;

View File

@@ -1,6 +1,6 @@
use anyhow::Result;
use argh::FromArgs;
use chrono::NaiveDateTime;
use chrono::{NaiveDateTime, NaiveDate, Utc};
use dotenv::dotenv;
use sqlx::postgres::PgPoolOptions;
use std::env;
@@ -15,8 +15,8 @@ mod plugin_processor;
use commands::{
backfills::backfill_is_base_game, backfills::backfill_is_translation,
backfills::deduplicate_interior_cells, download_tiles, dump_cell_data, dump_cell_edit_counts,
dump_file_data, dump_games, dump_mod_cell_counts, dump_mod_data, dump_mod_search_index,
dump_plugin_data, update,
dump_cell_edit_counts_over_time, dump_file_data, dump_games, dump_mod_cell_counts,
dump_mod_data, dump_mod_search_index, dump_plugin_data, update,
};
#[derive(FromArgs)]
@@ -42,6 +42,10 @@ struct Args {
#[argh(option, short = 'e')]
dump_edits: Option<String>,
/// file to output the cell mod edit counts over time as json
#[argh(option, short = 'E')]
dump_edits_over_time: Option<String>,
/// folder to output all cell data as json files
#[argh(option, short = 'c')]
cell_data: Option<String>,
@@ -107,6 +111,15 @@ pub async fn main() -> Result<()> {
if let Some(path) = args.dump_edits {
return dump_cell_edit_counts(&pool, &path).await;
}
if let Some(path) = args.dump_edits_over_time {
return dump_cell_edit_counts_over_time(
&pool,
NaiveDate::from_ymd_opt(2011, 11, 11).unwrap().and_hms_opt(0, 0, 0).unwrap(),
Utc::now().naive_utc(),
&path,
)
.await;
}
if let Some(dir) = args.cell_data {
return dump_cell_data(&pool, &dir).await;
}

View File

@@ -150,6 +150,43 @@ pub async fn count_mod_edits(
.context("Failed to count mod edits on cell")
}
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct CellFileEditCount {
pub x: Option<i32>,
pub y: Option<i32>,
pub count: Option<i64>,
}
#[instrument(level = "debug", skip(pool))]
pub async fn count_file_edits_in_time_range(
pool: &sqlx::Pool<sqlx::Postgres>,
master: &str,
world_id: i32,
start_date: NaiveDateTime,
end_date: NaiveDateTime,
) -> Result<Vec<CellFileEditCount>> {
sqlx::query_as!(
CellFileEditCount,
"SELECT cells.x, cells.y, COUNT(DISTINCT files.id)
FROM cells
JOIN plugin_cells on cells.id = cell_id
JOIN plugins ON plugins.id = plugin_id
JOIN files ON files.id = plugins.file_id
WHERE master = $1 AND world_id = $2
AND cells.x IS NOT NULL and cells.y IS NOT NULL
AND files.uploaded_at BETWEEN $3 AND $4
GROUP BY cells.x, cells.y
",
master,
world_id,
start_date,
end_date,
)
.fetch_all(pool)
.await
.context("Failed to count file-based mod edits on cell")
}
/// Returns cell properties plus a list of mods that edit the cell
#[instrument(level = "debug", skip(pool))]
pub async fn get_cell_data(