refactor: combine models and db crate together

This commit is contained in:
Paul Makles
2023-04-22 12:12:02 +01:00
parent f2bb388b3b
commit e43833c0ea
27 changed files with 306 additions and 147 deletions

20
Cargo.lock generated
View File

@@ -2828,8 +2828,14 @@ name = "revolt-database"
version = "0.1.0"
dependencies = [
"async-recursion",
"async-std",
"async-trait",
"authifier",
"futures",
"log",
"mongodb",
"nanoid",
"optional_struct",
"serde",
"serde_json",
]
@@ -2857,7 +2863,6 @@ dependencies = [
"regex",
"reqwest",
"revolt-database",
"revolt-models",
"revolt-quark",
"revolt_rocket_okapi",
"rocket",
@@ -2875,15 +2880,6 @@ dependencies = [
[[package]]
name = "revolt-models"
version = "0.1.0"
dependencies = [
"async-std",
"async-trait",
"authifier",
"futures",
"log",
"revolt-database",
"serde",
]
[[package]]
name = "revolt-quark"
@@ -2933,6 +2929,10 @@ dependencies = [
"web-push",
]
[[package]]
name = "revolt-result"
version = "0.1.0"
[[package]]
name = "revolt_okapi"
version = "0.9.1"

View File

@@ -6,17 +6,35 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
# Databases
mongodb = [ "dep:mongodb" ]
default = [ "mongodb" ]
# ... Other
async-std-runtime = [ "async-std" ]
# Default Features
default = [ "mongodb", "async-std-runtime" ]
[dependencies]
# Utility
log = "*"
nanoid = "0.4.0"
# Serialisation
serde_json = "1"
serde = { version = "1", features = ["derive"] }
optional_struct = { git = "https://github.com/insertish/OptionalStruct", rev = "ee56427cee1f007839825d93d07fffd5a5e038c7" }
# Database
mongodb = { optional = true, version = "2.1.0", default-features = false }
# Async Language Features
futures = "0.3.19"
async-trait = "0.1.51"
async-recursion = "1.0.4"
# Async
async-std = { version = "1.8.0", features = ["attributes"], optional = true }
# Authifier
authifier = { version = "1.0", default-features = false }

View File

@@ -1,4 +0,0 @@
database_derived!(
/// Dummy implementation
pub struct DummyDb {}
);

View File

@@ -1,5 +1,51 @@
mod dummy;
mod mongodb;
mod reference;
pub use self::dummy::*;
pub use self::mongodb::*;
pub use self::reference::*;
/// Database information to use to create a client
pub enum DatabaseInfo {
/// Auto-detect the database in use
Auto,
/// Use the mock database
Reference,
/// Connect to MongoDB
MongoDb(String),
/// Use existing MongoDB connection
MongoDbFromClient(::mongodb::Client),
}
/// Database
#[derive(Clone)]
pub enum Database {
/// Mock database
Reference(ReferenceDb),
/// MongoDB database
MongoDb(MongoDb),
}
impl DatabaseInfo {
/// Create a database client from the given database information
#[async_recursion]
pub async fn connect(self) -> Result<Database, String> {
Ok(match self {
DatabaseInfo::Auto => {
if let Ok(uri) = std::env::var("MONGODB") {
return DatabaseInfo::MongoDb(uri).connect().await;
}
DatabaseInfo::Reference.connect().await?
}
DatabaseInfo::Reference => Database::Reference(Default::default()),
DatabaseInfo::MongoDb(uri) => {
let client = ::mongodb::Client::with_uri_str(uri)
.await
.map_err(|_| "Failed to init db connection.".to_string())?;
Database::MongoDb(MongoDb(client))
}
DatabaseInfo::MongoDbFromClient(client) => Database::MongoDb(MongoDb(client)),
})
}
}

View File

@@ -0,0 +1,13 @@
use std::{collections::HashMap, sync::Arc};
use futures::lock::Mutex;
use crate::Bot;
database_derived!(
/// Reference implementation
#[derive(Default)]
pub struct ReferenceDb {
pub bots: Arc<Mutex<HashMap<String, Bot>>>,
}
);

View File

@@ -4,6 +4,18 @@ extern crate serde;
#[macro_use]
extern crate async_recursion;
#[macro_use]
extern crate async_trait;
#[macro_use]
extern crate log;
#[macro_use]
extern crate optional_struct;
#[cfg(feature = "mongodb")]
pub use mongodb;
macro_rules! database_derived {
( $( $item:item )+ ) => {
$(
@@ -13,54 +25,33 @@ macro_rules! database_derived {
};
}
#[cfg(feature = "mongodb")]
pub use mongodb;
macro_rules! auto_derived {
( $( $item:item )+ ) => {
$(
#[derive(Serialize, Deserialize, Debug, Clone)]
$item
)+
};
}
macro_rules! auto_derived_partial {
( $item:item, $name:expr ) => {
#[derive(OptionalStruct, Serialize, Deserialize, Debug, Clone)]
#[optional_derive(Serialize, Deserialize, Debug, Clone)]
#[optional_name = $name]
#[opt_skip_serializing_none]
#[opt_some_priority]
$item
};
}
mod drivers;
pub use drivers::*;
/// Database information to use to create a client
pub enum DatabaseInfo {
/// Auto-detect the database in use
Auto,
/// Use the mock database
Dummy,
/// Connect to MongoDB
MongoDb(String),
/// Use existing MongoDB connection
MongoDbFromClient(::mongodb::Client),
}
/// Database
#[derive(Clone)]
pub enum Database {
/// Mock database
Dummy(DummyDb),
/// MongoDB database
MongoDb(MongoDb),
}
impl DatabaseInfo {
/// Create a database client from the given database information
#[async_recursion]
pub async fn connect(self) -> Result<Database, String> {
Ok(match self {
DatabaseInfo::Auto => {
if let Ok(uri) = std::env::var("MONGODB") {
return DatabaseInfo::MongoDb(uri).connect().await;
}
DatabaseInfo::Dummy.connect().await?
}
DatabaseInfo::Dummy => Database::Dummy(DummyDb {}),
DatabaseInfo::MongoDb(uri) => {
let client = mongodb::Client::with_uri_str(uri)
.await
.map_err(|_| "Failed to init db connection.".to_string())?;
Database::MongoDb(MongoDb(client))
}
DatabaseInfo::MongoDbFromClient(client) => Database::MongoDb(MongoDb(client)),
})
}
mod models;
pub use models::*;
/// Utility function to check if a boolean value is false
pub fn if_false(t: &bool) -> bool {
!t
}

View File

@@ -0,0 +1,5 @@
mod model;
mod ops;
pub use model::*;
pub use ops::*;

View File

@@ -1,5 +1,5 @@
mod dummy;
mod mongodb;
mod reference;
#[async_trait]
pub trait AbstractMigrations: Sync + Send {

View File

@@ -1,4 +1,4 @@
use revolt_database::MongoDb;
use crate::MongoDb;
use super::AbstractMigrations;

View File

@@ -1,8 +1,8 @@
use super::scripts::LATEST_REVISION;
use revolt_database::mongodb::bson::doc;
use revolt_database::mongodb::options::CreateCollectionOptions;
use revolt_database::MongoDb;
use crate::mongodb::bson::doc;
use crate::mongodb::options::CreateCollectionOptions;
use crate::MongoDb;
pub async fn create_database(db: &MongoDb) {
info!("Creating database.");

View File

@@ -1,13 +1,13 @@
use std::{ops::BitXor, time::Duration};
use futures::StreamExt;
use revolt_database::{
use crate::{
mongodb::{
bson::{doc, from_bson, from_document, to_document, Bson, DateTime, Document},
options::FindOptions,
},
MongoDb,
};
use futures::StreamExt;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]

View File

@@ -1,11 +1,12 @@
use revolt_database::DummyDb;
use crate::ReferenceDb;
use super::AbstractMigrations;
#[async_trait]
impl AbstractMigrations for DummyDb {
impl AbstractMigrations for ReferenceDb {
/// Migrate the database
async fn migrate_database(&self) -> Result<(), ()> {
// Here you would do your typical migrations if this was a real database.
Ok(())
}
}

View File

@@ -0,0 +1,5 @@
mod model;
// mod ops;
pub use model::*;
// pub use ops::*;

View File

@@ -0,0 +1,74 @@
use crate::Database;
auto_derived_partial!(
/// Bot
pub struct Bot {
/// Bot Id
///
/// This equals the associated bot user's id.
#[serde(rename = "_id")]
pub id: String,
/// User Id of the bot owner
pub owner: String,
/// Token used to authenticate requests for this bot
pub token: String,
/// Whether the bot is public
/// (may be invited by anyone)
pub public: bool,
/// Whether to enable analytics
#[serde(skip_serializing_if = "crate::if_false", default)]
pub analytics: bool,
/// Whether this bot should be publicly discoverable
#[serde(skip_serializing_if = "crate::if_false", default)]
pub discoverable: bool,
/// Reserved; URL for handling interactions
#[serde(skip_serializing_if = "Option::is_none")]
pub interactions_url: Option<String>,
/// URL for terms of service
#[serde(skip_serializing_if = "Option::is_none")]
pub terms_of_service_url: Option<String>,
/// URL for privacy policy
#[serde(skip_serializing_if = "Option::is_none")]
pub privacy_policy_url: Option<String>,
/// Enum of bot flags
#[serde(skip_serializing_if = "Option::is_none")]
pub flags: Option<i32>,
},
"PartialBot"
);
auto_derived!(
/// Flags that may be attributed to a bot
#[repr(i32)]
pub enum BotFlags {
Verified = 1,
Official = 2,
}
/// Optional fields on bot object
pub enum FieldsBot {
Token,
InteractionsURL,
}
);
impl Bot {
/// Remove a field from this object
pub fn remove(&mut self, field: &FieldsBot) {
match field {
FieldsBot::Token => self.token = nanoid::nanoid!(64),
FieldsBot::InteractionsURL => {
self.interactions_url.take();
}
}
}
/// Delete this bot
pub async fn delete(&self, db: &Database) -> Result<(), ()> {
// db.fetch_user(&self.id).await?.mark_deleted(db).await?;
// db.delete_bot(&self.id).await
Ok(())
}
}

View File

@@ -0,0 +1,26 @@
mod dummy;
mod mongodb;
#[async_trait]
pub trait AbstractBots: Sync + Send {
/// Fetch a bot by its id
async fn fetch_bot(&self, id: &str) -> Result<Bot>;
/// Fetch a bot by its token
async fn fetch_bot_by_token(&self, token: &str) -> Result<Bot>;
/// Insert new bot into the database
async fn insert_bot(&self, bot: &Bot) -> Result<()>;
/// Update bot with new information
async fn update_bot(&self, id: &str, bot: &PartialBot, remove: Vec<FieldsBot>) -> Result<()>;
/// Delete a bot from the database
async fn delete_bot(&self, id: &str) -> Result<()>;
/// Fetch bots owned by a user
async fn fetch_bots_by_user(&self, user_id: &str) -> Result<Vec<Bot>>;
/// Get the number of bots owned by a user
async fn get_number_of_bots_by_user(&self, user_id: &str) -> Result<usize>;
}

View File

@@ -0,0 +1,9 @@
use revolt_database::MongoDb;
use super::AbstractBots;
mod init;
mod scripts;
#[async_trait]
impl AbstractBots for MongoDb {}

View File

@@ -0,0 +1,6 @@
use revolt_database::DummyDb;
use super::AbstractBots;
#[async_trait]
impl AbstractBots for DummyDb {}

View File

@@ -0,0 +1,22 @@
mod admin_migrations;
mod bots;
pub use admin_migrations::*;
pub use bots::*;
use crate::{Database, MongoDb, ReferenceDb};
pub trait AbstractDatabase: Sync + Send + admin_migrations::AbstractMigrations {}
impl AbstractDatabase for ReferenceDb {}
impl AbstractDatabase for MongoDb {}
impl std::ops::Deref for Database {
type Target = dyn AbstractDatabase;
fn deref(&self) -> &Self::Target {
match &self {
Database::Reference(dummy) => dummy,
Database::MongoDb(mongo) => mongo,
}
}
}

View File

@@ -5,29 +5,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
serde = [ "dep:serde" ]
async-std-runtime = [ "async-std" ]
database = [ "revolt-database", "revolt-database/default", "authifier/database-mongodb" ]
default = [ "serde", "async-std-runtime", "database" ]
[dependencies]
# Utility
log = "*"
# Serialisation
serde = { version = "1", features = ["derive"], optional = true }
# Async Language Features
futures = "0.3.19"
async-trait = "0.1.51"
# Async
async-std = { version = "1.8.0", features = ["attributes"], optional = true }
# Peer dependencies
revolt-database = { path = "../database", optional = true, default-features = false }
# Authifier
authifier = { version = "1.0", default-features = false }

View File

@@ -1,9 +0,0 @@
mod model;
pub use model::*;
#[cfg(feature = "database")]
mod ops;
#[cfg(feature = "database")]
pub use ops::*;

View File

@@ -1,40 +1 @@
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
#[macro_use]
extern crate async_trait;
#[macro_use]
extern crate log;
macro_rules! auto_derived {
( $( $item:item )+ ) => {
$(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
$item
)+
};
}
mod admin_migrations;
pub use admin_migrations::*;
pub struct Database(pub revolt_database::Database);
pub trait AbstractDatabase: Sync + Send + admin_migrations::AbstractMigrations {}
impl AbstractDatabase for revolt_database::DummyDb {}
impl AbstractDatabase for revolt_database::MongoDb {}
impl std::ops::Deref for Database {
type Target = dyn AbstractDatabase;
fn deref(&self) -> &Self::Target {
match &self.0 {
revolt_database::Database::Dummy(dummy) => dummy,
revolt_database::Database::MongoDb(mongo) => mongo,
}
}
}

View File

@@ -0,0 +1,8 @@
[package]
name = "revolt-result"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@@ -0,0 +1,14 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

View File

@@ -57,7 +57,6 @@ revolt-quark = { path = "../quark" }
# core
revolt-database = { path = "../core/database" }
revolt-models = { path = "../core/models" }
[build-dependencies]
vergen = "7.5.0"

View File

@@ -23,7 +23,6 @@ async fn rocket() -> _ {
// Setup database
let db = revolt_database::DatabaseInfo::Auto.connect().await.unwrap();
let db = revolt_models::Database(db);
db.migrate_database().await.unwrap();
// Legacy database setup from quark