mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 05:26:59 +00:00
refactor: combine models and db crate together
This commit is contained in:
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
database_derived!(
|
||||
/// Dummy implementation
|
||||
pub struct DummyDb {}
|
||||
);
|
||||
@@ -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)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
13
crates/core/database/src/drivers/reference.rs
Normal file
13
crates/core/database/src/drivers/reference.rs
Normal 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>>>,
|
||||
}
|
||||
);
|
||||
@@ -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
|
||||
}
|
||||
|
||||
5
crates/core/database/src/models/admin_migrations/mod.rs
Normal file
5
crates/core/database/src/models/admin_migrations/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod model;
|
||||
mod ops;
|
||||
|
||||
pub use model::*;
|
||||
pub use ops::*;
|
||||
@@ -1,5 +1,5 @@
|
||||
mod dummy;
|
||||
mod mongodb;
|
||||
mod reference;
|
||||
|
||||
#[async_trait]
|
||||
pub trait AbstractMigrations: Sync + Send {
|
||||
@@ -1,4 +1,4 @@
|
||||
use revolt_database::MongoDb;
|
||||
use crate::MongoDb;
|
||||
|
||||
use super::AbstractMigrations;
|
||||
|
||||
@@ -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.");
|
||||
@@ -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)]
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
5
crates/core/database/src/models/bots/mod.rs
Normal file
5
crates/core/database/src/models/bots/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod model;
|
||||
// mod ops;
|
||||
|
||||
pub use model::*;
|
||||
// pub use ops::*;
|
||||
74
crates/core/database/src/models/bots/model.rs
Normal file
74
crates/core/database/src/models/bots/model.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
26
crates/core/database/src/models/bots/ops.rs
Normal file
26
crates/core/database/src/models/bots/ops.rs
Normal 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>;
|
||||
}
|
||||
9
crates/core/database/src/models/bots/ops/mongodb.rs
Normal file
9
crates/core/database/src/models/bots/ops/mongodb.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use revolt_database::MongoDb;
|
||||
|
||||
use super::AbstractBots;
|
||||
|
||||
mod init;
|
||||
mod scripts;
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractBots for MongoDb {}
|
||||
6
crates/core/database/src/models/bots/ops/reference.rs
Normal file
6
crates/core/database/src/models/bots/ops/reference.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
use revolt_database::DummyDb;
|
||||
|
||||
use super::AbstractBots;
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractBots for DummyDb {}
|
||||
22
crates/core/database/src/models/mod.rs
Normal file
22
crates/core/database/src/models/mod.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
mod model;
|
||||
|
||||
pub use model::*;
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
mod ops;
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
pub use ops::*;
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
crates/core/result/Cargo.toml
Normal file
8
crates/core/result/Cargo.toml
Normal 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]
|
||||
14
crates/core/result/src/lib.rs
Normal file
14
crates/core/result/src/lib.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user