mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 17:36:29 +03:00
sql: use transaction in Contact::add_or_lookup()
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
- use transaction in `Contact::add_or_lookup()` #4059
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
|
|||||||
235
src/contact.rs
235
src/contact.rs
@@ -13,6 +13,7 @@ use async_channel::{self as channel, Receiver, Sender};
|
|||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use rusqlite::OptionalExtension;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tokio::time::{timeout, Duration};
|
use tokio::time::{timeout, Duration};
|
||||||
@@ -520,8 +521,6 @@ impl Contact {
|
|||||||
/// Depending on the origin, both, "row_name" and "row_authname" are updated from "name".
|
/// Depending on the origin, both, "row_name" and "row_authname" are updated from "name".
|
||||||
///
|
///
|
||||||
/// Returns the contact_id and a `Modifier` value indicating if a modification occurred.
|
/// Returns the contact_id and a `Modifier` value indicating if a modification occurred.
|
||||||
///
|
|
||||||
/// Returns None if the contact with such address cannot exist.
|
|
||||||
pub(crate) async fn add_or_lookup(
|
pub(crate) async fn add_or_lookup(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -566,14 +565,12 @@ impl Contact {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut update_addr = false;
|
let mut update_addr = false;
|
||||||
let mut row_id = 0;
|
|
||||||
|
|
||||||
if let Some((id, row_name, row_addr, row_origin, row_authname)) = context
|
let row_id = context.sql.transaction(|transaction| {
|
||||||
.sql
|
let row = transaction.query_row(
|
||||||
.query_row_optional(
|
"SELECT id, name, addr, origin, authname
|
||||||
"SELECT id, name, addr, origin, authname \
|
FROM contacts WHERE addr=? COLLATE NOCASE",
|
||||||
FROM contacts WHERE addr=? COLLATE NOCASE;",
|
[addr.to_string()],
|
||||||
paramsv![addr.to_string()],
|
|
||||||
|row| {
|
|row| {
|
||||||
let row_id: isize = row.get(0)?;
|
let row_id: isize = row.get(0)?;
|
||||||
let row_name: String = row.get(1)?;
|
let row_name: String = row.get(1)?;
|
||||||
@@ -582,120 +579,130 @@ impl Contact {
|
|||||||
let row_authname: String = row.get(4)?;
|
let row_authname: String = row.get(4)?;
|
||||||
|
|
||||||
Ok((row_id, row_name, row_addr, row_origin, row_authname))
|
Ok((row_id, row_name, row_addr, row_origin, row_authname))
|
||||||
},
|
}).optional()?;
|
||||||
)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
let update_name = manual && name != row_name;
|
|
||||||
let update_authname = !manual
|
|
||||||
&& name != row_authname
|
|
||||||
&& !name.is_empty()
|
|
||||||
&& (origin >= row_origin
|
|
||||||
|| origin == Origin::IncomingUnknownFrom
|
|
||||||
|| row_authname.is_empty());
|
|
||||||
|
|
||||||
row_id = u32::try_from(id)?;
|
let row_id;
|
||||||
if origin >= row_origin && addr.as_ref() != row_addr {
|
if let Some((id, row_name, row_addr, row_origin, row_authname)) = row {
|
||||||
update_addr = true;
|
let update_name = manual && name != row_name;
|
||||||
}
|
let update_authname = !manual
|
||||||
if update_name || update_authname || update_addr || origin > row_origin {
|
&& name != row_authname
|
||||||
let new_name = if update_name {
|
&& !name.is_empty()
|
||||||
name.to_string()
|
&& (origin >= row_origin
|
||||||
} else {
|
|| origin == Origin::IncomingUnknownFrom
|
||||||
row_name
|
|| row_authname.is_empty());
|
||||||
};
|
|
||||||
|
|
||||||
context
|
row_id = u32::try_from(id)?;
|
||||||
.sql
|
if origin >= row_origin && addr.as_ref() != row_addr {
|
||||||
.execute(
|
update_addr = true;
|
||||||
"UPDATE contacts SET name=?, addr=?, origin=?, authname=? WHERE id=?;",
|
}
|
||||||
paramsv![
|
if update_name || update_authname || update_addr || origin > row_origin {
|
||||||
new_name,
|
let new_name = if update_name {
|
||||||
if update_addr {
|
name.to_string()
|
||||||
addr.to_string()
|
} else {
|
||||||
} else {
|
row_name
|
||||||
row_addr
|
};
|
||||||
},
|
|
||||||
if origin > row_origin {
|
|
||||||
origin
|
|
||||||
} else {
|
|
||||||
row_origin
|
|
||||||
},
|
|
||||||
if update_authname {
|
|
||||||
name.to_string()
|
|
||||||
} else {
|
|
||||||
row_authname
|
|
||||||
},
|
|
||||||
row_id
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
if update_name || update_authname {
|
transaction
|
||||||
// Update the contact name also if it is used as a group name.
|
.execute(
|
||||||
// This is one of the few duplicated data, however, getting the chat list is easier this way.
|
"UPDATE contacts SET name=?, addr=?, origin=?, authname=? WHERE id=?;",
|
||||||
let chat_id: Option<i32> = context.sql.query_get_value(
|
paramsv![
|
||||||
"SELECT id FROM chats WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?)",
|
new_name,
|
||||||
paramsv![Chattype::Single, isize::try_from(row_id)?]
|
if update_addr {
|
||||||
).await?;
|
addr.to_string()
|
||||||
if let Some(chat_id) = chat_id {
|
} else {
|
||||||
let contact = Contact::get_by_id(context, ContactId::new(row_id)).await?;
|
row_addr
|
||||||
let chat_name = contact.get_display_name();
|
},
|
||||||
match context
|
if origin > row_origin {
|
||||||
.sql
|
origin
|
||||||
.execute(
|
} else {
|
||||||
"UPDATE chats SET name=?1 WHERE id=?2 AND name!=?3",
|
row_origin
|
||||||
paramsv![chat_name, chat_id, chat_name],
|
},
|
||||||
)
|
if update_authname {
|
||||||
.await
|
name.to_string()
|
||||||
{
|
} else {
|
||||||
Err(err) => warn!(context, "Can't update chat name: {}", err),
|
row_authname
|
||||||
Ok(count) => {
|
},
|
||||||
if count > 0 {
|
row_id
|
||||||
// Chat name updated
|
],
|
||||||
context.emit_event(EventType::ChatModified(ChatId::new(
|
)?;
|
||||||
chat_id.try_into()?,
|
|
||||||
)));
|
if update_name || update_authname {
|
||||||
}
|
// Update the contact name also if it is used as a group name.
|
||||||
|
// This is one of the few duplicated data, however, getting the chat list is easier this way.
|
||||||
|
let chat_id: Option<ChatId> = transaction.query_row(
|
||||||
|
"SELECT id FROM chats WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?)",
|
||||||
|
params![Chattype::Single, isize::try_from(row_id)?],
|
||||||
|
|row| {
|
||||||
|
let chat_id: ChatId = row.get(0)?;
|
||||||
|
Ok(chat_id)
|
||||||
|
}
|
||||||
|
).optional()?;
|
||||||
|
|
||||||
|
if let Some(chat_id) = chat_id {
|
||||||
|
let contact_id = ContactId::new(row_id);
|
||||||
|
let (addr, name, authname) =
|
||||||
|
transaction.query_row(
|
||||||
|
"SELECT addr, name, authname
|
||||||
|
FROM contacts
|
||||||
|
WHERE id=?",
|
||||||
|
params![contact_id],
|
||||||
|
|row| {
|
||||||
|
let addr: String = row.get(0)?;
|
||||||
|
let name: String = row.get(1)?;
|
||||||
|
let authname: String = row.get(2)?;
|
||||||
|
Ok((addr, name, authname))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let chat_name = if !name.is_empty() {
|
||||||
|
name
|
||||||
|
} else if !authname.is_empty() {
|
||||||
|
authname
|
||||||
|
} else {
|
||||||
|
addr
|
||||||
|
};
|
||||||
|
|
||||||
|
let count = transaction.execute(
|
||||||
|
"UPDATE chats SET name=?1 WHERE id=?2 AND name!=?1",
|
||||||
|
params![chat_name, chat_id])?;
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
// Chat name updated
|
||||||
|
context.emit_event(EventType::ChatModified(chat_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sth_modified = Modifier::Modified;
|
||||||
}
|
}
|
||||||
sth_modified = Modifier::Modified;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let update_name = manual;
|
|
||||||
let update_authname = !manual;
|
|
||||||
|
|
||||||
if let Ok(new_row_id) = context
|
|
||||||
.sql
|
|
||||||
.insert(
|
|
||||||
"INSERT INTO contacts (name, addr, origin, authname) VALUES(?, ?, ?, ?);",
|
|
||||||
paramsv![
|
|
||||||
if update_name {
|
|
||||||
name.to_string()
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
},
|
|
||||||
addr,
|
|
||||||
origin,
|
|
||||||
if update_authname {
|
|
||||||
name.to_string()
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
}
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
row_id = u32::try_from(new_row_id)?;
|
|
||||||
sth_modified = Modifier::Created;
|
|
||||||
info!(context, "added contact id={} addr={}", row_id, &addr);
|
|
||||||
} else {
|
} else {
|
||||||
error!(context, "Cannot add contact.");
|
let update_name = manual;
|
||||||
|
let update_authname = !manual;
|
||||||
|
|
||||||
|
transaction
|
||||||
|
.execute(
|
||||||
|
"INSERT INTO contacts (name, addr, origin, authname)
|
||||||
|
VALUES (?, ?, ?, ?);",
|
||||||
|
params![
|
||||||
|
if update_name {
|
||||||
|
name.to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
},
|
||||||
|
addr,
|
||||||
|
origin,
|
||||||
|
if update_authname {
|
||||||
|
name.to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
sth_modified = Modifier::Created;
|
||||||
|
row_id = u32::try_from(transaction.last_insert_rowid())?;
|
||||||
|
info!(context, "added contact id={} addr={}", row_id, &addr);
|
||||||
}
|
}
|
||||||
}
|
Ok(row_id)
|
||||||
|
}).await?;
|
||||||
|
|
||||||
Ok((ContactId::new(row_id), sth_modified))
|
Ok((ContactId::new(row_id), sth_modified))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user