Bug 1927526 - Add geographic coordinates to weather suggestions

I had to remove some of the derived implementations on `Geoname` (`Eq`, `Hash`,
`PartialEq`) due to the addition of these `f64`s. That had a couple of
consequences: I also had to remove `Geoname::geoname_type` since nothing uses it
anymore, and that meant I also had to remove `GeonameType::Other`. Equality
comparison and hashing are now based on `Geoname::geoname_id`, which is probably
how it should have worked all along.
This commit is contained in:
Drew Willcoxon 2024-10-28 15:09:05 -07:00 коммит произвёл Drew
Родитель 55982952d1
Коммит 9841bd97c0
5 изменённых файлов: 241 добавлений и 357 удалений

Просмотреть файл

@ -13,12 +13,13 @@
use rusqlite::{named_params, Connection};
use serde::Deserialize;
use sql_support::ConnExt;
use std::hash::{Hash, Hasher};
use crate::{
db::SuggestDao,
error::RusqliteResultExt,
metrics::MetricsContext,
rs::{Client, Record, SuggestRecordId},
rs::{deserialize_f64_or_default, Client, Record, SuggestRecordId},
store::SuggestStoreInner,
Result,
};
@ -27,7 +28,6 @@ use crate::{
pub enum GeonameType {
City,
Region,
Other,
}
/// This corresponds to a single row in the main "geoname" table described in
@ -35,18 +35,20 @@ pub enum GeonameType {
/// fields we don't need.
///
/// [1] https://download.geonames.org/export/dump/readme.txt
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug)]
pub struct Geoname {
/// The `geonameid` straight from the geoname table.
pub geoname_id: i64,
/// This is not present in the geoname table. Added for convenience.
pub geoname_type: GeonameType,
/// This is pretty much the place's canonical name. Usually there will be a
/// row in the alternates table with the same name, but not always. When
/// there is such a row, it doesn't always have `is_preferred_name` set, and
/// in fact fact there may be another row with a different name with
/// `is_preferred_name` set.
pub name: String,
/// Latitude in decimal degrees.
pub latitude: f64,
/// Longitude in decimal degrees.
pub longitude: f64,
/// ISO-3166 two-letter uppercase country code, e.g., "US".
pub country_code: String,
/// The top-level administrative region for the place within its country,
@ -66,6 +68,20 @@ impl Geoname {
}
}
impl PartialEq for Geoname {
fn eq(&self, other: &Geoname) -> bool {
self.geoname_id == other.geoname_id
}
}
impl Eq for Geoname {}
impl Hash for Geoname {
fn hash<H: Hasher>(&self, state: &mut H) {
self.geoname_id.hash(state)
}
}
/// This data is used to service every query handled by the weather provider and
/// potentially other providers, so we cache it from the DB.
#[derive(Debug, Default)]
@ -113,6 +129,12 @@ pub(crate) struct DownloadedGeoname {
/// This can be helpful for resolving name conflicts. If two geonames have
/// the same name, we might prefer the one with the larger population.
pub population: u64,
/// Latitude in decimal degrees. Expected to be a string in the RS data.
#[serde(deserialize_with = "deserialize_f64_or_default")]
pub latitude: f64,
/// Longitude in decimal degrees. Expected to be a string in the RS data.
#[serde(deserialize_with = "deserialize_f64_or_default")]
pub longitude: f64,
/// List of lowercase names that the place is known by. Despite the word
/// "alternate", this often includes the place's proper name. This list is
/// pulled from the "alternate names" table described in the GeoNames
@ -132,7 +154,10 @@ impl SuggestDao<'_> {
/// returned geonames will have at least one name prefixed by `query`. If
/// `false`, returned geonames will have at least one name equal to `query`.
///
/// `geoname_type` restricts returned geonames to the specified type.
/// `geoname_type` restricts returned geonames to the specified type. `None`
/// restricts geonames to cities and regions. There's no way to return
/// geonames of other types, but we shouldn't ingest other types to begin
/// with.
///
/// `filter` restricts returned geonames to certain cities or regions.
/// Cities can be restricted to certain regions by including the regions in
@ -154,7 +179,6 @@ impl SuggestDao<'_> {
None => format!("({} OR {})", city_pred, region_pred),
Some(GeonameType::City) => city_pred.to_string(),
Some(GeonameType::Region) => region_pred.to_string(),
Some(GeonameType::Other) => format!("((NOT {}) AND (NOT {}))", city_pred, region_pred),
};
Ok(self
.conn
@ -164,6 +188,8 @@ impl SuggestDao<'_> {
SELECT
g.id,
g.name,
g.latitude,
g.longitude,
g.feature_class,
g.country_code,
g.admin1_code,
@ -194,14 +220,11 @@ impl SuggestDao<'_> {
let geoname = Geoname {
geoname_id: row.get("id")?,
name: row.get("name")?,
latitude: row.get("latitude")?,
longitude: row.get("longitude")?,
country_code: row.get("country_code")?,
admin1_code: row.get("admin1_code")?,
population: row.get("population")?,
geoname_type: match row.get::<_, String>("feature_class")?.as_str() {
"P" => GeonameType::City,
"A" => GeonameType::Region,
_ => GeonameType::Other,
},
};
if let Some(geonames) = &filter {
geonames
@ -304,13 +327,15 @@ impl<'conn> GeonameInsertStatement<'conn> {
id,
record_id,
name,
latitude,
longitude,
feature_class,
feature_code,
country_code,
admin1_code,
population
)
VALUES(?, ?, ?, ?, ?, ?, ?, ?)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
",
)?))
}
@ -321,6 +346,8 @@ impl<'conn> GeonameInsertStatement<'conn> {
&g.id,
record_id.as_str(),
&g.name,
&g.latitude,
&g.longitude,
&g.feature_class,
&g.feature_code,
&g.country_code,
@ -404,6 +431,8 @@ pub(crate) mod tests {
{
"id": 1,
"name": "Waterloo",
"latitude": "34.91814",
"longitude": "-88.0642",
"feature_class": "P",
"feature_code": "PPL",
"country_code": "US",
@ -415,6 +444,8 @@ pub(crate) mod tests {
{
"id": 2,
"name": "Alabama",
"latitude": "32.75041",
"longitude": "-86.75026",
"feature_class": "A",
"feature_code": "ADM1",
"country_code": "US",
@ -426,6 +457,8 @@ pub(crate) mod tests {
{
"id": 3,
"name": "Waterloo",
"latitude": "42.49276",
"longitude": "-92.34296",
"feature_class": "P",
"feature_code": "PPLA2",
"country_code": "US",
@ -437,6 +470,8 @@ pub(crate) mod tests {
{
"id": 4,
"name": "Iowa",
"latitude": "42.00027",
"longitude": "-93.50049",
"feature_class": "A",
"feature_code": "ADM1",
"country_code": "US",
@ -448,6 +483,8 @@ pub(crate) mod tests {
{
"id": 5,
"name": "waterloo lake",
"latitude": "31.25044",
"longitude": "-99.25061",
"feature_class": "H",
"feature_code": "LK",
"country_code": "US",
@ -459,6 +496,8 @@ pub(crate) mod tests {
{
"id": 6,
"name": "New York City",
"latitude": "40.71427",
"longitude": "-74.00597",
"feature_class": "P",
"feature_code": "PPL",
"country_code": "US",
@ -470,6 +509,8 @@ pub(crate) mod tests {
{
"id": 7,
"name": "Rochester",
"latitude": "43.15478",
"longitude": "-77.61556",
"feature_class": "P",
"feature_code": "PPLA2",
"country_code": "US",
@ -481,6 +522,8 @@ pub(crate) mod tests {
{
"id": 8,
"name": "New York",
"latitude": "43.00035",
"longitude": "-75.4999",
"feature_class": "A",
"feature_code": "ADM1",
"country_code": "US",
@ -488,10 +531,12 @@ pub(crate) mod tests {
"population": 19274244,
"alternate_names": ["ny", "new york"],
},
// long name
// Made-up city with a long name
{
"id": 999,
"name": "Long Name",
"latitude": "38.06084",
"longitude": "-97.92977",
"feature_class": "P",
"feature_code": "PPLA2",
"country_code": "US",
@ -504,66 +549,96 @@ pub(crate) mod tests {
))
}
fn waterloo_al() -> Geoname {
pub(crate) fn waterloo_al() -> Geoname {
Geoname {
geoname_id: 1,
geoname_type: GeonameType::City,
name: "Waterloo".to_string(),
latitude: 34.91814,
longitude: -88.0642,
country_code: "US".to_string(),
admin1_code: "AL".to_string(),
population: 200,
}
}
fn waterloo_ia() -> Geoname {
pub(crate) fn waterloo_ia() -> Geoname {
Geoname {
geoname_id: 3,
geoname_type: GeonameType::City,
name: "Waterloo".to_string(),
latitude: 42.49276,
longitude: -92.34296,
country_code: "US".to_string(),
admin1_code: "IA".to_string(),
population: 68460,
}
}
fn ny_city() -> Geoname {
pub(crate) fn nyc() -> Geoname {
Geoname {
geoname_id: 6,
geoname_type: GeonameType::City,
name: "New York City".to_string(),
latitude: 40.71427,
longitude: -74.00597,
country_code: "US".to_string(),
admin1_code: "NY".to_string(),
population: 8804190,
}
}
fn al() -> Geoname {
pub(crate) fn rochester() -> Geoname {
Geoname {
geoname_id: 7,
name: "Rochester".to_string(),
latitude: 43.15478,
longitude: -77.61556,
country_code: "US".to_string(),
admin1_code: "NY".to_string(),
population: 209802,
}
}
pub(crate) fn long_name_city() -> Geoname {
Geoname {
geoname_id: 999,
name: "Long Name".to_string(),
latitude: 38.06084,
longitude: -97.92977,
country_code: "US".to_string(),
admin1_code: "NY".to_string(),
population: 2,
}
}
pub(crate) fn al() -> Geoname {
Geoname {
geoname_id: 2,
geoname_type: GeonameType::Region,
name: "Alabama".to_string(),
latitude: 32.75041,
longitude: -86.75026,
country_code: "US".to_string(),
admin1_code: "AL".to_string(),
population: 4530315,
}
}
fn ia() -> Geoname {
pub(crate) fn ia() -> Geoname {
Geoname {
geoname_id: 4,
geoname_type: GeonameType::Region,
name: "Iowa".to_string(),
latitude: 42.00027,
longitude: -93.50049,
country_code: "US".to_string(),
admin1_code: "IA".to_string(),
population: 2955010,
}
}
fn ny_state() -> Geoname {
pub(crate) fn ny_state() -> Geoname {
Geoname {
geoname_id: 8,
geoname_type: GeonameType::Region,
name: "New York".to_string(),
latitude: 43.00035,
longitude: -75.4999,
country_code: "US".to_string(),
admin1_code: "NY".to_string(),
population: 19274244,
@ -633,13 +708,6 @@ pub(crate) mod tests {
filter: None,
expected: vec![],
},
Test {
query: "ia",
prefix: false,
geoname_type: Some(GeonameType::Other),
filter: None,
expected: vec![],
},
Test {
query: "ia",
prefix: false,
@ -718,35 +786,35 @@ pub(crate) mod tests {
geoname_type: None,
filter: None,
// NYC should be first since cities are ordered before regions.
expected: vec![ny_city(), ny_state()],
expected: vec![nyc(), ny_state()],
},
Test {
query: "ny",
prefix: true,
geoname_type: None,
filter: None,
expected: vec![ny_city(), ny_state()],
expected: vec![nyc(), ny_state()],
},
Test {
query: "ny",
prefix: false,
geoname_type: None,
filter: Some(vec![ny_city()]),
expected: vec![ny_city(), ny_state()],
filter: Some(vec![nyc()]),
expected: vec![nyc(), ny_state()],
},
Test {
query: "ny",
prefix: false,
geoname_type: None,
filter: Some(vec![ny_state()]),
expected: vec![ny_city(), ny_state()],
expected: vec![nyc(), ny_state()],
},
Test {
query: "ny",
prefix: false,
geoname_type: Some(GeonameType::City),
filter: None,
expected: vec![ny_city()],
expected: vec![nyc()],
},
Test {
query: "ny",
@ -755,26 +823,19 @@ pub(crate) mod tests {
filter: None,
expected: vec![ny_state()],
},
Test {
query: "ny",
prefix: false,
geoname_type: Some(GeonameType::Other),
filter: None,
expected: vec![],
},
Test {
query: "NeW YoRk",
prefix: false,
geoname_type: None,
filter: None,
expected: vec![ny_city(), ny_state()],
expected: vec![nyc(), ny_state()],
},
Test {
query: "NY",
prefix: false,
geoname_type: None,
filter: None,
expected: vec![ny_city(), ny_state()],
expected: vec![nyc(), ny_state()],
},
Test {
query: "new",
@ -788,7 +849,7 @@ pub(crate) mod tests {
prefix: true,
geoname_type: None,
filter: None,
expected: vec![ny_city(), ny_state()],
expected: vec![nyc(), ny_state()],
},
Test {
query: "new york foo",
@ -839,8 +900,9 @@ pub(crate) mod tests {
filter: None,
expected: vec![Geoname {
geoname_id: 999,
geoname_type: GeonameType::City,
name: "Long Name".to_string(),
latitude: 38.06084,
longitude: -97.92977,
country_code: "US".to_string(),
admin1_code: "NY".to_string(),
population: 2,
@ -853,8 +915,9 @@ pub(crate) mod tests {
filter: None,
expected: vec![Geoname {
geoname_id: 999,
geoname_type: GeonameType::City,
name: "Long Name".to_string(),
latitude: 38.06084,
longitude: -97.92977,
country_code: "US".to_string(),
admin1_code: "NY".to_string(),
population: 2,

Просмотреть файл

@ -648,6 +648,15 @@ pub(crate) struct DownloadedGlobalConfigInner {
pub show_less_frequently_cap: i32,
}
pub(crate) fn deserialize_f64_or_default<'de, D>(
deserializer: D,
) -> std::result::Result<f64, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer).map(|s| s.parse().ok().unwrap_or_default())
}
#[cfg(test)]
mod test {
use super::*;

Просмотреть файл

@ -19,7 +19,7 @@ use sql_support::{
/// [`SuggestConnectionInitializer::upgrade_from`].
/// a. If suggestions should be re-ingested after the migration, call `clear_database()` inside
/// the migration.
pub const VERSION: u32 = 27;
pub const VERSION: u32 = 28;
/// The current Suggest database schema.
pub const SQL: &str = "
@ -193,11 +193,13 @@ CREATE TABLE geonames(
id INTEGER PRIMARY KEY,
record_id TEXT NOT NULL,
name TEXT NOT NULL,
latitude REAL NOT NULL,
longitude REAL NOT NULL,
feature_class TEXT NOT NULL,
feature_code TEXT NOT NULL,
country_code TEXT NOT NULL,
admin1_code TEXT NOT NULL,
population INTEGER
population INTEGER NOT NULL
);
CREATE INDEX geonames_feature_class ON geonames(feature_class);
CREATE INDEX geonames_feature_code ON geonames(feature_code);
@ -521,6 +523,33 @@ CREATE TABLE geonames_metrics(
)?;
Ok(())
}
27 => {
// Add latitude and longitude to the geonames table. Clear the
// database so geonames are reingested.
clear_database(tx)?;
tx.execute_batch(
"
DROP INDEX geonames_feature_class;
DROP INDEX geonames_feature_code;
DROP TABLE geonames;
CREATE TABLE geonames(
id INTEGER PRIMARY KEY,
record_id TEXT NOT NULL,
name TEXT NOT NULL,
latitude REAL NOT NULL,
longitude REAL NOT NULL,
feature_class TEXT NOT NULL,
feature_code TEXT NOT NULL,
country_code TEXT NOT NULL,
admin1_code TEXT NOT NULL,
population INTEGER NOT NULL
);
CREATE INDEX geonames_feature_class ON geonames(feature_class);
CREATE INDEX geonames_feature_code ON geonames(feature_code);
",
)?;
Ok(())
}
_ => Err(open_database::Error::IncompatibleVersion(version)),
}
}

Просмотреть файл

@ -82,6 +82,8 @@ pub enum Suggestion {
city: Option<String>,
region: Option<String>,
country: Option<String>,
latitude: Option<f64>,
longitude: Option<f64>,
score: f64,
},
Fakespot {

Просмотреть файл

@ -175,6 +175,8 @@ impl SuggestDao<'_> {
city: city.as_ref().map(|c| c.name.clone()),
region: city.as_ref().map(|c| c.admin1_code.clone()),
country: city.as_ref().map(|c| c.country_code.clone()),
latitude: city.as_ref().map(|c| c.latitude),
longitude: city.as_ref().map(|c| c.longitude),
score: w_cache.score,
})
.collect())
@ -422,7 +424,20 @@ impl Token {
#[cfg(test)]
mod tests {
use super::*;
use crate::{store::tests::TestStore, testing::*, SuggestIngestionConstraints};
use crate::{geoname, store::tests::TestStore, testing::*, SuggestIngestionConstraints};
impl From<Geoname> for Suggestion {
fn from(g: Geoname) -> Self {
Suggestion::Weather {
city: Some(g.name),
region: Some(g.admin1_code),
country: Some(g.country_code),
latitude: Some(g.latitude),
longitude: Some(g.longitude),
score: 0.24,
}
}
}
#[test]
fn weather_provider_config() -> anyhow::Result<()> {
@ -514,6 +529,8 @@ mod tests {
city: None,
region: None,
country: None,
latitude: None,
longitude: None,
},]
);
}
@ -557,6 +574,8 @@ mod tests {
city: None,
region: None,
country: None,
latitude: None,
longitude: None,
},]
);
}
@ -568,7 +587,7 @@ mod tests {
fn cities_and_regions() -> anyhow::Result<()> {
before_each();
let mut store = crate::geoname::tests::new_test_store();
let mut store = geoname::tests::new_test_store();
store.client_mut().add_record(
"weather",
"weather-1",
@ -592,229 +611,104 @@ mod tests {
vec![
// Waterloo, IA should be first since its population is
// larger than Waterloo, AL.
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("AL".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
geoname::tests::waterloo_ia().into(),
geoname::tests::waterloo_al().into(),
],
),
(
"waterloo ia",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_ia().into()],
),
(
"ia waterloo",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_ia().into()],
),
(
"waterloo al",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("AL".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_al().into()],
),
(
"al waterloo",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("AL".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_al().into()],
),
("waterloo ia al", vec![]),
("waterloo ny", vec![]),
(
"new york",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new york new york",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"ny ny",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
("ny ny ny", vec![]),
(
"ny new york",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new york ny",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"weather ny",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"ny weather",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"weather ny ny",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"ny weather ny",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"ny ny weather",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"rochester ny",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"ny rochester",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"weather rochester ny",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"rochester weather ny",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"rochester ny weather",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"weather ny rochester",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"ny weather rochester",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"ny rochester weather",
vec![Suggestion::Weather {
city: Some("Rochester".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::rochester().into()],
),
(
"weather new york",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new weather york",
@ -822,72 +716,32 @@ mod tests {
),
(
"new york weather",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"weather new york new york",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new york weather new york",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new york new york weather",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"weather water",
vec![
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("AL".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
geoname::tests::waterloo_ia().into(),
geoname::tests::waterloo_al().into(),
],
),
(
"waterloo w",
vec![
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("AL".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
geoname::tests::waterloo_ia().into(),
geoname::tests::waterloo_al().into(),
],
),
("waterloo foo", vec![]),
@ -895,187 +749,114 @@ mod tests {
("foo waterloo", vec![]),
("foo waterloo weather", vec![]),
(
crate::geoname::tests::LONG_NAME,
vec![
Suggestion::Weather {
city: Some("Long Name".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
],
geoname::tests::LONG_NAME,
vec![geoname::tests::long_name_city().into()],
),
(
" WaTeRlOo ",
vec![
// Waterloo, IA should be first since its population is
// larger than Waterloo, AL.
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("AL".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
geoname::tests::waterloo_ia().into(),
geoname::tests::waterloo_al().into(),
],
),
(
" waterloo ia",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_ia().into()],
),
(
"waterloo ia",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_ia().into()],
),
(
"waterloo ia ",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_ia().into()],
),
(
" waterloo ia ",
vec![Suggestion::Weather {
city: Some("Waterloo".to_string()),
region: Some("IA".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::waterloo_ia().into()],
),
(
" new york weather",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new york weather",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new york weather",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
"new york weather ",
vec![Suggestion::Weather {
city: Some("New York City".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
}],
vec![geoname::tests::nyc().into()],
),
(
&format!("{} weather", crate::geoname::tests::LONG_NAME),
vec![
Suggestion::Weather {
city: Some("Long Name".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
],
&format!("{} weather", geoname::tests::LONG_NAME),
vec![geoname::tests::long_name_city().into()],
),
(
&format!("weather {}", crate::geoname::tests::LONG_NAME),
vec![
Suggestion::Weather {
city: Some("Long Name".to_string()),
region: Some("NY".to_string()),
country: Some("US".to_string()),
score: 0.24,
},
],
&format!("weather {}", geoname::tests::LONG_NAME),
vec![geoname::tests::long_name_city().into()],
),
(
&format!("{} and some other words that don't match anything but that is neither here nor there", crate::geoname::tests::LONG_NAME),
&format!("{} and some other words that don't match anything but that is neither here nor there", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("and some other words that don't match anything {} but that is neither here nor there", crate::geoname::tests::LONG_NAME),
&format!("and some other words that don't match anything {} but that is neither here nor there", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("and some other words that don't match anything but that is neither here nor there {}", crate::geoname::tests::LONG_NAME),
&format!("and some other words that don't match anything but that is neither here nor there {}", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("weather {} and some other words that don't match anything but that is neither here nor there", crate::geoname::tests::LONG_NAME),
&format!("weather {} and some other words that don't match anything but that is neither here nor there", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("{} weather and some other words that don't match anything but that is neither here nor there", crate::geoname::tests::LONG_NAME),
&format!("{} weather and some other words that don't match anything but that is neither here nor there", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("{} and some other words that don't match anything weather but that is neither here nor there", crate::geoname::tests::LONG_NAME),
&format!("{} and some other words that don't match anything weather but that is neither here nor there", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("{} and some other words that don't match anything but that is neither here nor there weather", crate::geoname::tests::LONG_NAME),
&format!("{} and some other words that don't match anything but that is neither here nor there weather", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("weather and some other words that don't match anything {} but that is neither here nor there", crate::geoname::tests::LONG_NAME),
&format!("weather and some other words that don't match anything {} but that is neither here nor there", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("weather and some other words that don't match anything but that is neither here nor there {}", crate::geoname::tests::LONG_NAME),
&format!("weather and some other words that don't match anything but that is neither here nor there {}", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("and some other words that don't match anything weather {} but that is neither here nor there", crate::geoname::tests::LONG_NAME),
&format!("and some other words that don't match anything weather {} but that is neither here nor there", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("and some other words that don't match anything but that is neither here nor there weather {}", crate::geoname::tests::LONG_NAME),
&format!("and some other words that don't match anything but that is neither here nor there weather {}", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("{} weather and then this also doesn't match anything down here", crate::geoname::tests::LONG_NAME),
&format!("{} weather and then this also doesn't match anything down here", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("{} and then this also doesn't match anything down here weather", crate::geoname::tests::LONG_NAME),
&format!("{} and then this also doesn't match anything down here weather", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("and then this also doesn't match anything down here {} weather", crate::geoname::tests::LONG_NAME),
&format!("and then this also doesn't match anything down here {} weather", geoname::tests::LONG_NAME),
vec![]
),
(
&format!("and then this also doesn't match anything down here weather {}", crate::geoname::tests::LONG_NAME),
&format!("and then this also doesn't match anything down here weather {}", geoname::tests::LONG_NAME),
vec![]
),
];