docbox_database/models/
link_resolved_metadata.rs

1use crate::{DbExecutor, DbResult};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use sqlx::{postgres::PgQueryResult, prelude::FromRow};
5
6#[derive(Debug, Clone, FromRow, Serialize)]
7pub struct LinkResolvedMetadata {
8    /// URL of the resolved metadata
9    pub url: String,
10    /// The metadata itself
11    #[sqlx(json)]
12    pub metadata: StoredResolvedWebsiteMetadata,
13    /// Timestamp of when the metadata will expire
14    pub expires_at: DateTime<Utc>,
15}
16
17#[derive(Debug, Clone, Serialize, PartialEq, Eq, Deserialize)]
18pub struct StoredResolvedWebsiteMetadata {
19    pub title: Option<String>,
20    pub og_title: Option<String>,
21    pub og_description: Option<String>,
22    pub og_image: Option<String>,
23    pub best_favicon: Option<String>,
24}
25
26pub struct CreateLinkResolvedMetadata {
27    pub url: String,
28    pub metadata: StoredResolvedWebsiteMetadata,
29    pub expires_at: DateTime<Utc>,
30}
31
32impl LinkResolvedMetadata {
33    /// Create and insert a new resolved link metadata
34    pub async fn create(
35        db: impl DbExecutor<'_>,
36        create: CreateLinkResolvedMetadata,
37    ) -> DbResult<()> {
38        let metadata = serde_json::to_value(&create.metadata)
39            .map_err(|error| sqlx::Error::Encode(error.into()))?;
40
41        sqlx::query(
42            r#"
43            INSERT INTO "docbox_links_resolved_metadata" ("url", "metadata", "expires_at")
44            VALUES ($1, $2, $3)
45            ON CONFLICT ("url") DO UPDATE
46            SET
47                "metadata" = EXCLUDED."metadata",
48                "expires_at" = EXCLUDED."expires_at"
49        "#,
50        )
51        .bind(create.url)
52        .bind(metadata)
53        .bind(create.expires_at)
54        .execute(db)
55        .await?;
56
57        Ok(())
58    }
59
60    /// Query the resolved link metadata for the provided URL
61    pub async fn query(
62        db: impl DbExecutor<'_>,
63        url: &str,
64    ) -> DbResult<Option<LinkResolvedMetadata>> {
65        sqlx::query_as(r#"SELECT * FROM "docbox_links_resolved_metadata" WHERE "url" = $1"#)
66            .bind(url)
67            .fetch_optional(db)
68            .await
69    }
70
71    /// Deletes all metadata where the expiry date is less than `before`
72    pub async fn delete_expired(
73        db: impl DbExecutor<'_>,
74        before: DateTime<Utc>,
75    ) -> DbResult<PgQueryResult> {
76        sqlx::query(r#"DELETE FROM "docbox_links_resolved_metadata" WHERE "expires_at" < $1"#)
77            .bind(before)
78            .execute(db)
79            .await
80    }
81}