feat: Model are created

This commit is contained in:
Max batleforc 2025-05-23 00:16:01 +02:00
parent 37c5c7235e
commit 49419cbc4c
No known key found for this signature in database
GPG Key ID: 25D243AB4B6AC9E7
6 changed files with 406 additions and 12 deletions

View File

@ -1,6 +1,6 @@
use config::parse_local_config; use config::parse_local_config;
use poise::serenity_prelude as serenity; use poise::serenity_prelude as serenity;
use tracing::{error, info}; use tracing::{error, info, instrument};
pub mod config; pub mod config;
pub mod dotenv; pub mod dotenv;
@ -11,6 +11,7 @@ type Error = Box<dyn std::error::Error + Send + Sync>;
type Context<'a> = poise::Context<'a, Data, Error>; type Context<'a> = poise::Context<'a, Data, Error>;
/// Displays your or another user's account creation date /// Displays your or another user's account creation date
#[instrument(skip(ctx), level = "info", fields(channel_id = ctx.channel_id().get() , guild_id = ?ctx.guild_id(), user_id = ?ctx.author().id.get(), user_name = ctx.author().name))]
#[poise::command(slash_command, prefix_command)] #[poise::command(slash_command, prefix_command)]
async fn age( async fn age(
ctx: Context<'_>, ctx: Context<'_>,

View File

@ -1,6 +1,9 @@
use std::{error::Error, sync::Arc}; use std::{error::Error, sync::Arc};
pub mod trivial; pub mod trivial;
pub mod trivial_point;
pub mod trivial_question;
pub mod trivial_round;
use clickhouse_pool::{ use clickhouse_pool::{
config::{ClickhouseConfig, DatalakeConfig, RetryConfig}, config::{ClickhouseConfig, DatalakeConfig, RetryConfig},
@ -9,6 +12,9 @@ use clickhouse_pool::{
}; };
use tracing::{error, info, instrument}; use tracing::{error, info, instrument};
use trivial::Trivial; use trivial::Trivial;
use trivial_point::TrivialPoint;
use trivial_question::TrivialQuestion;
use trivial_round::TrivialRound;
use crate::config::PersistenceConfig; use crate::config::PersistenceConfig;
@ -37,20 +43,51 @@ pub fn create_pool_manager(db_config: PersistenceConfig) -> Result<Arc<DatalakeC
pub async fn create_manager_and_init( pub async fn create_manager_and_init(
datalake_config: Arc<DatalakeConfig>, datalake_config: Arc<DatalakeConfig>,
) -> Result<Arc<PoolManager>, Box<dyn Error>> { ) -> Result<Arc<PoolManager>, Box<dyn Error>> {
let manager = PoolManager::new(datalake_config, None).await; let mut manager = PoolManager::new(datalake_config, None).await;
let _ = match manager manager = match create_table::<Trivial>(manager).await {
.execute_with_retry(Trivial::create_table_sql()) Ok(manager) => manager,
.await
{
Ok(_) => {
info!("Table {} created successfully", Trivial::table_name());
}
Err(e) => { Err(e) => {
error!("Failed to create table {} : {}", Trivial::table_name(), e); return Err(e);
return Err(Box::new(e));
} }
}; };
manager = match create_table::<TrivialQuestion>(manager).await {
Ok(manager) => manager,
Err(e) => {
return Err(e);
}
};
manager = match create_table::<TrivialRound>(manager).await {
Ok(manager) => manager,
Err(e) => {
return Err(e);
}
};
manager = match create_table::<TrivialPoint>(manager).await {
Ok(manager) => manager,
Err(e) => {
return Err(e);
}
};
info!("All tables created successfully");
Ok(Arc::new(manager)) Ok(Arc::new(manager))
} }
#[instrument(skip(manager))]
pub async fn create_table<T: Model>(manager: PoolManager) -> Result<PoolManager, Box<dyn Error>> {
let _ = match manager.execute_with_retry(T::create_table_sql()).await {
Ok(_) => {
info!("Table {} created successfully", T::table_name());
}
Err(e) => {
error!("Failed to create table {} : {}", T::table_name(), e);
return Err(Box::new(e));
}
};
Ok(manager)
}

View File

@ -0,0 +1,121 @@
use chrono::{DateTime, Utc};
use clickhouse::Row;
use clickhouse_pool::traits::Model;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, PartialOrd, Row, Serialize, Deserialize)]
pub struct TrivialPoint {
#[serde(with = "clickhouse::serde::uuid")]
pub id: Uuid,
#[serde(with = "clickhouse::serde::uuid")]
pub trivial_id: Uuid,
pub user_id: u64,
pub points: i64,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
pub created_at: DateTime<Utc>,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
pub updated_at: DateTime<Utc>,
pub updater_id: u64,
}
impl Model for TrivialPoint {
type T = TrivialPoint;
fn table_name() -> &'static str {
"trivial_point"
}
fn create_table_sql() -> &'static str {
r#"
CREATE TABLE IF NOT EXISTS trivial_point (
id UUID PRIMARY KEY,
trivial_id UUID,
user_id UInt64,
points Int64,
created_at DateTime64(3),
updated_at DateTime64(3),
updater_id UInt64
) ENGINE = MergeTree()
ORDER BY (id, trivial_id)
"#
.trim()
}
fn column_names() -> Vec<&'static str> {
vec![
"id",
"trivial_id",
"user_id",
"points",
"created_at",
"updated_at",
"updater_id",
]
}
fn to_row(&self) -> (Vec<&'static str>, Vec<String>) {
(
Self::column_names(),
vec![
self.id.to_string(),
self.trivial_id.to_string(),
self.user_id.to_string(),
self.points.to_string(),
self.created_at.to_rfc3339(),
self.updated_at.to_rfc3339(),
self.updater_id.to_string(),
],
)
}
fn insert_query(&self) -> String {
let (columns, values) = self.to_row();
let columns = columns.join(", ");
let values = values.join(", ");
format!(
"INSERT INTO {} ({}) VALUES ({})",
Self::table_name(),
columns,
values
)
}
fn batch_insert_query(items: &[Self::T]) -> String {
let mut queries = Vec::new();
for item in items {
let (columns, values) = item.to_row();
let columns = columns.join(", ");
let values = values.join(", ");
queries.push(format!(
"INSERT INTO {} ({}) VALUES ({})",
Self::table_name(),
columns,
values
));
}
queries.join("; ")
}
fn build_select_query(
where_clause: Option<&str>,
limit: Option<u64>,
offset: Option<u64>,
) -> String {
let mut query = format!("SELECT * FROM {}", Self::table_name());
if let Some(where_clause) = where_clause {
query.push_str(&format!(" WHERE {}", where_clause));
}
if let Some(limit) = limit {
query.push_str(&format!(" LIMIT {}", limit));
}
if let Some(offset) = offset {
query.push_str(&format!(" OFFSET {}", offset));
}
query
}
}

View File

@ -0,0 +1,119 @@
use chrono::{DateTime, Utc};
use clickhouse::Row;
use clickhouse_pool::traits::Model;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Row, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TrivialQuestion {
#[serde(with = "clickhouse::serde::uuid")]
pub id: Uuid,
#[serde(with = "clickhouse::serde::uuid")]
pub trivial_id: Uuid,
pub question: String,
pub answer: String,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
pub created_at: DateTime<Utc>,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
pub updated_at: DateTime<Utc>,
pub creator_id: u64,
pub updater_id: u64,
}
impl Model for TrivialQuestion {
type T = TrivialQuestion;
fn table_name() -> &'static str {
"trivial_question"
}
fn create_table_sql() -> &'static str {
r#"
CREATE TABLE IF NOT EXISTS trivial_question (
id UUID PRIMARY KEY,
trivial_id UUID,
question String,
answer String,
created_at DateTime64(3),
updated_at DateTime64(3),
creator_id UInt64,
updater_id UInt64
) ENGINE = MergeTree()
ORDER BY (id, trivial_id)
"#
.trim()
}
fn column_names() -> Vec<&'static str> {
vec![
"id",
"trivial_id",
"question",
"answer",
"created_at",
"updated_at",
"creator_id",
"updater_id",
]
}
fn to_row(&self) -> (Vec<&'static str>, Vec<String>) {
(
Self::column_names(),
vec![
self.id.to_string(),
self.trivial_id.to_string(),
self.question.clone(),
self.answer.clone(),
self.created_at.to_string(),
self.updated_at.to_string(),
self.creator_id.to_string(),
self.updater_id.to_string(),
],
)
}
fn insert_query(&self) -> String {
let (columns, values) = self.to_row();
let columns = columns.join(", ");
let values = values.join(", ");
format!(
"INSERT INTO {} ({}) VALUES ({})",
Self::table_name(),
columns,
values
)
}
fn batch_insert_query(items: &[Self::T]) -> String {
let mut queries = Vec::new();
for item in items {
let (columns, values) = item.to_row();
let columns = columns.join(", ");
let values = values.join(", ");
queries.push(format!("({}, {})", columns, values));
}
queries.join(", ")
}
fn build_select_query(
where_clause: Option<&str>,
limit: Option<u64>,
offset: Option<u64>,
) -> String {
let mut query = format!("SELECT * FROM {}", Self::table_name());
if let Some(where_clause) = where_clause {
query.push_str(&format!(" WHERE {}", where_clause));
}
if let Some(limit) = limit {
query.push_str(&format!(" LIMIT {}", limit));
}
if let Some(offset) = offset {
query.push_str(&format!(" OFFSET {}", offset));
}
query
}
}

View File

@ -0,0 +1,116 @@
use chrono::{DateTime, Utc};
use clickhouse::Row;
use clickhouse_pool::traits::Model;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, PartialOrd, Row, Serialize, Deserialize)]
pub struct TrivialRound {
#[serde(with = "clickhouse::serde::uuid")]
pub id: Uuid,
#[serde(with = "clickhouse::serde::uuid")]
pub trivial_id: Uuid,
#[serde(with = "clickhouse::serde::uuid")]
pub question_id: Uuid,
pub answer: Vec<(u64, String, DateTime<Utc>)>,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
pub created_at: DateTime<Utc>,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
pub updated_at: DateTime<Utc>,
}
impl Model for TrivialRound {
type T = TrivialRound;
fn table_name() -> &'static str {
"trivial_round"
}
fn create_table_sql() -> &'static str {
r#"
CREATE TABLE IF NOT EXISTS trivial_round (
id UUID PRIMARY KEY,
trivial_id UUID,
question_id UUID,
answer Array(Tuple(UInt64, String, DateTime64(3))),
created_at DateTime64(3),
updated_at DateTime64(3)
) ENGINE = MergeTree()
ORDER BY (id, trivial_id)
"#
.trim()
}
fn column_names() -> Vec<&'static str> {
vec![
"id",
"trivial_id",
"question_id",
"answer",
"created_at",
"updated_at",
]
}
fn to_row(&self) -> (Vec<&'static str>, Vec<String>) {
(
Self::column_names(),
vec![
self.id.to_string(),
self.trivial_id.to_string(),
self.question_id.to_string(),
format!("{:?}", self.answer),
self.created_at.to_string(),
self.updated_at.to_string(),
],
)
}
fn insert_query(&self) -> String {
let (columns, values) = self.to_row();
let columns_str = columns.join(", ");
let values_str = values.join(", ");
format!(
"INSERT INTO {} ({}) VALUES ({})",
Self::table_name(),
columns_str,
values_str
)
}
fn batch_insert_query(items: &[Self::T]) -> String {
let mut queries = Vec::new();
for item in items {
let (columns, values) = item.to_row();
let columns_str = columns.join(", ");
let values_str = values.join(", ");
queries.push(format!(
"INSERT INTO {} ({}) VALUES ({})",
Self::table_name(),
columns_str,
values_str
));
}
queries.join("; ")
}
fn build_select_query(
where_clause: Option<&str>,
limit: Option<u64>,
offset: Option<u64>,
) -> String {
let mut query = format!("SELECT * FROM {}", Self::table_name());
if let Some(where_clause) = where_clause {
query.push_str(&format!(" WHERE {}", where_clause));
}
if let Some(limit) = limit {
query.push_str(&format!(" LIMIT {}", limit));
}
if let Some(offset) = offset {
query.push_str(&format!(" OFFSET {}", offset));
}
query
}
}

View File

@ -35,7 +35,7 @@ services:
SERVER_click: database SERVER_click: database
USER_click: default USER_click: default
PASSWORD_click: password PASSWORD_click: password
PORT_click: 9000 PORT_click: 8123
ENGINE_click: clickhouse@dbgate-plugin-clickhouse ENGINE_click: clickhouse@dbgate-plugin-clickhouse
DATABASE_click: default DATABASE_click: default
depends_on: depends_on: