@mailwoman/resolver-wof-sqlite 9.1.0 → 9.3.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 +36 -20
- package/lib/address/index.ts +9 -0
- package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +40 -28
- package/{address-point-schema.ts → lib/address/point-schema.ts} +34 -8
- package/lib/address/point.ts +280 -0
- package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
- package/{ancestry.ts → lib/ancestry/index.ts} +13 -8
- package/{build-candidate.ts → lib/build-candidate.ts} +243 -199
- package/{build-slim.ts → lib/build-slim.ts} +153 -168
- package/lib/candidate/alias-bags.ts +56 -0
- package/lib/candidate/ancestors-sidecar.ts +204 -0
- package/lib/candidate/country-display-names.ts +79 -0
- package/lib/candidate/extract-fold.ts +138 -0
- package/lib/candidate/name-roles.ts +238 -0
- package/lib/candidate/own-name.ts +146 -0
- package/lib/candidate/place-attrs.ts +44 -0
- package/lib/candidate-ancestors-schema.ts +195 -0
- package/{candidate-fts.ts → lib/candidate-fts.ts} +7 -5
- package/{candidate-importance.ts → lib/candidate-importance.ts} +54 -57
- package/lib/candidate-lookup.ts +976 -0
- package/{candidate-schema.ts → lib/candidate-schema.ts} +34 -6
- package/lib/candidate-scoring.ts +261 -0
- package/lib/capital-schema.ts +89 -0
- package/lib/capitals.ts +148 -0
- package/{coincident-roles.ts → lib/coincident-roles.ts} +75 -19
- package/{convention.ts → lib/convention/index.ts} +5 -5
- package/lib/convention/schema.ts +72 -0
- package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +15 -16
- package/lib/currency-backfill.ts +334 -0
- package/lib/env.ts +50 -0
- package/lib/exact-match.ts +113 -0
- package/{sharding.ts → lib/extracts.ts} +63 -60
- package/lib/fst/autocomplete.ts +176 -0
- package/{fst-builder.ts → lib/fst/builder.ts} +30 -27
- package/{fst-deserialize-web.ts → lib/fst/deserialize-web.ts} +27 -87
- package/lib/fst/format.ts +106 -0
- package/{fst-freshness.ts → lib/fst/freshness.ts} +42 -75
- package/lib/fst/index.ts +14 -0
- package/{fst-matcher.ts → lib/fst/matcher.ts} +1 -1
- package/{fst-serialize.ts → lib/fst/serialize.ts} +37 -115
- package/{fst-types.ts → lib/fst/types.ts} +4 -2
- package/{fts.ts → lib/fts/index.ts} +28 -23
- package/{fts-query.ts → lib/fts/query.ts} +2 -2
- package/{geonames-aliases.ts → lib/geonames/aliases.ts} +13 -13
- package/lib/geonames/index.ts +8 -0
- package/{geonames-postal.ts → lib/geonames/postal.ts} +16 -15
- package/{index.ts → lib/index.ts} +52 -48
- package/{interpolation.ts → lib/interpolation.ts} +137 -41
- package/lib/lookup.ts +861 -0
- package/{name-score.ts → lib/name-score.ts} +6 -4
- package/lib/nsul/index.ts +8 -0
- package/lib/nsul/lookup.ts +144 -0
- package/lib/nsul/schema.ts +130 -0
- package/{place-importance-schema.ts → lib/place-importance-schema.ts} +70 -22
- package/lib/poi/index.ts +8 -0
- package/{poi-lookup.ts → lib/poi/lookup.ts} +32 -39
- package/{poi-schema.ts → lib/poi/schema.ts} +10 -6
- package/lib/polygon-schema.ts +47 -0
- package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +15 -21
- package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +4 -2
- package/lib/postal/index.ts +9 -0
- package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
- package/lib/primary-preference.ts +226 -0
- package/lib/proximity-rerank.ts +120 -0
- package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
- package/lib/region-keys.ts +144 -0
- package/{reverse.ts → lib/reverse.ts} +45 -56
- package/{schema.ts → lib/schema.ts} +11 -1
- package/lib/search-fetch.ts +257 -0
- package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
- package/lib/sqlite-utils.ts +83 -0
- package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +12 -6
- package/{street-centroid.ts → lib/street/centroid.ts} +26 -28
- package/lib/street/index.ts +13 -0
- package/{street-morphology-fst-builder.ts → lib/street/morphology-fst-builder.ts} +24 -14
- package/{street-morphology-fst-loader.ts → lib/street/morphology-fst-loader.ts} +14 -12
- package/{street-name-lookup.ts → lib/street/name-lookup.ts} +14 -30
- package/lib/street/normalize.ts +572 -0
- package/{street-segment-schema.ts → lib/street/segment-schema.ts} +13 -8
- package/{types.ts → lib/types.ts} +49 -9
- package/{unified-schema.ts → lib/unified-schema.ts} +21 -25
- package/lib/uprn/existence.ts +84 -0
- package/lib/uprn/index.ts +9 -0
- package/lib/uprn/lookup.ts +206 -0
- package/lib/uprn/schema.ts +124 -0
- package/lib/weights-overlay-linker.ts +878 -0
- package/out/address/index.d.ts +9 -0
- package/out/address/index.d.ts.map +1 -0
- package/out/address/index.js +9 -0
- package/out/address/index.js.map +1 -0
- package/out/{address-point-interpolation.d.ts → address/point-interpolation.d.ts} +11 -10
- package/out/address/point-interpolation.d.ts.map +1 -0
- package/out/{address-point-interpolation.js → address/point-interpolation.js} +29 -23
- package/out/address/point-interpolation.js.map +1 -0
- package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +30 -10
- package/out/address/point-schema.d.ts.map +1 -0
- package/out/{address-point-schema.js → address/point-schema.js} +7 -3
- package/out/address/point-schema.js.map +1 -0
- package/out/{address-point.d.ts → address/point.d.ts} +16 -8
- package/out/address/point.d.ts.map +1 -0
- package/out/address/point.js +191 -0
- package/out/address/point.js.map +1 -0
- package/out/{ancestry-backfill.d.ts → ancestry/backfill.d.ts} +7 -5
- package/out/ancestry/backfill.d.ts.map +1 -0
- package/out/{ancestry-backfill.js → ancestry/backfill.js} +12 -16
- package/out/ancestry/backfill.js.map +1 -0
- package/out/{ancestry.d.ts → ancestry/index.d.ts} +6 -5
- package/out/ancestry/index.d.ts.map +1 -0
- package/out/{ancestry.js → ancestry/index.js} +7 -7
- package/out/ancestry/index.js.map +1 -0
- package/out/build-candidate.d.ts +88 -7
- package/out/build-candidate.d.ts.map +1 -1
- package/out/build-candidate.js +145 -149
- package/out/build-candidate.js.map +1 -1
- package/out/build-slim.d.ts +5 -5
- package/out/build-slim.d.ts.map +1 -1
- package/out/build-slim.js +127 -142
- package/out/build-slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +19 -0
- package/out/candidate/alias-bags.d.ts.map +1 -0
- package/out/candidate/alias-bags.js +39 -0
- package/out/candidate/alias-bags.js.map +1 -0
- package/out/candidate/ancestors-sidecar.d.ts +32 -0
- package/out/candidate/ancestors-sidecar.d.ts.map +1 -0
- package/out/candidate/ancestors-sidecar.js +140 -0
- package/out/candidate/ancestors-sidecar.js.map +1 -0
- package/out/candidate/country-display-names.d.ts +35 -0
- package/out/candidate/country-display-names.d.ts.map +1 -0
- package/out/candidate/country-display-names.js +59 -0
- package/out/candidate/country-display-names.js.map +1 -0
- package/out/candidate/extract-fold.d.ts +32 -0
- package/out/candidate/extract-fold.d.ts.map +1 -0
- package/out/candidate/extract-fold.js +104 -0
- package/out/candidate/extract-fold.js.map +1 -0
- package/out/candidate/name-roles.d.ts +57 -0
- package/out/candidate/name-roles.d.ts.map +1 -0
- package/out/candidate/name-roles.js +166 -0
- package/out/candidate/name-roles.js.map +1 -0
- package/out/candidate/own-name.d.ts +50 -0
- package/out/candidate/own-name.d.ts.map +1 -0
- package/out/candidate/own-name.js +132 -0
- package/out/candidate/own-name.js.map +1 -0
- package/out/candidate/place-attrs.d.ts +43 -0
- package/out/candidate/place-attrs.d.ts.map +1 -0
- package/out/candidate/place-attrs.js +15 -0
- package/out/candidate/place-attrs.js.map +1 -0
- package/out/candidate-ancestors-schema.d.ts +150 -0
- package/out/candidate-ancestors-schema.d.ts.map +1 -0
- package/out/candidate-ancestors-schema.js +123 -0
- package/out/candidate-ancestors-schema.js.map +1 -0
- package/out/candidate-fts.d.ts +7 -5
- package/out/candidate-fts.d.ts.map +1 -1
- package/out/candidate-fts.js +5 -3
- package/out/candidate-fts.js.map +1 -1
- package/out/candidate-importance.d.ts +16 -16
- package/out/candidate-importance.d.ts.map +1 -1
- package/out/candidate-importance.js +47 -52
- package/out/candidate-importance.js.map +1 -1
- package/out/candidate-lookup.d.ts +31 -52
- package/out/candidate-lookup.d.ts.map +1 -1
- package/out/candidate-lookup.js +380 -172
- package/out/candidate-lookup.js.map +1 -1
- package/out/candidate-schema.d.ts +31 -7
- package/out/candidate-schema.d.ts.map +1 -1
- package/out/candidate-schema.js +3 -0
- package/out/candidate-schema.js.map +1 -1
- package/out/candidate-scoring.d.ts +34 -0
- package/out/candidate-scoring.d.ts.map +1 -0
- package/out/candidate-scoring.js +196 -0
- package/out/candidate-scoring.js.map +1 -0
- package/out/capital-schema.d.ts +51 -0
- package/out/capital-schema.d.ts.map +1 -0
- package/out/capital-schema.js +63 -0
- package/out/capital-schema.js.map +1 -0
- package/out/capitals.d.ts +69 -0
- package/out/capitals.d.ts.map +1 -0
- package/out/capitals.js +98 -0
- package/out/capitals.js.map +1 -0
- package/out/coincident-roles.d.ts +12 -4
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +43 -11
- package/out/coincident-roles.js.map +1 -1
- package/out/{convention.d.ts → convention/index.d.ts} +5 -5
- package/out/convention/index.d.ts.map +1 -0
- package/out/{convention.js → convention/index.js} +4 -4
- package/out/convention/index.js.map +1 -0
- package/out/convention/schema.d.ts +51 -0
- package/out/convention/schema.d.ts.map +1 -0
- package/out/convention/schema.js +34 -0
- package/out/convention/schema.js.map +1 -0
- package/out/coverage-manifest-schema.d.ts +8 -8
- package/out/coverage-manifest-schema.d.ts.map +1 -1
- package/out/coverage-manifest-schema.js +6 -10
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +90 -0
- package/out/currency-backfill.d.ts.map +1 -0
- package/out/currency-backfill.js +196 -0
- package/out/currency-backfill.js.map +1 -0
- package/out/env.d.ts +43 -0
- package/out/env.d.ts.map +1 -0
- package/out/env.js +48 -0
- package/out/env.js.map +1 -0
- package/out/exact-match.d.ts +25 -0
- package/out/exact-match.d.ts.map +1 -0
- package/out/exact-match.js +88 -0
- package/out/exact-match.js.map +1 -0
- package/out/extracts.d.ts +114 -0
- package/out/extracts.d.ts.map +1 -0
- package/out/{sharding.js → extracts.js} +38 -38
- package/out/extracts.js.map +1 -0
- package/out/{fst-autocomplete.d.ts → fst/autocomplete.d.ts} +13 -13
- package/out/fst/autocomplete.d.ts.map +1 -0
- package/out/fst/autocomplete.js +113 -0
- package/out/fst/autocomplete.js.map +1 -0
- package/out/{fst-builder.d.ts → fst/builder.d.ts} +5 -5
- package/out/fst/builder.d.ts.map +1 -0
- package/out/{fst-builder.js → fst/builder.js} +24 -24
- package/out/fst/builder.js.map +1 -0
- package/out/{fst-deserialize-web.d.ts → fst/deserialize-web.d.ts} +3 -3
- package/out/fst/deserialize-web.d.ts.map +1 -0
- package/out/{fst-deserialize-web.js → fst/deserialize-web.js} +10 -74
- package/out/fst/deserialize-web.js.map +1 -0
- package/out/fst/format.d.ts +80 -0
- package/out/fst/format.d.ts.map +1 -0
- package/out/fst/format.js +91 -0
- package/out/fst/format.js.map +1 -0
- package/out/{fst-freshness.d.ts → fst/freshness.d.ts} +11 -14
- package/out/fst/freshness.d.ts.map +1 -0
- package/out/{fst-freshness.js → fst/freshness.js} +42 -74
- package/out/fst/freshness.js.map +1 -0
- package/out/fst/index.d.ts +14 -0
- package/out/fst/index.d.ts.map +1 -0
- package/out/fst/index.js +14 -0
- package/out/fst/index.js.map +1 -0
- package/out/{fst-matcher.d.ts → fst/matcher.d.ts} +2 -2
- package/out/fst/matcher.d.ts.map +1 -0
- package/out/{fst-matcher.js → fst/matcher.js} +1 -1
- package/out/fst/matcher.js.map +1 -0
- package/out/{fst-serialize.d.ts → fst/serialize.d.ts} +5 -10
- package/out/fst/serialize.d.ts.map +1 -0
- package/out/{fst-serialize.js → fst/serialize.js} +18 -98
- package/out/fst/serialize.js.map +1 -0
- package/out/{fst-types.d.ts → fst/types.d.ts} +4 -3
- package/out/fst/types.d.ts.map +1 -0
- package/out/{fst-types.js → fst/types.js} +1 -1
- package/out/fst/types.js.map +1 -0
- package/out/{fts.d.ts → fts/index.d.ts} +20 -13
- package/out/fts/index.d.ts.map +1 -0
- package/out/{fts.js → fts/index.js} +20 -15
- package/out/fts/index.js.map +1 -0
- package/out/{fts-query.d.ts → fts/query.d.ts} +2 -2
- package/out/fts/query.d.ts.map +1 -0
- package/out/{fts-query.js → fts/query.js} +2 -2
- package/out/fts/query.js.map +1 -0
- package/out/{geonames-aliases.d.ts → geonames/aliases.d.ts} +8 -6
- package/out/geonames/aliases.d.ts.map +1 -0
- package/out/{geonames-aliases.js → geonames/aliases.js} +7 -7
- package/out/geonames/aliases.js.map +1 -0
- package/out/geonames/index.d.ts +8 -0
- package/out/geonames/index.d.ts.map +1 -0
- package/out/geonames/index.js +8 -0
- package/out/geonames/index.js.map +1 -0
- package/out/{geonames-postal.d.ts → geonames/postal.d.ts} +12 -10
- package/out/geonames/postal.d.ts.map +1 -0
- package/out/{geonames-postal.js → geonames/postal.js} +11 -11
- package/out/geonames/postal.js.map +1 -0
- package/out/index.d.ts +32 -31
- package/out/index.d.ts.map +1 -1
- package/out/index.js +24 -24
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +18 -9
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +108 -36
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +25 -25
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +174 -558
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +0 -10
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js +6 -4
- package/out/name-score.js.map +1 -1
- package/out/nsul/index.d.ts +8 -0
- package/out/nsul/index.d.ts.map +1 -0
- package/out/nsul/index.js +8 -0
- package/out/nsul/index.js.map +1 -0
- package/out/nsul/lookup.d.ts +83 -0
- package/out/nsul/lookup.d.ts.map +1 -0
- package/out/nsul/lookup.js +80 -0
- package/out/nsul/lookup.js.map +1 -0
- package/out/nsul/schema.d.ts +100 -0
- package/out/nsul/schema.d.ts.map +1 -0
- package/out/nsul/schema.js +78 -0
- package/out/nsul/schema.js.map +1 -0
- package/out/place-importance-schema.d.ts +47 -10
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +56 -10
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi/index.d.ts +8 -0
- package/out/poi/index.d.ts.map +1 -0
- package/out/poi/index.js +8 -0
- package/out/poi/index.js.map +1 -0
- package/out/{poi-lookup.d.ts → poi/lookup.d.ts} +8 -10
- package/out/poi/lookup.d.ts.map +1 -0
- package/out/{poi-lookup.js → poi/lookup.js} +24 -29
- package/out/poi/lookup.js.map +1 -0
- package/out/{poi-schema.d.ts → poi/schema.d.ts} +10 -6
- package/out/poi/schema.d.ts.map +1 -0
- package/out/{poi-schema.js → poi/schema.js} +1 -1
- package/out/poi/schema.js.map +1 -0
- package/out/polygon-schema.d.ts +37 -0
- package/out/polygon-schema.d.ts.map +1 -0
- package/out/polygon-schema.js +23 -0
- package/out/polygon-schema.js.map +1 -0
- package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +7 -6
- package/out/postal/city-alias-lookup.d.ts.map +1 -0
- package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +12 -16
- package/out/postal/city-alias-lookup.js.map +1 -0
- package/out/{postal-city-alias-schema.d.ts → postal/city-alias-schema.d.ts} +1 -1
- package/out/{postal-city-alias-schema.d.ts.map → postal/city-alias-schema.d.ts.map} +1 -1
- package/out/{postal-city-alias-schema.js → postal/city-alias-schema.js} +1 -1
- package/out/{postal-city-alias-schema.js.map → postal/city-alias-schema.js.map} +1 -1
- package/out/{postal-city-candidate-schema.d.ts → postal/city-candidate-schema.d.ts} +4 -3
- package/out/postal/city-candidate-schema.d.ts.map +1 -0
- package/out/{postal-city-candidate-schema.js → postal/city-candidate-schema.js} +2 -2
- package/out/{postal-city-candidate-schema.js.map → postal/city-candidate-schema.js.map} +1 -1
- package/out/postal/index.d.ts +9 -0
- package/out/postal/index.d.ts.map +1 -0
- package/out/postal/index.js +9 -0
- package/out/postal/index.js.map +1 -0
- package/out/postcode-point-lookup.d.ts +10 -10
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +13 -13
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/primary-preference.d.ts +133 -0
- package/out/primary-preference.d.ts.map +1 -0
- package/out/primary-preference.js +146 -0
- package/out/primary-preference.js.map +1 -0
- package/out/proximity-rerank.d.ts +77 -0
- package/out/proximity-rerank.d.ts.map +1 -0
- package/out/proximity-rerank.js +86 -0
- package/out/proximity-rerank.js.map +1 -0
- package/out/ranking-weights.d.ts +15 -3
- package/out/ranking-weights.d.ts.map +1 -1
- package/out/ranking-weights.js +21 -3
- package/out/ranking-weights.js.map +1 -1
- package/out/region-keys.d.ts +47 -0
- package/out/region-keys.d.ts.map +1 -0
- package/out/region-keys.js +121 -0
- package/out/region-keys.js.map +1 -0
- package/out/reverse.d.ts +6 -6
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +23 -35
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +10 -1
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +59 -0
- package/out/search-fetch.d.ts.map +1 -0
- package/out/search-fetch.js +184 -0
- package/out/search-fetch.js.map +1 -0
- package/out/sqlite-convention-source.d.ts +7 -7
- package/out/sqlite-convention-source.d.ts.map +1 -1
- package/out/sqlite-convention-source.js +5 -5
- package/out/sqlite-convention-source.js.map +1 -1
- package/out/sqlite-utils.d.ts +24 -6
- package/out/sqlite-utils.d.ts.map +1 -1
- package/out/sqlite-utils.js +24 -7
- package/out/sqlite-utils.js.map +1 -1
- package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +12 -7
- package/out/street/centroid-schema.d.ts.map +1 -0
- package/out/{street-centroid-schema.js → street/centroid-schema.js} +5 -5
- package/out/{street-centroid-schema.js.map → street/centroid-schema.js.map} +1 -1
- package/out/{street-centroid.d.ts → street/centroid.d.ts} +6 -6
- package/out/street/centroid.d.ts.map +1 -0
- package/out/{street-centroid.js → street/centroid.js} +18 -24
- package/out/street/centroid.js.map +1 -0
- package/out/street/index.d.ts +13 -0
- package/out/street/index.d.ts.map +1 -0
- package/out/street/index.js +13 -0
- package/out/street/index.js.map +1 -0
- package/out/{street-morphology-fst-builder.d.ts → street/morphology-fst-builder.d.ts} +4 -4
- package/out/street/morphology-fst-builder.d.ts.map +1 -0
- package/out/{street-morphology-fst-builder.js → street/morphology-fst-builder.js} +18 -13
- package/out/street/morphology-fst-builder.js.map +1 -0
- package/out/{street-morphology-fst-loader.d.ts → street/morphology-fst-loader.d.ts} +5 -5
- package/out/street/morphology-fst-loader.d.ts.map +1 -0
- package/out/{street-morphology-fst-loader.js → street/morphology-fst-loader.js} +11 -10
- package/out/street/morphology-fst-loader.js.map +1 -0
- package/out/{street-name-lookup.d.ts → street/name-lookup.d.ts} +4 -7
- package/out/street/name-lookup.d.ts.map +1 -0
- package/out/{street-name-lookup.js → street/name-lookup.js} +9 -23
- package/out/street/name-lookup.js.map +1 -0
- package/out/street/normalize.d.ts +179 -0
- package/out/street/normalize.d.ts.map +1 -0
- package/out/street/normalize.js +457 -0
- package/out/street/normalize.js.map +1 -0
- package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +13 -9
- package/out/street/segment-schema.d.ts.map +1 -0
- package/out/{street-segment-schema.js → street/segment-schema.js} +4 -4
- package/out/{street-segment-schema.js.map → street/segment-schema.js.map} +1 -1
- package/out/types.d.ts +49 -9
- package/out/types.d.ts.map +1 -1
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +6 -5
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +16 -19
- package/out/unified-schema.js.map +1 -1
- package/out/uprn/existence.d.ts +53 -0
- package/out/uprn/existence.d.ts.map +1 -0
- package/out/uprn/existence.js +61 -0
- package/out/uprn/existence.js.map +1 -0
- package/out/uprn/index.d.ts +9 -0
- package/out/uprn/index.d.ts.map +1 -0
- package/out/uprn/index.js +9 -0
- package/out/uprn/index.js.map +1 -0
- package/out/uprn/lookup.d.ts +85 -0
- package/out/uprn/lookup.d.ts.map +1 -0
- package/out/uprn/lookup.js +149 -0
- package/out/uprn/lookup.js.map +1 -0
- package/out/uprn/schema.d.ts +93 -0
- package/out/uprn/schema.d.ts.map +1 -0
- package/out/uprn/schema.js +78 -0
- package/out/uprn/schema.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +299 -0
- package/out/weights-overlay-linker.d.ts.map +1 -0
- package/out/weights-overlay-linker.js +511 -0
- package/out/weights-overlay-linker.js.map +1 -0
- package/package.json +622 -154
- package/address-point.ts +0 -125
- package/candidate-lookup.ts +0 -720
- package/fst-autocomplete.ts +0 -204
- package/geo.ts +0 -121
- package/lookup.ts +0 -1354
- package/out/address-point-interpolation.d.ts.map +0 -1
- package/out/address-point-interpolation.js.map +0 -1
- package/out/address-point-schema.d.ts.map +0 -1
- package/out/address-point-schema.js.map +0 -1
- package/out/address-point.d.ts.map +0 -1
- package/out/address-point.js +0 -84
- package/out/address-point.js.map +0 -1
- package/out/ancestry-backfill.d.ts.map +0 -1
- package/out/ancestry-backfill.js.map +0 -1
- package/out/ancestry.d.ts.map +0 -1
- package/out/ancestry.js.map +0 -1
- package/out/convention.d.ts.map +0 -1
- package/out/convention.js.map +0 -1
- package/out/fst-autocomplete.d.ts.map +0 -1
- package/out/fst-autocomplete.js +0 -130
- package/out/fst-autocomplete.js.map +0 -1
- package/out/fst-builder.d.ts.map +0 -1
- package/out/fst-builder.js.map +0 -1
- package/out/fst-deserialize-web.d.ts.map +0 -1
- package/out/fst-deserialize-web.js.map +0 -1
- package/out/fst-freshness.d.ts.map +0 -1
- package/out/fst-freshness.js.map +0 -1
- package/out/fst-matcher.d.ts.map +0 -1
- package/out/fst-matcher.js.map +0 -1
- package/out/fst-serialize.d.ts.map +0 -1
- package/out/fst-serialize.js.map +0 -1
- package/out/fst-types.d.ts.map +0 -1
- package/out/fst-types.js.map +0 -1
- package/out/fts-query.d.ts.map +0 -1
- package/out/fts-query.js.map +0 -1
- package/out/fts.d.ts.map +0 -1
- package/out/fts.js.map +0 -1
- package/out/geo.d.ts +0 -74
- package/out/geo.d.ts.map +0 -1
- package/out/geo.js +0 -71
- package/out/geo.js.map +0 -1
- package/out/geonames-aliases.d.ts.map +0 -1
- package/out/geonames-aliases.js.map +0 -1
- package/out/geonames-postal.d.ts.map +0 -1
- package/out/geonames-postal.js.map +0 -1
- package/out/poi-lookup.d.ts.map +0 -1
- package/out/poi-lookup.js.map +0 -1
- package/out/poi-schema.d.ts.map +0 -1
- package/out/poi-schema.js.map +0 -1
- package/out/postal-city-alias-lookup.d.ts.map +0 -1
- package/out/postal-city-alias-lookup.js.map +0 -1
- package/out/postal-city-candidate-schema.d.ts.map +0 -1
- package/out/sharding.d.ts +0 -114
- package/out/sharding.d.ts.map +0 -1
- package/out/sharding.js.map +0 -1
- package/out/street-centroid-schema.d.ts.map +0 -1
- package/out/street-centroid.d.ts.map +0 -1
- package/out/street-centroid.js.map +0 -1
- package/out/street-morphology-fst-builder.d.ts.map +0 -1
- package/out/street-morphology-fst-builder.js.map +0 -1
- package/out/street-morphology-fst-loader.d.ts.map +0 -1
- package/out/street-morphology-fst-loader.js.map +0 -1
- package/out/street-name-lookup.d.ts.map +0 -1
- package/out/street-name-lookup.js.map +0 -1
- package/out/street-normalize.d.ts +0 -95
- package/out/street-normalize.d.ts.map +0 -1
- package/out/street-normalize.js +0 -272
- package/out/street-normalize.js.map +0 -1
- package/out/street-segment-schema.d.ts.map +0 -1
- package/sqlite-utils.ts +0 -46
- package/street-normalize.ts +0 -318
- /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* SQLite implementation of core's `AddressPointLookup` (#476): exact `(street, number)` within a
|
|
7
|
+
* postcode (preferred), locality, or — for extracts whose points carry no scope tag (OSM, #247) —
|
|
8
|
+
* the resolved locality's BBOX. Query-side normalization is THE shared normalizer
|
|
9
|
+
* (`street-normalize.ts`), selected per the extract's `streetLocale` so build-side and probe-side
|
|
10
|
+
* stay identical by construction (US delegates to the USPS pipeline; FR/DE/NL use the locale rules).
|
|
11
|
+
*
|
|
12
|
+
* Matching is exact-after-normalization only — no fuzzy street matching in this tier (measure how
|
|
13
|
+
* far exact gets first; fuzz is a later, separate decision). Scope order is most-selective first:
|
|
14
|
+
* postcode, then locality, then the bbox fall-through (only when a bbox is supplied AND the prior
|
|
15
|
+
* scopes missed). Multiple hits return the first by rowid — unit siblings share the building coord.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { AddressPointHit, AddressPointLookup } from "@mailwoman/resolver"
|
|
19
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
20
|
+
|
|
21
|
+
import type { AddressPointDatabase, AddressPointTable } from "#address/point-schema"
|
|
22
|
+
import { hasTable, prepareGet, type PreparedGet } from "#sqlite-utils"
|
|
23
|
+
import {
|
|
24
|
+
normalizeLocalityForKey,
|
|
25
|
+
type NameKey,
|
|
26
|
+
type StreetKey,
|
|
27
|
+
streetKeyVariants,
|
|
28
|
+
streetLocaleForSurface,
|
|
29
|
+
stripArrondissement,
|
|
30
|
+
type StreetLocale,
|
|
31
|
+
} from "#street/normalize"
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The columns this lookup projects — a typed slice of the SHARED {@link AddressPointTable}, so a column rename in
|
|
35
|
+
* `build-address-point-extract.ts` (the writer) is a compile error here (the reader).
|
|
36
|
+
*/
|
|
37
|
+
type AddressPointRow = Pick<AddressPointTable, "lat" | "lon" | "source" | "release" | "locality_norm" | "postcode">
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The 4 columns the reader SELECTs, in the schema's order — referenced by the prepared SELECTs so the projected
|
|
41
|
+
* `AddressPointRow` stays in lockstep with the shared schema.
|
|
42
|
+
*/
|
|
43
|
+
const SELECT_COLS = "lat, lon, source, release, locality_norm, postcode"
|
|
44
|
+
|
|
45
|
+
export class AddressPointSqliteLookup<DB extends AddressPointDatabase = AddressPointDatabase>
|
|
46
|
+
implements AddressPointLookup, Disposable
|
|
47
|
+
{
|
|
48
|
+
readonly #db: DatabaseClient<DB>
|
|
49
|
+
readonly #locale: StreetLocale
|
|
50
|
+
readonly #localityKeys: "full" | "abbreviated"
|
|
51
|
+
readonly #byPostcode: PreparedGet<[postcode: string, street: StreetKey, number: string], AddressPointRow> | undefined
|
|
52
|
+
readonly #byPostcodeLocality:
|
|
53
|
+
| PreparedGet<[postcode: string, locality: NameKey, street: StreetKey, number: string], AddressPointRow>
|
|
54
|
+
| undefined
|
|
55
|
+
readonly #byLocality: PreparedGet<[locality: NameKey, street: StreetKey, number: string], AddressPointRow> | undefined
|
|
56
|
+
readonly #byBbox:
|
|
57
|
+
| PreparedGet<
|
|
58
|
+
[street: StreetKey, number: string, minLat: number, maxLat: number, minLon: number, maxLon: number],
|
|
59
|
+
AddressPointRow
|
|
60
|
+
>
|
|
61
|
+
| undefined
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param dbPath Extract path.
|
|
65
|
+
* @param opts.streetLocale The street-normalization locale this extract was BUILT with — must match, or every key
|
|
66
|
+
* misses. Defaults to `"us"` (the situs tier), so existing callers are unchanged.
|
|
67
|
+
* @param opts.localityKeys Whether the extract's `locality_norm` is a FULL place name a query can be held to. The BAN
|
|
68
|
+
* and OSM extracts write the commune or `addr:city` in full; the US situs extract writes the NAD city field, which
|
|
69
|
+
* several counties abbreviate (`addi` for Addison on 5,174 Texas rows, 327,264 Texas rows at four characters or
|
|
70
|
+
* fewer) or give as the parent town (`easton` for North Easton). A key like that can steer WHICH row answers but
|
|
71
|
+
* cannot refuse one, so it never contradicts. Defaults from the street locale: `"us"` is abbreviated, the rest
|
|
72
|
+
* full.
|
|
73
|
+
*/
|
|
74
|
+
constructor(dbPath: string, opts: { streetLocale?: StreetLocale; localityKeys?: "full" | "abbreviated" } = {}) {
|
|
75
|
+
this.#db = new DatabaseClient<DB>(dbPath, { readOnly: true })
|
|
76
|
+
this.#locale = opts.streetLocale ?? "us"
|
|
77
|
+
this.#localityKeys = opts.localityKeys ?? (this.#locale === "us" ? "abbreviated" : "full")
|
|
78
|
+
|
|
79
|
+
// Degrade gracefully on an empty/tableless extract (interrupted build, stray 0-byte file): with no
|
|
80
|
+
// `address_point` table this lookup is a no-op miss, not a crash that loses the whole state (#568).
|
|
81
|
+
if (hasTable(this.#db, "address_point")) {
|
|
82
|
+
this.#byPostcode = prepareGet(
|
|
83
|
+
this.#db,
|
|
84
|
+
`SELECT ${SELECT_COLS} FROM address_point
|
|
85
|
+
WHERE postcode = ? AND street_norm = ? AND number = ? LIMIT 1`
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
this.#byPostcodeLocality = prepareGet(
|
|
89
|
+
this.#db,
|
|
90
|
+
`SELECT ${SELECT_COLS} FROM address_point
|
|
91
|
+
WHERE postcode = ? AND locality_norm = ? AND street_norm = ? AND number = ? LIMIT 1`
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
this.#byLocality = prepareGet(
|
|
95
|
+
this.#db,
|
|
96
|
+
`SELECT ${SELECT_COLS} FROM address_point
|
|
97
|
+
WHERE locality_norm = ? AND street_norm = ? AND number = ? LIMIT 1`
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
this.#byBbox = prepareGet(
|
|
101
|
+
this.#db,
|
|
102
|
+
`SELECT ${SELECT_COLS} FROM address_point
|
|
103
|
+
WHERE street_norm = ? AND number = ? AND lat BETWEEN ? AND ? AND lon BETWEEN ? AND ? LIMIT 1`
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
find(query: {
|
|
109
|
+
street: string
|
|
110
|
+
number: string
|
|
111
|
+
postcode?: string
|
|
112
|
+
locality?: string
|
|
113
|
+
bbox?: { minLat: number; maxLat: number; minLon: number; maxLon: number }
|
|
114
|
+
}): AddressPointHit | null {
|
|
115
|
+
if (!this.#byPostcode || !this.#byLocality || !this.#byBbox) return null
|
|
116
|
+
const number = query.number.trim().toLowerCase()
|
|
117
|
+
|
|
118
|
+
if (!number) return null
|
|
119
|
+
|
|
120
|
+
// Key-variant ladder (see `streetKeyVariants`): the literal key first, then the doubled-type
|
|
121
|
+
// collapse and the saint↔st register swap — each variant runs the FULL number ladder below, and
|
|
122
|
+
// the first variant to answer wins, so an attested literal key is never second-guessed.
|
|
123
|
+
let row: AddressPointRow | undefined
|
|
124
|
+
|
|
125
|
+
for (const streetNorm of streetKeyVariants(query.street, streetLocaleForSurface(query.street, this.#locale))) {
|
|
126
|
+
row = this.#findForKey(streetNorm, number, query)
|
|
127
|
+
|
|
128
|
+
if (row) break
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!row) return null
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
lat: row.lat,
|
|
135
|
+
lon: row.lon,
|
|
136
|
+
source: row.source,
|
|
137
|
+
release: row.release,
|
|
138
|
+
...(row.locality_norm ? { localityNorm: row.locality_norm } : {}),
|
|
139
|
+
...(row.postcode ? { postcode: row.postcode } : {}),
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The full number ladder for ONE normalized street key: exact, then the range low-end, then letter-suffix spacing
|
|
145
|
+
* with the base-number fall — see each rung's note in place.
|
|
146
|
+
*/
|
|
147
|
+
#findForKey(
|
|
148
|
+
streetNorm: StreetKey,
|
|
149
|
+
number: string,
|
|
150
|
+
query: {
|
|
151
|
+
street: string
|
|
152
|
+
number: string
|
|
153
|
+
postcode?: string
|
|
154
|
+
locality?: string
|
|
155
|
+
bbox?: { minLat: number; maxLat: number; minLon: number; maxLon: number }
|
|
156
|
+
}
|
|
157
|
+
) {
|
|
158
|
+
let row = this.#probe(streetNorm, number, query)
|
|
159
|
+
|
|
160
|
+
// Range-surface fallback: every register this reader serves stores ONE number per point
|
|
161
|
+
// (G-NAF `NUMBER_FIRST`, BAN, OA, OSM `addr:housenumber`), but the attested surface is often
|
|
162
|
+
// a range — "385-387 Esplanade" keys `385`. Null-only: an exact range key that matched above
|
|
163
|
+
// (some OSM points DO carry "385-387" verbatim) is never second-guessed.
|
|
164
|
+
if (!row) {
|
|
165
|
+
const low = /^(\d+[a-z]?)-\d+[a-z]?$/.exec(number)?.[1]
|
|
166
|
+
|
|
167
|
+
if (low) {
|
|
168
|
+
row = this.#probe(streetNorm, low, query)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Letter-suffix spacing fallback: the registers disagree on the joint — BAN stores "3 a"
|
|
173
|
+
// (space-separated), G-NAF and most OA sources store "3a" — and the parsed surface can arrive
|
|
174
|
+
// either way. On a miss, retry the OTHER spacing; on a double miss, the BASE number (the
|
|
175
|
+
// register attests no 3A but does attest 3 — the adjacent-parcel approximation, priced the
|
|
176
|
+
// same as the range fallback's low end). Null-only throughout, and only for the
|
|
177
|
+
// digits+single-letter shape (never touches "12 1/2" or unit-bearing forms).
|
|
178
|
+
if (!row) {
|
|
179
|
+
const joined = /^(\d+)\s+([a-z])$/.exec(number)
|
|
180
|
+
const spaced = /^(\d+)([a-z])$/.exec(number)
|
|
181
|
+
|
|
182
|
+
if (joined) {
|
|
183
|
+
row = this.#probe(streetNorm, `${joined[1]}${joined[2]}`, query) ?? this.#probe(streetNorm, joined[1]!, query)
|
|
184
|
+
} else if (spaced) {
|
|
185
|
+
row = this.#probe(streetNorm, `${spaced[1]} ${spaced[2]}`, query) ?? this.#probe(streetNorm, spaced[1]!, query)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return row
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The scope ladder for one (street, number) key: postcode, then locality, then the bbox fall-through — each rung only
|
|
194
|
+
* when the prior missed.
|
|
195
|
+
*/
|
|
196
|
+
#probe(
|
|
197
|
+
streetNorm: StreetKey,
|
|
198
|
+
number: string,
|
|
199
|
+
query: {
|
|
200
|
+
postcode?: string
|
|
201
|
+
locality?: string
|
|
202
|
+
bbox?: { minLat: number; maxLat: number; minLon: number; maxLon: number }
|
|
203
|
+
}
|
|
204
|
+
): AddressPointRow | undefined {
|
|
205
|
+
let row: AddressPointRow | undefined
|
|
206
|
+
|
|
207
|
+
if (query.postcode) {
|
|
208
|
+
const postcode = query.postcode.trim()
|
|
209
|
+
const localityKey = query.locality ? this.#localityKey(query.locality) : undefined
|
|
210
|
+
|
|
211
|
+
// A postcode can span several places — DE 04509 covers Schönwölkau and Werlitzsch, both with a Teichstraße 3 —
|
|
212
|
+
// so when the query names a locality the row whose own locality agrees is asked for FIRST. Only when no such
|
|
213
|
+
// row exists does the postcode-only row answer, and then only if its locality does not name a different place
|
|
214
|
+
// (see `#scopeContradicts` for what "different" tolerates): a query naming a third village under the postcode
|
|
215
|
+
// falls through to the locality rung rather than answering the wrong rooftop.
|
|
216
|
+
const agreeing = localityKey ? this.#byPostcodeLocality!(postcode, localityKey, streetNorm, number) : undefined
|
|
217
|
+
const candidate = agreeing ?? this.#byPostcode!(postcode, streetNorm, number)
|
|
218
|
+
|
|
219
|
+
row = candidate && !this.#scopeContradicts(candidate, query) ? candidate : undefined
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!row && query.locality) {
|
|
223
|
+
// FR extracts key arrondissement communes at the base city (both-sides fold, see the BAN
|
|
224
|
+
// builder + stripArrondissement) — fold the probe too so "Paris 13e Arrondissement" and
|
|
225
|
+
// "Paris" both hit. No-op for "us" extracts and every non-arrondissement commune.
|
|
226
|
+
row = this.#byLocality!(this.#localityKey(query.locality), streetNorm, number)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Bbox fall-through (#247): the point carries no postcode/locality of its own, but its coordinate falls
|
|
230
|
+
// inside the resolved locality's box. Only reached when the scoped probes missed AND a bbox was supplied.
|
|
231
|
+
if (!row && query.bbox) {
|
|
232
|
+
const b = query.bbox
|
|
233
|
+
const candidate = this.#byBbox!(streetNorm, number, b.minLat, b.maxLat, b.minLon, b.maxLon)
|
|
234
|
+
|
|
235
|
+
// A register row that carries its own scope and was NOT found by the scoped rungs is a different address that
|
|
236
|
+
// happens to share the street and number inside the box: `10 rue de la République, 75008 Paris` reached
|
|
237
|
+
// Servon's `10 rue de la République` (postcode 77170) 26 km away this way, at rooftop tier and 1 m uncertainty.
|
|
238
|
+
// The rung exists for points with no scope of their own; a point whose scope disagrees with the query is a miss.
|
|
239
|
+
row = candidate && !this.#scopeContradicts(candidate, query) ? candidate : undefined
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return row
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The query's locality folded the way the extract's builder folded its `locality_norm`. FR extracts key
|
|
247
|
+
* arrondissement communes at the base city (both-sides fold, see the BAN builder + stripArrondissement), so "Paris
|
|
248
|
+
* 13e Arrondissement" and "Paris" both hit; a no-op for every other locale.
|
|
249
|
+
*/
|
|
250
|
+
#localityKey(locality: string): NameKey {
|
|
251
|
+
return this.#locale === "fr"
|
|
252
|
+
? stripArrondissement(normalizeLocalityForKey(locality))
|
|
253
|
+
: normalizeLocalityForKey(locality)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Whether a row's OWN postcode or locality names a different place than the query did. Absent scope on the row is not
|
|
258
|
+
* a contradiction — it is the case the bbox rung was built for — and a rung that matched ON a field cannot contradict
|
|
259
|
+
* it, so at the postcode rung only the locality can disagree and at the bbox rung either can.
|
|
260
|
+
*
|
|
261
|
+
* The locality is consulted only on an extract whose keys are full names (the constructor's `localityKeys`). Under
|
|
262
|
+
* exact comparison against the US extract's abbreviated keys, the postcode rung refused `4900 Airport Pkwy, Addison
|
|
263
|
+
* TX 75001`'s own rooftop row (`addi`) and `678 Depot St, North Easton, MA 02356`'s (`easton`), and both `pass` board
|
|
264
|
+
* rows fell to interpolation 144–198 m away — invisible to a 1 km grade (#2155). `servon` against `paris` and
|
|
265
|
+
* `werlitzsch` against `krensitz`, on the BAN and OSM extracts, are different places and still refuse.
|
|
266
|
+
*/
|
|
267
|
+
#scopeContradicts(row: AddressPointRow, query: { postcode?: string; locality?: string }): boolean {
|
|
268
|
+
if (query.postcode && row.postcode && row.postcode.trim() !== query.postcode.trim()) return true
|
|
269
|
+
|
|
270
|
+
if (this.#localityKeys === "full" && query.locality && row.locality_norm) {
|
|
271
|
+
return row.locality_norm !== this.#localityKey(query.locality)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return false
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
[Symbol.dispose](): void {
|
|
278
|
+
this.#db[Symbol.dispose]()
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -45,14 +45,12 @@
|
|
|
45
45
|
* nothing.
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
-
import {
|
|
49
|
-
import type { DatabaseSync } from "node:sqlite"
|
|
50
|
-
|
|
51
|
-
import { DatabaseClient } from "@mailwoman/core/kysley/client"
|
|
48
|
+
import { readDirectoryEntries } from "@mailwoman/core/fs/readers"
|
|
52
49
|
import { readWOFFeature } from "@mailwoman/core/resources/whosonfirst"
|
|
53
|
-
import {
|
|
50
|
+
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
51
|
+
import { join, resolvePath, type PathBuilderLike } from "path-ts"
|
|
54
52
|
|
|
55
|
-
import type { WOFDatabase } from "
|
|
53
|
+
import type { WOFDatabase } from "#schema"
|
|
56
54
|
|
|
57
55
|
/**
|
|
58
56
|
* Genuinely top-level placetypes — they never have (or need) an ancestor, so skip them.
|
|
@@ -76,23 +74,21 @@ export interface AncestryBackfillResult {
|
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
/**
|
|
79
|
-
* Discover the `data` directories under a WOF repos root that hold
|
|
77
|
+
* Discover the `data` directories under a WOF repos root that hold attached geojson, e.g.
|
|
80
78
|
* `<root>/whosonfirst-data/whosonfirst-data-admin-us/data`. Resolves an id to its geojson via these roots. Accepts both
|
|
81
79
|
* the nested lab layout (a `whosonfirst-data` group dir holding the admin repos) and a flat layout (admin repos
|
|
82
80
|
* directly under the root); searches at most two directory levels deep.
|
|
83
81
|
*/
|
|
84
|
-
export function discoverAdminDataRoots(reposRoot:
|
|
82
|
+
export async function discoverAdminDataRoots(reposRoot: PathBuilderLike): Promise<string[]> {
|
|
85
83
|
const roots: string[] = []
|
|
86
84
|
|
|
87
|
-
const visit = (dir: string, depth: number): void => {
|
|
85
|
+
const visit = async (dir: string, depth: number): Promise<void> => {
|
|
88
86
|
if (depth > 2) return
|
|
89
87
|
|
|
90
88
|
let names: string[]
|
|
91
89
|
|
|
92
90
|
try {
|
|
93
|
-
names =
|
|
94
|
-
.filter((e) => e.isDirectory())
|
|
95
|
-
.map((e) => e.name)
|
|
91
|
+
names = (await readDirectoryEntries(dir)).filter((e) => e.isDirectory()).map((e) => e.name)
|
|
96
92
|
} catch {
|
|
97
93
|
return
|
|
98
94
|
}
|
|
@@ -103,12 +99,12 @@ export function discoverAdminDataRoots(reposRoot: string): string[] {
|
|
|
103
99
|
if (name === "data") {
|
|
104
100
|
roots.push(child)
|
|
105
101
|
} else if (name.startsWith("whosonfirst-data")) {
|
|
106
|
-
visit(child, depth + 1)
|
|
102
|
+
await visit(child, depth + 1)
|
|
107
103
|
}
|
|
108
104
|
}
|
|
109
105
|
}
|
|
110
106
|
|
|
111
|
-
visit(reposRoot, 0)
|
|
107
|
+
await visit(resolvePath(reposRoot), 0)
|
|
112
108
|
|
|
113
109
|
return roots
|
|
114
110
|
}
|
|
@@ -136,18 +132,17 @@ function placetypeFromKey(key: string): string | null {
|
|
|
136
132
|
* skipped rows would have `noGeojson`-skipped anyway. Omit `maxID` (default) for the legacy WOF-only DBs.
|
|
137
133
|
*/
|
|
138
134
|
export async function backfillAncestorsFromHierarchy(
|
|
139
|
-
db:
|
|
135
|
+
db: DatabaseClient<WOFDatabase>,
|
|
140
136
|
geojsonRoots: readonly string[],
|
|
141
137
|
opts: { maxID?: number } = {}
|
|
142
138
|
): Promise<AncestryBackfillResult> {
|
|
143
139
|
const maxID = opts.maxID ?? Number.MAX_SAFE_INTEGER
|
|
144
|
-
const kdb = new DatabaseClient<WOFDatabase>({ database: db })
|
|
145
140
|
|
|
146
141
|
// "No country-tier ancestor" is the dead-end signal at any depth — see the module docstring. The
|
|
147
142
|
// earlier "<= 1 ancestor row" test only caught the dead end's origin, never the children that
|
|
148
143
|
// inherit it (a child of a repaired -4 place has two rows: itself and that parent) (#1445).
|
|
149
144
|
// The id bound is stated first so SQLite prunes by the PK index before the NOT EXISTS runs at all.
|
|
150
|
-
const candidateBase =
|
|
145
|
+
const candidateBase = db
|
|
151
146
|
.selectFrom("spr")
|
|
152
147
|
.where("id", "<", maxID)
|
|
153
148
|
.where((eb) =>
|
|
@@ -172,7 +167,7 @@ export async function backfillAncestorsFromHierarchy(
|
|
|
172
167
|
// (measured 2026-08-04).
|
|
173
168
|
const alreadyPresent = new Map<number, Set<number>>()
|
|
174
169
|
|
|
175
|
-
for (const row of await
|
|
170
|
+
for (const row of await db
|
|
176
171
|
.selectFrom("ancestors")
|
|
177
172
|
.select(["id", "ancestor_id"])
|
|
178
173
|
.where("id", "in", candidateBase.select("spr.id"))
|
|
@@ -198,7 +193,7 @@ export async function backfillAncestorsFromHierarchy(
|
|
|
198
193
|
|
|
199
194
|
for (const { id, placetype } of candidates) {
|
|
200
195
|
if (placetype && TOP_PLACETYPES.has(placetype)) continue
|
|
201
|
-
const gj = readWOFFeature(id, geojsonRoots)
|
|
196
|
+
const gj = await readWOFFeature(id, geojsonRoots)
|
|
202
197
|
const hierarchy = gj?.properties?.["wof:hierarchy"]
|
|
203
198
|
|
|
204
199
|
if (!hierarchy || !hierarchy.length) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* joined with `spr` for canonical names + centroids, ordered NEAREST-FIRST (deepest placetype
|
|
8
8
|
* first, country last).
|
|
9
9
|
*
|
|
10
|
-
* Factored out of `
|
|
10
|
+
* Factored out of `WOFSQLitePlaceLookup.ancestors()` (#404) so the reverse geocoder (`reverse.ts`,
|
|
11
11
|
* #484) reuses the SAME walk instead of growing a second one. The placetype-specificity ordering
|
|
12
12
|
* lives here as `PLACETYPE_DEPTH` — a single TS map instead of the previous SQL CASE, and
|
|
13
13
|
* extended below `localadmin` (locality/borough/neighbourhood/microhood now rank correctly
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
* geocoding always does).
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type {
|
|
18
|
+
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
19
|
+
|
|
20
|
+
import { allRows } from "#sqlite-utils"
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* WOF placetype → containment depth, coarsest = 1. Higher = finer. Placetypes we never resolve (continent, empire, …)
|
|
@@ -57,19 +59,22 @@ export interface AncestorPlaceRow {
|
|
|
57
59
|
|
|
58
60
|
/**
|
|
59
61
|
* The ancestor lineage of `id` — self excluded, nearest-first. Returns `[]` when the place has no recorded ancestry.
|
|
60
|
-
* NOT memoized here; `
|
|
62
|
+
* NOT memoized here; `WOFSQLitePlaceLookup` keeps its own per-id cache.
|
|
61
63
|
*/
|
|
62
|
-
export function ancestorLineage(db:
|
|
63
|
-
const rows =
|
|
64
|
-
.prepare(
|
|
64
|
+
export function ancestorLineage<DB>(db: DatabaseClient<DB>, id: number, schemaName = "main"): AncestorPlaceRow[] {
|
|
65
|
+
const rows = allRows<AncestorPlaceRow>(
|
|
66
|
+
db.prepare(
|
|
65
67
|
`SELECT a.ancestor_id AS id, a.ancestor_placetype AS placetype, s.name AS name,
|
|
66
68
|
s.country AS country, s.latitude AS lat, s.longitude AS lon
|
|
67
69
|
FROM ${schemaName}.ancestors a JOIN ${schemaName}.spr s ON s.id = a.ancestor_id
|
|
68
70
|
WHERE a.id = ? AND a.ancestor_id != a.id`
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
+
),
|
|
72
|
+
id
|
|
73
|
+
)
|
|
71
74
|
|
|
72
75
|
rows.sort((a, b) => placetypeDepth(b.placetype) - placetypeDepth(a.placetype))
|
|
73
76
|
|
|
74
77
|
return rows
|
|
75
78
|
}
|
|
79
|
+
|
|
80
|
+
export * from "#ancestry/backfill"
|