Compare commits

...

2 Commits

Author SHA1 Message Date
f71de5c149
先写一部分shipdata 2024-09-05 23:44:33 +08:00
69b75d8e8f
准备迁移一下 2024-09-05 22:12:51 +08:00
6 changed files with 226 additions and 30 deletions

View File

@ -9,7 +9,7 @@ use crate::model;
use crate::model::sea_orm_active_enums::SaveType; use crate::model::sea_orm_active_enums::SaveType;
use migration::{SaveId, FULL_DATA_VIEW, TEXT_DATA_MAX_LEN}; use migration::{SaveId, FULL_DATA_VIEW, TEXT_DATA_MAX_LEN};
pub mod definitions; pub mod defines;
pub mod search; pub mod search;
pub mod updates; pub mod updates;
pub mod utils; pub mod utils;

View File

@ -1,8 +1,12 @@
use sea_orm::sea_query::{ColumnDef, ForeignKey, ForeignKeyAction, Table};
use sea_orm::{ConnectionTrait, DatabaseBackend, DatabaseConnection, Statement}; use sea_orm::{ConnectionTrait, DatabaseBackend, DatabaseConnection, Statement};
use crate::config::ConfigFile; use crate::config::ConfigFile;
pub mod full_data_view;
pub mod long_data_table;
pub mod main_data_table;
pub mod ships_table;
pub mod db_names { pub mod db_names {
/// 主数据表 /// 主数据表
pub const MAIN_DATA_TABLE: &str = "main_data"; pub const MAIN_DATA_TABLE: &str = "main_data";
@ -16,52 +20,43 @@ pub mod db_names {
pub const SEA_ORM_TABLE: &str = "seaql_migrations"; pub const SEA_ORM_TABLE: &str = "seaql_migrations";
} }
pub async fn check_table_exists( pub const CURRENT_DB_VERSION: i32 = 1;
db: &DatabaseConnection,
table_name: &str, pub const TEXT_DATA_MAX_LEN: usize = 1024;
schema: &str, pub type SaveId = u32;
) -> Option<bool> {
pub async fn check_table_exists(db: &DatabaseConnection, table_name: &str, schema: &str) -> bool {
let sql = format!( let sql = format!(
"SELECT EXISTS (SELECT FROM pg_tables WHERE tablename = '{}' AND schemaname = '{}');", "SELECT EXISTS (SELECT FROM pg_tables WHERE tablename = '{}' AND schemaname = '{}');",
table_name, schema table_name, schema
); );
let exists = db if let Ok(Some(exists)) = db
.query_one(Statement::from_string(DatabaseBackend::Postgres, sql)) .query_one(Statement::from_string(DatabaseBackend::Postgres, sql))
.await.ok()?; .await
exists?.try_get("", "exists").ok() {
if let Ok(exists) = exists.try_get("", "exists") {
return exists;
}
}
false
} }
pub async fn check_main_data_exists( pub async fn check_main_data_exists(db: &DatabaseConnection, conf: &ConfigFile) -> bool {
db: &DatabaseConnection,
conf: &ConfigFile,
) -> Option<bool> {
check_table_exists(db, db_names::MAIN_DATA_TABLE, &conf.db.schema).await check_table_exists(db, db_names::MAIN_DATA_TABLE, &conf.db.schema).await
} }
pub async fn check_long_data_exists( pub async fn check_long_data_exists(db: &DatabaseConnection, conf: &ConfigFile) -> bool {
db: &DatabaseConnection,
conf: &ConfigFile,
) -> Option<bool> {
check_table_exists(db, db_names::LONG_DATA_TABLE, &conf.db.schema).await check_table_exists(db, db_names::LONG_DATA_TABLE, &conf.db.schema).await
} }
pub async fn check_full_data_exists( pub async fn check_full_data_exists(db: &DatabaseConnection, conf: &ConfigFile) -> bool {
db: &DatabaseConnection,
conf: &ConfigFile,
) -> Option<bool> {
check_table_exists(db, db_names::FULL_DATA_TABLE, &conf.db.schema).await check_table_exists(db, db_names::FULL_DATA_TABLE, &conf.db.schema).await
} }
pub async fn check_db_version_exists( pub async fn check_db_version_exists(db: &DatabaseConnection, conf: &ConfigFile) -> bool {
db: &DatabaseConnection,
conf: &ConfigFile,
) -> Option<bool> {
check_table_exists(db, db_names::DB_VERSION_TABLE, &conf.db.schema).await check_table_exists(db, db_names::DB_VERSION_TABLE, &conf.db.schema).await
} }
pub async fn check_sea_orm_exists( pub async fn check_sea_orm_exists(db: &DatabaseConnection, conf: &ConfigFile) -> bool {
db: &DatabaseConnection,
conf: &ConfigFile,
) -> Option<bool> {
check_table_exists(db, db_names::SEA_ORM_TABLE, &conf.db.schema).await check_table_exists(db, db_names::SEA_ORM_TABLE, &conf.db.schema).await
} }

View File

@ -0,0 +1,42 @@
use sea_orm::DeriveIden;
pub const FULL_DATA_SQL: &str = r"
CREATE OR REPLACE VIEW full_data as
SELECT
md.save_id,
md.save_type,
md.blake_hash,
md.xml_tested,
md.len,
CASE
WHEN md.len > 1024 THEN
ld.text
ELSE md.short_data
END AS data
FROM main_data md
LEFT JOIN long_data ld ON md.save_id = ld.save_id
";
#[derive(DeriveIden)]
pub enum FullData {
/// 表 (实际上是个视图)
Table,
/// 这个存档的 Id
SaveId,
/// 存档类型
/// - ship: 船
/// - save: 存档
/// - unknown: 未知 (没下载呢)
/// - none: 没有存档 (这个 Id 为 空)
SaveType,
/// blake3 hash
/// len = 64
/// 64 位的 blake3 hash
BlakeHash,
/// 存档的长度 (用来过滤太长的存档)
Len,
/// 完整的数据
Data,
/// 数据是不是合法的 XML 数据
XmlTested,
}

View File

@ -0,0 +1,39 @@
use sea_orm::sea_query::{ColumnDef, ForeignKey, Table};
use sea_orm::{DatabaseBackend, DeriveIden, ForeignKeyAction, Iden, Statement};
use super::main_data_table::MainData;
pub fn long_data_table() -> Statement {
let mut table = Table::create();
table
.table(LongData::Table)
.if_not_exists()
.col(
ColumnDef::new(LongData::SaveId)
.integer()
.not_null()
.primary_key(),
)
.foreign_key(
ForeignKey::create()
.name(LongData::SaveId.to_string())
.to(MainData::Table, MainData::SaveId)
.from(LongData::Table, LongData::SaveId)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
)
.col(ColumnDef::new(LongData::Len).big_integer().not_null())
.col(ColumnDef::new(LongData::Text).string().not_null());
DatabaseBackend::Postgres.build(&table)
}
#[derive(DeriveIden)]
pub enum LongData {
Table,
/// 存档 ID
SaveId,
/// 二次校验长度(?)
Len,
/// 1024 ~ 2MB 长度的数据
Text,
}

View File

@ -0,0 +1,76 @@
use sea_orm::sea_query::{ColumnDef, Table};
use sea_orm::{DatabaseBackend, DeriveIden, EnumIter, Iterable, Statement};
use super::TEXT_DATA_MAX_LEN;
pub fn main_table() -> Statement {
let mut table = Table::create();
table
.table(MainData::Table)
.if_not_exists()
.col(
ColumnDef::new(MainData::SaveId)
.integer()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(MainData::SaveType)
.enumeration(SaveTypeEnum, SaveTypeVariants::iter())
.not_null(),
)
// blake hash:
// ad4a4c99162bac6766fa9a658651688c6db4955922f8e5447cb14ad1c1b05825
// len = 64
.col(ColumnDef::new(MainData::BlakeHash).char_len(64).not_null())
.col(ColumnDef::new(MainData::Len).big_integer().not_null())
.col(ColumnDef::new(MainData::ShortData).string_len(TEXT_DATA_MAX_LEN as u32))
.col(ColumnDef::new(MainData::XmlTested).boolean().null());
DatabaseBackend::Postgres.build(&table)
}
#[derive(DeriveIden)]
#[sea_orm(iden = "save_type")]
pub struct SaveTypeEnum;
#[derive(DeriveIden, EnumIter)]
pub enum SaveTypeVariants {
#[sea_orm(iden = "ship")]
/// 飞船
Ship,
#[sea_orm(iden = "save")]
/// 存档
Save,
#[sea_orm(iden = "unknown")]
/// 未知 (预计用作下载中的占位符)
Unknown,
#[sea_orm(iden = "none")]
/// 没有存档 (这个 Id 为 空)
None,
}
#[derive(DeriveIden)]
pub enum MainData {
/// 表
Table,
/// 这个存档的 Id
SaveId,
/// 存档类型
/// - ship: 船
/// - save: 存档
/// - unknown: 未知 (没下载呢)
/// - none: 没有存档 (这个 Id 为 空)
SaveType,
/// blake3 hash
/// len = 64
/// 64 位的 blake3 hash
BlakeHash,
/// 存档的长度 (用来过滤太长的存档)
/// 长度 > 1024 的存档会存在隔壁表
Len,
/// 如果长度 < 1024
/// 那就直接存在这
ShortData,
/// 数据是不是合法的 XML 数据
XmlTested,
}

View File

@ -0,0 +1,44 @@
use sea_orm::sea_query::{ColumnDef, ForeignKey, Table};
use sea_orm::{DatabaseBackend, DeriveIden, ForeignKeyAction, Iden, Statement};
use super::main_data_table::MainData;
pub fn ships_table() -> Statement {
let mut table = Table::create();
table
.table(Ships::Table)
.if_not_exists()
.col(
ColumnDef::new(Ships::SaveId)
.integer()
.not_null()
.primary_key(),
)
.foreign_key(
ForeignKey::create()
.name(Ships::SaveId.to_string())
.to(MainData::Table, MainData::SaveId)
.from(Ships::Table, Ships::SaveId)
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade),
);
DatabaseBackend::Postgres.build(&table)
}
#[derive(DeriveIden)]
pub enum Ships {
Table,
/// 存档 ID
SaveId,
/// 解析过的 xml 数据
/// 这样就不用每次解析一遍了
XmlData,
/// 飞船质量
/// (按照原版数据计算, 经过比例缩放)
Mass,
/// 是否检查到了使用 mod 的迹象
/// 比如 多 pod 之类的
ModUsed,
/// 是否有 docxConnection (xml使用迹象)
DocxConnectionUsed,
}