Skip to content

Commit

Permalink
Add new areas to elements mapping table
Browse files Browse the repository at this point in the history
  • Loading branch information
bubelov committed Sep 9, 2024
1 parent da9a18e commit f9e66ef
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
17 changes: 17 additions & 0 deletions migrations/60.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CREATE TABLE area_element(
id INTEGER PRIMARY KEY NOT NULL,
area_id INTEGER NOT NULL REFERENCES area(id),
element_id INTEGER NOT NULL REFERENCES element(id),
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ')),
deleted_at TEXT
) STRICT;

CREATE TRIGGER area_element_updated_at UPDATE OF area_id, element_id, created_at, deleted_at ON area_element
BEGIN
UPDATE area_element SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ') WHERE id = old.id;
END;

CREATE INDEX area_element_area_id ON area_element(area_id);

CREATE INDEX area_element_element_id ON area_element(element_id);
1 change: 1 addition & 0 deletions src/area_element/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod model;
166 changes: 166 additions & 0 deletions src/area_element/model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use std::{
thread::sleep,
time::{Duration, Instant},
};

use crate::Result;
use rusqlite::{named_params, Connection, OptionalExtension, Row};
use serde::Serialize;
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
use tracing::{debug, info};

#[derive(Debug, Eq, PartialEq, Serialize)]
pub struct AreaElement {
pub id: i64,
pub area_id: i64,
pub element_id: i64,
#[serde(with = "time::serde::rfc3339")]
pub created_at: OffsetDateTime,
#[serde(with = "time::serde::rfc3339")]
pub updated_at: OffsetDateTime,
#[serde(with = "time::serde::rfc3339::option")]
pub deleted_at: Option<OffsetDateTime>,
}

const TABLE: &str = "area_element";
const ALL_COLUMNS: &str = "id, area_id, element_id, created_at, updated_at, deleted_at";
const COL_ID: &str = "id";
const COL_AREA_ID: &str = "area_id";
const COL_ELEMENT_ID: &str = "element_id";
const _COL_CREATED_AT: &str = "created_at";
const COL_UPDATED_AT: &str = "updated_at";
const _COL_DELETED_AT: &str = "deleted_at ";

impl AreaElement {
pub fn insert(area_id: i64, element_id: i64, conn: &Connection) -> Result<AreaElement> {
sleep(Duration::from_millis(10));
let query = format!(
r#"
INSERT INTO {TABLE} (
{COL_AREA_ID},
{COL_ELEMENT_ID}
) VALUES (
:area_id,
:element_id
)
"#
);
debug!(query);
conn.execute(
&query,
named_params! {
":area_id": area_id,
":element_id": element_id,
},
)?;
Ok(AreaElement::select_by_id(conn.last_insert_rowid(), conn)?.unwrap())
}

pub fn select_updated_since(
updated_since: &OffsetDateTime,
limit: Option<i64>,
conn: &Connection,
) -> Result<Vec<AreaElement>> {
let start = Instant::now();
let query = format!(
r#"
SELECT {ALL_COLUMNS}
FROM {TABLE}
WHERE {COL_UPDATED_AT} > :updated_since
ORDER BY {COL_UPDATED_AT}, {COL_ID}
LIMIT :limit
"#
);
debug!(query);
let res = conn
.prepare(&query)?
.query_map(
named_params! {
":updated_since": updated_since.format(&Rfc3339)?,
":limit": limit.unwrap_or(i64::MAX),
},
mapper(),
)?
.collect::<Result<Vec<_>, _>>()?;
let time_ms = start.elapsed().as_millis();
info!(
count = res.len(),
time_ms,
"Loaded {} area_elements in {} ms",
res.len(),
time_ms,
);
Ok(res)
}

pub fn select_by_area_id(area_id: i64, conn: &Connection) -> Result<Vec<AreaElement>> {
let query = format!(
r#"
SELECT {ALL_COLUMNS}
FROM {TABLE}
WHERE {COL_AREA_ID} = :area_id
ORDER BY {COL_UPDATED_AT}, {COL_ID}
"#
);
debug!(query);
let res = conn
.prepare(&query)?
.query_map(
named_params! {
":area_id": area_id,
},
mapper(),
)?
.collect::<Result<Vec<_>, _>>()?;
Ok(res)
}

pub fn select_by_element_id(element_id: i64, conn: &Connection) -> Result<Vec<AreaElement>> {
let query = format!(
r#"
SELECT {ALL_COLUMNS}
FROM {TABLE}
WHERE {COL_ELEMENT_ID} = :element_id
ORDER BY {COL_UPDATED_AT}, {COL_ID}
"#
);
debug!(query);
let res = conn
.prepare(&query)?
.query_map(
named_params! {
":element_id": element_id,
},
mapper(),
)?
.collect::<Result<Vec<_>, _>>()?;
Ok(res)
}

pub fn select_by_id(id: i64, conn: &Connection) -> Result<Option<AreaElement>> {
let query = format!(
r#"
SELECT {ALL_COLUMNS}
FROM {TABLE}
WHERE {COL_ID} = :id
"#
);
debug!(query);
Ok(conn
.query_row(&query, named_params! { ":id": id }, mapper())
.optional()?)
}
}

const fn mapper() -> fn(&Row) -> rusqlite::Result<AreaElement> {
|row: &Row| -> rusqlite::Result<AreaElement> {
Ok(AreaElement {
id: row.get(0)?,
area_id: row.get(1)?,
element_id: row.get(2)?,
created_at: row.get(3)?,
updated_at: row.get(4)?,
deleted_at: row.get(5)?,
})
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;
mod area;
mod area_element;
mod element_comment;
mod rpc;
mod vacuum;
Expand Down

0 comments on commit f9e66ef

Please sign in to comment.