feat: define core DB traits to store, check for existence and delete

forges
This commit is contained in:
Aravinth Manivannan 2022-04-12 17:35:09 +05:30
parent 5af8888936
commit 2a8283acc0
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
7 changed files with 412 additions and 0 deletions

2
db/db-core/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
.env

122
db/db-core/Cargo.lock generated Normal file
View file

@ -0,0 +1,122 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "async-trait"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "db-core"
version = "0.1.0"
dependencies = [
"async-trait",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "proc-macro2"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"

25
db/db-core/Cargo.toml Normal file
View file

@ -0,0 +1,25 @@
[package]
name = "db-core"
version = "0.1.0"
edition = "2021"
homepage = "https://github.com/forgeflux-org/starchart"
repository = "https://github.com/forgeflux-org/starchart"
documentation = "https://github.con/forgeflux-org/starchart"
readme = "https://github.com/forgeflux-org/starchart/blob/master/README.md"
license = "AGPLv3 or later version"
authors = ["Aravinth Manivannan <realaravinth@batsense.net>"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-trait = "0.1.51"
thiserror = "1.0.30"
serde = { version = "1", features = ["derive"]}
[features]
default = []
test = []
[dev-dependencies]
serde_json = "1"

48
db/db-core/src/errors.rs Normal file
View file

@ -0,0 +1,48 @@
/*
* ForgeFlux StarChart - A federated software forge spider
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//! represents all the ways a trait can fail using this crate
use std::error::Error as StdError;
//use derive_more::{error, Error as DeriveError};
use thiserror::Error;
/// Error data structure grouping various error subtypes
#[derive(Debug, Error)]
pub enum DBError {
/// DNS challenge value is already taken
#[error("DNS challenge is already taken")]
DuplicateChallengeText,
/// DNS challenge hostname is already taken
#[error("DNS challenge hostname is already taken")]
DuplicateChallengeHostname,
/// forge instance type is unknown
#[error("Unknown forge instance specifier {}", _0)]
UnknownForgeType(String),
/// errors that are specific to a database implementation
#[error("{0}")]
DBError(#[source] BoxDynError),
}
/// Convenience type alias for grouping driver-specific errors
pub type BoxDynError = Box<dyn StdError + 'static + Send + Sync>;
/// Generic result data structure
pub type DBResult<V> = std::result::Result<V, DBError>;

136
db/db-core/src/lib.rs Normal file
View file

@ -0,0 +1,136 @@
/*
* ForgeFlux StarChart - A federated software forge spider
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![warn(missing_docs)]
//! # `Starchart` database operations
//!
//! Traits and datastructures used in Starchart to interact with database.
//!
//! To use an unsupported database with Starchart, traits present within this crate should be
//! implemented.
//!
//!
//! ## Organisation
//!
//! Database functionallity is divided accross various modules:
//!
//! - [errors](crate::auth): error data structures used in this crate
//! - [ops](crate::ops): meta operations like connection pool creation, migrations and getting
//! connection from pool
use std::str::FromStr;
use serde::{Deserialize, Serialize};
pub mod errors;
pub mod ops;
#[cfg(feature = "test")]
pub mod tests;
pub use ops::GetConnection;
pub mod prelude {
//! useful imports for users working with a supported database
pub use super::errors::*;
pub use super::ops::*;
pub use super::*;
}
pub mod dev {
//! useful imports for supporting a new database
pub use super::prelude::*;
pub use async_trait::async_trait;
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
/// create a new forge on the database
pub struct CreateForge<'a> {
/// hostname of the forge instance: with scheme but remove trailing slash
pub hostname: &'a str,
/// forge type: which software is the instance running?
pub forge_type: ForgeImplementation,
}
use dev::*;
#[async_trait]
/// Starchart's database requirements. To implement support for $Database, kindly implement this
/// trait.
pub trait SCDatabase: std::marker::Send + std::marker::Sync + CloneSPDatabase {
/// ping DB
async fn ping(&self) -> bool;
/// create forge isntance
async fn create_forge_isntance(&self, f: &CreateForge) -> DBResult<()>;
/// delete forge isntance
async fn delete_forge_instance(&self, hostname: &str) -> DBResult<()>;
/// check if a forge instance exists
async fn forge_exists(&self, hostname: &str) -> DBResult<bool>;
}
/// Trait to clone SCDatabase
pub trait CloneSPDatabase {
/// clone DB
fn clone_db(&self) -> Box<dyn SCDatabase>;
}
impl<T> CloneSPDatabase for T
where
T: SCDatabase + Clone + 'static,
{
fn clone_db(&self) -> Box<dyn SCDatabase> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn SCDatabase> {
fn clone(&self) -> Self {
(**self).clone_db()
}
}
/// Forge type: Gitea, Sourcehut, GitLab, etc. Support is currently only available for Gitea
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ForgeImplementation {
/// [Gitea](https://gitea.io) softare forge
Gitea,
}
impl ForgeImplementation {
/// Convert [ForgeImplementation] to [str]
pub const fn to_str(&self) -> &'static str {
match self {
ForgeImplementation::Gitea => "gitea",
}
}
}
impl FromStr for ForgeImplementation {
type Err = DBError;
/// Convert [str] to [ForgeImplementation]
fn from_str(s: &str) -> DBResult<Self> {
const GITEA: &str = ForgeImplementation::Gitea.to_str();
let s = s.trim();
match s {
GITEA => Ok(Self::Gitea),
_ => Err(DBError::UnknownForgeType(s.to_owned())),
}
}
}

50
db/db-core/src/ops.rs Normal file
View file

@ -0,0 +1,50 @@
/*
* ForgeFlux StarChart - A federated software forge spider
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//! meta operations like migration and connecting to a database
use crate::dev::*;
/// Database operations trait(migrations, pool creation and fetching connection from pool)
pub trait DBOps: GetConnection + Migrate {}
/// Get database connection
#[async_trait]
pub trait GetConnection {
/// database connection type
type Conn;
/// database specific error-type
/// get connection from connection pool
async fn get_conn(&self) -> DBResult<Self::Conn>;
}
/// Create databse connection
#[async_trait]
pub trait Connect {
/// database specific pool-type
type Pool: SCDatabase;
/// database specific error-type
/// create connection pool
async fn connect(self) -> DBResult<Self::Pool>;
}
/// database migrations
#[async_trait]
pub trait Migrate: SCDatabase {
/// database specific error-type
/// run migrations
async fn migrate(&self) -> DBResult<()>;
}

29
db/db-core/src/tests.rs Normal file
View file

@ -0,0 +1,29 @@
/*
* ForgeFlux StarChart - A federated software forge spider
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//! Test utilities
use crate::prelude::*;
/// adding forge works
pub async fn adding_forge_works<T: SCDatabase>(
db: &T,
create_forge_msg: CreateForge<'static>
) {
let _ = db.delete_forge_instance(&create_forge_msg.hostname).await;
db.create_forge_isntance(&create_forge_msg).await.unwrap();
assert!(db.forge_exists(create_forge_msg.hostname).await.unwrap(), "forge creation failed, forge existance check failure");
}