@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/lib/address/point/interpolation.ts +45 -39
- package/lib/address/point/schema.ts +17 -40
- package/lib/address/point.ts +316 -0
- package/lib/{address/index.ts → address.ts} +1 -1
- package/lib/ancestry/backfill.ts +20 -86
- package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
- package/lib/build/candidate.ts +122 -174
- package/lib/build/population-corrections.ts +64 -0
- package/lib/build/slim.ts +44 -114
- package/lib/candidate/alias-bags.ts +16 -17
- package/lib/candidate/ancestors/schema.ts +77 -61
- package/lib/candidate/ancestors/sidecar.ts +15 -22
- package/lib/candidate/country-display-names.ts +6 -20
- package/lib/candidate/extract-fold.ts +10 -55
- package/lib/candidate/fts.ts +5 -23
- package/lib/candidate/importance.ts +65 -68
- package/lib/candidate/lookup.ts +124 -415
- package/lib/candidate/name-roles.ts +15 -33
- package/lib/candidate/own-name.ts +35 -32
- package/lib/candidate/place-attrs.ts +20 -13
- package/lib/candidate/schema.ts +29 -65
- package/lib/candidate/scoring.ts +54 -93
- package/lib/capital-schema.ts +21 -17
- package/lib/capitals.ts +29 -27
- package/lib/coincident-roles.ts +85 -55
- package/lib/convention/schema.ts +15 -16
- package/lib/convention.ts +144 -0
- package/lib/coverage-manifest-schema.ts +40 -45
- package/lib/currency-backfill.ts +34 -79
- package/lib/env.ts +1 -1
- package/lib/exact-match.ts +32 -21
- package/lib/extracts.ts +97 -74
- package/lib/fst/autocomplete.ts +54 -37
- package/lib/fst/builder.ts +37 -41
- package/lib/fst/deserialize-web.ts +16 -17
- package/lib/fst/format.ts +41 -23
- package/lib/fst/freshness.ts +43 -120
- package/lib/fst/matcher.ts +7 -5
- package/lib/fst/serialize.ts +54 -74
- package/lib/fst/types.ts +78 -75
- package/lib/{fst/index.ts → fst.ts} +1 -0
- package/lib/fts/query.ts +5 -36
- package/lib/fts.ts +280 -0
- package/lib/geonames/aliases.ts +73 -144
- package/lib/geonames/postal.ts +162 -71
- package/lib/index.ts +9 -8
- package/lib/interpolation.ts +48 -100
- package/lib/lookup.ts +155 -270
- package/lib/name-score.ts +9 -7
- package/lib/nsul/lookup.ts +37 -54
- package/lib/nsul/schema.ts +16 -43
- package/lib/paths.ts +159 -0
- package/lib/place-importance-schema.ts +62 -169
- package/lib/poi/lookup.ts +104 -121
- package/lib/poi/schema.ts +42 -26
- package/lib/polygon-schema.ts +10 -6
- package/lib/postal/city/alias/lookup.ts +22 -40
- package/lib/postal/city/alias/schema.ts +14 -10
- package/lib/postal/city/candidate-schema.ts +26 -20
- package/lib/postcode-point-lookup.ts +8 -27
- package/lib/primary-preference.ts +46 -126
- package/lib/proximity-rerank.ts +44 -33
- package/lib/ranking-weights.ts +105 -78
- package/lib/region-keys.ts +70 -42
- package/lib/reverse.ts +149 -86
- package/lib/schema.ts +73 -50
- package/lib/search-fetch.ts +90 -68
- package/lib/sqlite/convention-source.ts +15 -23
- package/lib/sqlite/utils.ts +19 -22
- package/lib/street/centroid/schema.ts +37 -42
- package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
- package/lib/street/morphology/fst/builder.ts +60 -42
- package/lib/street/morphology/fst/loader.ts +40 -32
- package/lib/street/name-lookup.ts +45 -41
- package/lib/street/normalize.ts +88 -219
- package/lib/street/segment-schema.ts +116 -43
- package/lib/{street/index.ts → street.ts} +1 -1
- package/lib/types.ts +109 -150
- package/lib/unified-schema.ts +29 -29
- package/lib/uprn/existence.ts +30 -19
- package/lib/uprn/lookup.ts +29 -68
- package/lib/uprn/schema.ts +18 -40
- package/lib/weights-overlay-linker.ts +236 -252
- package/out/address/point/interpolation.d.ts +20 -23
- package/out/address/point/interpolation.d.ts.map +1 -1
- package/out/address/point/interpolation.js +42 -39
- package/out/address/point/interpolation.js.map +1 -1
- package/out/address/point/schema.d.ts +12 -35
- package/out/address/point/schema.d.ts.map +1 -1
- package/out/address/point/schema.js +3 -19
- package/out/address/point/schema.js.map +1 -1
- package/out/address/point.d.ts +57 -0
- package/out/address/point.d.ts.map +1 -0
- package/out/address/point.js +206 -0
- package/out/address/point.js.map +1 -0
- package/out/{address/index.js → address.d.ts} +2 -2
- package/out/address.d.ts.map +1 -0
- package/out/{address/index.d.ts → address.js} +2 -2
- package/out/address.js.map +1 -0
- package/out/ancestry/backfill.d.ts +11 -64
- package/out/ancestry/backfill.d.ts.map +1 -1
- package/out/ancestry/backfill.js +14 -74
- package/out/ancestry/backfill.js.map +1 -1
- package/out/ancestry.d.ts +49 -0
- package/out/ancestry.d.ts.map +1 -0
- package/out/ancestry.js +59 -0
- package/out/ancestry.js.map +1 -0
- package/out/build/candidate.d.ts +82 -112
- package/out/build/candidate.d.ts.map +1 -1
- package/out/build/candidate.js +17 -100
- package/out/build/candidate.js.map +1 -1
- package/out/build/population-corrections.d.ts +52 -0
- package/out/build/population-corrections.d.ts.map +1 -0
- package/out/build/population-corrections.js +40 -0
- package/out/build/population-corrections.js.map +1 -0
- package/out/build/slim.d.ts +8 -44
- package/out/build/slim.d.ts.map +1 -1
- package/out/build/slim.js +33 -94
- package/out/build/slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +6 -6
- package/out/candidate/alias-bags.d.ts.map +1 -1
- package/out/candidate/alias-bags.js +16 -17
- package/out/candidate/alias-bags.js.map +1 -1
- package/out/candidate/ancestors/schema.d.ts +73 -57
- package/out/candidate/ancestors/schema.d.ts.map +1 -1
- package/out/candidate/ancestors/schema.js +56 -48
- package/out/candidate/ancestors/schema.js.map +1 -1
- package/out/candidate/ancestors/sidecar.d.ts +3 -8
- package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
- package/out/candidate/ancestors/sidecar.js +15 -22
- package/out/candidate/ancestors/sidecar.js.map +1 -1
- package/out/candidate/country-display-names.d.ts +5 -15
- package/out/candidate/country-display-names.d.ts.map +1 -1
- package/out/candidate/country-display-names.js +6 -20
- package/out/candidate/country-display-names.js.map +1 -1
- package/out/candidate/extract-fold.d.ts +7 -15
- package/out/candidate/extract-fold.d.ts.map +1 -1
- package/out/candidate/extract-fold.js +5 -47
- package/out/candidate/extract-fold.js.map +1 -1
- package/out/candidate/fts.d.ts +5 -23
- package/out/candidate/fts.d.ts.map +1 -1
- package/out/candidate/fts.js +5 -23
- package/out/candidate/fts.js.map +1 -1
- package/out/candidate/importance.d.ts +60 -65
- package/out/candidate/importance.d.ts.map +1 -1
- package/out/candidate/importance.js +56 -63
- package/out/candidate/importance.js.map +1 -1
- package/out/candidate/lookup.d.ts +18 -55
- package/out/candidate/lookup.d.ts.map +1 -1
- package/out/candidate/lookup.js +82 -385
- package/out/candidate/lookup.js.map +1 -1
- package/out/candidate/name-roles.d.ts +9 -21
- package/out/candidate/name-roles.d.ts.map +1 -1
- package/out/candidate/name-roles.js +15 -33
- package/out/candidate/name-roles.js.map +1 -1
- package/out/candidate/own-name.d.ts +23 -25
- package/out/candidate/own-name.d.ts.map +1 -1
- package/out/candidate/own-name.js +35 -32
- package/out/candidate/own-name.js.map +1 -1
- package/out/candidate/place-attrs.d.ts +20 -13
- package/out/candidate/place-attrs.d.ts.map +1 -1
- package/out/candidate/place-attrs.js +4 -5
- package/out/candidate/place-attrs.js.map +1 -1
- package/out/candidate/schema.d.ts +27 -62
- package/out/candidate/schema.d.ts.map +1 -1
- package/out/candidate/schema.js +10 -22
- package/out/candidate/schema.js.map +1 -1
- package/out/candidate/scoring.d.ts +7 -8
- package/out/candidate/scoring.d.ts.map +1 -1
- package/out/candidate/scoring.js +52 -89
- package/out/candidate/scoring.js.map +1 -1
- package/out/capital-schema.d.ts +21 -17
- package/out/capital-schema.d.ts.map +1 -1
- package/out/capital-schema.js +17 -15
- package/out/capital-schema.js.map +1 -1
- package/out/capitals.d.ts +27 -25
- package/out/capitals.d.ts.map +1 -1
- package/out/capitals.js +23 -21
- package/out/capitals.js.map +1 -1
- package/out/coincident-roles.d.ts +60 -43
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +72 -50
- package/out/coincident-roles.js.map +1 -1
- package/out/convention/schema.d.ts +14 -14
- package/out/convention/schema.d.ts.map +1 -1
- package/out/convention/schema.js +6 -4
- package/out/convention/schema.js.map +1 -1
- package/out/convention.d.ts +97 -0
- package/out/convention.d.ts.map +1 -0
- package/out/convention.js +81 -0
- package/out/convention.js.map +1 -0
- package/out/coverage-manifest-schema.d.ts +34 -39
- package/out/coverage-manifest-schema.d.ts.map +1 -1
- package/out/coverage-manifest-schema.js +25 -34
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +16 -38
- package/out/currency-backfill.d.ts.map +1 -1
- package/out/currency-backfill.js +19 -46
- package/out/currency-backfill.js.map +1 -1
- package/out/env.d.ts +1 -1
- package/out/env.js +1 -1
- package/out/exact-match.d.ts +19 -10
- package/out/exact-match.d.ts.map +1 -1
- package/out/exact-match.js +32 -21
- package/out/exact-match.js.map +1 -1
- package/out/extracts.d.ts +66 -55
- package/out/extracts.d.ts.map +1 -1
- package/out/extracts.js +63 -55
- package/out/extracts.js.map +1 -1
- package/out/fst/autocomplete.d.ts +29 -21
- package/out/fst/autocomplete.d.ts.map +1 -1
- package/out/fst/autocomplete.js +39 -28
- package/out/fst/autocomplete.js.map +1 -1
- package/out/fst/builder.d.ts.map +1 -1
- package/out/fst/builder.js +37 -41
- package/out/fst/builder.js.map +1 -1
- package/out/fst/deserialize-web.d.ts +4 -4
- package/out/fst/deserialize-web.d.ts.map +1 -1
- package/out/fst/deserialize-web.js +15 -16
- package/out/fst/deserialize-web.js.map +1 -1
- package/out/fst/format.d.ts +41 -23
- package/out/fst/format.d.ts.map +1 -1
- package/out/fst/format.js +41 -23
- package/out/fst/format.js.map +1 -1
- package/out/fst/freshness.d.ts +19 -81
- package/out/fst/freshness.d.ts.map +1 -1
- package/out/fst/freshness.js +31 -94
- package/out/fst/freshness.js.map +1 -1
- package/out/fst/matcher.d.ts +5 -4
- package/out/fst/matcher.d.ts.map +1 -1
- package/out/fst/matcher.js +2 -2
- package/out/fst/matcher.js.map +1 -1
- package/out/fst/serialize.d.ts +28 -28
- package/out/fst/serialize.d.ts.map +1 -1
- package/out/fst/serialize.js +53 -71
- package/out/fst/serialize.js.map +1 -1
- package/out/fst/types.d.ts +78 -74
- package/out/fst/types.d.ts.map +1 -1
- package/out/fst/types.js +1 -4
- package/out/fst/types.js.map +1 -1
- package/out/{fst/index.js → fst.d.ts} +2 -1
- package/out/fst.d.ts.map +1 -0
- package/out/{fst/index.d.ts → fst.js} +2 -1
- package/out/fst.js.map +1 -0
- package/out/fts/query.d.ts +2 -27
- package/out/fts/query.d.ts.map +1 -1
- package/out/fts/query.js +5 -36
- package/out/fts/query.js.map +1 -1
- package/out/fts.d.ts +126 -0
- package/out/fts.d.ts.map +1 -0
- package/out/fts.js +188 -0
- package/out/fts.js.map +1 -0
- package/out/geonames/aliases.d.ts +26 -62
- package/out/geonames/aliases.d.ts.map +1 -1
- package/out/geonames/aliases.js +45 -117
- package/out/geonames/aliases.js.map +1 -1
- package/out/geonames/postal.d.ts +84 -44
- package/out/geonames/postal.d.ts.map +1 -1
- package/out/geonames/postal.js +115 -73
- package/out/geonames/postal.js.map +1 -1
- package/out/{geonames/index.js → geonames.d.ts} +1 -1
- package/out/geonames.d.ts.map +1 -0
- package/out/{geonames/index.d.ts → geonames.js} +1 -1
- package/out/geonames.js.map +1 -0
- package/out/index.d.ts +9 -8
- package/out/index.d.ts.map +1 -1
- package/out/index.js +6 -5
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +18 -55
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +27 -69
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +23 -51
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +136 -234
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +2 -2
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js +9 -7
- package/out/name-score.js.map +1 -1
- package/out/nsul/lookup.d.ts +33 -34
- package/out/nsul/lookup.d.ts.map +1 -1
- package/out/nsul/lookup.js +26 -40
- package/out/nsul/lookup.js.map +1 -1
- package/out/nsul/schema.d.ts +16 -43
- package/out/nsul/schema.d.ts.map +1 -1
- package/out/nsul/schema.js +9 -35
- package/out/nsul/schema.js.map +1 -1
- package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
- package/out/nsul.d.ts.map +1 -0
- package/out/{nsul/index.js → nsul.js} +1 -1
- package/out/nsul.js.map +1 -0
- package/out/paths.d.ts +124 -0
- package/out/paths.d.ts.map +1 -0
- package/out/paths.js +104 -0
- package/out/paths.js.map +1 -0
- package/out/place-importance-schema.d.ts +51 -143
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +28 -143
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi/lookup.d.ts +40 -47
- package/out/poi/lookup.d.ts.map +1 -1
- package/out/poi/lookup.js +69 -96
- package/out/poi/lookup.js.map +1 -1
- package/out/poi/schema.d.ts +41 -25
- package/out/poi/schema.d.ts.map +1 -1
- package/out/poi/schema.js +25 -17
- package/out/poi/schema.js.map +1 -1
- package/out/{poi/index.js → poi.d.ts} +1 -1
- package/out/poi.d.ts.map +1 -0
- package/out/{poi/index.d.ts → poi.js} +1 -1
- package/out/poi.js.map +1 -0
- package/out/polygon-schema.d.ts +10 -6
- package/out/polygon-schema.d.ts.map +1 -1
- package/out/polygon-schema.js +2 -2
- package/out/polygon-schema.js.map +1 -1
- package/out/postal/city/alias/lookup.d.ts +20 -23
- package/out/postal/city/alias/lookup.d.ts.map +1 -1
- package/out/postal/city/alias/lookup.js +17 -30
- package/out/postal/city/alias/lookup.js.map +1 -1
- package/out/postal/city/alias/schema.d.ts +14 -10
- package/out/postal/city/alias/schema.d.ts.map +1 -1
- package/out/postal/city/alias/schema.js +10 -8
- package/out/postal/city/alias/schema.js.map +1 -1
- package/out/postal/city/candidate-schema.d.ts +25 -19
- package/out/postal/city/candidate-schema.d.ts.map +1 -1
- package/out/postal/city/candidate-schema.js +21 -17
- package/out/postal/city/candidate-schema.js.map +1 -1
- package/out/{postal/index.d.ts → postal.d.ts} +1 -1
- package/out/postal.d.ts.map +1 -0
- package/out/{postal/index.js → postal.js} +1 -1
- package/out/postal.js.map +1 -0
- package/out/postcode-point-lookup.d.ts +6 -24
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +5 -17
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/primary-preference.d.ts +38 -92
- package/out/primary-preference.d.ts.map +1 -1
- package/out/primary-preference.js +15 -99
- package/out/primary-preference.js.map +1 -1
- package/out/proximity-rerank.d.ts +41 -30
- package/out/proximity-rerank.d.ts.map +1 -1
- package/out/proximity-rerank.js +38 -29
- package/out/proximity-rerank.js.map +1 -1
- package/out/ranking-weights.d.ts +98 -64
- package/out/ranking-weights.d.ts.map +1 -1
- package/out/ranking-weights.js +26 -25
- package/out/ranking-weights.js.map +1 -1
- package/out/region-keys.d.ts +50 -31
- package/out/region-keys.d.ts.map +1 -1
- package/out/region-keys.js +68 -40
- package/out/region-keys.js.map +1 -1
- package/out/reverse.d.ts +78 -50
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +98 -61
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +72 -49
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js +4 -5
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +16 -12
- package/out/search-fetch.d.ts.map +1 -1
- package/out/search-fetch.js +83 -63
- package/out/search-fetch.js.map +1 -1
- package/out/sqlite/convention-source.d.ts +12 -16
- package/out/sqlite/convention-source.d.ts.map +1 -1
- package/out/sqlite/convention-source.js +13 -22
- package/out/sqlite/convention-source.js.map +1 -1
- package/out/sqlite/utils.d.ts +19 -19
- package/out/sqlite/utils.d.ts.map +1 -1
- package/out/sqlite/utils.js +14 -15
- package/out/sqlite/utils.js.map +1 -1
- package/out/street/centroid/schema.d.ts +37 -42
- package/out/street/centroid/schema.d.ts.map +1 -1
- package/out/street/centroid/schema.js +9 -21
- package/out/street/centroid/schema.js.map +1 -1
- package/out/street/centroid.d.ts +30 -0
- package/out/street/centroid.d.ts.map +1 -0
- package/out/street/{centroid/index.js → centroid.js} +13 -24
- package/out/street/centroid.js.map +1 -0
- package/out/street/morphology/fst/builder.d.ts +20 -10
- package/out/street/morphology/fst/builder.d.ts.map +1 -1
- package/out/street/morphology/fst/builder.js +44 -34
- package/out/street/morphology/fst/builder.js.map +1 -1
- package/out/street/morphology/fst/loader.d.ts +33 -26
- package/out/street/morphology/fst/loader.d.ts.map +1 -1
- package/out/street/morphology/fst/loader.js +23 -22
- package/out/street/morphology/fst/loader.js.map +1 -1
- package/out/street/name-lookup.d.ts +24 -18
- package/out/street/name-lookup.d.ts.map +1 -1
- package/out/street/name-lookup.js +34 -35
- package/out/street/name-lookup.js.map +1 -1
- package/out/street/normalize.d.ts +35 -136
- package/out/street/normalize.d.ts.map +1 -1
- package/out/street/normalize.js +77 -194
- package/out/street/normalize.js.map +1 -1
- package/out/street/segment-schema.d.ts +79 -39
- package/out/street/segment-schema.d.ts.map +1 -1
- package/out/street/segment-schema.js +71 -21
- package/out/street/segment-schema.js.map +1 -1
- package/out/{street/index.js → street.d.ts} +2 -2
- package/out/street.d.ts.map +1 -0
- package/out/{street/index.d.ts → street.js} +2 -2
- package/out/street.js.map +1 -0
- package/out/types.d.ts +84 -149
- package/out/types.d.ts.map +1 -1
- package/out/types.js +0 -6
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +8 -12
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +29 -29
- package/out/unified-schema.js.map +1 -1
- package/out/uprn/existence.d.ts +28 -17
- package/out/uprn/existence.d.ts.map +1 -1
- package/out/uprn/existence.js +26 -16
- package/out/uprn/existence.js.map +1 -1
- package/out/uprn/lookup.d.ts +14 -44
- package/out/uprn/lookup.d.ts.map +1 -1
- package/out/uprn/lookup.js +21 -57
- package/out/uprn/lookup.js.map +1 -1
- package/out/uprn/schema.d.ts +18 -40
- package/out/uprn/schema.d.ts.map +1 -1
- package/out/uprn/schema.js +10 -32
- package/out/uprn/schema.js.map +1 -1
- package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
- package/out/uprn.d.ts.map +1 -0
- package/out/{uprn/index.js → uprn.js} +1 -1
- package/out/uprn.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +138 -144
- package/out/weights-overlay-linker.d.ts.map +1 -1
- package/out/weights-overlay-linker.js +105 -159
- package/out/weights-overlay-linker.js.map +1 -1
- package/package.json +91 -596
- package/lib/address/point/index.ts +0 -328
- package/lib/convention/index.ts +0 -154
- package/lib/fts/index.ts +0 -361
- package/out/address/index.d.ts.map +0 -1
- package/out/address/index.js.map +0 -1
- package/out/address/point/index.d.ts +0 -53
- package/out/address/point/index.d.ts.map +0 -1
- package/out/address/point/index.js +0 -222
- package/out/address/point/index.js.map +0 -1
- package/out/ancestry/index.d.ts +0 -45
- package/out/ancestry/index.d.ts.map +0 -1
- package/out/ancestry/index.js +0 -55
- package/out/ancestry/index.js.map +0 -1
- package/out/convention/index.d.ts +0 -106
- package/out/convention/index.d.ts.map +0 -1
- package/out/convention/index.js +0 -93
- package/out/convention/index.js.map +0 -1
- package/out/fst/index.d.ts.map +0 -1
- package/out/fst/index.js.map +0 -1
- package/out/fts/index.d.ts +0 -184
- package/out/fts/index.d.ts.map +0 -1
- package/out/fts/index.js +0 -277
- package/out/fts/index.js.map +0 -1
- package/out/geonames/index.d.ts.map +0 -1
- package/out/geonames/index.js.map +0 -1
- package/out/nsul/index.d.ts.map +0 -1
- package/out/nsul/index.js.map +0 -1
- package/out/poi/index.d.ts.map +0 -1
- package/out/poi/index.js.map +0 -1
- package/out/postal/index.d.ts.map +0 -1
- package/out/postal/index.js.map +0 -1
- package/out/street/centroid/index.d.ts +0 -40
- package/out/street/centroid/index.d.ts.map +0 -1
- package/out/street/centroid/index.js.map +0 -1
- package/out/street/index.d.ts.map +0 -1
- package/out/street/index.js.map +0 -1
- package/out/uprn/index.d.ts.map +0 -1
- package/out/uprn/index.js.map +0 -1
- /package/lib/{geonames/index.ts → geonames.ts} +0 -0
- /package/lib/{nsul/index.ts → nsul.ts} +0 -0
- /package/lib/{poi/index.ts → poi.ts} +0 -0
- /package/lib/{postal/index.ts → postal.ts} +0 -0
- /package/lib/{uprn/index.ts → uprn.ts} +0 -0
package/lib/reverse.ts
CHANGED
|
@@ -3,29 +3,23 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Reverse geocoding
|
|
7
|
-
* implementation, per the 2026-06-11 scoping notes:
|
|
6
|
+
* Reverse geocoding: map a `(lat, lon)` point to the containing admin hierarchy.
|
|
8
7
|
*
|
|
9
|
-
* 1.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* locality → …) through the winner's DESCENDANTS (the `ancestors` table, reversed), taking
|
|
22
|
-
* the PIP-confirmed child when a polygon exists and the nearest-centroid child otherwise —
|
|
23
|
-
* the latter flagged `containment: "approximate"`, the demo's honesty convention.
|
|
24
|
-
* 4. **Hierarchy assembly** — the deepest place's ancestor chain via the SAME walk forward resolution
|
|
25
|
-
* uses (`ancestry.ts`, #404), so consumers get a symmetric tree.
|
|
8
|
+
* 1. Fetch the admin DB's `place_bbox` R*Tree candidates whose bbox contains the point,
|
|
9
|
+
* smallest-area-first, so the first polygon confirmation is the deepest.
|
|
10
|
+
* 2. Confirm each candidate by ray-cast (geo.ts, the canonical TS port of
|
|
11
|
+
* `scripts/eval/pip-containment.py`) against the polygon sidecar DB (`wof-polygons.db`,
|
|
12
|
+
* `polygons(id, geom)` with GeoJSON text, built by `scripts/build-wof-polygons.mjs`). A
|
|
13
|
+
* candidate whose polygon exists but rejects the point is a bbox false positive and is
|
|
14
|
+
* dropped. A candidate with no polygon row stays eligible for the approximate fallback.
|
|
15
|
+
* 3. Descend tier-by-tier through the winner's descendants (the `ancestors` table, reversed),
|
|
16
|
+
* taking the PIP-confirmed child when a polygon exists and the nearest-centroid child
|
|
17
|
+
* otherwise. A centroid-fallback step is flagged `containment: "approximate"`.
|
|
18
|
+
* 4. Assemble the deepest place's ancestor chain through the same walk forward resolution uses,
|
|
19
|
+
* so consumers get a symmetric tree.
|
|
26
20
|
*
|
|
27
|
-
* Reverse quality is country-dependent
|
|
28
|
-
*
|
|
21
|
+
* Reverse quality is country-dependent, because polygon coverage is. `containment` records this per
|
|
22
|
+
* result.
|
|
29
23
|
*/
|
|
30
24
|
|
|
31
25
|
import { tryParsingJSON } from "@mailwoman/core/json"
|
|
@@ -33,9 +27,10 @@ import { allRows } from "@mailwoman/core/utils"
|
|
|
33
27
|
import { bboxAround, geometryContains, haversineKm, type ParsedGeometry } from "@mailwoman/spatial"
|
|
34
28
|
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
35
29
|
import { tableExists } from "@mailwoman/sqlite/introspection"
|
|
30
|
+
import type { PathBuilderLike } from "path-ts"
|
|
36
31
|
|
|
37
|
-
import { ancestorLineage, placetypeDepth } from "#ancestry
|
|
38
|
-
import { PLACE_BBOX_TABLE } from "#fts
|
|
32
|
+
import { ancestorLineage, placetypeDepth } from "#ancestry"
|
|
33
|
+
import { PLACE_BBOX_TABLE } from "#fts"
|
|
39
34
|
import type { WOFDatabase } from "#schema"
|
|
40
35
|
import type { PlaceCandidate, WOFPlacetype } from "#types"
|
|
41
36
|
/**
|
|
@@ -51,62 +46,88 @@ const MAX_ABS_LONGITUDE = 180
|
|
|
51
46
|
/**
|
|
52
47
|
* How the deepest returned place was confirmed:
|
|
53
48
|
*
|
|
54
|
-
* - `"polygon"
|
|
55
|
-
* - `"approximate"
|
|
56
|
-
*
|
|
57
|
-
*
|
|
49
|
+
* - `"polygon"`: the point ray-cast inside the place's real (DP-simplified) admin boundary.
|
|
50
|
+
* - `"approximate"`: the place has no polygon on record.
|
|
51
|
+
* It returns the nearest-centroid candidate among places whose bbox or parent contains the point.
|
|
52
|
+
* The demo's approximate circles use the same convention.
|
|
53
|
+
* Both results expose country-dependent data coverage.
|
|
58
54
|
*/
|
|
59
55
|
export type ContainmentKind = "polygon" | "approximate"
|
|
60
56
|
|
|
61
57
|
export interface ReverseGeocodeResult {
|
|
62
58
|
/**
|
|
63
|
-
* The containment chain,
|
|
64
|
-
*
|
|
65
|
-
*
|
|
59
|
+
* The containment chain, deepest-first.
|
|
60
|
+
*
|
|
61
|
+
* `[0]` is the winning place, then its ancestors up to country.
|
|
62
|
+
* This is the same tree shape forward resolution attaches via `includeAncestors`.
|
|
63
|
+
*
|
|
64
|
+
* Empty when no candidate's bbox contains the point (open ocean, or outside the gazetteer's coverage).
|
|
66
65
|
*/
|
|
67
66
|
hierarchy: PlaceCandidate[]
|
|
68
67
|
/**
|
|
69
|
-
* Containment kind of the
|
|
68
|
+
* Containment kind of the deepest place in `hierarchy` (see {@link ContainmentKind}).
|
|
70
69
|
*/
|
|
71
70
|
containment: ContainmentKind
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
export interface WOFReverseGeocoderOpts {
|
|
75
74
|
/**
|
|
76
|
-
* Path to the admin gazetteer DB (e.g. `admin-global-priority.db`)
|
|
77
|
-
*
|
|
75
|
+
* Path to the admin gazetteer DB (e.g. `admin-global-priority.db`).
|
|
76
|
+
*
|
|
77
|
+
* It must include `spr`, `ancestors`, and the package-built `place_bbox`
|
|
78
|
+
* R*Tree (`mailwoman gazetteer build fts`).
|
|
79
|
+
*
|
|
80
|
+
* Mutually exclusive with `adminDatabase`.
|
|
78
81
|
*/
|
|
79
|
-
adminDBPath?:
|
|
82
|
+
adminDBPath?: PathBuilderLike
|
|
80
83
|
/**
|
|
81
|
-
* Pre-opened admin DB
|
|
84
|
+
* Pre-opened admin DB, primarily for tests against an inline fixture.
|
|
82
85
|
*/
|
|
83
86
|
adminDatabase?: DatabaseClient<WOFDatabase>
|
|
84
87
|
/**
|
|
85
|
-
* Path to the polygon sidecar DB (`wof-polygons.db`, table `polygons(id, geom)`).
|
|
86
|
-
*
|
|
88
|
+
* Path to the polygon sidecar DB (`wof-polygons.db`, table `polygons(id, geom)`).
|
|
89
|
+
*
|
|
90
|
+
* Optional.
|
|
91
|
+
* Without it every result is `containment: "approximate"` (centroid-only mode).
|
|
92
|
+
*
|
|
93
|
+
* Mutually exclusive with `polygonDatabase`.
|
|
87
94
|
*/
|
|
88
|
-
polygonDBPath?:
|
|
95
|
+
polygonDBPath?: PathBuilderLike
|
|
89
96
|
/**
|
|
90
|
-
* Pre-opened polygon DB
|
|
97
|
+
* Pre-opened polygon DB, primarily for tests.
|
|
91
98
|
*/
|
|
92
99
|
polygonDatabase?: DatabaseClient<WOFDatabase>
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
export interface ReverseGeocodeOpts {
|
|
96
103
|
/**
|
|
97
|
-
* Restrict the hierarchy to these placetypes (both the bbox candidates and the descent tiers).
|
|
98
|
-
*
|
|
104
|
+
* Restrict the hierarchy to these placetypes (both the bbox candidates and the descent tiers).
|
|
105
|
+
*
|
|
106
|
+
* E.g.
|
|
107
|
+
*
|
|
108
|
+
* `["region", "county", "locality"]` to skip the neighborhood grain.
|
|
109
|
+
*
|
|
110
|
+
* @defaultValue every admin placetype in the gazetteer.
|
|
99
111
|
*/
|
|
100
112
|
placetypes?: WOFPlacetype[]
|
|
101
113
|
/**
|
|
102
|
-
* Cap on the bbox candidate fetch.
|
|
103
|
-
*
|
|
114
|
+
* Cap on the bbox candidate fetch.
|
|
115
|
+
*
|
|
116
|
+
* Current measurements show that this covers a dense metro.
|
|
117
|
+
*
|
|
118
|
+
* The most bbox-overlapping point we have measured is a few dozen neighborhoods plus the admin chain.
|
|
119
|
+
*
|
|
120
|
+
* @defaultValue `128`
|
|
104
121
|
*/
|
|
105
122
|
maxCandidates?: number
|
|
106
123
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
124
|
+
* The lookup skips approximate (nearest-centroid) steps farther than this from the query point.
|
|
125
|
+
*
|
|
126
|
+
* This keeps a sparse gazetteer from "refining" to a far-away sibling.
|
|
127
|
+
*
|
|
128
|
+
* Polygon-confirmed steps ignore it (containment is exact regardless of centroid distance).
|
|
129
|
+
*
|
|
130
|
+
* @defaultValue `25 km`
|
|
110
131
|
*/
|
|
111
132
|
maxApproximateKm?: number
|
|
112
133
|
}
|
|
@@ -115,8 +136,10 @@ const DEFAULT_MAX_CANDIDATES = 128
|
|
|
115
136
|
const DEFAULT_MAX_APPROXIMATE_KM = 25
|
|
116
137
|
|
|
117
138
|
/**
|
|
118
|
-
* The tier ladder for the approximate descent, coarsest-first.
|
|
119
|
-
*
|
|
139
|
+
* The tier ladder for the approximate descent, coarsest-first.
|
|
140
|
+
*
|
|
141
|
+
* Each tier is attempted among the current winner's descendants.
|
|
142
|
+
* A tier with no rows is skipped (e.g. counties without localadmins jump straight to locality).
|
|
120
143
|
*/
|
|
121
144
|
const DESCENT_TIERS: readonly WOFPlacetype[] = [
|
|
122
145
|
"county",
|
|
@@ -140,23 +163,35 @@ interface CandidateRow {
|
|
|
140
163
|
lon: number
|
|
141
164
|
}
|
|
142
165
|
|
|
143
|
-
|
|
144
|
-
|
|
166
|
+
const ABSENT_CANDIDATE_FIELDS = {
|
|
167
|
+
parent_id: null,
|
|
168
|
+
distanceKm: null,
|
|
169
|
+
exactMatch: null,
|
|
170
|
+
prominence: null,
|
|
171
|
+
population: null,
|
|
172
|
+
referential: null,
|
|
173
|
+
encyclopedic: null,
|
|
174
|
+
importance: null,
|
|
175
|
+
bbox: null,
|
|
176
|
+
mismatch: null,
|
|
177
|
+
containedByQualifier: null,
|
|
178
|
+
regionScopeMiss: null,
|
|
179
|
+
variantAliasExempted: null,
|
|
180
|
+
} as const satisfies Partial<PlaceCandidate>
|
|
181
|
+
|
|
182
|
+
function toPlaceCandidate(row: CandidateRow, distanceKm: number | null = null): PlaceCandidate {
|
|
183
|
+
return {
|
|
184
|
+
...ABSENT_CANDIDATE_FIELDS,
|
|
145
185
|
id: row.id,
|
|
146
186
|
name: row.name,
|
|
147
187
|
placetype: row.placetype as WOFPlacetype,
|
|
148
188
|
country: row.country ?? "",
|
|
149
189
|
lat: row.lat,
|
|
150
190
|
lon: row.lon,
|
|
151
|
-
parent_id: row.parent_id ??
|
|
191
|
+
parent_id: row.parent_id ?? null,
|
|
152
192
|
score: 0,
|
|
193
|
+
distanceKm,
|
|
153
194
|
}
|
|
154
|
-
|
|
155
|
-
if (distanceKm !== undefined) {
|
|
156
|
-
c.distanceKm = distanceKm
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return c
|
|
160
195
|
}
|
|
161
196
|
|
|
162
197
|
export class WOFReverseGeocoder implements Disposable {
|
|
@@ -165,10 +200,12 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
165
200
|
readonly #polygons: DatabaseClient<WOFDatabase> | null
|
|
166
201
|
readonly #ownsPolygons: boolean
|
|
167
202
|
/**
|
|
168
|
-
* Parsed-geometry cache.
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
203
|
+
* Parsed-geometry cache.
|
|
204
|
+
*
|
|
205
|
+
* Reverse queries cluster geographically, so caching the JSON.parse avoids repeated work.
|
|
206
|
+
* The cache is bounded and clears wholesale at the cap.
|
|
207
|
+
*
|
|
208
|
+
* The polygons are DP-simplified and small, so the cap only bounds a long-lived server process.
|
|
172
209
|
*/
|
|
173
210
|
readonly #geometryCache = new Map<number, ParsedGeometry | null>()
|
|
174
211
|
static readonly #GEOMETRY_CACHE_CAP = 4096
|
|
@@ -195,8 +232,9 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
195
232
|
|
|
196
233
|
this.#ownsPolygons = !opts.polygonDatabase && Boolean(opts.polygonDBPath)
|
|
197
234
|
|
|
198
|
-
// Fail loudly up front
|
|
199
|
-
//
|
|
235
|
+
// Fail loudly up front.
|
|
236
|
+
// The R*Tree is a build artifact and is not part of the upstream WOF distribution,
|
|
237
|
+
// so a missing index would otherwise surface as an opaque SQL error per query.
|
|
200
238
|
if (!tableExists(this.#admin, PLACE_BBOX_TABLE)) {
|
|
201
239
|
throw new Error(
|
|
202
240
|
`WOFReverseGeocoder: the admin DB has no \`${PLACE_BBOX_TABLE}\` R*Tree. Build it with ` +
|
|
@@ -213,18 +251,25 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
213
251
|
}
|
|
214
252
|
|
|
215
253
|
/**
|
|
216
|
-
* Resolve a WGS-84 point to its containing admin hierarchy.
|
|
217
|
-
*
|
|
254
|
+
* Resolve a WGS-84 point to its containing admin hierarchy.
|
|
255
|
+
*
|
|
256
|
+
* Async for symmetry with `PlaceLookup.findPlace`
|
|
257
|
+
* (the work is sync `node:sqlite` underneath, the same convention).
|
|
258
|
+
* Thin wrapper over {@link reverseGeocodeSync}.
|
|
218
259
|
*/
|
|
219
260
|
async reverseGeocode(lat: number, lon: number, opts: ReverseGeocodeOpts = {}): Promise<ReverseGeocodeResult> {
|
|
220
261
|
return this.reverseGeocodeSync(lat, lon, opts)
|
|
221
262
|
}
|
|
222
263
|
|
|
223
264
|
/**
|
|
224
|
-
* Synchronous core of {@link reverseGeocode}
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
265
|
+
* Synchronous core of {@link reverseGeocode}.
|
|
266
|
+
*
|
|
267
|
+
* Every step underneath is already sync `node:sqlite`, so this is the real implementation.
|
|
268
|
+
* The async method above exists only for call-site symmetry with `PlaceLookup.findPlace`.
|
|
269
|
+
*
|
|
270
|
+
* Exposed directly for callers that can't await mid-call
|
|
271
|
+
* (e.g. `mailwoman/poi-executor.ts`'s `createPOIExecutor`, whose `POIQueryResult`
|
|
272
|
+
* return type is synchronous by interface. See `poi-intent.ts`'s `deps.execute`).
|
|
228
273
|
*/
|
|
229
274
|
reverseGeocodeSync(lat: number, lon: number, opts: ReverseGeocodeOpts = {}): ReverseGeocodeResult {
|
|
230
275
|
if (
|
|
@@ -239,8 +284,9 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
239
284
|
const maxApproximateKm = opts.maxApproximateKm ?? DEFAULT_MAX_APPROXIMATE_KM
|
|
240
285
|
const candidates = this.#bboxCandidates(lat, lon, opts)
|
|
241
286
|
|
|
242
|
-
// PIP walk, smallest-bbox-first
|
|
243
|
-
// polygon
|
|
287
|
+
// PIP walk, smallest-bbox-first.
|
|
288
|
+
// The first polygon that contains the point is the deepest polygon-confirmable place.
|
|
289
|
+
// Drop candidates whose bounding boxes match but whose polygons reject the point.
|
|
244
290
|
let winner: CandidateRow | null = null
|
|
245
291
|
let winnerConfirmed = false
|
|
246
292
|
const pointOnly: CandidateRow[] = []
|
|
@@ -261,7 +307,7 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
261
307
|
}
|
|
262
308
|
|
|
263
309
|
if (!winner) {
|
|
264
|
-
// No polygon confirmed anywhere
|
|
310
|
+
// No polygon confirmed anywhere, so take the nearest centroid among the polygon-less bbox candidates.
|
|
265
311
|
let bestKm = Infinity
|
|
266
312
|
|
|
267
313
|
for (const c of pointOnly) {
|
|
@@ -279,7 +325,7 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
279
325
|
// Approximate descent into finer tiers than the winner.
|
|
280
326
|
let current = winner
|
|
281
327
|
let currentConfirmed = winnerConfirmed
|
|
282
|
-
let currentDistanceKm = currentConfirmed ?
|
|
328
|
+
let currentDistanceKm = currentConfirmed ? null : haversineKm(lat, lon, current.lat, current.lon)
|
|
283
329
|
|
|
284
330
|
for (const tier of DESCENT_TIERS) {
|
|
285
331
|
if (placetypeDepth(tier) <= placetypeDepth(current.placetype)) continue
|
|
@@ -288,7 +334,7 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
288
334
|
const kids = this.#descendants(current.id, tier, lat, lon, maxApproximateKm)
|
|
289
335
|
let next: CandidateRow | null = null
|
|
290
336
|
let nextConfirmed = false
|
|
291
|
-
let nextKm: number |
|
|
337
|
+
let nextKm: number | null = null
|
|
292
338
|
let bestKm = Infinity
|
|
293
339
|
|
|
294
340
|
for (const k of kids) {
|
|
@@ -297,12 +343,12 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
297
343
|
if (contains === true) {
|
|
298
344
|
next = k
|
|
299
345
|
nextConfirmed = true
|
|
300
|
-
nextKm =
|
|
346
|
+
nextKm = null
|
|
301
347
|
|
|
302
348
|
break
|
|
303
349
|
}
|
|
304
350
|
|
|
305
|
-
if (contains === false) continue // known not-here
|
|
351
|
+
if (contains === false) continue // known not-here, polygon rejected
|
|
306
352
|
const km = haversineKm(lat, lon, k.lat, k.lon)
|
|
307
353
|
|
|
308
354
|
if (km <= maxApproximateKm && km < bestKm) {
|
|
@@ -318,17 +364,24 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
318
364
|
currentConfirmed = nextConfirmed
|
|
319
365
|
currentDistanceKm = nextKm
|
|
320
366
|
}
|
|
321
|
-
// An empty tier is
|
|
367
|
+
// An empty tier is not terminal.
|
|
368
|
+
// Counties without localadmins jump straight to locality.
|
|
322
369
|
}
|
|
323
370
|
|
|
324
|
-
// Hierarchy assembly via the shared ancestor walk.
|
|
325
|
-
// (the deepest place's recorded lineage misses the PIP root),
|
|
326
|
-
// region/country are always present when a polygon confirmed them.
|
|
371
|
+
// Hierarchy assembly via the shared ancestor walk.
|
|
372
|
+
// If the descent crossed an ancestry gap (the deepest place's recorded lineage misses the PIP root),
|
|
373
|
+
// merge the root's own chain so region/country are always present when a polygon confirmed them.
|
|
327
374
|
const byID = new Map<number, PlaceCandidate>([[current.id, toPlaceCandidate(current, currentDistanceKm)]])
|
|
328
375
|
|
|
329
376
|
for (const a of ancestorLineage(this.#admin, current.id)) {
|
|
330
377
|
if (!byID.has(a.id)) {
|
|
331
|
-
byID.set(a.id, {
|
|
378
|
+
byID.set(a.id, {
|
|
379
|
+
...ABSENT_CANDIDATE_FIELDS,
|
|
380
|
+
...a,
|
|
381
|
+
placetype: a.placetype as WOFPlacetype,
|
|
382
|
+
country: a.country ?? "",
|
|
383
|
+
score: 0,
|
|
384
|
+
})
|
|
332
385
|
}
|
|
333
386
|
}
|
|
334
387
|
|
|
@@ -337,7 +390,13 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
337
390
|
|
|
338
391
|
for (const a of ancestorLineage(this.#admin, winner.id)) {
|
|
339
392
|
if (!byID.has(a.id)) {
|
|
340
|
-
byID.set(a.id, {
|
|
393
|
+
byID.set(a.id, {
|
|
394
|
+
...ABSENT_CANDIDATE_FIELDS,
|
|
395
|
+
...a,
|
|
396
|
+
placetype: a.placetype as WOFPlacetype,
|
|
397
|
+
country: a.country ?? "",
|
|
398
|
+
score: 0,
|
|
399
|
+
})
|
|
341
400
|
}
|
|
342
401
|
}
|
|
343
402
|
}
|
|
@@ -395,9 +454,12 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
395
454
|
}
|
|
396
455
|
|
|
397
456
|
/**
|
|
398
|
-
* Descendants of `parentID` at one placetype tier, pre-filtered to a centroid window
|
|
399
|
-
* generous 4× the approximate cap
|
|
400
|
-
*
|
|
457
|
+
* Descendants of `parentID` at one placetype tier, pre-filtered to a centroid window
|
|
458
|
+
* around the query point (a generous 4× the approximate cap, since polygon-holding
|
|
459
|
+
* children may legitimately have far centroids, e.g. a sprawling consolidated city).
|
|
460
|
+
*
|
|
461
|
+
* The caller applies the precise cap per candidate.
|
|
462
|
+
* It limits centroid-fallback steps only.
|
|
401
463
|
*/
|
|
402
464
|
#descendants(
|
|
403
465
|
parentID: number,
|
|
@@ -439,7 +501,8 @@ export class WOFReverseGeocoder implements Disposable {
|
|
|
439
501
|
}
|
|
440
502
|
|
|
441
503
|
const row = this.#polygons.prepare(`SELECT geom FROM polygons WHERE id = ?`).get(id) as { geom: string } | undefined
|
|
442
|
-
// Malformed row parses to null
|
|
504
|
+
// Malformed row parses to null.
|
|
505
|
+
// Treat it as no-polygon so the query does not fail.
|
|
443
506
|
const geometry = row ? tryParsingJSON<ParsedGeometry>(row.geom) : null
|
|
444
507
|
|
|
445
508
|
this.#geometryCache.set(id, geometry)
|
package/lib/schema.ts
CHANGED
|
@@ -3,22 +3,25 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Kysely table types for the subset of the Who's On First SQLite schema
|
|
6
|
+
* Kysely table types for the subset of the Who's On First SQLite schema this package touches.
|
|
7
7
|
*
|
|
8
|
-
* The full upstream distribution at data.geocode.earth/wof/dist/sqlite/ ships
|
|
9
|
-
* models only the
|
|
10
|
-
* verified their shapes and they're not part of the resolver's contract.
|
|
8
|
+
* The full upstream distribution at data.geocode.earth/wof/dist/sqlite/ ships about seven tables.
|
|
9
|
+
* This file models only the tables we read. The others are outside the resolver interface. Their shapes remain unverified.
|
|
11
10
|
*
|
|
12
11
|
* Authoritative schema docs:
|
|
13
12
|
*
|
|
14
|
-
* - Whosonfirst SQLite
|
|
13
|
+
* - Whosonfirst SQLite readme: https://github.com/whosonfirst/go-whosonfirst-sqlite
|
|
15
14
|
* - Per-table sources under https://github.com/whosonfirst/go-whosonfirst-sqlite-features
|
|
16
15
|
*/
|
|
17
16
|
|
|
17
|
+
import type { KeyValueMetaTable } from "@mailwoman/sqlite/database-schema"
|
|
18
|
+
|
|
18
19
|
/**
|
|
19
|
-
* The FTS5 virtual table
|
|
20
|
+
* The FTS5 virtual table this package builds on first open.
|
|
21
|
+
* It is local to this repository.
|
|
20
22
|
*
|
|
21
|
-
* `content` is unindexed
|
|
23
|
+
* `content` is unindexed and is there so we can roundtrip the original name
|
|
24
|
+
* back to the caller without a second select.
|
|
22
25
|
* The actual FTS rebuild happens in `fts.ts::buildPlaceSearchFTS`.
|
|
23
26
|
*/
|
|
24
27
|
export interface PlaceSearchTable {
|
|
@@ -29,16 +32,19 @@ export interface PlaceSearchTable {
|
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
|
-
* `spr
|
|
33
|
-
*
|
|
35
|
+
* `spr`, the Who's On First "Standard Places Response": a denormalized lightweight
|
|
36
|
+
* summary of one row per place.
|
|
37
|
+
*
|
|
38
|
+
* The resolver's main lookup table.
|
|
39
|
+
*
|
|
40
|
+
* Lifecycle flags use two conventions, both meaning "currently valid": `is_current = -1`
|
|
41
|
+
* for modern Who's On First and `is_current = 1` for the legacy Mapzen era.
|
|
42
|
+
* Only `is_current = 0` means "not current".
|
|
34
43
|
*
|
|
35
|
-
*
|
|
36
|
-
* `is_current = 1` (legacy Mapzen-era). Only `is_current = 0` means "not current". Filters in `lookup.ts` and `fts.ts`
|
|
37
|
-
* use `is_current != 0 AND is_deprecated = 0` — see #91 for the diagnostic that uncovered the mixed-convention
|
|
38
|
-
* reality.
|
|
44
|
+
* Filters in `lookup.ts` and `fts.ts` use `is_current != 0 and is_deprecated = 0`.
|
|
39
45
|
*
|
|
40
|
-
* Lat/lon live directly on this row
|
|
41
|
-
* bounding box if callers want one
|
|
46
|
+
* Lat/lon live directly on this row, so centroid resolution needs no GeoJSON extraction.
|
|
47
|
+
* `min_*` and `max_*` form a bounding box if callers want one.
|
|
42
48
|
*/
|
|
43
49
|
export interface SprTable {
|
|
44
50
|
id: number
|
|
@@ -63,15 +69,21 @@ export interface SprTable {
|
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
/**
|
|
66
|
-
* Alternate names per place, keyed by language tag subfields (BCP-47 components).
|
|
67
|
-
*
|
|
68
|
-
*
|
|
72
|
+
* Alternate names per place, keyed by language tag subfields (BCP-47 components).
|
|
73
|
+
*
|
|
74
|
+
* Joins back to `spr.id` via `id`.
|
|
75
|
+
* The real WOF schema uses the same column name as the spr primary key, so this is
|
|
76
|
+
* a normal join across two tables with the same FK column name.
|
|
77
|
+
*
|
|
78
|
+
* No `kind` column in real WOF.
|
|
79
|
+
* The FTS build concatenates all names per id.
|
|
69
80
|
*
|
|
70
|
-
*
|
|
81
|
+
* `official` marks a preferred-form name in an official language of the place's country.
|
|
82
|
+
* This column appears only in unified builds.
|
|
71
83
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* See `unified-schema.ts` for the full
|
|
84
|
+
* Real WOF dumps omit it.
|
|
85
|
+
* These are the aliases eligible to join the name-exact tier.
|
|
86
|
+
* See `unified-schema.ts` for the full interface.
|
|
75
87
|
*/
|
|
76
88
|
export interface NamesTable {
|
|
77
89
|
id: number
|
|
@@ -90,8 +102,11 @@ export interface NamesTable {
|
|
|
90
102
|
}
|
|
91
103
|
|
|
92
104
|
/**
|
|
93
|
-
* Per-place GeoJSON blob.
|
|
94
|
-
*
|
|
105
|
+
* Per-place GeoJSON blob.
|
|
106
|
+
*
|
|
107
|
+
* Centroid lat/lon are already exposed via `spr.{latitude,longitude}`,
|
|
108
|
+
* so the resolver does not need to parse this.
|
|
109
|
+
* The table stays modeled so a caller that wants the full geometry for bbox or polygon work can read it.
|
|
95
110
|
*/
|
|
96
111
|
export interface GeojsonTable {
|
|
97
112
|
id: number
|
|
@@ -103,8 +118,10 @@ export interface GeojsonTable {
|
|
|
103
118
|
}
|
|
104
119
|
|
|
105
120
|
/**
|
|
106
|
-
* Adjacency table for ancestor relationships.
|
|
107
|
-
*
|
|
121
|
+
* Adjacency table for ancestor relationships.
|
|
122
|
+
*
|
|
123
|
+
* One row per (place, ancestor) pair, including transitive ancestors.
|
|
124
|
+
* Used to implement `FindPlaceQuery.parentID` (descendant lookup).
|
|
108
125
|
*/
|
|
109
126
|
export interface AncestorsTable {
|
|
110
127
|
id: number
|
|
@@ -114,9 +131,14 @@ export interface AncestorsTable {
|
|
|
114
131
|
}
|
|
115
132
|
|
|
116
133
|
/**
|
|
117
|
-
* `place_population` — `id → wof:population`, split off `spr` so a population-rank
|
|
118
|
-
*
|
|
119
|
-
*
|
|
134
|
+
* `place_population` — `id → wof:population`, split off `spr` so a population-rank
|
|
135
|
+
* join is a single indexed probe.
|
|
136
|
+
*
|
|
137
|
+
* Written by the build/augment ingest + the GeoNames backfill.
|
|
138
|
+
* Read by the candidate build's `neg_rank`.
|
|
139
|
+
*
|
|
140
|
+
* WOF records population for ~15% of localities.
|
|
141
|
+
* Absent = unknown rather than zero.
|
|
120
142
|
*/
|
|
121
143
|
export interface PlacePopulationTable {
|
|
122
144
|
id: number
|
|
@@ -124,8 +146,10 @@ export interface PlacePopulationTable {
|
|
|
124
146
|
}
|
|
125
147
|
|
|
126
148
|
/**
|
|
127
|
-
* `place_abbr` — `id → abbreviation` (e.g. `IL → Illinois`), derived from
|
|
128
|
-
*
|
|
149
|
+
* `place_abbr` — `id → abbreviation` (e.g. `IL → Illinois`), derived from
|
|
150
|
+
* `names` rows whose `language = 'abbr'`.
|
|
151
|
+
*
|
|
152
|
+
* Lets the resolver accept a 2-letter region abbreviation as an exact match.
|
|
129
153
|
*/
|
|
130
154
|
export interface PlaceAbbrTable {
|
|
131
155
|
id: number
|
|
@@ -133,8 +157,11 @@ export interface PlaceAbbrTable {
|
|
|
133
157
|
}
|
|
134
158
|
|
|
135
159
|
/**
|
|
136
|
-
* `concordances` — external-id cross-references per place (`id → (other_source, other_id)`),
|
|
137
|
-
*
|
|
160
|
+
* `concordances` — external-id cross-references per place (`id → (other_source, other_id)`),
|
|
161
|
+
* e.g. a GeoNames or Overture gers id.
|
|
162
|
+
*
|
|
163
|
+
* Metadata only.
|
|
164
|
+
* Not part of the resolve path.
|
|
138
165
|
*/
|
|
139
166
|
export interface ConcordancesTable {
|
|
140
167
|
id: number
|
|
@@ -144,9 +171,12 @@ export interface ConcordancesTable {
|
|
|
144
171
|
}
|
|
145
172
|
|
|
146
173
|
/**
|
|
147
|
-
* `coincident_roles
|
|
148
|
-
*
|
|
149
|
-
*
|
|
174
|
+
* `coincident_roles`.
|
|
175
|
+
*
|
|
176
|
+
* The dual-role relation, where a place is both an admin region and a locality (Berlin the city-state).
|
|
177
|
+
*
|
|
178
|
+
* One row per (admin, locality) pair the resolver can complete a hierarchy with.
|
|
179
|
+
* Surfaced by {@link MailwomanLookupLike.coincidentRolesFor}.
|
|
150
180
|
*/
|
|
151
181
|
export interface CoincidentRolesTable {
|
|
152
182
|
admin_id: number
|
|
@@ -158,22 +188,15 @@ export interface CoincidentRolesTable {
|
|
|
158
188
|
}
|
|
159
189
|
|
|
160
190
|
/**
|
|
161
|
-
* The full schema we hand to `Kysely<WOFDatabase>` / `new DatabaseClient<WOFDatabase>(...)`.
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
* The provenance row every built extract carries: source fingerprints travelling WITH the database rather than in a
|
|
168
|
-
* document that can drift from it. Written by the postcode builders in `mailwoman/gazetteer-pipeline`.
|
|
191
|
+
* The full schema we hand to `Kysely<WOFDatabase>` / `new DatabaseClient<WOFDatabase>(...)`.
|
|
192
|
+
*
|
|
193
|
+
* Tables not listed here will fail type-checked queries, by design.
|
|
194
|
+
* The reader ({@link WOFSQLitePlaceLookup}) already consumes this.
|
|
195
|
+
*
|
|
196
|
+
* The build and augment writers adopt it so a column rename is a compile error on both sides.
|
|
169
197
|
*/
|
|
170
|
-
export interface ExtractMetaTable {
|
|
171
|
-
key: string
|
|
172
|
-
value: string | null
|
|
173
|
-
}
|
|
174
|
-
|
|
175
198
|
export interface WOFDatabase {
|
|
176
|
-
meta:
|
|
199
|
+
meta: KeyValueMetaTable
|
|
177
200
|
place_search: PlaceSearchTable
|
|
178
201
|
spr: SprTable
|
|
179
202
|
names: NamesTable
|