Remove usages of FIND_IN_SET
FIND_IN_SET doesn't make use of indexes
This commit is contained in:
parent
137ae6f24b
commit
6f223b1bc2
@ -31,31 +31,33 @@ impl Recordable for Options {
|
|||||||
.filter(|(_, channel)| channel.is_text_based())
|
.filter(|(_, channel)| channel.is_text_based())
|
||||||
.map(|(id, _)| id.get().to_string())
|
.map(|(id, _)| id.get().to_string())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(",")
|
|
||||||
}) {
|
}) {
|
||||||
sqlx::query!(
|
let placeholder = vec!["?"; channels.len()].join(",");
|
||||||
|
let sql = format!(
|
||||||
"
|
"
|
||||||
UPDATE reminders
|
UPDATE reminders
|
||||||
INNER JOIN `channels`
|
INNER JOIN `channels`
|
||||||
ON `channels`.id = reminders.channel_id
|
ON `channels`.id = reminders.channel_id
|
||||||
SET reminders.`utc_time` = DATE_ADD(reminders.`utc_time`, INTERVAL ? SECOND)
|
SET reminders.`utc_time` = DATE_ADD(reminders.`utc_time`, INTERVAL ? SECOND)
|
||||||
WHERE FIND_IN_SET(channels.`channel`, ?)
|
WHERE channels.`channel` IN ({placeholder})
|
||||||
",
|
"
|
||||||
combined_time as i64,
|
);
|
||||||
channels
|
|
||||||
)
|
let mut query = sqlx::query(&sql).bind(combined_time);
|
||||||
.execute(&ctx.data().database)
|
for channel in channels {
|
||||||
.await
|
query = query.bind(channel);
|
||||||
.unwrap();
|
}
|
||||||
|
|
||||||
|
query.execute(&ctx.data().database).await.unwrap();
|
||||||
} else {
|
} else {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"
|
"
|
||||||
UPDATE reminders
|
UPDATE reminders
|
||||||
INNER JOIN `channels`
|
INNER JOIN `channels`
|
||||||
ON `channels`.id = reminders.channel_id
|
ON `channels`.id = reminders.channel_id
|
||||||
SET reminders.`utc_time` = reminders.`utc_time` + ?
|
SET reminders.`utc_time` = reminders.`utc_time` + ?
|
||||||
WHERE channels.`channel` = ?
|
WHERE channels.`channel` = ?
|
||||||
",
|
",
|
||||||
combined_time as i64,
|
combined_time as i64,
|
||||||
ctx.channel_id().get()
|
ctx.channel_id().get()
|
||||||
)
|
)
|
||||||
|
@ -153,12 +153,12 @@ impl ComponentDataModel {
|
|||||||
ComponentDataModel::DelSelector(selector) => {
|
ComponentDataModel::DelSelector(selector) => {
|
||||||
if let ComponentInteractionDataKind::StringSelect { values } = &component.data.kind
|
if let ComponentInteractionDataKind::StringSelect { values } = &component.data.kind
|
||||||
{
|
{
|
||||||
let placeholder = values.iter().map(|_| "?").collect::<Vec<&str>>().join(",");
|
let placeholder = vec!["?"; values.len()].join(",");
|
||||||
let sql = format!(
|
let sql = format!(
|
||||||
"UPDATE reminders SET `status` = 'deleted' WHERE id IN ({placeholder})"
|
"UPDATE reminders SET `status` = 'deleted' WHERE id IN ({placeholder})"
|
||||||
);
|
);
|
||||||
let mut query = sqlx::query(&sql);
|
|
||||||
|
|
||||||
|
let mut query = sqlx::query(&sql);
|
||||||
for id in values {
|
for id in values {
|
||||||
query = query.bind(id);
|
query = query.bind(id);
|
||||||
}
|
}
|
||||||
@ -269,17 +269,15 @@ impl ComponentDataModel {
|
|||||||
if let ComponentInteractionDataKind::StringSelect { values } =
|
if let ComponentInteractionDataKind::StringSelect { values } =
|
||||||
&component.data.kind
|
&component.data.kind
|
||||||
{
|
{
|
||||||
let selected_id = values.join(",");
|
let placeholder = vec!["?"; values.len()].join(",");
|
||||||
|
let sql = format!("DELETE FROM todos WHERE id IN ({placeholder})");
|
||||||
|
|
||||||
sqlx::query!(
|
let mut query = sqlx::query(&sql);
|
||||||
"
|
for id in values {
|
||||||
DELETE FROM todos WHERE FIND_IN_SET(id, ?)
|
query = query.bind(id);
|
||||||
",
|
}
|
||||||
selected_id
|
|
||||||
)
|
query.execute(&data.database).await.unwrap();
|
||||||
.execute(&data.database)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let values = if let Some(uid) = selector.user_id {
|
let values = if let Some(uid) = selector.user_id {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
|
@ -8,17 +8,6 @@ use std::{
|
|||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
|
||||||
use chrono_tz::Tz;
|
|
||||||
use poise::{
|
|
||||||
serenity_prelude::{
|
|
||||||
model::id::{ChannelId, GuildId, UserId},
|
|
||||||
ButtonStyle, Cache, ChannelType, CreateActionRow, CreateButton, CreateEmbed, ReactionType,
|
|
||||||
},
|
|
||||||
CreateReply,
|
|
||||||
};
|
|
||||||
use sqlx::Executor;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::look::{LookFlags, TimeDisplayType},
|
commands::look::{LookFlags, TimeDisplayType},
|
||||||
component_models::{ComponentDataModel, UndoReminder},
|
component_models::{ComponentDataModel, UndoReminder},
|
||||||
@ -36,8 +25,18 @@ use crate::{
|
|||||||
utils::{check_guild_subscription, check_subscription},
|
utils::{check_guild_subscription, check_subscription},
|
||||||
Context, Database, Error,
|
Context, Database, Error,
|
||||||
};
|
};
|
||||||
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
|
use chrono_tz::Tz;
|
||||||
|
use poise::{
|
||||||
|
serenity_prelude::{
|
||||||
|
model::id::{ChannelId, GuildId, UserId},
|
||||||
|
ButtonStyle, Cache, ChannelType, CreateActionRow, CreateButton, CreateEmbed, ReactionType,
|
||||||
|
},
|
||||||
|
CreateReply,
|
||||||
|
};
|
||||||
|
use sqlx::{Executor, FromRow};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, FromRow)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Reminder {
|
pub struct Reminder {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
@ -140,7 +139,7 @@ impl Reminder {
|
|||||||
channel_id: C,
|
channel_id: C,
|
||||||
flags: &LookFlags,
|
flags: &LookFlags,
|
||||||
) -> Vec<Self> {
|
) -> Vec<Self> {
|
||||||
let enabled = if flags.show_disabled { "0,1" } else { "1" };
|
let enabled = if flags.show_disabled { "0" } else { "1" };
|
||||||
let channel_id = channel_id.into();
|
let channel_id = channel_id.into();
|
||||||
|
|
||||||
sqlx::query_as_unchecked!(
|
sqlx::query_as_unchecked!(
|
||||||
@ -168,7 +167,7 @@ impl Reminder {
|
|||||||
WHERE
|
WHERE
|
||||||
`status` = 'pending' AND
|
`status` = 'pending' AND
|
||||||
channels.channel = ? AND
|
channels.channel = ? AND
|
||||||
FIND_IN_SET(reminders.enabled, ?)
|
reminders.enabled >= ?
|
||||||
ORDER BY
|
ORDER BY
|
||||||
reminders.utc_time
|
reminders.utc_time
|
||||||
",
|
",
|
||||||
@ -194,17 +193,16 @@ impl Reminder {
|
|||||||
.keys()
|
.keys()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|k| k.get().to_string())
|
.map(|k| k.get().to_string())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>(),
|
||||||
.join(","),
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
match channel_query {
|
match channel_query {
|
||||||
Some(channel_query) => {
|
Some(channels) => {
|
||||||
sqlx::query_as_unchecked!(
|
let placeholder = vec!["?"; channels.len()].join(",");
|
||||||
Self,
|
let sql = format!(
|
||||||
"
|
"
|
||||||
SELECT
|
SELECT
|
||||||
reminders.id,
|
reminders.id,
|
||||||
@ -227,12 +225,16 @@ impl Reminder {
|
|||||||
channels.id = reminders.channel_id
|
channels.id = reminders.channel_id
|
||||||
WHERE
|
WHERE
|
||||||
`status` = 'pending' AND
|
`status` = 'pending' AND
|
||||||
FIND_IN_SET(channels.channel, ?)
|
channels.channel IN ({placeholder})
|
||||||
",
|
"
|
||||||
channel_query
|
);
|
||||||
)
|
|
||||||
.fetch_all(pool)
|
let mut query = sqlx::query_as::<Database, Self>(&sql);
|
||||||
.await
|
for channel in channels {
|
||||||
|
query = query.bind(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
query.fetch_all(pool).await
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
sqlx::query_as_unchecked!(
|
sqlx::query_as_unchecked!(
|
||||||
|
@ -72,55 +72,60 @@ pub async fn get_reminders(
|
|||||||
|
|
||||||
match channels_res {
|
match channels_res {
|
||||||
Ok(channels) => {
|
Ok(channels) => {
|
||||||
let channels = channels
|
let channels =
|
||||||
.keys()
|
channels.keys().into_iter().map(|k| k.get().to_string()).collect::<Vec<String>>();
|
||||||
.into_iter()
|
|
||||||
.map(|k| k.get().to_string())
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(",");
|
|
||||||
|
|
||||||
sqlx::query_as_unchecked!(
|
let placeholder = vec!["?"; channels.len()].join(",");
|
||||||
GetReminder,
|
let sql = format!(
|
||||||
"
|
"
|
||||||
SELECT
|
SELECT
|
||||||
reminders.attachment_name,
|
reminders.attachment_name,
|
||||||
reminders.avatar,
|
reminders.avatar,
|
||||||
channels.channel,
|
channels.channel,
|
||||||
reminders.content,
|
reminders.content,
|
||||||
reminders.embed_author,
|
reminders.embed_author,
|
||||||
reminders.embed_author_url,
|
reminders.embed_author_url,
|
||||||
reminders.embed_color,
|
reminders.embed_color,
|
||||||
reminders.embed_description,
|
reminders.embed_description,
|
||||||
reminders.embed_footer,
|
reminders.embed_footer,
|
||||||
reminders.embed_footer_url,
|
reminders.embed_footer_url,
|
||||||
reminders.embed_image_url,
|
reminders.embed_image_url,
|
||||||
reminders.embed_thumbnail_url,
|
reminders.embed_thumbnail_url,
|
||||||
reminders.embed_title,
|
reminders.embed_title,
|
||||||
IFNULL(reminders.embed_fields, '[]') AS embed_fields,
|
IFNULL(reminders.embed_fields, '[]') AS embed_fields,
|
||||||
reminders.enabled,
|
reminders.enabled,
|
||||||
reminders.expires,
|
reminders.expires,
|
||||||
reminders.interval_seconds,
|
reminders.interval_seconds,
|
||||||
reminders.interval_days,
|
reminders.interval_days,
|
||||||
reminders.interval_months,
|
reminders.interval_months,
|
||||||
reminders.name,
|
reminders.name,
|
||||||
reminders.restartable,
|
reminders.restartable,
|
||||||
reminders.tts,
|
reminders.tts,
|
||||||
reminders.uid,
|
reminders.uid,
|
||||||
reminders.username,
|
reminders.username,
|
||||||
reminders.utc_time
|
reminders.utc_time
|
||||||
FROM reminders
|
FROM reminders
|
||||||
INNER JOIN channels ON channels.id = reminders.channel_id
|
INNER JOIN channels
|
||||||
WHERE `status` = 'pending' AND FIND_IN_SET(channels.channel, ?)",
|
ON channels.id = reminders.channel_id
|
||||||
channels
|
WHERE `status` = 'pending'
|
||||||
)
|
AND channels.channel IN ({placeholder})
|
||||||
.fetch_all(pool.inner())
|
"
|
||||||
.await
|
);
|
||||||
.map(|r| Ok(json!(r)))
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
warn!("Failed to complete SQL query: {:?}", e);
|
|
||||||
|
|
||||||
json_err!("Could not load reminders")
|
let mut query = sqlx::query_as::<Database, GetReminder>(&sql);
|
||||||
})
|
for channel in channels {
|
||||||
|
query = query.bind(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
query
|
||||||
|
.fetch_all(pool.inner())
|
||||||
|
.await
|
||||||
|
.map(|reminders| Ok(json!(reminders)))
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
warn!("Failed to complete SQL query: {:?}", e);
|
||||||
|
|
||||||
|
json_err!("Could not load reminders")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Could not fetch channels from {}: {:?}", id, e);
|
warn!("Could not fetch channels from {}: {:?}", id, e);
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
use crate::web::{
|
||||||
|
check_authorization,
|
||||||
|
guards::transaction::Transaction,
|
||||||
|
routes::{
|
||||||
|
dashboard::{
|
||||||
|
create_reminder, CreateReminder, ImportBody, ReminderCsv, ReminderTemplateCsv, TodoCsv,
|
||||||
|
},
|
||||||
|
JsonResult,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use crate::Database;
|
||||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||||
use csv::{QuoteStyle, WriterBuilder};
|
use csv::{QuoteStyle, WriterBuilder};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
@ -14,17 +25,6 @@ use serenity::{
|
|||||||
};
|
};
|
||||||
use sqlx::{MySql, Pool};
|
use sqlx::{MySql, Pool};
|
||||||
|
|
||||||
use crate::web::{
|
|
||||||
check_authorization,
|
|
||||||
guards::transaction::Transaction,
|
|
||||||
routes::{
|
|
||||||
dashboard::{
|
|
||||||
create_reminder, CreateReminder, ImportBody, ReminderCsv, ReminderTemplateCsv, TodoCsv,
|
|
||||||
},
|
|
||||||
JsonResult,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[get("/api/guild/<id>/export/reminders")]
|
#[get("/api/guild/<id>/export/reminders")]
|
||||||
pub async fn export_reminders(
|
pub async fn export_reminders(
|
||||||
id: u64,
|
id: u64,
|
||||||
@ -40,48 +40,47 @@ pub async fn export_reminders(
|
|||||||
|
|
||||||
match channels_res {
|
match channels_res {
|
||||||
Ok(channels) => {
|
Ok(channels) => {
|
||||||
let channels = channels
|
let channels =
|
||||||
.keys()
|
channels.keys().into_iter().map(|k| k.get().to_string()).collect::<Vec<String>>();
|
||||||
.into_iter()
|
let placeholder = vec!["?"; channels.len()].join(",");
|
||||||
.map(|k| k.get().to_string())
|
let sql = format!(
|
||||||
.collect::<Vec<String>>()
|
"
|
||||||
.join(",");
|
SELECT
|
||||||
|
reminders.attachment,
|
||||||
let result = sqlx::query_as_unchecked!(
|
reminders.attachment_name,
|
||||||
ReminderCsv,
|
reminders.avatar,
|
||||||
"SELECT
|
CONCAT('#', channels.channel) AS channel,
|
||||||
reminders.attachment,
|
reminders.content,
|
||||||
reminders.attachment_name,
|
reminders.embed_author,
|
||||||
reminders.avatar,
|
reminders.embed_author_url,
|
||||||
CONCAT('#', channels.channel) AS channel,
|
reminders.embed_color,
|
||||||
reminders.content,
|
reminders.embed_description,
|
||||||
reminders.embed_author,
|
reminders.embed_footer,
|
||||||
reminders.embed_author_url,
|
reminders.embed_footer_url,
|
||||||
reminders.embed_color,
|
reminders.embed_image_url,
|
||||||
reminders.embed_description,
|
reminders.embed_thumbnail_url,
|
||||||
reminders.embed_footer,
|
reminders.embed_title,
|
||||||
reminders.embed_footer_url,
|
reminders.embed_fields,
|
||||||
reminders.embed_image_url,
|
reminders.enabled,
|
||||||
reminders.embed_thumbnail_url,
|
reminders.expires,
|
||||||
reminders.embed_title,
|
reminders.interval_seconds,
|
||||||
reminders.embed_fields,
|
reminders.interval_days,
|
||||||
reminders.enabled,
|
reminders.interval_months,
|
||||||
reminders.expires,
|
reminders.name,
|
||||||
reminders.interval_seconds,
|
reminders.restartable,
|
||||||
reminders.interval_days,
|
reminders.tts,
|
||||||
reminders.interval_months,
|
reminders.username,
|
||||||
reminders.name,
|
reminders.utc_time
|
||||||
reminders.restartable,
|
|
||||||
reminders.tts,
|
|
||||||
reminders.username,
|
|
||||||
reminders.utc_time
|
|
||||||
FROM reminders
|
FROM reminders
|
||||||
LEFT JOIN channels ON channels.id = reminders.channel_id
|
LEFT JOIN channels
|
||||||
WHERE FIND_IN_SET(channels.channel, ?) AND status = 'pending'",
|
ON channels.id = reminders.channel_id
|
||||||
channels
|
WHERE status = 'pending'
|
||||||
)
|
AND channels.channel IN ({placeholder})
|
||||||
.fetch_all(pool.inner())
|
"
|
||||||
.await;
|
);
|
||||||
|
|
||||||
|
let result =
|
||||||
|
sqlx::query_as::<Database, ReminderCsv>(&sql).fetch_all(pool.inner()).await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(reminders) => {
|
Ok(reminders) => {
|
||||||
|
@ -17,6 +17,7 @@ use serenity::{
|
|||||||
model::id::{ChannelId, GuildId, UserId},
|
model::id::{ChannelId, GuildId, UserId},
|
||||||
};
|
};
|
||||||
use sqlx::types::Json;
|
use sqlx::types::Json;
|
||||||
|
use sqlx::FromRow;
|
||||||
|
|
||||||
use crate::web::{
|
use crate::web::{
|
||||||
catchers::internal_server_error,
|
catchers::internal_server_error,
|
||||||
@ -177,7 +178,7 @@ pub struct CreateReminder {
|
|||||||
utc_time: NaiveDateTime,
|
utc_time: NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize, FromRow)]
|
||||||
pub struct GetReminder {
|
pub struct GetReminder {
|
||||||
attachment_name: Option<String>,
|
attachment_name: Option<String>,
|
||||||
avatar: Option<String>,
|
avatar: Option<String>,
|
||||||
@ -209,7 +210,7 @@ pub struct GetReminder {
|
|||||||
utc_time: NaiveDateTime,
|
utc_time: NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, FromRow)]
|
||||||
pub struct ReminderCsv {
|
pub struct ReminderCsv {
|
||||||
attachment: Option<Attachment>,
|
attachment: Option<Attachment>,
|
||||||
attachment_name: Option<String>,
|
attachment_name: Option<String>,
|
||||||
|
@ -9,7 +9,7 @@ WorkingDirectory=/etc/reminder-rs
|
|||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=10
|
RestartSec=10
|
||||||
Environment="RUST_LOG=warn,rocket=info,reminder_rs=debug,postman=debug"
|
Environment="RUST_LOG=warn,rocket=info,reminder_rs=debug,postman=debug"
|
||||||
WatchdogSec=120
|
WatchdogSec=300
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
Loading…
Reference in New Issue
Block a user