1
//! Traits and implementations for accessing databases and caches.
2
//!
3
//! Currently we only provide pure MongoDB/SQLite implementation. Mixing implementation is
4
//! possible. For example, put users/clients in MongoDB and put tokens/codes in Redis. Then use a
5
//! model struct and impl to mix both databases.
6

            
7
use std::{error::Error as StdError, sync::Arc};
8

            
9
use async_trait::async_trait;
10

            
11
pub mod access_token;
12
pub mod authorization_code;
13
pub mod client;
14
pub mod login_session;
15
pub mod redis;
16
pub mod refresh_token;
17
pub mod user;
18

            
19
mod model_mongodb;
20
mod model_sqlite;
21
mod mongodb;
22
mod sqlite;
23

            
24
pub use self::{
25
    mongodb::conn::{self as mongodb_conn, Options as MongoDbOptions},
26
    redis::conn::{self as redis_conn, Options as RedisOptions},
27
    sqlite::conn::{self as sqlite_conn, Options as SqliteOptions},
28
};
29
pub use model_mongodb::Model as MongoDbModel;
30
pub use model_sqlite::Model as SqliteModel;
31

            
32
/// Database connection options for model implementation.
33
pub enum ConnOptions {
34
    // Pure MongoDB model implementation.
35
    MongoDB(MongoDbOptions),
36
    //MongoRedis(MongoDbOptions, RedisOptions),
37
    /// Pure SQLite model implementation.
38
    Sqlite(SqliteOptions),
39
}
40

            
41
/// The top level trait to get all models (tables/collections).
42
#[async_trait]
43
pub trait Model: Send + Sync {
44
    /// Close database connection.
45
    async fn close(&self) -> Result<(), Box<dyn StdError>>;
46

            
47
    /// To get the user model.
48
    fn user(&self) -> &dyn user::UserModel;
49

            
50
    /// To get the client model.
51
    fn client(&self) -> &dyn client::ClientModel;
52

            
53
    /// To get the login session model.
54
    fn login_session(&self) -> &dyn login_session::LoginSessionModel;
55

            
56
    /// To get the authorization code model.
57
    fn authorization_code(&self) -> &dyn authorization_code::AuthorizationCodeModel;
58

            
59
    /// To get the access token model.
60
    fn access_token(&self) -> &dyn access_token::AccessTokenModel;
61

            
62
    /// To get the refresh token model.
63
    fn refresh_token(&self) -> &dyn refresh_token::RefreshTokenModel;
64
}
65

            
66
/// To create the database model with the specified database implementation.
67
12
pub async fn new(opts: &ConnOptions) -> Result<Arc<dyn Model>, Box<dyn StdError>> {
68
12
    let model: Arc<dyn Model> = match opts {
69
68
        ConnOptions::MongoDB(opts) => Arc::new(MongoDbModel::new(opts).await?),
70
133
        ConnOptions::Sqlite(opts) => Arc::new(SqliteModel::new(opts).await?),
71
    };
72
24
    model.user().init().await?;
73
24
    model.client().init().await?;
74
24
    model.login_session().init().await?;
75
24
    model.authorization_code().init().await?;
76
24
    model.access_token().init().await?;
77
24
    model.refresh_token().init().await?;
78
12
    Ok(model)
79
12
}