fix(messages): accept null version on legacy message rows (#3004)

This commit is contained in:
Hampus
2026-09-28 01:10:52 +02:00
committed by GitHub
parent dfd46ccc2c
commit 0ca035c547
2 changed files with 43 additions and 13 deletions
+30 -12
View File
@@ -2382,8 +2382,6 @@ fn decode_postgres_message(row: serde_json::Value) -> anyhow::Result<Message> {
.get("pinned_timestamp")
.is_some_and(|value| !value.is_null());
row.insert("pinned".to_owned(), serde_json::Value::Bool(pinned));
default_i32_field(&mut row, "type", 0);
default_i32_field(&mut row, "version", 0);
Ok(serde_json::from_value(serde_json::Value::Object(row))?)
}
@@ -2415,16 +2413,6 @@ fn decode_postgres_attachment_decay(
Ok((row.attachment_id, expires_at))
}
fn default_i32_field(
row: &mut serde_json::Map<String, serde_json::Value>,
field: &str,
value: i32,
) {
if row.get(field).is_none_or(serde_json::Value::is_null) {
row.insert(field.to_owned(), serde_json::Value::Number(value.into()));
}
}
#[cfg(feature = "scylla")]
fn rows_to_messages(rows: QueryRowsResult) -> anyhow::Result<Vec<Message>> {
let rows: Vec<MessageDbRow> = rows.rows::<MessageDbRow>()?.collect::<Result<_, _>>()?;
@@ -3404,6 +3392,36 @@ mod tests {
);
}
#[test]
fn build_responses_request_accepts_legacy_null_version_rows() {
let request: MessageRequest = serde_json::from_value(json!({
"op": "BuildResponses",
"messages": [{
"message_id": "1449544529132171273",
"channel_id": "1431572375251247158",
"bucket": 399,
"author_id": "1130650140672000000",
"type": null,
"version": null,
"content": ""
}],
"viewer_user_id": "1130650140672000000",
"source_guild_id": null,
"message_history_cutoff_ms": null,
"can_read_message_history": true,
"media_endpoint": "https://media.example",
"media_proxy_secret_key": "secret",
"include_reactions": true
}))
.unwrap();
let MessageRequest::BuildResponses { messages, .. } = request else {
panic!("expected BuildResponses");
};
assert_eq!(messages[0].message_type, 0);
assert_eq!(messages[0].version, 0);
}
#[test]
fn mention_context_carries_embed_user_ids_for_message_and_snapshots() {
let message: Message = serde_json::from_value(json!({
+13 -1
View File
@@ -58,6 +58,13 @@ mod serde_id {
.map(StringOrI64::into_i64)
.collect()
}
pub fn i32_or_null_as_default<'de, D>(deserializer: D) -> Result<i32, D::Error>
where
D: Deserializer<'de>,
{
Ok(Option::<i32>::deserialize(deserializer)?.unwrap_or_default())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -164,7 +171,11 @@ pub struct Message {
pub bucket: i32,
#[serde(default, deserialize_with = "serde_id::opt_i64_from_string_or_number")]
pub author_id: Option<i64>,
#[serde(rename = "type")]
#[serde(
rename = "type",
default,
deserialize_with = "serde_id::i32_or_null_as_default"
)]
pub message_type: i32,
#[serde(default, deserialize_with = "serde_id::opt_i64_from_string_or_number")]
pub webhook_id: Option<i64>,
@@ -191,6 +202,7 @@ pub struct Message {
)]
pub mention_channels: Vec<i64>,
pub has_reaction: Option<bool>,
#[serde(default, deserialize_with = "serde_id::i32_or_null_as_default")]
pub version: i32,
#[serde(skip_serializing_if = "Option::is_none")]
pub attachments: Option<Vec<MessageAttachment>>,