219 lines
6.2 KiB
Rust
219 lines
6.2 KiB
Rust
use chrono::{DateTime, Utc};
|
|
use clickhouse::Row;
|
|
use clickhouse_pool::traits::Model;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize_repr, Deserialize_repr)]
|
|
#[repr(u8)]
|
|
pub enum TrivialRewardKind {
|
|
OnlyTheFirstOne = 0,
|
|
TopThree = 1,
|
|
TopFive = 2,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize_repr, Deserialize_repr)]
|
|
#[repr(u8)]
|
|
pub enum TrivialStatus {
|
|
Init = 0,
|
|
Started = 1,
|
|
Finished = 2,
|
|
Paused = 3,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Row, Serialize, Deserialize)]
|
|
pub struct Trivial {
|
|
#[serde(with = "clickhouse::serde::uuid")]
|
|
pub id: Uuid,
|
|
pub name: String,
|
|
pub description: String,
|
|
|
|
pub guild_id: u64,
|
|
pub channel_id: u64,
|
|
|
|
#[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,
|
|
|
|
pub random_question: bool,
|
|
pub role_ping: u64,
|
|
pub role_ping_enabled: bool,
|
|
pub reward_kind: TrivialRewardKind,
|
|
pub reward_amount: u64,
|
|
/// Whether or not the bot should send an ephemeral message to the user when their answer is taken into account.
|
|
pub taken_into_account: bool,
|
|
pub status: TrivialStatus,
|
|
}
|
|
|
|
impl Default for Trivial {
|
|
fn default() -> Self {
|
|
Self {
|
|
id: Uuid::new_v4(),
|
|
name: String::new(),
|
|
description: String::new(),
|
|
guild_id: 0,
|
|
channel_id: 0,
|
|
created_at: Utc::now(),
|
|
updated_at: Utc::now(),
|
|
creator_id: 0,
|
|
updater_id: 0,
|
|
random_question: true,
|
|
role_ping: 0,
|
|
role_ping_enabled: false,
|
|
reward_kind: TrivialRewardKind::TopThree,
|
|
reward_amount: 3,
|
|
taken_into_account: true,
|
|
status: TrivialStatus::Init,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Trivial {
|
|
pub fn new(
|
|
name: String,
|
|
description: String,
|
|
guild_id: u64,
|
|
channel_id: u64,
|
|
creator_id: u64,
|
|
updater_id: u64,
|
|
) -> Self {
|
|
Self {
|
|
name,
|
|
description,
|
|
guild_id,
|
|
channel_id,
|
|
creator_id,
|
|
updater_id,
|
|
..Default::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Model for Trivial {
|
|
type T = Trivial;
|
|
|
|
fn table_name() -> &'static str {
|
|
"trivial"
|
|
}
|
|
|
|
fn create_table_sql() -> &'static str {
|
|
r#"
|
|
CREATE TABLE IF NOT EXISTS trivial (
|
|
id UUID PRIMARY KEY,
|
|
name String,
|
|
description String,
|
|
guild_id UInt64,
|
|
channel_id UInt64,
|
|
created_at DateTime64(3, 'UTC'),
|
|
updated_at DateTime64(3, 'UTC'),
|
|
creator_id UInt64,
|
|
updater_id UInt64,
|
|
random_question Bool,
|
|
role_ping UInt64,
|
|
role_ping_enabled Bool,
|
|
reward_kind Enum8('OnlyTheFirstOne' = 0, 'TopThree' = 1, 'TopFive' = 2),
|
|
reward_amount UInt64,
|
|
taken_into_account Bool,
|
|
status Enum8('Init' = 0, 'Started' = 1, 'Finished' = 2, 'Paused' = 3)
|
|
) ENGINE = MergeTree()
|
|
ORDER BY id
|
|
"#
|
|
}
|
|
|
|
fn column_names() -> Vec<&'static str> {
|
|
vec![
|
|
"id",
|
|
"name",
|
|
"description",
|
|
"guild_id",
|
|
"channel_id",
|
|
"created_at",
|
|
"updated_at",
|
|
"creator_id",
|
|
"updater_id",
|
|
"random_question",
|
|
"role_ping",
|
|
"role_ping_enabled",
|
|
"reward_kind",
|
|
"reward_amount",
|
|
"taken_into_account",
|
|
"status",
|
|
]
|
|
}
|
|
|
|
fn to_row(&self) -> (Vec<&'static str>, Vec<String>) {
|
|
(
|
|
Self::column_names(),
|
|
vec![
|
|
format!("'{}'", self.id),
|
|
format!("'{}'", self.name),
|
|
format!("'{}'", self.description),
|
|
self.guild_id.to_string(),
|
|
self.channel_id.to_string(),
|
|
format!("'{}'", self.created_at.to_rfc3339()),
|
|
format!("'{}'", self.updated_at.to_rfc3339()),
|
|
self.creator_id.to_string(),
|
|
self.updater_id.to_string(),
|
|
self.random_question.to_string(),
|
|
self.role_ping.to_string(),
|
|
self.role_ping_enabled.to_string(),
|
|
format!("'{:?}'", serde_json::to_string(&self.reward_kind)),
|
|
self.reward_amount.to_string(),
|
|
self.taken_into_account.to_string(),
|
|
format!("'{:?}'", serde_json::to_string(&self.status)),
|
|
],
|
|
)
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|