// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. //! Git-LFS object bookkeeping: which content-addressed objects (by sha256 oid) //! each repository has stored. The bytes themselves live on disk under //! `storage.lfs_dir`; this table answers "does this repo have this object?" for //! the batch API and access control. use sqlx::Row; use crate::{Store, StoreError, new_id, now_ms}; impl Store { /// Whether `repo_id` has an LFS object with this `oid` recorded. /// /// # Errors /// /// Returns [`StoreError::Query`] on a database failure. pub async fn lfs_object_exists(&self, repo_id: &str, oid: &str) -> Result { let row = sqlx::query("SELECT 1 AS n FROM lfs_objects WHERE repo_id = $1 AND oid = $2") .bind(repo_id) .bind(oid) .fetch_optional(&self.pool) .await?; Ok(row.is_some()) } /// The stored size (bytes) of an LFS object in `repo_id`, if present. /// /// # Errors /// /// Returns [`StoreError::Query`] on a database failure. pub async fn lfs_object_size( &self, repo_id: &str, oid: &str, ) -> Result, StoreError> { let row = sqlx::query("SELECT size AS n FROM lfs_objects WHERE repo_id = $1 AND oid = $2") .bind(repo_id) .bind(oid) .fetch_optional(&self.pool) .await?; Ok(row.map(|r| r.try_get("n")).transpose()?) } /// Record that `repo_id` holds an LFS object (`oid`, `size`). Idempotent: a /// repeat upload of the same object is a no-op. /// /// # Errors /// /// Returns [`StoreError::Query`] on a database failure. pub async fn lfs_object_add( &self, repo_id: &str, oid: &str, size: i64, ) -> Result<(), StoreError> { sqlx::query( "INSERT INTO lfs_objects (id, repo_id, oid, size, created_at) \ VALUES ($1, $2, $3, $4, $5) ON CONFLICT (repo_id, oid) DO NOTHING", ) .bind(new_id()) .bind(repo_id) .bind(oid) .bind(size) .bind(now_ms()) .execute(&self.pool) .await?; Ok(()) } /// The total bytes of LFS objects tracked for `repo_id`. /// /// # Errors /// /// Returns [`StoreError::Query`] on a database failure. pub async fn lfs_repo_bytes(&self, repo_id: &str) -> Result { let n: i64 = sqlx::query("SELECT COALESCE(SUM(size), 0) AS n FROM lfs_objects WHERE repo_id = $1") .bind(repo_id) .fetch_one(&self.pool) .await? .try_get("n")?; Ok(n) } }