Bug 1928239 - Vendor release-v133-desktop a=dsmith

This commit is contained in:
Drew Willcoxon 2024-10-31 13:20:50 -04:00
parent f8c0802719
commit 29c5224ba3
13 changed files with 607 additions and 485 deletions

View File

@ -60,9 +60,9 @@ git = "https://github.com/mozilla-spidermonkey/jsparagus"
rev = "61f399c53a641ebd3077c1f39f054f6d396a633c"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a"]
[source."git+https://github.com/mozilla/application-services?branch=release-v133-desktop"]
git = "https://github.com/mozilla/application-services"
rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
branch = "release-v133-desktop"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/audioipc?rev=e6f44a2bd1e57d11dfc737632a9e849077632330"]

30
Cargo.lock generated
View File

@ -1767,7 +1767,7 @@ dependencies = [
[[package]]
name = "error-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"error-support-macros",
"lazy_static",
@ -1779,7 +1779,7 @@ dependencies = [
[[package]]
name = "error-support-macros"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"proc-macro2",
"quote",
@ -3143,7 +3143,7 @@ dependencies = [
[[package]]
name = "interrupt-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"lazy_static",
"parking_lot",
@ -4442,7 +4442,7 @@ dependencies = [
[[package]]
name = "nss_build_common"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
[[package]]
name = "nsstring"
@ -4655,7 +4655,7 @@ checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
[[package]]
name = "payload-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"serde",
"serde_derive",
@ -5140,7 +5140,7 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "relevancy"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"anyhow",
"base64 0.21.3",
@ -5163,7 +5163,7 @@ dependencies = [
[[package]]
name = "remote_settings"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"error-support",
"log",
@ -5729,7 +5729,7 @@ dependencies = [
[[package]]
name = "sql-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"interrupt-support",
"lazy_static",
@ -5908,7 +5908,7 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "suggest"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"anyhow",
"chrono",
@ -5960,7 +5960,7 @@ dependencies = [
[[package]]
name = "sync-guid"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"base64 0.21.3",
"rand",
@ -5971,7 +5971,7 @@ dependencies = [
[[package]]
name = "sync15"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"anyhow",
"error-support",
@ -6011,7 +6011,7 @@ dependencies = [
[[package]]
name = "tabs"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"anyhow",
"error-support",
@ -6335,7 +6335,7 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "types"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"rusqlite",
"serde",
@ -6710,7 +6710,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "viaduct"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"ffi-support",
"log",
@ -6858,7 +6858,7 @@ dependencies = [
[[package]]
name = "webext-storage"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=a0121f35125bd61ebd10fab969f6cfcc02f94d5a#a0121f35125bd61ebd10fab969f6cfcc02f94d5a"
source = "git+https://github.com/mozilla/application-services?branch=release-v133-desktop#72b039fee61a1f5b7d7290f1c746e83fb02d72f3"
dependencies = [
"anyhow",
"error-support",

View File

@ -215,13 +215,13 @@ midir = { git = "https://github.com/mozilla/midir.git", rev = "85156e360a37d8517
malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" }
# application-services overrides to make updating them all simpler.
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
relevancy = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
sql-support = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
suggest = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
sync15 = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
tabs = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
viaduct = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
webext-storage = { git = "https://github.com/mozilla/application-services", rev = "a0121f35125bd61ebd10fab969f6cfcc02f94d5a" }
interrupt-support = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
relevancy = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
sql-support = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
suggest = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
sync15 = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
tabs = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
viaduct = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
webext-storage = { git = "https://github.com/mozilla/application-services", branch = "release-v133-desktop"}
allocator-api2 = { path = "third_party/rust/allocator-api2" }

View File

@ -694,6 +694,8 @@ class _QuickSuggestTestUtils {
{
id: 1,
name: "Waterloo",
latitude: "34.91814",
longitude: "-88.0642",
feature_class: "P",
feature_code: "PPL",
country_code: "US",
@ -705,6 +707,8 @@ class _QuickSuggestTestUtils {
{
id: 2,
name: "Alabama",
latitude: "32.75041",
longitude: "-86.75026",
feature_class: "A",
feature_code: "ADM1",
country_code: "US",
@ -716,6 +720,8 @@ class _QuickSuggestTestUtils {
{
id: 3,
name: "Waterloo",
latitude: "42.49276",
longitude: "-92.34296",
feature_class: "P",
feature_code: "PPLA2",
country_code: "US",
@ -727,6 +733,8 @@ class _QuickSuggestTestUtils {
{
id: 4,
name: "Iowa",
latitude: "42.00027",
longitude: "-93.50049",
feature_class: "A",
feature_code: "ADM1",
country_code: "US",
@ -738,23 +746,27 @@ class _QuickSuggestTestUtils {
// larger population.
{
id: 100,
name: "US/CA City",
name: "US CA City",
latitude: "38.06084",
longitude: "-97.92977",
feature_class: "P",
feature_code: "PPL",
country_code: "US",
admin1_code: "IA",
population: 1,
alternate_names: ["us/ca city"],
alternate_names: ["us ca city"],
},
{
id: 101,
name: "US/CA City",
name: "US CA City",
latitude: "45.50884",
longitude: "-73.58781",
feature_class: "P",
feature_code: "PPL",
country_code: "CA",
admin1_code: "08",
population: 2,
alternate_names: ["us/ca city"],
alternate_names: ["us ca city"],
},
];
let [maxLen, maxWordCount] = geonames.reduce(

View File

@ -551,7 +551,7 @@ add_task(async function cityWithoutRegion() {
await doCityTest({
desc: "Query matches a US and CA city; should get geolocation; US returned; so match the US city",
query: "us/ca city",
query: "us ca city",
geolocation: {
region_code: "HI",
country_code: "US",
@ -559,17 +559,17 @@ add_task(async function cityWithoutRegion() {
expected: {
geolocationCalled: true,
weatherParams: {
city: "US/CA City",
city: "US CA City",
region: "IA",
country: "US",
},
suggestionCity: "US/CA City",
suggestionCity: "US CA City",
},
});
await doCityTest({
desc: "Query matches a US and CA city; should get geolocation; CA returned; so match the CA city",
query: "us/ca city",
query: "us ca city",
geolocation: {
region_code: "01",
country_code: "CA",
@ -577,11 +577,11 @@ add_task(async function cityWithoutRegion() {
expected: {
geolocationCalled: true,
weatherParams: {
city: "US/CA City",
city: "US CA City",
region: "08",
country: "CA",
},
suggestionCity: "US/CA City",
suggestionCity: "US CA City",
},
});
});

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"2ac3a843e4d5e3945a8ae61d2267c067a59bdca39bc82ea2e66057eef59791ba","README.md":"5e28baf874b643d756228bdab345e287bf107d3182dfe6a18aafadcc4b9a3fc9","benches/benchmark_all.rs":"3582f21af9758766ff32ed95f90b69984b32091b1e31e0c0bef307c22fd82f18","metrics.yaml":"0540ab2271aeab7f07335c7ceec12acde942995f9dcb3c29070489aa61899d56","src/benchmarks/README.md":"ccee8dbddba8762d0453fa855bd6984137b224b8c019f3dd8e86a3c303f51d71","src/benchmarks/client.rs":"a777c0b876a481a21f9d5fbb696b42672ed0b4af359f62f047ac8240d3e35853","src/benchmarks/ingest.rs":"504d00f09e88e01676ee2de3787b942a538e1ae7b46919e937df3f5b8edd8be9","src/benchmarks/mod.rs":"2d7c20d47d6c7e17bc738255a31119bd0c4a4e495419a00c7b10b251ace9ef6b","src/benchmarks/query.rs":"ce78057e0ed43a419cc92d2bceb0bbef8aad9b113ef0341cf5f1d8d1578848e0","src/bin/debug_ingestion_sizes.rs":"ce6e810be7b3fc19e826d75b622b82cfab5a1a99397a6d0833c2c4eebff2d364","src/config.rs":"0ca876e845841bb6429862c0904c82265003f53b55aea053fac60aed278586a7","src/db.rs":"7801af3ba446774dd067c374ac034bee2416bc20ed49e8ac7ff6ec98a44768ff","src/error.rs":"e2ef3ec0e0b2b8ecbb8f2f1717d4cb753af06913b8395d086b7643098ad100a7","src/fakespot.rs":"03d3aac07b3a3a9ceb8d2c452d4a122bfebf04579829e62e83487877055312d4","src/geoname.rs":"a3e41a928bf08b17d21694a86b7f07dcac76d13aaad09228b09333d2e6880568","src/lib.rs":"1c82651061b9a17909c0f05390ee643328cc9d3026f2ebff10798183c09a7d6e","src/metrics.rs":"6e390af144e3e0644ab87a79ded0c76421658ab7d10201fb8b93dd7e299e9d27","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"2bca934214366c59c4628cf88313057ce7256c167aabe77119f1703bd65a4cc6","src/query.rs":"84b97997036a3a597b0574e719e7407ddf0f18bd55c07a704bd2cacd549e8509","src/rs.rs":"0221ace1a58422c4dca1f0a81d8dc0c65e83961366d050f2430fabb43b3ff5e0","src/schema.rs":"774207f4bf5835139ee940a40485fdd498e954e28db7655addb389a7f4f92768","src/store.rs":"6e5d50058367dd5b8cd60b76362aef90de030c46983f698bff86221e8da612b4","src/suggestion.rs":"50be7e08fa452a434f3d5e28f3d3fb5844ffea6c1614d2cca604b216cb286bf8","src/testing/client.rs":"f8c9bd32d0f4cf364daebe114d580c7e36a83b69c07884d14170969620d9a437","src/testing/data.rs":"d4fc5227996a8b115d93243fdbd83bc57d73a8c2d4c0b20dffa15bbec27925cb","src/testing/mod.rs":"4d2781c77ed9ace9d80d6d00c63a06bf28a4156f223616fffe3c07e64a8041db","src/util.rs":"da091eba661633ea959db59bf4cb5b89f80e6f0295fdbd7893be253b48635c26","src/weather.rs":"aa2375c9a4ae3a2aa77a17573c1cd50c93a22eea6a39a0caa4371a2e95c635e1","src/yelp.rs":"bc036ff71b438d53ce8811acd8d650d83ef03faeea476f5b659b403c1e64ff2b","uniffi.toml":"19ea9cfd30d2e57ffad125b7eeef7f9228d43347fceb8bb9a54a0e66177eb2e5"},"package":null}
{"files":{"Cargo.toml":"2ac3a843e4d5e3945a8ae61d2267c067a59bdca39bc82ea2e66057eef59791ba","README.md":"5e28baf874b643d756228bdab345e287bf107d3182dfe6a18aafadcc4b9a3fc9","benches/benchmark_all.rs":"3582f21af9758766ff32ed95f90b69984b32091b1e31e0c0bef307c22fd82f18","metrics.yaml":"0540ab2271aeab7f07335c7ceec12acde942995f9dcb3c29070489aa61899d56","src/benchmarks/README.md":"ccee8dbddba8762d0453fa855bd6984137b224b8c019f3dd8e86a3c303f51d71","src/benchmarks/client.rs":"a777c0b876a481a21f9d5fbb696b42672ed0b4af359f62f047ac8240d3e35853","src/benchmarks/ingest.rs":"504d00f09e88e01676ee2de3787b942a538e1ae7b46919e937df3f5b8edd8be9","src/benchmarks/mod.rs":"2d7c20d47d6c7e17bc738255a31119bd0c4a4e495419a00c7b10b251ace9ef6b","src/benchmarks/query.rs":"ce78057e0ed43a419cc92d2bceb0bbef8aad9b113ef0341cf5f1d8d1578848e0","src/bin/debug_ingestion_sizes.rs":"ce6e810be7b3fc19e826d75b622b82cfab5a1a99397a6d0833c2c4eebff2d364","src/config.rs":"0ca876e845841bb6429862c0904c82265003f53b55aea053fac60aed278586a7","src/db.rs":"7801af3ba446774dd067c374ac034bee2416bc20ed49e8ac7ff6ec98a44768ff","src/error.rs":"e2ef3ec0e0b2b8ecbb8f2f1717d4cb753af06913b8395d086b7643098ad100a7","src/fakespot.rs":"03d3aac07b3a3a9ceb8d2c452d4a122bfebf04579829e62e83487877055312d4","src/geoname.rs":"a75b4ec012a5881fd63656714d964dae1a7768beff0faf3ccb66cf6bc8a047f0","src/lib.rs":"1c82651061b9a17909c0f05390ee643328cc9d3026f2ebff10798183c09a7d6e","src/metrics.rs":"6e390af144e3e0644ab87a79ded0c76421658ab7d10201fb8b93dd7e299e9d27","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"2bca934214366c59c4628cf88313057ce7256c167aabe77119f1703bd65a4cc6","src/query.rs":"84b97997036a3a597b0574e719e7407ddf0f18bd55c07a704bd2cacd549e8509","src/rs.rs":"953f978b30ca6ebaf18dab5ba8fa02dd076851e83d5f936ea8ab6016e7e17db9","src/schema.rs":"050504a7d108b5808d74dfdfbb861a1bb6a700d6b02b07db13af403c95c9353c","src/store.rs":"6e5d50058367dd5b8cd60b76362aef90de030c46983f698bff86221e8da612b4","src/suggestion.rs":"cf4b457d7499dc8dabedbc14536fe915969378a25cc45ca9f25139843558b68d","src/testing/client.rs":"f8c9bd32d0f4cf364daebe114d580c7e36a83b69c07884d14170969620d9a437","src/testing/data.rs":"d4fc5227996a8b115d93243fdbd83bc57d73a8c2d4c0b20dffa15bbec27925cb","src/testing/mod.rs":"4d2781c77ed9ace9d80d6d00c63a06bf28a4156f223616fffe3c07e64a8041db","src/util.rs":"2de919f66ea12dea8558d5793e6a165a515b1cead3da466398693fd9753622e1","src/weather.rs":"2c463f064e76b38d7765251ccbc2fb96ca12cd08424f97ff11d5eb233983a996","src/yelp.rs":"bc036ff71b438d53ce8811acd8d650d83ef03faeea476f5b659b403c1e64ff2b","uniffi.toml":"19ea9cfd30d2e57ffad125b7eeef7f9228d43347fceb8bb9a54a0e66177eb2e5"},"package":null}

View File

@ -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::DownloadTimer,
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,

View File

@ -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::*;

View File

@ -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)),
}
}

View File

@ -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 {

View File

@ -41,11 +41,11 @@ pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String {
}
/// Performs a depth-first traversal over all possible chunk sequences in a
/// string, applies a filter-map function to each chunk in each sequence, and
/// collects the filter-mapped sequences in a `Vec`. A "chunk" is a slice of one
/// or more consecutive words in the string such that the slices do not overlap.
/// It's analogous to the concept of slice chunks described in [1] where the
/// elements in this case are words in a string.
/// slice, applies a filter-map function to each chunk in each sequence, and
/// collects the filter-mapped sequences in a `Vec`.
///
/// "Chunks" are non-overlapping subslices of the parent slice as described in
/// [`slice::chunks()`].
///
/// IMPORTANT: This function potentially does an exponential amount of work! You
/// should always be careful to prune the traversal space by returning `None`
@ -56,15 +56,14 @@ pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String {
/// influences the branching factor at each step in the traversal.
///
/// At each traversal step, the filter-map function is passed the chunk at that
/// step and the chunk's word-based index in the `query` string. The function
/// can map the chunk to one or more values. Each value expands the branching
/// factor at the current step by `max_chunk_size`. In other words, the
/// branching factor at a given traversal step is `max_chunk_size` multiplied by
/// the number of values returned by the filter-map function at that step. The
/// traversed path of mapped values at that step is also passed to the
/// filter-map function. Each path is a sequence of chunks in the original
/// `query` string except the chunks have been replaced by mapped values from
/// the filter-map function.
/// step and the chunk's index in the parent `words` slice. The function can map
/// the chunk to one or more values. Each value expands the branching factor at
/// the current step by `max_chunk_size`. In other words, the branching factor
/// at a given traversal step is `max_chunk_size` multiplied by the number of
/// values returned by the filter-map function at that step. The traversed path
/// of mapped values at that step is also passed to the filter-map function.
/// Each path is a sequence of chunks in the parent `words` slice except the
/// chunks have been replaced by mapped values from the filter-map function.
///
/// The filter-map function can return `None` to halt traversal at the current
/// step. Returning `None` sets the branching factor at that step to zero,
@ -75,15 +74,14 @@ pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String {
/// Traversal ends and the function returns when all paths have been visited.
/// The returned `Vec` will contain all traversal paths that weren't pruned.
///
/// [1] https://doc.rust-lang.org/std/vec/struct.Vec.html#method.chunks
///
/// # Examples
///
/// Mapping chunks in "a b c" to uppercase, up to a max chunk size of `3`:
/// Mapping chunks in `["a", "b", "c"]` to uppercase, up to a max chunk size of
/// `3`:
///
/// ```
/// # use suggest::util::filter_map_chunks;
/// let paths = filter_map_chunks("a b c", 3, |chunk, _, _| {
/// let paths = filter_map_chunks(&["a", "b", "c"], 3, |chunk, _, _| {
/// Ok(Some(vec![chunk.to_uppercase()]))
/// });
/// assert_eq!(paths.unwrap(), vec![
@ -99,7 +97,7 @@ pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String {
///
/// ```
/// # use suggest::util::filter_map_chunks;
/// let paths = filter_map_chunks("a b c", 3, |chunk, chunk_index, _| {
/// let paths = filter_map_chunks(&["a", "b", "c"], 3, |chunk, chunk_index, _| {
/// if chunk_index > 0 || chunk == "a" {
/// Ok(Some(vec![chunk.to_uppercase()]))
/// } else {
@ -117,7 +115,7 @@ pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String {
///
/// ```
/// # use suggest::util::filter_map_chunks;
/// let paths = filter_map_chunks("a b c", 3, |chunk, _, path| {
/// let paths = filter_map_chunks(&["a", "b", "c"], 3, |chunk, _, path| {
/// if path.iter().any(|value| value == "A B") {
/// Ok(None)
/// } else {
@ -135,7 +133,7 @@ pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String {
///
/// ```
/// # use suggest::util::filter_map_chunks;
/// let paths = filter_map_chunks("a b c", 3, |chunk, _, _| {
/// let paths = filter_map_chunks(&["a", "b", "c"], 3, |chunk, _, _| {
/// Ok(Some(vec![format!("{chunk}0"), format!("{chunk}1")]))
/// });
/// assert_eq!(paths.unwrap(), vec![
@ -160,20 +158,12 @@ pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String {
/// ]);
/// ```
pub fn filter_map_chunks<T: Clone>(
query: &str,
words: &[&str],
max_chunk_size: usize,
f: impl Fn(&str, usize, &[T]) -> Result<Option<Vec<T>>>,
) -> Result<Vec<Vec<T>>> {
let words: Vec<_> = query.split_whitespace().collect();
let normalized_query = words.join(" ");
filter_map_chunks_recurse(
&words,
&normalized_query,
&mut vec![],
0,
max_chunk_size,
&f,
)
filter_map_chunks_recurse(words, &normalized_query, &mut vec![], 0, max_chunk_size, &f)
}
/// `remaining_words` is the slice of remaining words in the query string at
@ -307,6 +297,15 @@ mod tests {
);
}
fn fmc<T: Clone>(
query: &str,
max_chunk_size: usize,
f: impl Fn(&str, usize, &[T]) -> Result<Option<Vec<T>>>,
) -> Result<Vec<Vec<T>>> {
let words: Vec<_> = query.split_whitespace().collect();
filter_map_chunks(&words, max_chunk_size, f)
}
fn check_paths(actual: Vec<Vec<(String, usize)>>, expected: Vec<Vec<(&str, usize)>>) {
assert_eq!(
actual,
@ -322,7 +321,7 @@ mod tests {
#[test]
fn filter_map_chunks_1() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 1, |chunk, chunk_index, _| {
let paths = fmc("a b c d e", 1, |chunk, chunk_index, _| {
Ok(Some(vec![(chunk.to_string(), chunk_index)]))
})?;
check_paths(
@ -334,7 +333,7 @@ mod tests {
#[test]
fn filter_map_chunks_2() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| {
Ok(Some(vec![(chunk.to_string(), chunk_index)]))
})?;
check_paths(
@ -355,7 +354,7 @@ mod tests {
#[test]
fn filter_map_chunks_3() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| {
Ok(Some(vec![(chunk.to_string(), chunk_index)]))
})?;
check_paths(
@ -381,7 +380,7 @@ mod tests {
#[test]
fn filter_map_chunks_4() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| {
Ok(Some(vec![(chunk.to_string(), chunk_index)]))
})?;
check_paths(
@ -409,7 +408,7 @@ mod tests {
#[test]
fn filter_map_chunks_5() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 5, |chunk, chunk_index, _| {
let paths = fmc("a b c d e", 5, |chunk, chunk_index, _| {
Ok(Some(vec![(chunk.to_string(), chunk_index)]))
})?;
check_paths(
@ -438,7 +437,7 @@ mod tests {
#[test]
fn filter_map_chunks_1_map_many() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c", 1, |chunk, _, _| {
let paths = fmc("a b c", 1, |chunk, _, _| {
Ok(Some((0..3).map(|i| format!("{chunk}{i}")).collect()))
})?;
assert_eq!(
@ -478,7 +477,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_map_many() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c", 2, |chunk, _, _| {
let paths = fmc("a b c", 2, |chunk, _, _| {
Ok(Some((0..3).map(|i| format!("{chunk}{i}")).collect()))
})?;
assert_eq!(
@ -536,7 +535,7 @@ mod tests {
#[test]
fn filter_map_chunks_1_prune_a() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 1, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 1, |chunk, chunk_index, _| match chunk {
"a" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -546,7 +545,7 @@ mod tests {
#[test]
fn filter_map_chunks_1_prune_b() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 1, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 1, |chunk, chunk_index, _| match chunk {
"b" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -556,7 +555,7 @@ mod tests {
#[test]
fn filter_map_chunks_1_prune_c() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 1, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 1, |chunk, chunk_index, _| match chunk {
"c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -566,7 +565,7 @@ mod tests {
#[test]
fn filter_map_chunks_1_prune_d() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 1, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 1, |chunk, chunk_index, _| match chunk {
"d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -576,7 +575,7 @@ mod tests {
#[test]
fn filter_map_chunks_1_prune_e() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 1, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 1, |chunk, chunk_index, _| match chunk {
"e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -586,7 +585,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_a() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"a" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -603,7 +602,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_b() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"b" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -622,7 +621,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_c() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -640,7 +639,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_d() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -659,7 +658,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_e() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -676,7 +675,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_ab() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"a b" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -695,7 +694,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_bc() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"b c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -715,7 +714,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_cd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -735,7 +734,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_de() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -754,7 +753,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_a_bc() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"a" | "b c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -771,7 +770,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_a_cd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"a" | "c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -787,7 +786,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_bc_cd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"b c" | "c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -805,7 +804,7 @@ mod tests {
#[test]
fn filter_map_chunks_2_prune_bc_de() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 2, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 2, |chunk, chunk_index, _| match chunk {
"b c" | "d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -823,7 +822,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_a() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"a" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -843,7 +842,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_b() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"b" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -866,7 +865,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_c() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -889,7 +888,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_d() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -912,7 +911,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_e() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -932,7 +931,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_ab() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"a b" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -955,7 +954,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_bc() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"b c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -980,7 +979,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_cd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1005,7 +1004,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_de() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1028,7 +1027,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_abc() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"a b c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1053,7 +1052,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_bcd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"b c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1079,7 +1078,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_cde() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"c d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1104,7 +1103,7 @@ mod tests {
#[test]
fn filter_map_chunks_3_prune_a_bc_cde() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 3, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 3, |chunk, chunk_index, _| match chunk {
"a" | "b c" | "c d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1123,7 +1122,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_a() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"a" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1144,7 +1143,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_b() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"b" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1169,7 +1168,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_c() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1194,7 +1193,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_d() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1219,7 +1218,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_e() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1240,7 +1239,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_ab() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"a b" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1265,7 +1264,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_bc() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"b c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1292,7 +1291,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_cd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1319,7 +1318,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_de() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1344,7 +1343,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_abc() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"a b c" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1371,7 +1370,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_bcd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"b c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1399,7 +1398,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_cde() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"c d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1426,7 +1425,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_abcd() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"a b c d" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1454,7 +1453,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_bcde() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"b c d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1482,7 +1481,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_a_bc_de() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"a" | "b c" | "d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1501,7 +1500,7 @@ mod tests {
#[test]
fn filter_map_chunks_4_prune_a_bc_cde() -> anyhow::Result<()> {
let paths = filter_map_chunks("a b c d e", 4, |chunk, chunk_index, _| match chunk {
let paths = fmc("a b c d e", 4, |chunk, chunk_index, _| match chunk {
"a" | "b c" | "c d e" => Ok(None),
_ => Ok(Some(vec![(chunk.to_string(), chunk_index)])),
})?;
@ -1521,7 +1520,7 @@ mod tests {
#[test]
fn filter_map_chunks_spaces() -> anyhow::Result<()> {
let paths = filter_map_chunks(" a b c d e ", 2, |chunk, chunk_index, _| {
let paths = fmc(" a b c d e ", 2, |chunk, chunk_index, _| {
Ok(Some(vec![(chunk.to_string(), chunk_index)]))
})?;
check_paths(

View File

@ -76,10 +76,10 @@ impl SuggestDao<'_> {
// into words. We want to avoid that work for strings that are so long
// they can't possibly match. The longest possible weather query is two
// geonames + one weather keyword + at least two spaces between those
// three components, say, 10 spaces total for some wiggle room. There's
// not much point in an analogous min length check since weather
// suggestions can be matched on city alone and many city names are only
// a few characters long ("nyc").
// three components, say, 10 extra characters total for spaces and
// punctuation. There's no point in an analogous min length check since
// weather suggestions can be matched on city alone and many city names
// are only a few characters long ("nyc").
let g_cache = self.geoname_cache();
let w_cache = self.weather_cache();
let max_query_len = 2 * g_cache.max_name_length + w_cache.max_keyword_length + 10;
@ -89,10 +89,19 @@ impl SuggestDao<'_> {
let max_chunk_size =
std::cmp::max(g_cache.max_name_word_count, w_cache.max_keyword_word_count);
let kw = query.keyword.to_lowercase();
// Lowercase, strip punctuation, and split the query into words.
let kw_lower = query.keyword.to_lowercase();
let words: Vec<_> = kw_lower
.split_whitespace()
.flat_map(|w| {
w.split(|c| !char::is_alphabetic(c))
.filter(|s| !s.is_empty())
})
.collect();
let mut matches =
filter_map_chunks::<Token>(&kw, max_chunk_size, |chunk, chunk_i, path| {
filter_map_chunks::<Token>(&words, max_chunk_size, |chunk, chunk_i, path| {
// Match the chunk to token types that haven't already been matched
// in this path. `all_tokens` will remain `None` until a token is
// matched.
@ -175,6 +184,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 +433,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 +538,8 @@ mod tests {
city: None,
region: None,
country: None,
latitude: None,
longitude: None,
},]
);
}
@ -557,6 +583,8 @@ mod tests {
city: None,
region: None,
country: None,
latitude: None,
longitude: None,
},]
);
}
@ -568,7 +596,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 +620,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,260 +725,318 @@ 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(),
],
),
("weather w w", vec![]),
("weather w water", vec![]),
("weather w waterloo", vec![]),
("weather water w", vec![]),
("weather waterloo water", vec![]),
("weather water water", vec![]),
("weather water waterloo", vec![]),
("waterloo foo", vec![]),
("waterloo weather foo", vec![]),
("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,
},
],
"rochester,",
vec![geoname::tests::rochester().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,
},
],
"rochester ,",
vec![geoname::tests::rochester().into()],
),
(
&format!("{} and some other words that don't match anything but that is neither here nor there", crate::geoname::tests::LONG_NAME),
"rochester , ",
vec![geoname::tests::rochester().into()],
),
(
"rochester,ny",
vec![geoname::tests::rochester().into()],
),
(
"rochester, ny",
vec![geoname::tests::rochester().into()],
),
(
"rochester ,ny",
vec![geoname::tests::rochester().into()],
),
(
"rochester , ny",
vec![geoname::tests::rochester().into()],
),
(
"weather rochester,",
vec![geoname::tests::rochester().into()],
),
(
"weather rochester, ",
vec![geoname::tests::rochester().into()],
),
(
"weather rochester , ",
vec![geoname::tests::rochester().into()],
),
(
"weather rochester,ny",
vec![geoname::tests::rochester().into()],
),
(
"weather rochester, ny",
vec![geoname::tests::rochester().into()],
),
(
"weather rochester ,ny",
vec![geoname::tests::rochester().into()],
),
(
"weather rochester , ny",
vec![geoname::tests::rochester().into()],
),
(
"rochester,weather",
vec![geoname::tests::rochester().into()],
),
(
"rochester, weather",
vec![geoname::tests::rochester().into()],
),
(
"rochester ,weather",
vec![geoname::tests::rochester().into()],
),
(
"rochester , weather",
vec![geoname::tests::rochester().into()],
),
(
"rochester,ny weather",
vec![geoname::tests::rochester().into()],
),
(
"rochester, ny weather",
vec![geoname::tests::rochester().into()],
),
(
"rochester ,ny weather",
vec![geoname::tests::rochester().into()],
),
(
"rochester , ny weather",
vec![geoname::tests::rochester().into()],
),
(
"new york,",
vec![geoname::tests::nyc().into()],
),
(
"new york ,",
vec![geoname::tests::nyc().into()],
),
(
"new york , ",
vec![geoname::tests::nyc().into()],
),
(
"new york,ny",
vec![geoname::tests::nyc().into()],
),
(
"new york, ny",
vec![geoname::tests::nyc().into()],
),
(
"new york ,ny",
vec![geoname::tests::nyc().into()],
),
(
"new york , ny",
vec![geoname::tests::nyc().into()],
),
(
"weather new york,ny",
vec![geoname::tests::nyc().into()],
),
(
"weather new york, ny",
vec![geoname::tests::nyc().into()],
),
(
"weather new york ,ny",
vec![geoname::tests::nyc().into()],
),
(
"weather new york , ny",
vec![geoname::tests::nyc().into()],
),
(
"new york,weather",
vec![geoname::tests::nyc().into()],
),
(
"new york, weather",
vec![geoname::tests::nyc().into()],
),
(
"new york ,weather",
vec![geoname::tests::nyc().into()],
),
(
"new york , weather",
vec![geoname::tests::nyc().into()],
),
(
"new york,ny weather",
vec![geoname::tests::nyc().into()],
),
(
"new york, ny weather",
vec![geoname::tests::nyc().into()],
),
(
"new york ,ny weather",
vec![geoname::tests::nyc().into()],
),
(
"new york , ny weather",
vec![geoname::tests::nyc().into()],
),
(
&format!("{} weather", geoname::tests::LONG_NAME),
vec![geoname::tests::long_name_city().into()],
),
(
&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", 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![]
),
];

View File

@ -1810,12 +1810,16 @@ Suggestion.Weather = class extends Suggestion{
city,
region,
country,
latitude,
longitude,
score
) {
super();
this.city = city;
this.region = region;
this.country = country;
this.latitude = latitude;
this.longitude = longitude;
this.score = score;
}
}
@ -1923,6 +1927,8 @@ export class FfiConverterTypeSuggestion extends FfiConverterArrayBuffer {
FfiConverterOptionalstring.read(dataStream),
FfiConverterOptionalstring.read(dataStream),
FfiConverterOptionalstring.read(dataStream),
FfiConverterOptionalf64.read(dataStream),
FfiConverterOptionalf64.read(dataStream),
FfiConverterF64.read(dataStream)
);
case 8:
@ -2019,6 +2025,8 @@ export class FfiConverterTypeSuggestion extends FfiConverterArrayBuffer {
FfiConverterOptionalstring.write(dataStream, value.city);
FfiConverterOptionalstring.write(dataStream, value.region);
FfiConverterOptionalstring.write(dataStream, value.country);
FfiConverterOptionalf64.write(dataStream, value.latitude);
FfiConverterOptionalf64.write(dataStream, value.longitude);
FfiConverterF64.write(dataStream, value.score);
return;
}
@ -2111,6 +2119,8 @@ export class FfiConverterTypeSuggestion extends FfiConverterArrayBuffer {
totalSize += FfiConverterOptionalstring.computeSize(value.city);
totalSize += FfiConverterOptionalstring.computeSize(value.region);
totalSize += FfiConverterOptionalstring.computeSize(value.country);
totalSize += FfiConverterOptionalf64.computeSize(value.latitude);
totalSize += FfiConverterOptionalf64.computeSize(value.longitude);
totalSize += FfiConverterF64.computeSize(value.score);
return totalSize;
}
@ -2279,6 +2289,43 @@ export class FfiConverterOptionali32 extends FfiConverterArrayBuffer {
}
}
// Export the FFIConverter object to make external types work.
export class FfiConverterOptionalf64 extends FfiConverterArrayBuffer {
static checkType(value) {
if (value !== undefined && value !== null) {
FfiConverterF64.checkType(value)
}
}
static read(dataStream) {
const code = dataStream.readUint8(0);
switch (code) {
case 0:
return null
case 1:
return FfiConverterF64.read(dataStream)
default:
throw UniFFIError(`Unexpected code: ${code}`);
}
}
static write(dataStream, value) {
if (value === null || value === undefined) {
dataStream.writeUint8(0);
return;
}
dataStream.writeUint8(1);
FfiConverterF64.write(dataStream, value)
}
static computeSize(value) {
if (value === null || value === undefined) {
return 1;
}
return 1 + FfiConverterF64.computeSize(value)
}
}
// Export the FFIConverter object to make external types work.
export class FfiConverterOptionalstring extends FfiConverterArrayBuffer {
static checkType(value) {