@jpgilldev / steid

steid/src/domain/repository/repo_repo.rs
2.8 KBRaw
1use std::time::SystemTime;
2
3use super::RepositoryResult;
4use crate::domain::{OrgId, RepoId, RepoName, Repository};
5
6/// Persistence for [`Repository`].
7pub trait RepoRepository: Send + Sync {
8 fn find_by_id(
9 &self,
10 id: &RepoId,
11 ) -> impl Future<Output = RepositoryResult<Option<Repository>>> + Send;
12
13 /// Looks a repository up by its owner and name — the `/{handle}/repos/{name}` pair.
14 fn find_by_org_and_name(
15 &self,
16 org_id: &OrgId,
17 name: &RepoName,
18 ) -> impl Future<Output = RepositoryResult<Option<Repository>>> + Send;
19
20 /// Every repository owned by an organisation, most recently updated first, ties
21 /// broken by name.
22 ///
23 /// Recency rather than alphabetical because the profile is a portfolio: alphabetical
24 /// is a filing rule and puts `dotfiles` above the thing being built. The name
25 /// tiebreak is what keeps a listing stable when several repositories share a second
26 /// — every repository that existed before `updated_at` did shares one exactly.
27 ///
28 /// Returns them all regardless of visibility. Filtering is an authorization
29 /// decision and belongs to the use case, so that the page and `/api` cannot end up
30 /// applying different rules.
31 fn list_by_org(
32 &self,
33 org_id: &OrgId,
34 ) -> impl Future<Output = RepositoryResult<Vec<Repository>>> + Send;
35
36 /// Inserts or replaces a repository.
37 ///
38 /// The owning organisation must already exist; the foreign key runs that direction.
39 fn save(&self, repo: &Repository) -> impl Future<Output = RepositoryResult<()>> + Send;
40
41 /// Moves a repository's `updated_at` to `now`, doing nothing if it is gone.
42 ///
43 /// The time is supplied rather than read here, so a test can say when a push
44 /// happened instead of racing the clock — and so the two implementations cannot
45 /// disagree about which clock they read.
46 ///
47 /// Succeeding on a missing row keeps the caller out of the business of a repository
48 /// deleted mid-push; there is nothing useful it could do about it either way.
49 fn touch(
50 &self,
51 id: &RepoId,
52 now: SystemTime,
53 ) -> impl Future<Output = RepositoryResult<()>> + Send;
54
55 /// Deletes a repository, succeeding if there was nothing to delete.
56 ///
57 /// A delete rather than a flag, for the same reason token revocation is: a row that
58 /// lingers is a repository that stops appearing only as long as every read remembers
59 /// to check. The bare repo on disk is a separate write and not this port's business.
60 ///
61 /// Succeeding on a missing row keeps the caller idempotent — two clicks on a delete
62 /// button must not turn the second one into an error.
63 fn delete(&self, id: &RepoId) -> impl Future<Output = RepositoryResult<()>> + Send;
64}