数据库:删除了资源库依赖表

后端:修复配置文件字段写错,暴露初始化接口
This commit is contained in:
lsy 2024-11-18 19:14:37 +08:00
parent 9d88e9a159
commit c19d21ce7d
6 changed files with 181 additions and 119 deletions

View File

@ -6,11 +6,11 @@
install = false # 是否为第一次安装
non_relational = true # 是否使用非关系型数据库
# 数据库
[db_config]
# 关系型数据库
[sql_config]
db_type = "postgresql" # 数据库类型
address = "localhost" # 地址
prot = 5432 # 端口
port = 5432 # 端口
user = "postgres" # 用户名
password = "postgres" # 密码
db_name = "echoes" # 数据库

View File

@ -6,34 +6,34 @@
use serde::Deserialize;
use std::{ env, fs};
#[derive(Deserialize)]
#[derive(Deserialize,Debug,Clone)]
pub struct Config {
pub info: Info, // 配置信息
pub sql_config: SqlConfig, // 关系型数据库配置
// pub no_sql_config:NoSqlConfig, 非关系型数据库配置
}
#[derive(Deserialize)]
#[derive(Deserialize,Debug,Clone)]
pub struct Info {
pub install: bool, // 是否安装
pub non_relational: bool, // 是否非关系型
}
#[derive(Deserialize)]
#[derive(Deserialize,Debug,Clone)]
pub struct SqlConfig {
pub db_type: String, // 数据库类型
pub address: String, // 地址
pub prot: u32, // 端口
pub port: u32, // 端口
pub user: String, // 用户名
pub password: String, // 密码
pub db_name: String, // 数据库名称
}
#[derive(Deserialize)]
#[derive(Deserialize,Debug,Clone)]
pub struct NoSqlConfig {
pub db_type: String, // 数据库类型
pub address: String, // 地址
pub prot: u32, // 端口
pub port: u32, // 端口
pub user: String, // 用户名
pub password: String, // 密码
pub db_name: String, // 数据库名称

View File

@ -2,6 +2,7 @@
/**
PostgreSQL
*/
mod postgresql;
@ -48,6 +49,13 @@ pub trait DatabaseTrait: Send + Sync {
&'a self,
builder: &QueryBuilder,
) -> Result<Vec<HashMap<String, String>>, Box<dyn Error + 'a>>;
/**
@param database
@return Result<(), Box<dyn Error>>
*/
async fn initialization(database: config::SqlConfig) -> Result<(), Box<dyn Error>> where Self: Sized;
}
#[derive(Clone)]
@ -70,7 +78,7 @@ impl Database {
@param database
@return Result<Self, Box<dyn Error>>
*/
pub async fn init(database: config::SqlConfig) -> Result<Self, Box<dyn Error>> {
pub async fn link(database: config::SqlConfig) -> Result<Self, Box<dyn Error>> {
let db = match database.db_type.as_str() {
"postgresql" => postgresql::Postgresql::connect(database).await?,
_ => return Err("unknown database type".into()),
@ -78,6 +86,19 @@ impl Database {
Ok(Self { db: Arc::new(Box::new(db)) })
}
/**
@param database
@return Result<(), Box<dyn Error>>
*/
pub async fn initial_setup(database: config::SqlConfig) -> Result<(), Box<dyn Error>> {
match database.db_type.as_str() {
"postgresql" => postgresql::Postgresql::initialization(database).await?,
_ => return Err("unknown database type".into()),
};
Ok(())
}
}
impl QueryBuilder {

View File

@ -1,7 +1,3 @@
--- 创建数据库
CREATE DATABASE echoes;
--- 切换数据库
\c echoes;
--- 安装自动生成uuid插件
CREATE EXTENSION IF NOT EXISTS pgcrypto;
--- 用户权限枚举
@ -18,7 +14,7 @@ CREATE TABLE persons
person_avatar VARCHAR(255), --- 用户头像URL
person_role VARCHAR(50), --- 用户角色
person_last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP, --- 最后登录时间
person_level privilege_level NOT NULL DEFULT 'contributor' --- 用户权限
person_level privilege_level NOT NULL DEFAULT 'contributor' --- 用户权限
);
--- 页面状态枚举
CREATE TYPE publication_status AS ENUM ('draft', 'published', 'private','hide');
@ -37,7 +33,7 @@ CREATE TABLE pages
--- 文章表
CREATE TABLE posts
(
post_author VARCHAR(100) NOT NULL REFERENCES person (person_name) ON DELETE CASCADE, --- 文章作者
post_author VARCHAR(100) NOT NULL REFERENCES persons (person_name) ON DELETE CASCADE, --- 文章作者
post_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), --- 文章主键
post_picture VARCHAR(255), --- 文章头图
post_title VARCHAR(255) NOT NULL, --- 文章标题
@ -79,26 +75,22 @@ CREATE TABLE post_categories
category_id VARCHAR(50) REFERENCES categories (category_name) ON DELETE CASCADE, --- 外键约束引用categories的主键
PRIMARY KEY (post_id, category_id) --- 复合主键
);
--- 资源库
CREATE TABLE library
(
library_author VARCHAR(100) NOT NULL REFERENCES person (person_name) ON DELETE CASCADE, --- 资源作者
library_author VARCHAR(100) NOT NULL REFERENCES persons (person_name) ON DELETE CASCADE, --- 资源作者
library_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), --- 资源ID
library_name VARCHAR(255) NOT NULL, --- 资源名称
library_size BIGINT NOT NULL, --- 大小
library_storage_path VARCHAR(255) NOT NULL UNIQUE, --- 储存路径
library_type VARCHAR(50) NOT NULL REFERENCES library_type (library_type) ON DELETE CASCADE, --- 资源类别
library_type VARCHAR(50) NOT NULL, --- 资源类别
library_class VARCHAR(50), --- 资源类
library_description VARCHAR(255), --- 资源描述
library_created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP --- 创建时间
);
--- 资源库类别
CREATE TABLE library_type
(
library_type VARCHAR(50) PRIMARY KEY CHECK (LOWER(library_type) = library_type), --- 资源类别
library_description VARCHAR(200) --- 资源类别描述
);
--- 配置文件库
CREATE TABLE config
(

View File

@ -1,13 +1,15 @@
// src/database/relational/postgresql/mod.rs
/*
// File path: src/database/relational/postgresql/mod.rs
/**
* PostgreSQL数据库的交互功能
*
*/
use super::{DatabaseTrait, QueryBuilder};
use crate::config;
use async_trait::async_trait;
use sqlx::{Column, PgPool, Row};
use sqlx::{Column, PgPool, Row, Executor};
use std::{collections::HashMap, error::Error};
use std::{env, fs};
#[derive(Clone)]
/// PostgreSQL数据库连接池结构体
@ -18,6 +20,41 @@ pub struct Postgresql {
#[async_trait]
impl DatabaseTrait for Postgresql {
/**
*
*
* #
* - `db_config`:
*
* #
* - `Result<(), Box<dyn Error>>`:
*/
async fn initialization(db_config: config::SqlConfig) -> Result<(), Box<dyn Error>> {
let path = env::current_dir()?
.join("src")
.join("database")
.join("relational")
.join("postgresql")
.join("init.sql");
let grammar = fs::read_to_string(&path)?;
// 创建初始连接(不指定数据库)
let connection_str = format!("postgres://{}:{}@{}:{}", db_config.user, db_config.password, db_config.address, db_config.port);
let pool = PgPool::connect(&connection_str).await?;
// 创建数据库
pool.execute(format!("CREATE DATABASE {}", db_config.db_name).as_str()).await?;
// 连接到新数据库
let new_connection_str = format!("postgres://{}:{}@{}:{}/{}", db_config.user, db_config.password, db_config.address, db_config.port, db_config.db_name);
let new_pool = PgPool::connect(&new_connection_str).await?;
// 执行初始化脚本
new_pool.execute(grammar.as_str()).await?;
Ok(())
}
/**
* PostgreSQL数据库并返回Postgresql实例
*
@ -27,11 +64,10 @@ impl DatabaseTrait for Postgresql {
* #
* - `Result<Self, Box<dyn Error>>`:
*/
async fn connect(db_config: config::SqlConfig) -> Result<Self, Box<dyn Error>> {
let connection_str = format!(
"postgres://{}:{}@{}:{}/{}",
db_config.user, db_config.password, db_config.address, db_config.prot, db_config.db_name
db_config.user, db_config.password, db_config.address, db_config.port, db_config.db_name
);
// 连接到数据库池
@ -85,5 +121,4 @@ impl DatabaseTrait for Postgresql {
Ok(results)
}
}

View File

@ -1,4 +1,4 @@
// main.rs
// File path: /d:/data/echoes/backend/src/main.rs
/**
* API接口
@ -9,100 +9,114 @@
*/
mod config; // 配置模块
mod database;
mod secret;
use chrono::Duration;
// 数据库模块
mod database; // 数据库模块
mod secret; // 密钥模块
use chrono::Duration; // 引入时间持续时间
use database::relational; // 引入关系型数据库
use once_cell::sync::Lazy; // 用于延迟初始化
use rocket::{get, http::Status, launch, response::status, routes, serde::json::Json}; // 引入Rocket框架相关功能
use std::sync::Arc;
// 引入Arc用于线程安全的引用计数
use rocket::{get, post, http::Status, launch, response::status, routes, serde::json::Json}; // 引入Rocket框架相关功能
use std::sync::Arc; // 引入Arc用于线程安全的引用计数
use tokio::sync::Mutex; // 引入Mutex用于异步锁
// 全局数据库连接变量
static DB: Lazy<Arc<Mutex<Option<relational::Database>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
static SQL: Lazy<Arc<Mutex<Option<relational::Database>>>> =
Lazy::new(|| Arc::new(Mutex::new(None)));
/**
*
*
* #
* - `database`:
*
* #
* - `Result<(), Box<dyn std::error::Error>>`:
*/
async fn init_db(database: config::SqlConfig) -> Result<(), Box<dyn std::error::Error>> {
let database = relational::Database::init(database).await?; // 初始化数据库
*DB.lock().await = Some(database); // 保存数据库实例
async fn init_sql(database: config::SqlConfig) -> Result<(), Box<dyn std::error::Error>> {
let database = relational::Database::link(database).await?; // 初始化数据库
*SQL.lock().await = Some(database); // 保存数据库实例
Ok(())
}
/**
*
*
* #
* - `Result<relational::Database, Box<dyn std::error::Error>>`:
*/
async fn get_db() -> Result<relational::Database, Box<dyn std::error::Error>> {
DB.lock()
async fn get_sql() -> Result<relational::Database, Box<dyn std::error::Error>> {
SQL.lock()
.await
.clone()
.ok_or_else(|| "Database not initialized".into()) // 返回错误信息
}
/**
*
*
*
* #
* - `data`:
*
* #
* - `Result<status::Custom<String>, status::Custom<String>>`:
*/
#[get("/sql")]
async fn ssql() -> Result<Json<Vec<std::collections::HashMap<String, String>>>, status::Custom<String>> {
let db = get_db().await.map_err(|e| {
#[post("/install", format = "json", data = "<data>")]
async fn install(data: Json<config::SqlConfig>) -> Result<status::Custom<String>, status::Custom<String>> {
relational::Database::initial_setup(data.into_inner()).await.map_err(|e| {
status::Custom(
Status::InternalServerError,
format!("Database error: {}", e), // 数据库错误信息
format!("Database initialization failed: {}", e), // 连接失败信息
)
})?;
let query_result = db
.get_db()
.query("SELECT * FROM info".to_string())
.await
.map_err(|e| status::Custom(Status::InternalServerError, format!("Query error: {}", e)))?;
Ok(Json(query_result)) // 返回查询结果
Ok(status::Custom(
Status::Ok,
format!("Initialization successful"),
))
}
/**
*
* JWT接口
*
* #
* - `Result<status::Custom<String>, status::Custom<String>>`: JWT令牌或错误信息
*/
#[get("/install")]
async fn install() -> status::Custom<String> {
get_db()
.await
.map(|_| status::Custom(Status::Ok, "Database connected successfully".into())) // 连接成功
.unwrap_or_else(|e| {
status::Custom(
Status::InternalServerError,
format!("Failed to connect: {}", e), // 连接失败信息
)
})
}
#[get("/system")]
async fn token_system() -> Result<status::Custom<String>, status::Custom<String>> {
// 创建 Claims
let claims = secret::CustomClaims {
user_id: String::from("system"),
device_ua: String::from("system"),
user_id: String::from("system"), // 用户ID
device_ua: String::from("system"), // 设备用户代理
};
// 生成JWT
let token = secret::generate_jwt(claims,Duration::seconds(1))
.map_err(|e| status::Custom(Status::InternalServerError, format!("JWT generation failed: {}", e)))?;
let token = secret::generate_jwt(claims, Duration::seconds(1)).map_err(|e| {
status::Custom(
Status::InternalServerError,
format!("JWT generation failed: {}", e), // JWT生成失败信息
)
})?;
Ok(status::Custom(Status::Ok, token))
Ok(status::Custom(Status::Ok, token)) // 返回JWT令牌
}
/**
* Rocket应用
*
* #
* - `rocket::Rocket`: Rocket应用实例
*/
#[launch]
async fn rocket() -> _ {
let config = config::Config::read().expect("Failed to read config"); // 读取配置
init_db(config.sql_config)
if config.info.install {
init_sql(config.sql_config)
.await
.expect("Failed to connect to database"); // 初始化数据库连接
rocket::build()
.mount("/", routes![install, ssql]) // 挂载API路由
.mount("/auth/token", routes![token_system])
} else {
rocket::build()
.mount("/", routes![install]) // 挂载API路由
}
}