bindizr-db 0.1.0-beta.4

Database repositories for bindizr
Documentation
use async_trait::async_trait;
use sqlx::{Pool, Postgres, Row};

use crate::{error::DatabaseError, model::api_token::ApiToken, repository::ApiTokenRepository};

pub struct PostgresApiTokenRepository {
    pool: Pool<Postgres>,
}

impl PostgresApiTokenRepository {
    pub fn new(pool: Pool<Postgres>) -> Self {
        Self { pool }
    }
}

#[async_trait]
impl ApiTokenRepository for PostgresApiTokenRepository {
    async fn create(&self, mut token: ApiToken) -> Result<ApiToken, DatabaseError> {
        let mut conn = self.pool.acquire().await?;

        let result = sqlx::query(
            r#"
            INSERT INTO api_tokens (token, description, expires_at)
            VALUES ($1, $2, $3)
            RETURNING id
        "#,
        )
        .bind(&token.token)
        .bind(&token.description)
        .bind(token.expires_at)
        .fetch_one(&mut *conn)
        .await?;

        token.id = result.get::<i32, _>(0);

        Ok(token)
    }

    async fn get_by_id(&self, id: i32) -> Result<Option<ApiToken>, DatabaseError> {
        let mut conn = self.pool.acquire().await?;

        let row = sqlx::query_as::<_, ApiToken>(
            "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE id = $1"
        )
        .bind(id)
        .fetch_optional(&mut *conn)
        .await
        ?;

        Ok(row)
    }

    async fn get_by_token(&self, token: &str) -> Result<Option<ApiToken>, DatabaseError> {
        let mut conn = self.pool.acquire().await?;

        let row = sqlx::query_as::<_, ApiToken>(
            "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens WHERE token = $1"
        )
        .bind(token)
        .fetch_optional(&mut *conn)
        .await
        ?;

        Ok(row)
    }

    async fn get_all(&self) -> Result<Vec<ApiToken>, DatabaseError> {
        let mut conn = self.pool.acquire().await?;

        let rows = sqlx::query_as::<_, ApiToken>(
            "SELECT id, token, description, expires_at, created_at, last_used_at FROM api_tokens ORDER BY created_at DESC"
        )
        .fetch_all(&mut *conn)
        .await
        ?;

        Ok(rows)
    }

    async fn update(&self, token: ApiToken) -> Result<ApiToken, DatabaseError> {
        let mut conn = self.pool.acquire().await?;

        sqlx::query(
            r#"
            UPDATE api_tokens 
            SET description = $1, expires_at = $2, last_used_at = $3
            WHERE id = $4
        "#,
        )
        .bind(&token.description)
        .bind(token.expires_at)
        .bind(token.last_used_at)
        .bind(token.id)
        .execute(&mut *conn)
        .await?;

        Ok(token)
    }

    async fn delete(&self, id: i32) -> Result<(), DatabaseError> {
        let mut conn = self.pool.acquire().await?;

        sqlx::query("DELETE FROM api_tokens WHERE id = $1")
            .bind(id)
            .execute(&mut *conn)
            .await?;

        Ok(())
    }
}