mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 17:36:29 +03:00
Use UPSERT to insert into msgs table
This way no temporary rows are created and it is easier to maintain because UPDATE statement is right below the INSERT statement, unlike `merge_messages` function which is easy to forget about.
This commit is contained in:
@@ -11,7 +11,7 @@ use crate::imap::{Imap, ImapActionResult};
|
|||||||
use crate::job::{self, Action, Job, Status};
|
use crate::job::{self, Action, Job, Status};
|
||||||
use crate::message::{Message, MsgId, Viewtype};
|
use crate::message::{Message, MsgId, Viewtype};
|
||||||
use crate::mimeparser::{MimeMessage, Part};
|
use crate::mimeparser::{MimeMessage, Part};
|
||||||
use crate::param::{Param, Params};
|
use crate::param::Params;
|
||||||
use crate::tools::time;
|
use crate::tools::time;
|
||||||
use crate::{job_try, stock_str, EventType};
|
use crate::{job_try, stock_str, EventType};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
@@ -69,76 +69,6 @@ impl Context {
|
|||||||
Ok(Some(max(MIN_DOWNLOAD_LIMIT, download_limit as u32)))
|
Ok(Some(max(MIN_DOWNLOAD_LIMIT, download_limit as u32)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merges the two messages to `placeholder_msg_id`;
|
|
||||||
// `full_msg_id` is no longer used afterwards.
|
|
||||||
pub(crate) async fn merge_messages(
|
|
||||||
&self,
|
|
||||||
full_msg_id: MsgId,
|
|
||||||
placeholder_msg_id: MsgId,
|
|
||||||
) -> Result<()> {
|
|
||||||
let placeholder = Message::load_from_db(self, placeholder_msg_id).await?;
|
|
||||||
self.sql
|
|
||||||
.transaction(move |transaction| {
|
|
||||||
// Move all the data from full message to placeholder.
|
|
||||||
// `id` stays the same, so foreign key constraints are not violated.
|
|
||||||
// For example, `reactions.msg_id` foreign key keeps pointing
|
|
||||||
// to the same message.
|
|
||||||
transaction.execute(
|
|
||||||
"UPDATE msgs
|
|
||||||
SET
|
|
||||||
rfc724_mid=full.rfc724_mid,
|
|
||||||
chat_id=full.chat_id,
|
|
||||||
from_id=full.from_id,
|
|
||||||
to_id=full.to_id,
|
|
||||||
timestamp=full.timestamp,
|
|
||||||
type=full.type,
|
|
||||||
state=full.state,
|
|
||||||
msgrmsg=full.msgrmsg,
|
|
||||||
bytes=full.bytes,
|
|
||||||
txt=full.txt,
|
|
||||||
txt_raw=full.txt_raw,
|
|
||||||
param=full.param,
|
|
||||||
starred=full.starred,
|
|
||||||
timestamp_sent=full.timestamp_sent,
|
|
||||||
timestamp_rcvd=full.timestamp_rcvd,
|
|
||||||
hidden=full.hidden,
|
|
||||||
mime_headers=full.mime_headers,
|
|
||||||
mime_in_reply_to=full.mime_in_reply_to,
|
|
||||||
mime_references=full.mime_references,
|
|
||||||
move_state=full.move_state,
|
|
||||||
location_id=full.location_id,
|
|
||||||
error=full.error,
|
|
||||||
ephemeral_timer=full.ephemeral_timer,
|
|
||||||
ephemeral_timestamp=full.ephemeral_timestamp,
|
|
||||||
mime_modified=full.mime_modified,
|
|
||||||
subject=full.subject,
|
|
||||||
download_state=full.download_state,
|
|
||||||
hop_info=full.hop_info
|
|
||||||
FROM msgs AS full
|
|
||||||
WHERE msgs.id=?1 AND full.id=?2",
|
|
||||||
paramsv![placeholder_msg_id, full_msg_id],
|
|
||||||
)?;
|
|
||||||
transaction.execute("DELETE FROM msgs WHERE id=?;", paramsv![full_msg_id])?;
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
let mut full = Message::load_from_db(self, placeholder_msg_id).await?;
|
|
||||||
|
|
||||||
for key in [
|
|
||||||
Param::WebxdcSummary,
|
|
||||||
Param::WebxdcSummaryTimestamp,
|
|
||||||
Param::WebxdcDocument,
|
|
||||||
Param::WebxdcDocumentTimestamp,
|
|
||||||
] {
|
|
||||||
if let Some(value) = placeholder.param.get(key) {
|
|
||||||
full.param.set(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
full.update_param(self).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MsgId {
|
impl MsgId {
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ async fn add_parts(
|
|||||||
from_id: ContactId,
|
from_id: ContactId,
|
||||||
seen: bool,
|
seen: bool,
|
||||||
is_partial_download: Option<u32>,
|
is_partial_download: Option<u32>,
|
||||||
replace_msg_id: Option<MsgId>,
|
mut replace_msg_id: Option<MsgId>,
|
||||||
fetching_existing_messages: bool,
|
fetching_existing_messages: bool,
|
||||||
prevent_rename: bool,
|
prevent_rename: bool,
|
||||||
) -> Result<ReceivedMsg> {
|
) -> Result<ReceivedMsg> {
|
||||||
@@ -1068,11 +1068,30 @@ async fn add_parts(
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut param = part.param.clone();
|
||||||
|
if is_system_message != SystemMessage::Unknown {
|
||||||
|
param.set_int(Param::Cmd, is_system_message as i32);
|
||||||
|
}
|
||||||
|
if let Some(replace_msg_id) = replace_msg_id {
|
||||||
|
let placeholder = Message::load_from_db(context, replace_msg_id).await?;
|
||||||
|
for key in [
|
||||||
|
Param::WebxdcSummary,
|
||||||
|
Param::WebxdcSummaryTimestamp,
|
||||||
|
Param::WebxdcDocument,
|
||||||
|
Param::WebxdcDocumentTimestamp,
|
||||||
|
] {
|
||||||
|
if let Some(value) = placeholder.param.get(key) {
|
||||||
|
param.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut txt_raw = "".to_string();
|
let mut txt_raw = "".to_string();
|
||||||
let mut stmt = conn.prepare_cached(
|
let mut stmt = conn.prepare_cached(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO msgs
|
INSERT INTO msgs
|
||||||
(
|
(
|
||||||
|
id,
|
||||||
rfc724_mid, chat_id,
|
rfc724_mid, chat_id,
|
||||||
from_id, to_id, timestamp, timestamp_sent,
|
from_id, to_id, timestamp, timestamp_sent,
|
||||||
timestamp_rcvd, type, state, msgrmsg,
|
timestamp_rcvd, type, state, msgrmsg,
|
||||||
@@ -1082,13 +1101,22 @@ INSERT INTO msgs
|
|||||||
ephemeral_timestamp, download_state, hop_info
|
ephemeral_timestamp, download_state, hop_info
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
|
?,
|
||||||
?, ?, ?, ?,
|
?, ?, ?, ?,
|
||||||
?, ?, ?, ?,
|
?, ?, ?, ?,
|
||||||
?, ?, ?, ?,
|
?, ?, ?, ?,
|
||||||
?, ?, ?, ?,
|
?, ?, ?, ?,
|
||||||
?, ?, ?, ?,
|
?, ?, ?, ?,
|
||||||
?, ?, ?, ?
|
?, ?, ?, ?
|
||||||
);
|
)
|
||||||
|
ON CONFLICT (id) DO UPDATE
|
||||||
|
SET rfc724_mid=excluded.rfc724_mid, chat_id=excluded.chat_id,
|
||||||
|
from_id=excluded.from_id, to_id=excluded.to_id, timestamp=excluded.timestamp, timestamp_sent=excluded.timestamp_sent,
|
||||||
|
timestamp_rcvd=excluded.timestamp_rcvd, type=excluded.type, state=excluded.state, msgrmsg=excluded.msgrmsg,
|
||||||
|
txt=excluded.txt, subject=excluded.subject, txt_raw=excluded.txt_raw, param=excluded.param,
|
||||||
|
bytes=excluded.bytes, mime_headers=excluded.mime_headers, mime_in_reply_to=excluded.mime_in_reply_to,
|
||||||
|
mime_references=excluded.mime_references, mime_modified=excluded.mime_modified, error=excluded.error, ephemeral_timer=excluded.ephemeral_timer,
|
||||||
|
ephemeral_timestamp=excluded.ephemeral_timestamp, download_state=excluded.download_state, hop_info=excluded.hop_info
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -1110,11 +1138,6 @@ INSERT INTO msgs
|
|||||||
txt_raw = format!("{}\n\n{}", subject, msg_raw);
|
txt_raw = format!("{}\n\n{}", subject, msg_raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut param = part.param.clone();
|
|
||||||
if is_system_message != SystemMessage::Unknown {
|
|
||||||
param.set_int(Param::Cmd, is_system_message as i32);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ephemeral_timestamp = if in_fresh {
|
let ephemeral_timestamp = if in_fresh {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
@@ -1131,6 +1154,7 @@ INSERT INTO msgs
|
|||||||
let trash = chat_id.is_trash() || (is_location_kml && msg.is_empty());
|
let trash = chat_id.is_trash() || (is_location_kml && msg.is_empty());
|
||||||
|
|
||||||
stmt.execute(paramsv![
|
stmt.execute(paramsv![
|
||||||
|
replace_msg_id,
|
||||||
rfc724_mid,
|
rfc724_mid,
|
||||||
if trash { DC_CHAT_ID_TRASH } else { chat_id },
|
if trash { DC_CHAT_ID_TRASH } else { chat_id },
|
||||||
if trash { ContactId::UNDEFINED } else { from_id },
|
if trash { ContactId::UNDEFINED } else { from_id },
|
||||||
@@ -1169,6 +1193,10 @@ INSERT INTO msgs
|
|||||||
},
|
},
|
||||||
mime_parser.hop_info
|
mime_parser.hop_info
|
||||||
])?;
|
])?;
|
||||||
|
|
||||||
|
// We only replace placeholder with a first part,
|
||||||
|
// afterwards insert additional parts.
|
||||||
|
replace_msg_id = None;
|
||||||
let row_id = conn.last_insert_rowid();
|
let row_id = conn.last_insert_rowid();
|
||||||
|
|
||||||
drop(stmt);
|
drop(stmt);
|
||||||
@@ -1177,14 +1205,8 @@ INSERT INTO msgs
|
|||||||
drop(conn);
|
drop(conn);
|
||||||
|
|
||||||
if let Some(replace_msg_id) = replace_msg_id {
|
if let Some(replace_msg_id) = replace_msg_id {
|
||||||
if let Some(created_msg_id) = created_db_entries.pop() {
|
// "Replace" placeholder with a message that has no parts.
|
||||||
context
|
replace_msg_id.delete_from_db(context).await?;
|
||||||
.merge_messages(created_msg_id, replace_msg_id)
|
|
||||||
.await?;
|
|
||||||
created_db_entries.push(replace_msg_id);
|
|
||||||
} else {
|
|
||||||
replace_msg_id.delete_from_db(context).await?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chat_id.unarchive_if_not_muted(context).await?;
|
chat_id.unarchive_if_not_muted(context).await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user