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:
Родитель
55982952d1
Коммит
9841bd97c0
|
@ -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![]
|
||||
),
|
||||
];
|
||||
|
|
Загрузка…
Ссылка в новой задаче