Skip to content

Commit

Permalink
Bind reports to areas by in instead of url_alias
Browse files Browse the repository at this point in the history
  • Loading branch information
bubelov committed Oct 26, 2023
1 parent 8ee9e53 commit 050c1cc
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 176 deletions.
16 changes: 16 additions & 0 deletions migrations/46.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
DROP TRIGGER report_updated_at;

UPDATE report SET area_url_alias = 'earth' WHERE area_url_alias = '';

ALTER TABLE report ADD COLUMN area_id INTEGER;

CREATE INDEX idx_area_tags_url_alias ON area(json_extract(tags, '$.url_alias'));

UPDATE report SET area_id = (SELECT rowid FROM area WHERE json_extract(tags, '$.url_alias') = area_url_alias);

ALTER TABLE report DROP COLUMN area_url_alias;

CREATE TRIGGER report_updated_at UPDATE OF area_id, date, tags, created_at, deleted_at ON report
BEGIN
UPDATE report SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ') WHERE rowid = old.rowid;
END;
31 changes: 21 additions & 10 deletions src/command/generate_reports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::model::report::Report;
use crate::model::Area;
use crate::service::overpass;
use crate::service::overpass::OverpassElement;
use crate::Error;
use crate::Result;
use geo::Contains;
use geo::LineString;
Expand All @@ -21,13 +22,23 @@ pub async fn run(mut db: Connection) -> Result<()> {
let today = OffsetDateTime::now_utc().date();
info!(date = ?today, "Generating report");

let existing_report = Report::select_by_area_url_alias_and_date("", &today, &db)?;
let existing_reports = Report::select_updated_since(&today.to_string(), None, &db)?;

if existing_report.is_some() {
info!("Found existing report, aborting");
if !existing_reports.is_empty() {
info!("Found existing reports, aborting");
return Ok(());
}

let earth = Area::select_by_url_alias("earth", &db)?;

if earth.is_none() {
Err(Error::Other(
"Can't find an area with url_alias = earth".into(),
))?
}

let earth = earth.unwrap();

let elements = overpass::query_bitcoin_merchants().await?;

let areas: Vec<Area> = Area::select_all(None, &db)?
Expand All @@ -38,7 +49,7 @@ pub async fn run(mut db: Connection) -> Result<()> {
let tx = db.transaction()?;

let report_tags = generate_report_tags(&elements.iter().collect::<Vec<_>>())?;
insert_report("", &report_tags, &tx).await?;
insert_report(earth.id, &report_tags, &tx).await?;

for area in areas {
info!(area.id, "Generating report");
Expand Down Expand Up @@ -106,7 +117,7 @@ pub async fn run(mut db: Connection) -> Result<()> {

info!(area.id, elements = area_elements.len(), "Processing area");
let report_tags = generate_report_tags(&area_elements)?;
insert_report(area.tags["url_alias"].as_str().unwrap(), &report_tags, &tx).await?;
insert_report(area.id, &report_tags, &tx).await?;
}

tx.commit()?;
Expand Down Expand Up @@ -223,14 +234,14 @@ fn generate_report_tags(elements: &[&OverpassElement]) -> Result<HashMap<String,
}

async fn insert_report(
area_url_alias: &str,
area_id: i32,
tags: &HashMap<String, Value>,
conn: &Connection,
) -> Result<()> {
let date = OffsetDateTime::now_utc().date();
info!(area_url_alias, ?date, ?tags, "Inserting new report");
Report::insert(area_url_alias, &date, &tags, conn)?;
info!(area_url_alias, ?date, "Inserted new report");
info!(area_id, ?date, ?tags, "Inserting new report");
Report::insert(area_id, &date, &tags, conn)?;
info!(area_id, ?date, "Inserted new report");
Ok(())
}

Expand All @@ -249,7 +260,7 @@ mod test {
db::migrate(&mut conn)?;

for i in 1..100 {
super::insert_report(&i.to_string(), &HashMap::new(), &conn).await?;
super::insert_report(i, &HashMap::new(), &conn).await?;
}

Ok(())
Expand Down
67 changes: 32 additions & 35 deletions src/controller/report_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use serde::Deserialize;
use serde::Serialize;
use serde_json::Value;
use time::format_description::well_known::Rfc3339;
use time::Date;
use time::OffsetDateTime;
use tracing::warn;

Expand All @@ -31,7 +30,7 @@ pub struct GetArgs {
pub struct GetItem {
pub id: i32,
pub area_id: String,
pub date: Date,
pub date: String,
pub tags: HashMap<String, Value>,
#[serde(with = "time::serde::rfc3339")]
pub created_at: OffsetDateTime,
Expand All @@ -42,10 +41,16 @@ pub struct GetItem {

impl Into<GetItem> for Report {
fn into(self) -> GetItem {
let area_id = if self.area_url_alias == "earth" {
"".into()
} else {
self.area_url_alias
};

GetItem {
id: self.id,
area_id: self.area_url_alias,
date: self.date,
area_id,
date: self.date.to_string(),
tags: self.tags,
created_at: self.created_at,
updated_at: self.updated_at,
Expand Down Expand Up @@ -129,7 +134,7 @@ async fn patch_tags(
mod tests {
use super::*;
use crate::command::db;
use crate::model::token;
use crate::model::{token, Area};
use crate::Result;
use actix_web::test::TestRequest;
use actix_web::web::scope;
Expand Down Expand Up @@ -160,12 +165,10 @@ mod tests {
#[actix_web::test]
async fn get_one_row() -> Result<()> {
let conn = db::setup_connection()?;
Report::insert(
"",
&OffsetDateTime::now_utc().date(),
&HashMap::new(),
&conn,
)?;
let mut area_tags = HashMap::new();
area_tags.insert("url_alias".into(), "test".into());
Area::insert(&area_tags, &conn)?;
Report::insert(1, &OffsetDateTime::now_utc().date(), &HashMap::new(), &conn)?;
let app = test::init_service(
App::new()
.app_data(Data::new(conn))
Expand All @@ -182,121 +185,115 @@ mod tests {
async fn get_with_limit() -> Result<()> {
let mut conn = Connection::open_in_memory()?;
db::migrate(&mut conn)?;

let mut area_tags = HashMap::new();
area_tags.insert("url_alias".into(), "test".into());
Area::insert(&area_tags, &conn)?;
conn.execute(
"INSERT INTO report (
area_url_alias,
area_id,
date,
updated_at
) VALUES (
'test1',
1,
'2023-05-06',
'2023-05-06T00:00:00Z'
)",
[],
)?;

conn.execute(
"INSERT INTO report (
area_url_alias,
area_id,
date,
updated_at
) VALUES (
'test1',
1,
'2023-05-07',
'2023-05-07T00:00:00Z'
)",
[],
)?;

conn.execute(
"INSERT INTO report (
area_url_alias,
area_id,
date,
updated_at
) VALUES (
'test1',
1,
'2023-05-08',
'2023-05-08T00:00:00Z'
)",
[],
)?;

let app = test::init_service(
App::new()
.app_data(Data::new(conn))
.service(scope("/").service(super::get)),
)
.await;

let req = TestRequest::get().uri("/?limit=2").to_request();
let res: Value = test::call_and_read_body_json(&app, req).await;
assert_eq!(res.as_array().unwrap().len(), 2);

Ok(())
}

#[actix_web::test]
async fn get_updated_since() -> Result<()> {
let mut conn = Connection::open_in_memory()?;
db::migrate(&mut conn)?;

let mut area_tags = HashMap::new();
area_tags.insert("url_alias".into(), "test".into());
Area::insert(&area_tags, &conn)?;
conn.execute(
"INSERT INTO report (area_url_alias, date, updated_at) VALUES ('', '2022-01-05', '2022-01-05T00:00:00Z')",
"INSERT INTO report (area_id, date, updated_at) VALUES (1, '2022-01-05', '2022-01-05T00:00:00Z')",
[],
)?;
conn.execute(
"INSERT INTO report (area_url_alias, date, updated_at) VALUES ('', '2022-02-05', '2022-02-05T00:00:00Z')",
"INSERT INTO report (area_id, date, updated_at) VALUES (1, '2022-02-05', '2022-02-05T00:00:00Z')",
[],
)?;

let app = test::init_service(
App::new()
.app_data(Data::new(conn))
.service(scope("/").service(super::get)),
)
.await;

let req = TestRequest::get()
.uri("/?updated_since=2022-01-10")
.to_request();
let res: Vec<GetItem> = test::call_and_read_body_json(&app, req).await;
assert_eq!(res.len(), 1);

Ok(())
}

#[actix_web::test]
async fn patch_tags() -> Result<()> {
let mut conn = Connection::open_in_memory()?;
db::migrate(&mut conn)?;

let mut area_tags = HashMap::new();
area_tags.insert("url_alias".into(), "test".into());
Area::insert(&area_tags, &conn)?;
let admin_token = "test";
conn.execute(
token::INSERT,
named_params! { ":user_id": 1, ":secret": admin_token },
)?;

conn.execute(
"INSERT INTO report (area_url_alias, date, updated_at) VALUES ('', '2020-01-01', '2022-01-05T00:00:00Z')",
"INSERT INTO report (area_id, date, updated_at) VALUES (1, '2020-01-01', '2022-01-05T00:00:00Z')",
[],
)?;

let app = test::init_service(
App::new()
.app_data(Data::new(conn))
.service(super::patch_tags),
)
.await;

let req = TestRequest::patch()
.uri(&format!("/1/tags"))
.append_header(("Authorization", format!("Bearer {admin_token}")))
.set_json(json!({ "foo": "bar" }))
.to_request();
let res = test::call_service(&app, req).await;
assert_eq!(res.status(), StatusCode::OK);

Ok(())
}
}
Loading

0 comments on commit 050c1cc

Please sign in to comment.