Compare commits

..

3 Commits

Author SHA1 Message Date
3adc3035f6 Move all sql queries to storage module 2025-02-09 22:50:29 +01:00
daa12a9dc4 Rename flake list template 2025-02-09 22:21:29 +01:00
bfbecb87d9 Display timestamp human readable 2025-02-09 22:18:43 +01:00
6 changed files with 107 additions and 44 deletions

View File

@ -15,6 +15,8 @@ use flake_tracker::{
FlakeUri, FlakeUri,
}, },
storage::{ storage::{
InputRow,
RevisionRow,
Storage, Storage,
}, },
}; };
@ -48,22 +50,17 @@ async fn main() -> Result<()> {
let flake_metadata: FlakeMetadata = serde_json::from_slice(&flake_metadata_raw.stdout) let flake_metadata: FlakeMetadata = serde_json::from_slice(&flake_metadata_raw.stdout)
.context("Failed to parse flake metadata")?; .context("Failed to parse flake metadata")?;
sqlx::query("INSERT INTO revisions (revision_uri, flake_uri, nix_store_path, nar_hash, last_modified, tracker_last_scanned) let revision_row = RevisionRow {
VALUES (?, ?, ?, ?, ?, ?) revision_uri: flake_metadata.locked.flake_uri()?.clone(),
ON CONFLICT(revision_uri) DO UPDATE SET flake_uri: Some(flake_metadata.resolved.flake_uri()?.clone()),
flake_uri=excluded.flake_uri, nix_store_path: Some(flake_metadata.path.clone()),
nix_store_path=excluded.nix_store_path, nar_hash: Some(flake_metadata.locked.narHash.clone()),
nar_hash=excluded.nar_hash, last_modified: Some(flake_metadata.locked.lastModified.clone()),
last_modified=excluded.last_modified, tracker_last_scanned: Some(scan_time.clone()),
tracker_last_scanned=excluded.tracker_last_scanned };
")
.bind(&flake_metadata.locked.flake_uri()?) storage.set_revision(revision_row)
.bind(&flake_metadata.resolved.flake_uri()?) .await?;
.bind(&flake_metadata.path)
.bind(&flake_metadata.locked.narHash)
.bind(&flake_metadata.locked.lastModified)
.bind(&scan_time)
.execute(&storage.db).await?;
let locks_root_name = &flake_metadata.locks.root; let locks_root_name = &flake_metadata.locks.root;
let locks_root_node = flake_metadata.locks.nodes.get(locks_root_name) let locks_root_node = flake_metadata.locks.nodes.get(locks_root_name)
@ -75,29 +72,27 @@ async fn main() -> Result<()> {
let locks_input_node = flake_metadata.locks.nodes.get(&locks_input_name) let locks_input_node = flake_metadata.locks.nodes.get(&locks_input_name)
.context("Failed to find lock of input")?; .context("Failed to find lock of input")?;
sqlx::query("INSERT INTO inputs (revision_uri, input_name, locked_revision_uri, locked_flake_uri, locked_nar_hash, last_modified) let input_row = InputRow {
VALUES (?, ?, ?, ?, ?, ?) revision_uri: flake_metadata.locked.flake_uri()?.clone(),
ON CONFLICT(revision_uri, input_name) DO UPDATE SET input_name: input_name.clone(),
locked_revision_uri=excluded.locked_revision_uri, locked_revision_uri: Some(locks_input_node.locked.clone().context("Unexpected missing lock")?.flake_uri()?),
locked_flake_uri=excluded.locked_flake_uri, locked_flake_uri: Some(locks_input_node.original.clone().context("Unexpected missing lock")?.flake_uri()?),
locked_nar_hash=excluded.locked_nar_hash, locked_nar_hash: Some(locks_input_node.locked.clone().context("Unexpected missing lock")?.narHash),
last_modified=excluded.last_modified last_modified: Some(locks_input_node.locked.clone().context("Unexpected missing lock")?.lastModified),
") };
.bind(flake_metadata.locked.flake_uri()?) storage.set_input(input_row)
.bind(input_name) .await?;
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.flake_uri()?)
.bind(locks_input_node.original.clone().context("Unexpected missing lock")?.flake_uri()?)
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.narHash)
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.lastModified)
.execute(&storage.db).await?;
sqlx::query("INSERT INTO revisions (revision_uri, flake_uri) let revision_row = RevisionRow {
VALUES (?, ?) revision_uri: locks_input_node.locked.clone().context("Unexpected missing lock")?.flake_uri()?.clone(),
ON CONFLICT(revision_uri) DO NOTHING flake_uri: Some(locks_input_node.original.clone().context("Unexpected missing lock")?.flake_uri()?.clone()),
") nix_store_path: None,
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.flake_uri()?) nar_hash: None,
.bind(locks_input_node.original.clone().context("Unexpected missing lock")?.flake_uri()?) last_modified: None,
.execute(&storage.db).await?; tracker_last_scanned: None,
};
storage.set_revision_exist(revision_row)
.await?;
} }
} }

View File

@ -24,8 +24,8 @@ use flake_tracker::{
Storage, Storage,
}, },
templates::{ templates::{
FlakeListTemplate,
FlakeTemplate, FlakeTemplate,
FlakesTemplate,
IndexTemplate, IndexTemplate,
RevisionTemplate, RevisionTemplate,
}, },
@ -113,7 +113,7 @@ async fn route_index() -> Result<impl IntoResponse, AppError> {
async fn route_flakes( async fn route_flakes(
State(state): State<AppState>, State(state): State<AppState>,
) -> Result<impl IntoResponse, AppError> { ) -> Result<impl IntoResponse, AppError> {
Ok(render_template(&FlakesTemplate { Ok(render_template(&FlakeListTemplate {
flakes: state.storage.flakes().await?, flakes: state.storage.flakes().await?,
})?) })?)
} }

View File

@ -2,13 +2,20 @@ use anyhow::{
Context, Context,
Result, Result,
}; };
use chrono::{
DateTime,
Utc,
};
use crate::utils::{ use crate::utils::{
urlencode, urlencode,
}; };
use sqlx::{ use sqlx::{
FromRow, FromRow,
SqlitePool, SqlitePool,
sqlite::SqlitePoolOptions, sqlite::{
SqlitePoolOptions,
SqliteQueryResult,
},
}; };
#[derive(Clone)] #[derive(Clone)]
@ -40,6 +47,39 @@ impl Storage {
.context("Failed to fetch data from database") .context("Failed to fetch data from database")
} }
pub async fn set_revision(&self, revision_row: RevisionRow) -> Result<SqliteQueryResult> {
sqlx::query("INSERT INTO revisions (revision_uri, flake_uri, nix_store_path, nar_hash, last_modified, tracker_last_scanned)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(revision_uri) DO UPDATE SET
flake_uri=excluded.flake_uri,
nix_store_path=excluded.nix_store_path,
nar_hash=excluded.nar_hash,
last_modified=excluded.last_modified,
tracker_last_scanned=excluded.tracker_last_scanned
")
.bind(&revision_row.revision_uri)
.bind(&revision_row.flake_uri)
.bind(&revision_row.nix_store_path)
.bind(&revision_row.nar_hash)
.bind(&revision_row.last_modified)
.bind(&revision_row.tracker_last_scanned)
.execute(&self.db)
.await
.context("Failed to execute database query")
}
pub async fn set_revision_exist(&self, revision_row: RevisionRow) -> Result<SqliteQueryResult> {
sqlx::query("INSERT INTO revisions (revision_uri, flake_uri)
VALUES (?, ?)
ON CONFLICT(revision_uri) DO NOTHING
")
.bind(&revision_row.revision_uri)
.bind(&revision_row.flake_uri)
.execute(&self.db)
.await
.context("Failed to execute database query")
}
pub async fn revisions_from_flake(&self, uri: &str) -> Result<Vec<RevisionRow>> { pub async fn revisions_from_flake(&self, uri: &str) -> Result<Vec<RevisionRow>> {
sqlx::query_as(" sqlx::query_as("
SELECT SELECT
@ -59,6 +99,27 @@ impl Storage {
.context("Failed to fetch data from database") .context("Failed to fetch data from database")
} }
pub async fn set_input(&self, input_row: InputRow) -> Result<SqliteQueryResult> {
sqlx::query("INSERT INTO inputs (revision_uri, input_name, locked_revision_uri, locked_flake_uri, locked_nar_hash, last_modified)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(revision_uri, input_name) DO UPDATE SET
locked_revision_uri=excluded.locked_revision_uri,
locked_flake_uri=excluded.locked_flake_uri,
locked_nar_hash=excluded.locked_nar_hash,
last_modified=excluded.last_modified
")
.bind(input_row.revision_uri)
.bind(input_row.input_name)
.bind(input_row.locked_revision_uri)
.bind(input_row.locked_flake_uri)
.bind(input_row.locked_nar_hash)
.bind(input_row.last_modified)
.execute(&self.db)
.await
.context("Failed to execute database query")
}
pub async fn inputs_for_revision(&self, revision_uri: &str) -> Result<Vec<InputRow>> { pub async fn inputs_for_revision(&self, revision_uri: &str) -> Result<Vec<InputRow>> {
sqlx::query_as(" sqlx::query_as("
SELECT SELECT
@ -147,6 +208,13 @@ impl RevisionRow {
None => String::from("#"), None => String::from("#"),
} }
} }
pub fn last_modified_time(&self) -> Option<DateTime<Utc>> {
match &self.last_modified {
Some(last_modified) => DateTime::from_timestamp(last_modified.clone(), 0),
None => None,
}
}
} }
#[derive(FromRow)] #[derive(FromRow)]

View File

@ -15,8 +15,8 @@ pub struct IndexTemplate {
} }
#[derive(Template)] #[derive(Template)]
#[template(path = "flakes.html")] #[template(path = "flake_list.html")]
pub struct FlakesTemplate { pub struct FlakeListTemplate {
pub flakes: Vec<FlakeRow>, pub flakes: Vec<FlakeRow>,
} }

View File

@ -11,7 +11,7 @@
<ul> <ul>
{% for revision in revisions %} {% for revision in revisions %}
<li><a href="{{ revision.revision_link() }}">{{ revision.revision_uri }}</a> {% match revision.last_modified %}{% when Some with (last_modified) %}({{ last_modified }}){% when None %}{% endmatch %}</li> <li><a href="{{ revision.revision_link() }}">{{ revision.revision_uri }}</a> {% match revision.last_modified_time() %}{% when Some with (last_modified_time) %}({{ last_modified_time }}){% when None %}{% endmatch %}</li>
{% endfor %} {% endfor %}
</ul> </ul>