数据库:删除了资源库依赖表
后端:修复配置文件字段写错,暴露初始化接口
This commit is contained in:
parent
9d88e9a159
commit
c19d21ce7d
@ -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" # 数据库
|
||||
|
@ -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, // 数据库名称
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
(
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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路由
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user