Skip to content

Commit cd9b7fe

Browse files
committed
Bug 1974122 - keywords_i18n needs to be updated when records are deleted and on clear_database
1 parent b7fcc15 commit cd9b7fe

File tree

3 files changed

+200
-2
lines changed

3 files changed

+200
-2
lines changed

components/suggest/src/db.rs

Lines changed: 187 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,11 @@ impl<'a> SuggestDao<'a> {
12031203
named_params! { ":record_id": record_id.as_str() },
12041204
)?;
12051205
self.scope.err_if_interrupted()?;
1206+
self.conn.execute_cached(
1207+
"DELETE FROM keywords_i18n WHERE suggestion_id IN (SELECT id from suggestions WHERE record_id = :record_id)",
1208+
named_params! { ":record_id": record_id.as_str() },
1209+
)?;
1210+
self.scope.err_if_interrupted()?;
12061211
self.conn.execute_cached(
12071212
"DELETE FROM full_keywords WHERE suggestion_id IN (SELECT id from suggestions WHERE record_id = :record_id)",
12081213
named_params! { ":record_id": record_id.as_str() },
@@ -1886,7 +1891,7 @@ fn provider_config_meta_key(provider: SuggestionProvider) -> String {
18861891
#[cfg(test)]
18871892
mod tests {
18881893
use super::*;
1889-
use crate::{store::tests::TestStore, testing::*};
1894+
use crate::{store::tests::TestStore, testing::*, SuggestIngestionConstraints};
18901895

18911896
#[test]
18921897
fn keywords_metrics_updater() -> anyhow::Result<()> {
@@ -2005,4 +2010,185 @@ mod tests {
20052010

20062011
Ok(())
20072012
}
2013+
2014+
// Keywords in `keywords_i18n` should be dropped when their records are
2015+
// deleted.
2016+
#[test]
2017+
fn keywords_i18n_delete_record() -> anyhow::Result<()> {
2018+
// Add some records whose keywords are stored in `keywords_i18n`. We'll
2019+
// use weather records.
2020+
let kws_1 = ["aaa", "bbb", "ccc"];
2021+
let kws_2 = ["yyy", "zzz"];
2022+
let mut store = TestStore::new(
2023+
MockRemoteSettingsClient::default()
2024+
.with_record(SuggestionProvider::Weather.record(
2025+
"weather-1",
2026+
json!({
2027+
"score": 0.24,
2028+
"keywords": kws_1,
2029+
}),
2030+
))
2031+
.with_record(SuggestionProvider::Weather.record(
2032+
"weather-2",
2033+
json!({
2034+
"score": 0.24,
2035+
"keywords": kws_2,
2036+
}),
2037+
)),
2038+
);
2039+
store.ingest(SuggestIngestionConstraints {
2040+
providers: Some(vec![SuggestionProvider::Weather]),
2041+
..SuggestIngestionConstraints::all_providers()
2042+
});
2043+
2044+
// Make sure all keywords are present.
2045+
assert_eq!(
2046+
store.count_rows("keywords_i18n") as usize,
2047+
kws_1.len() + kws_2.len()
2048+
);
2049+
2050+
for q in kws_1.iter().chain(kws_2.iter()) {
2051+
assert_eq!(
2052+
store.fetch_suggestions(SuggestionQuery::weather(q)),
2053+
vec![Suggestion::Weather {
2054+
score: 0.24,
2055+
city: None,
2056+
}],
2057+
"query: {:?}",
2058+
q
2059+
);
2060+
}
2061+
2062+
// Delete the first record.
2063+
store
2064+
.client_mut()
2065+
.delete_record(SuggestionProvider::Weather.empty_record("weather-1"));
2066+
store.ingest(SuggestIngestionConstraints {
2067+
providers: Some(vec![SuggestionProvider::Weather]),
2068+
..SuggestIngestionConstraints::all_providers()
2069+
});
2070+
2071+
// Its keywords should be dropped and the keywords from the second
2072+
// record should still be present.
2073+
assert_eq!(store.count_rows("keywords_i18n") as usize, kws_2.len());
2074+
2075+
for q in kws_1 {
2076+
assert_eq!(
2077+
store.fetch_suggestions(SuggestionQuery::weather(q)),
2078+
vec![],
2079+
"query: {:?}",
2080+
q
2081+
);
2082+
}
2083+
for q in kws_2 {
2084+
assert_eq!(
2085+
store.fetch_suggestions(SuggestionQuery::weather(q)),
2086+
vec![Suggestion::Weather {
2087+
score: 0.24,
2088+
city: None,
2089+
}],
2090+
"query: {:?}",
2091+
q
2092+
);
2093+
}
2094+
2095+
Ok(())
2096+
}
2097+
2098+
// Keywords in `keywords_i18n` should be dropped when their records are
2099+
// updated and the keywords are no longer present, and new keywords should
2100+
// be added.
2101+
#[test]
2102+
fn keywords_i18n_update_record() -> anyhow::Result<()> {
2103+
// Add some records whose keywords are stored in `keywords_i18n`. We'll
2104+
// use weather records.
2105+
let kws_1 = ["aaa", "bbb", "ccc"];
2106+
let kws_2 = ["yyy", "zzz"];
2107+
let mut store = TestStore::new(
2108+
MockRemoteSettingsClient::default()
2109+
.with_record(SuggestionProvider::Weather.record(
2110+
"weather-1",
2111+
json!({
2112+
"score": 0.24,
2113+
"keywords": kws_1,
2114+
}),
2115+
))
2116+
.with_record(SuggestionProvider::Weather.record(
2117+
"weather-2",
2118+
json!({
2119+
"score": 0.24,
2120+
"keywords": kws_2,
2121+
}),
2122+
)),
2123+
);
2124+
store.ingest(SuggestIngestionConstraints {
2125+
providers: Some(vec![SuggestionProvider::Weather]),
2126+
..SuggestIngestionConstraints::all_providers()
2127+
});
2128+
2129+
// Make sure all keywords are present.
2130+
assert_eq!(
2131+
store.count_rows("keywords_i18n") as usize,
2132+
kws_1.len() + kws_2.len()
2133+
);
2134+
2135+
for q in kws_1.iter().chain(kws_2.iter()) {
2136+
assert_eq!(
2137+
store.fetch_suggestions(SuggestionQuery::weather(q)),
2138+
vec![Suggestion::Weather {
2139+
score: 0.24,
2140+
city: None,
2141+
}],
2142+
"query: {:?}",
2143+
q
2144+
);
2145+
}
2146+
2147+
// Update the first record.
2148+
let kws_1_new = [
2149+
"bbb", // keyword from the old record
2150+
"mmm", // new keyword
2151+
];
2152+
store
2153+
.client_mut()
2154+
.update_record(SuggestionProvider::Weather.record(
2155+
"weather-1",
2156+
json!({
2157+
"score": 0.24,
2158+
"keywords": kws_1_new,
2159+
}),
2160+
));
2161+
store.ingest(SuggestIngestionConstraints {
2162+
providers: Some(vec![SuggestionProvider::Weather]),
2163+
..SuggestIngestionConstraints::all_providers()
2164+
});
2165+
2166+
// Check all keywords.
2167+
assert_eq!(
2168+
store.count_rows("keywords_i18n") as usize,
2169+
kws_1_new.len() + kws_2.len()
2170+
);
2171+
2172+
for q in ["aaa", "ccc"] {
2173+
assert_eq!(
2174+
store.fetch_suggestions(SuggestionQuery::weather(q)),
2175+
vec![],
2176+
"query: {:?}",
2177+
q
2178+
);
2179+
}
2180+
for q in kws_1_new.iter().chain(kws_2.iter()) {
2181+
assert_eq!(
2182+
store.fetch_suggestions(SuggestionQuery::weather(q)),
2183+
vec![Suggestion::Weather {
2184+
score: 0.24,
2185+
city: None,
2186+
}],
2187+
"query: {:?}",
2188+
q
2189+
);
2190+
}
2191+
2192+
Ok(())
2193+
}
20082194
}

components/suggest/src/schema.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,9 @@ impl ConnectionInitializer for SuggestConnectionInitializer<'_> {
815815

816816
/// Clears the database, removing all suggestions, icons, and metadata.
817817
pub fn clear_database(db: &Connection) -> rusqlite::Result<()> {
818+
// If you update this, you probably need to update
819+
// `SuggestDao::drop_suggestions` too!
820+
818821
db.execute_batch(
819822
"
820823
DELETE FROM meta;
@@ -833,6 +836,7 @@ pub fn clear_database(db: &Connection) -> rusqlite::Result<()> {
833836
"geonames",
834837
"geonames_metrics",
835838
"ingested_records",
839+
"keywords_i18n",
836840
"keywords_metrics",
837841
];
838842
for t in conditional_tables {

components/suggest/src/store.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1708,16 +1708,24 @@ pub(crate) mod tests {
17081708
SuggestionProvider::Amp.record("data-2", json!([good_place_eats_amp()])),
17091709
)
17101710
.with_record(SuggestionProvider::Amp.icon(los_pollos_icon()))
1711-
.with_record(SuggestionProvider::Amp.icon(good_place_eats_icon())),
1711+
.with_record(SuggestionProvider::Amp.icon(good_place_eats_icon()))
1712+
.with_record(
1713+
SuggestionProvider::Weather
1714+
.record("weather-1", json!({ "keywords": ["abcde"], })),
1715+
),
17121716
);
17131717
store.ingest(SuggestIngestionConstraints::all_providers());
17141718
assert!(store.count_rows("suggestions") > 0);
17151719
assert!(store.count_rows("keywords") > 0);
1720+
assert!(store.count_rows("keywords_i18n") > 0);
1721+
assert!(store.count_rows("keywords_metrics") > 0);
17161722
assert!(store.count_rows("icons") > 0);
17171723

17181724
store.inner.clear()?;
17191725
assert!(store.count_rows("suggestions") == 0);
17201726
assert!(store.count_rows("keywords") == 0);
1727+
assert!(store.count_rows("keywords_i18n") == 0);
1728+
assert!(store.count_rows("keywords_metrics") == 0);
17211729
assert!(store.count_rows("icons") == 0);
17221730

17231731
Ok(())

0 commit comments

Comments
 (0)