@mailwoman/resolver-wof-sqlite 9.2.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 +16 -19
- package/lib/address/index.ts +9 -0
- package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +24 -22
- package/{address-point-schema.ts → lib/address/point-schema.ts} +18 -4
- package/{address-point.ts → lib/address/point.ts} +89 -27
- package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
- package/{ancestry.ts → lib/ancestry/index.ts} +5 -3
- package/{build-candidate.ts → lib/build-candidate.ts} +84 -77
- package/{build-slim.ts → lib/build-slim.ts} +150 -165
- package/{candidate → lib/candidate}/alias-bags.ts +8 -6
- package/{candidate → lib/candidate}/ancestors-sidecar.ts +13 -15
- package/{candidate → lib/candidate}/country-display-names.ts +2 -2
- package/{candidate/shard-fold.ts → lib/candidate/extract-fold.ts} +26 -25
- package/{candidate → lib/candidate}/name-roles.ts +17 -16
- package/{candidate → lib/candidate}/own-name.ts +1 -1
- package/{candidate → lib/candidate}/place-attrs.ts +3 -3
- package/{candidate-ancestors-schema.ts → lib/candidate-ancestors-schema.ts} +4 -4
- package/{candidate-fts.ts → lib/candidate-fts.ts} +3 -3
- package/{candidate-importance.ts → lib/candidate-importance.ts} +53 -57
- package/{candidate-lookup.ts → lib/candidate-lookup.ts} +76 -73
- package/{candidate-schema.ts → lib/candidate-schema.ts} +5 -5
- package/{candidate-scoring.ts → lib/candidate-scoring.ts} +15 -22
- package/{capital-schema.ts → lib/capital-schema.ts} +5 -6
- package/{capitals.ts → lib/capitals.ts} +2 -2
- package/{coincident-roles.ts → lib/coincident-roles.ts} +8 -11
- package/{convention.ts → lib/convention/index.ts} +3 -3
- package/{convention-schema.ts → lib/convention/schema.ts} +2 -2
- package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +9 -10
- package/{currency-backfill.ts → lib/currency-backfill.ts} +126 -41
- package/lib/env.ts +50 -0
- package/{exact-match.ts → lib/exact-match.ts} +23 -14
- package/{sharding.ts → lib/extracts.ts} +61 -58
- package/{fst-autocomplete.ts → lib/fst/autocomplete.ts} +4 -4
- package/{fst-builder.ts → lib/fst/builder.ts} +17 -16
- 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} +41 -74
- 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} +24 -19
- package/{fts-query.ts → lib/fts/query.ts} +1 -1
- 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} +14 -13
- package/{index.ts → lib/index.ts} +37 -37
- package/{interpolation.ts → lib/interpolation.ts} +27 -25
- package/{lookup.ts → lib/lookup.ts} +129 -141
- 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} +7 -8
- package/lib/poi/index.ts +8 -0
- package/{poi-lookup.ts → lib/poi/lookup.ts} +22 -28
- package/{poi-schema.ts → lib/poi/schema.ts} +3 -4
- package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +14 -20
- package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +2 -2
- package/lib/postal/index.ts +9 -0
- package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
- package/{primary-preference.ts → lib/primary-preference.ts} +29 -10
- package/{proximity-rerank.ts → lib/proximity-rerank.ts} +2 -2
- package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
- package/{region-keys.ts → lib/region-keys.ts} +9 -9
- package/{reverse.ts → lib/reverse.ts} +34 -46
- package/{schema.ts → lib/schema.ts} +10 -0
- package/{search-fetch.ts → lib/search-fetch.ts} +29 -28
- package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
- package/{sqlite-utils.ts → lib/sqlite-utils.ts} +14 -18
- package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +5 -5
- package/{street-centroid.ts → lib/street/centroid.ts} +14 -21
- 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/{street-normalize.ts → lib/street/normalize.ts} +44 -19
- package/{street-segment-schema.ts → lib/street/segment-schema.ts} +7 -7
- package/{types.ts → lib/types.ts} +18 -12
- package/{unified-schema.ts → lib/unified-schema.ts} +20 -24
- package/lib/uprn/existence.ts +84 -0
- package/lib/uprn/index.ts +9 -0
- package/{uprn-lookup.ts → lib/uprn/lookup.ts} +14 -18
- package/{uprn-schema.ts → lib/uprn/schema.ts} +3 -3
- 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} +18 -18
- package/out/address/point-interpolation.js.map +1 -0
- package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +16 -6
- 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 → address/point.js} +71 -20
- 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} +4 -3
- package/out/ancestry/index.d.ts.map +1 -0
- package/out/{ancestry.js → ancestry/index.js} +3 -2
- package/out/ancestry/index.js.map +1 -0
- package/out/build-candidate.d.ts +30 -24
- package/out/build-candidate.d.ts.map +1 -1
- package/out/build-candidate.js +50 -52
- package/out/build-candidate.js.map +1 -1
- package/out/build-slim.d.ts +4 -4
- package/out/build-slim.d.ts.map +1 -1
- package/out/build-slim.js +124 -139
- package/out/build-slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +5 -3
- package/out/candidate/alias-bags.d.ts.map +1 -1
- package/out/candidate/alias-bags.js +2 -2
- package/out/candidate/alias-bags.js.map +1 -1
- package/out/candidate/ancestors-sidecar.d.ts +9 -10
- package/out/candidate/ancestors-sidecar.d.ts.map +1 -1
- package/out/candidate/ancestors-sidecar.js +7 -7
- package/out/candidate/ancestors-sidecar.js.map +1 -1
- package/out/candidate/country-display-names.d.ts +1 -1
- package/out/candidate/country-display-names.d.ts.map +1 -1
- package/out/candidate/country-display-names.js +1 -1
- package/out/candidate/country-display-names.js.map +1 -1
- package/out/candidate/extract-fold.d.ts +32 -0
- package/out/candidate/extract-fold.d.ts.map +1 -0
- package/out/candidate/{shard-fold.js → extract-fold.js} +20 -20
- package/out/candidate/extract-fold.js.map +1 -0
- package/out/candidate/name-roles.d.ts +13 -11
- package/out/candidate/name-roles.d.ts.map +1 -1
- package/out/candidate/name-roles.js +11 -10
- package/out/candidate/name-roles.js.map +1 -1
- package/out/candidate/own-name.d.ts +1 -1
- package/out/candidate/own-name.d.ts.map +1 -1
- package/out/candidate/own-name.js +1 -1
- package/out/candidate/own-name.js.map +1 -1
- package/out/candidate/place-attrs.d.ts +3 -3
- package/out/candidate/place-attrs.d.ts.map +1 -1
- package/out/candidate/place-attrs.js +1 -1
- package/out/candidate/place-attrs.js.map +1 -1
- package/out/candidate-ancestors-schema.d.ts +4 -4
- package/out/candidate-ancestors-schema.d.ts.map +1 -1
- package/out/candidate-ancestors-schema.js +2 -2
- package/out/candidate-ancestors-schema.js.map +1 -1
- package/out/candidate-fts.d.ts +3 -3
- package/out/candidate-fts.d.ts.map +1 -1
- package/out/candidate-fts.js +1 -1
- 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 +46 -51
- package/out/candidate-importance.js.map +1 -1
- package/out/candidate-lookup.d.ts +11 -9
- package/out/candidate-lookup.d.ts.map +1 -1
- package/out/candidate-lookup.js +61 -58
- package/out/candidate-lookup.js.map +1 -1
- package/out/candidate-schema.d.ts +5 -5
- package/out/candidate-schema.d.ts.map +1 -1
- package/out/candidate-schema.js.map +1 -1
- package/out/candidate-scoring.d.ts +7 -7
- package/out/candidate-scoring.d.ts.map +1 -1
- package/out/candidate-scoring.js +10 -14
- package/out/candidate-scoring.js.map +1 -1
- package/out/capital-schema.d.ts +3 -3
- package/out/capital-schema.d.ts.map +1 -1
- package/out/capital-schema.js +2 -2
- package/out/capital-schema.js.map +1 -1
- package/out/capitals.d.ts +1 -1
- package/out/capitals.d.ts.map +1 -1
- package/out/capitals.js +2 -2
- package/out/capitals.js.map +1 -1
- package/out/coincident-roles.d.ts +6 -5
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +2 -4
- package/out/coincident-roles.js.map +1 -1
- package/out/{convention.d.ts → convention/index.d.ts} +4 -4
- package/out/convention/index.d.ts.map +1 -0
- package/out/{convention.js → convention/index.js} +2 -2
- package/out/convention/index.js.map +1 -0
- package/out/{convention-schema.d.ts → convention/schema.d.ts} +2 -2
- package/out/convention/schema.d.ts.map +1 -0
- package/out/{convention-schema.js → convention/schema.js} +3 -3
- 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 +4 -4
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +51 -7
- package/out/currency-backfill.d.ts.map +1 -1
- package/out/currency-backfill.js +65 -49
- package/out/currency-backfill.js.map +1 -1
- 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 +5 -5
- package/out/exact-match.d.ts.map +1 -1
- package/out/exact-match.js +10 -11
- package/out/exact-match.js.map +1 -1
- 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} +2 -2
- package/out/fst/autocomplete.d.ts.map +1 -0
- package/out/{fst-autocomplete.js → fst/autocomplete.js} +3 -3
- 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} +14 -13
- 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} +10 -13
- package/out/fst/freshness.d.ts.map +1 -0
- package/out/{fst-freshness.js → fst/freshness.js} +41 -73
- 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} +16 -9
- package/out/fts/index.d.ts.map +1 -0
- package/out/{fts.js → fts/index.js} +16 -11
- 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} +1 -1
- 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} +10 -8
- package/out/geonames/postal.d.ts.map +1 -0
- package/out/{geonames-postal.js → geonames/postal.js} +9 -9
- package/out/geonames/postal.js.map +1 -0
- package/out/index.d.ts +32 -32
- 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 +10 -9
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +20 -20
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +21 -20
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +102 -112
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts.map +1 -1
- 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 +5 -5
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +3 -3
- 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} +14 -18
- package/out/poi/lookup.js.map +1 -0
- package/out/{poi-schema.d.ts → poi/schema.d.ts} +4 -4
- 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.map +1 -1
- package/out/polygon-schema.js.map +1 -1
- package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +6 -5
- package/out/postal/city-alias-lookup.d.ts.map +1 -0
- package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +11 -15
- 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} +3 -3
- package/out/{postal-city-candidate-schema.d.ts.map → postal/city-candidate-schema.d.ts.map} +1 -1
- 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 +13 -5
- package/out/primary-preference.d.ts.map +1 -1
- package/out/primary-preference.js +16 -8
- package/out/primary-preference.js.map +1 -1
- package/out/proximity-rerank.d.ts +2 -2
- package/out/proximity-rerank.d.ts.map +1 -1
- package/out/proximity-rerank.js +2 -2
- package/out/proximity-rerank.js.map +1 -1
- 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 +8 -8
- package/out/region-keys.d.ts.map +1 -1
- package/out/region-keys.js +9 -9
- package/out/region-keys.js.map +1 -1
- package/out/reverse.d.ts +6 -6
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +20 -29
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +9 -0
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +12 -10
- package/out/search-fetch.d.ts.map +1 -1
- package/out/search-fetch.js +21 -20
- package/out/search-fetch.js.map +1 -1
- 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 +8 -8
- package/out/sqlite-utils.d.ts.map +1 -1
- package/out/sqlite-utils.js +7 -8
- package/out/sqlite-utils.js.map +1 -1
- package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +6 -6
- package/out/{street-centroid-schema.d.ts.map → street/centroid-schema.d.ts.map} +1 -1
- 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} +13 -19
- 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 → street/normalize.d.ts} +25 -14
- package/out/street/normalize.d.ts.map +1 -0
- package/out/{street-normalize.js → street/normalize.js} +36 -17
- package/out/street/normalize.js.map +1 -0
- package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +8 -8
- package/out/{street-segment-schema.d.ts.map → street/segment-schema.d.ts.map} +1 -1
- 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 +18 -12
- package/out/types.d.ts.map +1 -1
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +5 -4
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +15 -18
- 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 → uprn/lookup.d.ts} +4 -4
- package/out/uprn/lookup.d.ts.map +1 -0
- package/out/{uprn-lookup.js → uprn/lookup.js} +11 -14
- package/out/uprn/lookup.js.map +1 -0
- package/out/{uprn-schema.d.ts → uprn/schema.d.ts} +4 -4
- package/out/uprn/schema.d.ts.map +1 -0
- package/out/{uprn-schema.js → uprn/schema.js} +4 -4
- package/out/uprn/schema.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +184 -26
- package/out/weights-overlay-linker.d.ts.map +1 -1
- package/out/weights-overlay-linker.js +338 -86
- package/out/weights-overlay-linker.js.map +1 -1
- package/package.json +465 -269
- 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.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/candidate/shard-fold.d.ts +0 -31
- package/out/candidate/shard-fold.d.ts.map +0 -1
- package/out/candidate/shard-fold.js.map +0 -1
- package/out/convention-schema.d.ts.map +0 -1
- package/out/convention-schema.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.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/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/sharding.d.ts +0 -114
- package/out/sharding.d.ts.map +0 -1
- package/out/sharding.js.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.map +0 -1
- package/out/street-normalize.js.map +0 -1
- package/out/uprn-lookup.d.ts.map +0 -1
- package/out/uprn-lookup.js.map +0 -1
- package/out/uprn-schema.d.ts.map +0 -1
- package/out/uprn-schema.js.map +0 -1
- package/weights-overlay-linker.ts +0 -377
- /package/{name-score.ts → lib/name-score.ts} +0 -0
- /package/{polygon-schema.ts → lib/polygon-schema.ts} +0 -0
- /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Node reader for `nsul.db` — the GB UPRN → unit-postcode register (`nsul/schema.ts`). Two probes,
|
|
7
|
+
* both synchronous `.prepare()` hits in the `uprn/lookup.ts` style:
|
|
8
|
+
*
|
|
9
|
+
* - **`postcodeForUPRN(uprn)`**: primary-key hit on the `WITHOUT ROWID` table.
|
|
10
|
+
* - **`uprnsForPostcode(postcode)`**: the `pcds_compact` index, answering every UPRN the register
|
|
11
|
+
* assigns to one unit postcode with the point OS publishes for each — the "assigned points and
|
|
12
|
+
* their bound" the physical-constraint design record names as the prior's soft structure.
|
|
13
|
+
*
|
|
14
|
+
* ## `null` and `[]` are claims, scoped by coverage
|
|
15
|
+
*
|
|
16
|
+
* The register designates GB complete (every UPRN in AddressBase with a Code-Point Open postcode),
|
|
17
|
+
* and the builder writes `layer_coverage` with basis `designated` for every cell the register
|
|
18
|
+
* touches. Inside a covered cell an empty answer is evidence of absence: no GB UPRN by that number
|
|
19
|
+
* carries a Code-Point postcode, or no UPRN carries that postcode. Two absences the reader cannot
|
|
20
|
+
* tell from those are recorded in `nsul_meta` as counts rather than as rows — a UPRN whose `PCDS` is
|
|
21
|
+
* null (its postcode is not in Code-Point Open) and one Open UPRN publishes no coordinate for — so a
|
|
22
|
+
* caller building negative evidence reads the coverage table and those counts, not this reader
|
|
23
|
+
* alone. Outside coverage (Northern Ireland, the Isle of Man, the Channel Islands) the answer is
|
|
24
|
+
* UNKNOWN, per the meaning-of-zero rule.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
28
|
+
|
|
29
|
+
import { compactPostcode, type NSULDatabase } from "#nsul/schema"
|
|
30
|
+
import { prepareAll, prepareGet } from "#sqlite-utils"
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The unit postcode the register assigns to a UPRN, in both stored forms.
|
|
34
|
+
*/
|
|
35
|
+
export interface NSULPostcode {
|
|
36
|
+
/**
|
|
37
|
+
* As NSUL writes it — `RG40 4HR`.
|
|
38
|
+
*/
|
|
39
|
+
pcds: string
|
|
40
|
+
/**
|
|
41
|
+
* Space removed — `RG404HR`, Code-Point Open's `spr.name` form.
|
|
42
|
+
*/
|
|
43
|
+
pcdsCompact: string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* One UPRN assigned to a unit postcode, with the point `uprn.db` holds for it.
|
|
48
|
+
*/
|
|
49
|
+
export interface NSULAssignedPoint {
|
|
50
|
+
uprn: number
|
|
51
|
+
latitude: number
|
|
52
|
+
longitude: number
|
|
53
|
+
/**
|
|
54
|
+
* 48-bit short res-9 H3 cell, as `uprn.db` stores it.
|
|
55
|
+
*/
|
|
56
|
+
h3Cell: number
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface NSULLookupOpts {
|
|
60
|
+
/**
|
|
61
|
+
* Path to a `nsul.db` built by `mailwoman`'s gazetteer pipeline. Opened read-only.
|
|
62
|
+
*/
|
|
63
|
+
databasePath?: string
|
|
64
|
+
/**
|
|
65
|
+
* Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
|
|
66
|
+
*/
|
|
67
|
+
database?: DatabaseClient<NSULDatabase>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface PostcodeRow {
|
|
71
|
+
pcds: string
|
|
72
|
+
pcds_compact: string
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface PointRow {
|
|
76
|
+
uprn: number
|
|
77
|
+
lat: number
|
|
78
|
+
lon: number
|
|
79
|
+
h3_cell: number
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Node reader over `nsul.db`. `implements Disposable` so callers can `using lookup = new NSULLookup(...)` — the same
|
|
84
|
+
* precedent as `UPRNLookup`.
|
|
85
|
+
*/
|
|
86
|
+
export class NSULLookup implements Disposable {
|
|
87
|
+
#db: DatabaseClient<NSULDatabase>
|
|
88
|
+
/**
|
|
89
|
+
* Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
|
|
90
|
+
* ownership is membership rather than a flag a later branch has to check.
|
|
91
|
+
*/
|
|
92
|
+
readonly #resources = new DisposableStack()
|
|
93
|
+
|
|
94
|
+
readonly #postcodeProbe: (uprn: number) => PostcodeRow | undefined
|
|
95
|
+
readonly #pointsProbe: (pcdsCompact: string) => PointRow[]
|
|
96
|
+
|
|
97
|
+
constructor(opts: NSULLookupOpts) {
|
|
98
|
+
if (opts.database) {
|
|
99
|
+
this.#db = opts.database
|
|
100
|
+
} else if (opts.databasePath) {
|
|
101
|
+
this.#db = this.#resources.use(new DatabaseClient<NSULDatabase>(opts.databasePath, { readOnly: true }))
|
|
102
|
+
} else {
|
|
103
|
+
throw new Error("NSULLookup needs `databasePath` or `database`")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.#postcodeProbe = prepareGet<[number], PostcodeRow, NSULDatabase>(
|
|
107
|
+
this.#db,
|
|
108
|
+
"SELECT pcds, pcds_compact FROM uprn_postcode WHERE uprn = ?"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
this.#pointsProbe = prepareAll<[string], PointRow, NSULDatabase>(
|
|
112
|
+
this.#db,
|
|
113
|
+
"SELECT uprn, lat, lon, h3_cell FROM uprn_postcode WHERE pcds_compact = ? ORDER BY uprn"
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The unit postcode the register assigns to `uprn`, or `null` when the register holds no row for it (see the module
|
|
119
|
+
* docstring for what that `null` claims).
|
|
120
|
+
*/
|
|
121
|
+
postcodeForUPRN(uprn: number): NSULPostcode | null {
|
|
122
|
+
const row = this.#postcodeProbe(uprn)
|
|
123
|
+
|
|
124
|
+
return row ? { pcds: row.pcds, pcdsCompact: row.pcds_compact } : null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Every UPRN the register assigns to one unit postcode, with its published point, in ascending UPRN order. The key is
|
|
129
|
+
* compacted through {@link compactPostcode} first, so `PO21 1HR` and `PO211HR` answer identically. An empty array is
|
|
130
|
+
* the register's answer, scoped as the module docstring says.
|
|
131
|
+
*/
|
|
132
|
+
uprnsForPostcode(postcode: string): NSULAssignedPoint[] {
|
|
133
|
+
return this.#pointsProbe(compactPostcode(postcode)).map((row) => ({
|
|
134
|
+
uprn: row.uprn,
|
|
135
|
+
latitude: row.lat,
|
|
136
|
+
longitude: row.lon,
|
|
137
|
+
h3Cell: row.h3_cell,
|
|
138
|
+
}))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
[Symbol.dispose](): void {
|
|
142
|
+
this.#resources[Symbol.dispose]()
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Typed schema for `nsul.db` — the GB UPRN → unit-postcode register: the ONS **National Statistics
|
|
7
|
+
* UPRN Lookup** (NSUL) joined to the WGS84 point OS Open UPRN publishes for the same UPRN. One row per
|
|
8
|
+
* GB UPRN that carries a unit postcode AND has a published coordinate; the postcode is Code-Point
|
|
9
|
+
* Open's, so this table and `postcode-gb.bin` agree by construction on the universe of unit postcodes.
|
|
10
|
+
*
|
|
11
|
+
* ## Why this table exists
|
|
12
|
+
*
|
|
13
|
+
* Code-Point Open gives one coordinate per unit postcode; Open UPRN gives one coordinate per
|
|
14
|
+
* addressable object; neither says which object carries which postcode. NSUL does, as field `PCDS`,
|
|
15
|
+
* under OGL-UK-3.0. The `PO`-area measurement that produced this design (recorded on #1975) showed a
|
|
16
|
+
* nearest-centroid reconstruction of the register is exact on 69.6% of 531,266 UPRNs and a building
|
|
17
|
+
* footprint adds nothing, so the register is stored rather than inferred.
|
|
18
|
+
*
|
|
19
|
+
* ## Shape
|
|
20
|
+
*
|
|
21
|
+
* `uprn_postcode` is `WITHOUT ROWID` keyed on the UPRN: small fixed rows, probed by primary key, with
|
|
22
|
+
* one secondary index on `pcds_compact`. The postcode is stored twice on purpose — `pcds` exactly as
|
|
23
|
+
* NSUL writes it (`RG40 4HR`, one space) and `pcds_compact` with the space removed (`RG404HR`), which
|
|
24
|
+
* is the form Code-Point Open's `spr.name` uses, so the two artifacts join on a column rather than an
|
|
25
|
+
* expression. `lat`/`lon`/`h3_cell` are COPIED from `uprn.db` at build time by UPRN join — OS's own
|
|
26
|
+
* WGS84 columns, never a reprojection of NSUL's `GRIDGB1E`/`GRIDGB1N` — so a coordinate here is
|
|
27
|
+
* byte-identical to the one `uprn.db` holds for the same UPRN.
|
|
28
|
+
*
|
|
29
|
+
* The DB also embeds the layer-contract tables from `@mailwoman/core/layers`; the builder
|
|
30
|
+
* (`packages/mailwoman/lib/gazetteer-pipeline/nsul-layer.ts`) writes the manifest and coverage.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import type { LayerContractDatabase } from "@mailwoman/core/layers"
|
|
34
|
+
import { sql, type Kysely } from "kysely"
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolution of the `h3_cell` column — the same res-9 spine `uprn.db` keys on, because the value is copied from it.
|
|
38
|
+
*/
|
|
39
|
+
export const NSUL_H3_RESOLUTION = 9
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolution of the layer's `layer_coverage` cells — coarse, per the contract, and the same as `uprn.db`'s so the two
|
|
43
|
+
* layers' coverage tables describe the same cells.
|
|
44
|
+
*/
|
|
45
|
+
export const NSUL_COVERAGE_H3_RESOLUTION = 6
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* One UPRN with its unit postcode and the point OS publishes for it.
|
|
49
|
+
*/
|
|
50
|
+
export interface UPRNPostcodeTable {
|
|
51
|
+
/**
|
|
52
|
+
* The Unique Property Reference Number — up to 12 digits, so always within `Number.MAX_SAFE_INTEGER`.
|
|
53
|
+
*/
|
|
54
|
+
uprn: number
|
|
55
|
+
/**
|
|
56
|
+
* The unit postcode as NSUL writes it — outward code, one space, inward code (`RG40 4HR`).
|
|
57
|
+
*/
|
|
58
|
+
pcds: string
|
|
59
|
+
/**
|
|
60
|
+
* {@link pcds} with the space removed (`RG404HR`) — the form Code-Point Open's `spr.name` carries, and the column
|
|
61
|
+
* `uprnsForPostcode` probes.
|
|
62
|
+
*/
|
|
63
|
+
pcds_compact: string
|
|
64
|
+
/**
|
|
65
|
+
* WGS84 latitude, copied from `uprn.db` for the same UPRN.
|
|
66
|
+
*/
|
|
67
|
+
lat: number
|
|
68
|
+
/**
|
|
69
|
+
* WGS84 longitude, copied from `uprn.db` for the same UPRN.
|
|
70
|
+
*/
|
|
71
|
+
lon: number
|
|
72
|
+
/**
|
|
73
|
+
* 48-bit short H3 cell at {@link NSUL_H3_RESOLUTION}, copied from `uprn.db` for the same UPRN.
|
|
74
|
+
*/
|
|
75
|
+
h3_cell: number
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build-provenance key/value pairs the fixed `layer_manifest` columns have no room for: the accounting counts, the
|
|
80
|
+
* header as found, the per-region row counts, the four attribution lines.
|
|
81
|
+
*/
|
|
82
|
+
export interface NSULMetaTable {
|
|
83
|
+
key: string
|
|
84
|
+
value: string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface NSULDatabase extends LayerContractDatabase {
|
|
88
|
+
uprn_postcode: UPRNPostcodeTable
|
|
89
|
+
nsul_meta: NSULMetaTable
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The compact form of a unit postcode: every space removed, upper-cased. `RG40 4HR` → `RG404HR`. The ONE derivation
|
|
94
|
+
* both the builder and every consumer share, so a caller holding NSUL's spaced form and one holding Code-Point's
|
|
95
|
+
* compact form reach the same key.
|
|
96
|
+
*/
|
|
97
|
+
export function compactPostcode(pcds: string): string {
|
|
98
|
+
return pcds.replaceAll(/\s+/g, "").toUpperCase()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function createUPRNPostcodeTable(db: Kysely<NSULDatabase>): Promise<void> {
|
|
102
|
+
await db.schema
|
|
103
|
+
.createTable("uprn_postcode")
|
|
104
|
+
.addColumn("uprn", "integer", (c) => c.primaryKey())
|
|
105
|
+
.addColumn("pcds", "text", (c) => c.notNull())
|
|
106
|
+
.addColumn("pcds_compact", "text", (c) => c.notNull())
|
|
107
|
+
.addColumn("lat", "real", (c) => c.notNull())
|
|
108
|
+
.addColumn("lon", "real", (c) => c.notNull())
|
|
109
|
+
.addColumn("h3_cell", "integer", (c) => c.notNull())
|
|
110
|
+
.modifyEnd(sql`without rowid`)
|
|
111
|
+
.execute()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function createNSULMetaTable(db: Kysely<NSULDatabase>): Promise<void> {
|
|
115
|
+
await db.schema
|
|
116
|
+
.createTable("nsul_meta")
|
|
117
|
+
.addColumn("key", "text", (c) => c.primaryKey())
|
|
118
|
+
.addColumn("value", "text", (c) => c.notNull())
|
|
119
|
+
.execute()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The `pcds_compact` index the `uprnsForPostcode` probe reads. Builders call this AFTER the bulk load
|
|
124
|
+
* (index-after-load). There is no index on the spaced `pcds`: it is derivable from `pcds_compact` through
|
|
125
|
+
* {@link compactPostcode}, and a second index over 40 million rows would buy nothing a caller cannot get by compacting
|
|
126
|
+
* its key first.
|
|
127
|
+
*/
|
|
128
|
+
export async function createNSULIndexes(db: Kysely<NSULDatabase>): Promise<void> {
|
|
129
|
+
await db.schema.createIndex("uprn_postcode_pcds_compact").on("uprn_postcode").column("pcds_compact").execute()
|
|
130
|
+
}
|
|
@@ -31,12 +31,11 @@
|
|
|
31
31
|
* should read it; new code reads the split columns.
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
import type { DatabaseSync } from "node:sqlite"
|
|
35
|
-
|
|
36
34
|
import { referentialFromPopulation } from "@mailwoman/core/resolver"
|
|
35
|
+
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
37
36
|
import type { Kysely } from "kysely"
|
|
38
37
|
|
|
39
|
-
import { allRows } from "
|
|
38
|
+
import { allRows } from "#sqlite-utils"
|
|
40
39
|
|
|
41
40
|
//#region Schema
|
|
42
41
|
|
|
@@ -205,12 +204,12 @@ export type ImportanceSplitSource = (typeof IMPORTANCE_SPLIT_SOURCES)[keyof type
|
|
|
205
204
|
*
|
|
206
205
|
* There is deliberately no ORDER BY counterpart, and there should never be one: §2's policy is that this score is
|
|
207
206
|
* carried and never ranked on. Without the column the select degrades to a literal `NULL` and the join is the empty
|
|
208
|
-
* string, so a pre-split
|
|
207
|
+
* string, so a pre-split extract's query plan is byte-identical to what it was before the split. No shipped gazetteer
|
|
209
208
|
* carries the column yet, so today that degraded form is the only one anything builds.
|
|
210
209
|
*
|
|
211
|
-
* Call it ONCE per
|
|
210
|
+
* Call it ONCE per extract and cache the result — it runs a `PRAGMA`, and the callers are per-keystroke hot.
|
|
212
211
|
*/
|
|
213
|
-
export function encyclopedicClauses(db:
|
|
212
|
+
export function encyclopedicClauses<DB>(db: DatabaseClient<DB>, schemaName: string): { select: string; join: string } {
|
|
214
213
|
let present: boolean
|
|
215
214
|
|
|
216
215
|
try {
|
|
@@ -300,7 +299,7 @@ export interface ImportanceSplit {
|
|
|
300
299
|
/**
|
|
301
300
|
* Does `table` exist in `db`, and if so which of `columns` does it have?
|
|
302
301
|
*/
|
|
303
|
-
function tableColumns(db:
|
|
302
|
+
function tableColumns<DB>(db: DatabaseClient<DB>, table: string): Set<string> {
|
|
304
303
|
try {
|
|
305
304
|
const rows = allRows<{ name: string }>(db.prepare(`PRAGMA table_info(${table})`))
|
|
306
305
|
|
|
@@ -317,7 +316,7 @@ function tableColumns(db: DatabaseSync, table: string): Set<string> {
|
|
|
317
316
|
* builder in particular must read the shipped population-only databases, the read-only 2026-08-05 staging database
|
|
318
317
|
* (legacy conflated column), and post-split builds with one code path.
|
|
319
318
|
*/
|
|
320
|
-
export function loadImportanceSplit(db:
|
|
319
|
+
export function loadImportanceSplit<DB>(db: DatabaseClient<DB>): ImportanceSplit {
|
|
321
320
|
const referential = new Map<number, number>()
|
|
322
321
|
const encyclopedic = new Map<number, number>()
|
|
323
322
|
const population = new Map<number, number>()
|
package/lib/poi/index.ts
ADDED
|
@@ -25,13 +25,12 @@
|
|
|
25
25
|
* it).
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import { DatabaseSync } from "node:sqlite"
|
|
29
|
-
|
|
30
28
|
import { haversineKm, shortCellToInt, type H3Cell } from "@mailwoman/spatial"
|
|
29
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
31
30
|
import { gridDisk, latLngToCell } from "h3-js"
|
|
32
31
|
|
|
33
|
-
import type { POICategoryCodeTable, POITable } from "
|
|
34
|
-
import { allRows } from "
|
|
32
|
+
import type { POICategoryCodeTable, POIDatabase, POITable } from "#poi/schema"
|
|
33
|
+
import { allRows } from "#sqlite-utils"
|
|
35
34
|
|
|
36
35
|
/**
|
|
37
36
|
* Resolution the `poi` table's `h3_cell` column is keyed at — matches the builder (spec §3.4).
|
|
@@ -48,8 +47,9 @@ export const POI_H3_RESOLUTION = 9
|
|
|
48
47
|
* unaffected: the loop breaks the ring it accumulates `limit` rows (cafe@Paris fills 20 by ring 2), so this ceiling
|
|
49
48
|
* never enters their probe budget. Only sparse-but-present categories that never reach `limit` scan the fuller budget —
|
|
50
49
|
* a cold, one-shot `mailwoman poi` path, not per-keystroke. 16 (not the bare threshold 14) leaves ~2 rings of margin so
|
|
51
|
-
* the
|
|
52
|
-
* window (no wrong-city false positives). The browser reader passes its own smaller `maxRings` and is
|
|
50
|
+
* the radius is stable against small db rebuilds, while staying ~4x tighter than the board's 25 km "roughly right
|
|
51
|
+
* place" window (no wrong-city false positives). The browser reader passes its own smaller `maxRings` and is
|
|
52
|
+
* untouched.
|
|
53
53
|
*/
|
|
54
54
|
const DEFAULT_MAX_RINGS = 16
|
|
55
55
|
|
|
@@ -112,7 +112,7 @@ export interface POISearchHit {
|
|
|
112
112
|
distanceM?: number
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
export interface POILookupOpts {
|
|
115
|
+
export interface POILookupOpts<DB extends POIDatabase = POIDatabase> {
|
|
116
116
|
/**
|
|
117
117
|
* Path to a `poi.db` built by the (future) POI builder. Opened read-only.
|
|
118
118
|
*/
|
|
@@ -120,7 +120,7 @@ export interface POILookupOpts {
|
|
|
120
120
|
/**
|
|
121
121
|
* Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
|
|
122
122
|
*/
|
|
123
|
-
database?:
|
|
123
|
+
database?: DatabaseClient<DB>
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
|
@@ -140,36 +140,36 @@ type POIRow = Pick<
|
|
|
140
140
|
>
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
|
-
* Node reader over `poi.db`.
|
|
144
|
-
* `[Symbol.dispose]()` explicitly), the same precedent as {@link WOFCandidateTableLookup} /
|
|
145
|
-
* {@link WOFSQLitePlaceLookup}.
|
|
143
|
+
* Node reader over `poi.db`.
|
|
146
144
|
*/
|
|
147
|
-
export class POILookup implements Disposable {
|
|
148
|
-
#db:
|
|
149
|
-
|
|
145
|
+
export class POILookup<DB extends POIDatabase = POIDatabase> implements Disposable {
|
|
146
|
+
#db: DatabaseClient<DB>
|
|
147
|
+
/**
|
|
148
|
+
* Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
|
|
149
|
+
* ownership is membership rather than a flag a later branch has to check.
|
|
150
|
+
*/
|
|
151
|
+
readonly #resources = new DisposableStack()
|
|
150
152
|
readonly #categoryToID = new Map<string, number>()
|
|
151
153
|
readonly #idToCategory = new Map<number, string>()
|
|
152
154
|
|
|
153
155
|
/**
|
|
154
156
|
* `(h3_cell, category_id)` → the cell's category-clustered range, most-confident-first.
|
|
155
157
|
*/
|
|
156
|
-
readonly #categoryCellProbe: ReturnType<
|
|
158
|
+
readonly #categoryCellProbe: ReturnType<DatabaseClient["prepare"]>
|
|
157
159
|
/**
|
|
158
160
|
* `brand_wikidata` → ALL of a brand's rows globally (partial-index range-scan); distance-sorted in JS, not SQL.
|
|
159
161
|
*/
|
|
160
|
-
readonly #brandProbe: ReturnType<
|
|
162
|
+
readonly #brandProbe: ReturnType<DatabaseClient["prepare"]>
|
|
161
163
|
/**
|
|
162
164
|
* FTS5 `MATCH` over `poi_search`, returning candidate `name_key`s to hydrate.
|
|
163
165
|
*/
|
|
164
|
-
readonly #nameFTSProbe: ReturnType<
|
|
166
|
+
readonly #nameFTSProbe: ReturnType<DatabaseClient["prepare"]>
|
|
165
167
|
|
|
166
|
-
constructor(opts: POILookupOpts) {
|
|
168
|
+
constructor(opts: POILookupOpts<DB>) {
|
|
167
169
|
if (opts.database) {
|
|
168
170
|
this.#db = opts.database
|
|
169
|
-
this.#ownsDB = false
|
|
170
171
|
} else if (opts.databasePath) {
|
|
171
|
-
this.#db = new
|
|
172
|
-
this.#ownsDB = true
|
|
172
|
+
this.#db = this.#resources.use(new DatabaseClient<DB>(opts.databasePath, { readOnly: true }))
|
|
173
173
|
} else {
|
|
174
174
|
throw new Error("POILookup needs `databasePath` or `database`")
|
|
175
175
|
}
|
|
@@ -352,14 +352,8 @@ export class POILookup implements Disposable {
|
|
|
352
352
|
return allRows<POIRow>(stmt, ...nameKeys)
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
-
close(): void {
|
|
356
|
-
if (this.#ownsDB) {
|
|
357
|
-
this.#db.close()
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
355
|
[Symbol.dispose](): void {
|
|
362
|
-
this.
|
|
356
|
+
this.#resources[Symbol.dispose]()
|
|
363
357
|
}
|
|
364
358
|
}
|
|
365
359
|
|
|
@@ -12,12 +12,11 @@
|
|
|
12
12
|
* manifest (tier `shipped`, spine `h3` res 9) and per-res-6-cell coverage.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import type { DatabaseSync } from "node:sqlite"
|
|
16
|
-
|
|
17
15
|
import type { LayerContractDatabase } from "@mailwoman/core/layers"
|
|
16
|
+
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
18
17
|
import { sql, type Kysely } from "kysely"
|
|
19
18
|
|
|
20
|
-
import type { NameKey } from "
|
|
19
|
+
import type { NameKey } from "#street/normalize"
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* One POI row. Clustered PK: h3_cell → category_id → neg_rank → rowid_key.
|
|
@@ -192,7 +191,7 @@ export const POI_FTS_TABLE = "poi_search"
|
|
|
192
191
|
/**
|
|
193
192
|
* FTS5 stays raw SQL by project rule (Kysely can't express virtual tables). Content-keyed by name_key.
|
|
194
193
|
*/
|
|
195
|
-
export function createPOISearchFTS(db:
|
|
194
|
+
export function createPOISearchFTS<DB>(db: DatabaseClient<DB>): void {
|
|
196
195
|
db.exec(
|
|
197
196
|
`CREATE VIRTUAL TABLE ${POI_FTS_TABLE} USING fts5(name, name_key UNINDEXED, h3_cell UNINDEXED, tokenize = 'unicode61')`
|
|
198
197
|
)
|
|
@@ -16,11 +16,9 @@
|
|
|
16
16
|
* uses), keeping one normalizer in one place.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
20
20
|
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
import type { PostalCityAliasDatabase } from "./postal-city-alias-schema.ts"
|
|
21
|
+
import type { PostalCityAliasDatabase } from "#postal/city-alias-schema"
|
|
24
22
|
|
|
25
23
|
export interface WOFPostalCityAliasLookupOpts {
|
|
26
24
|
/**
|
|
@@ -30,7 +28,7 @@ export interface WOFPostalCityAliasLookupOpts {
|
|
|
30
28
|
/**
|
|
31
29
|
* Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
|
|
32
30
|
*/
|
|
33
|
-
database?:
|
|
31
|
+
database?: DatabaseClient<PostalCityAliasDatabase>
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
/**
|
|
@@ -56,24 +54,22 @@ export interface PostalCityAlias {
|
|
|
56
54
|
* differs from the geographic name — the rows that carry alias signal), issued via the typed Kysely query builder
|
|
57
55
|
* against {@link PostalCityAliasDatabase}.
|
|
58
56
|
*/
|
|
59
|
-
export class WOFPostalCityAliasLookup {
|
|
60
|
-
#db:
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
export class WOFPostalCityAliasLookup implements Disposable {
|
|
58
|
+
#db: DatabaseClient<PostalCityAliasDatabase>
|
|
59
|
+
/**
|
|
60
|
+
* Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
|
|
61
|
+
* ownership is membership rather than a flag a later branch has to check.
|
|
62
|
+
*/
|
|
63
|
+
readonly #resources = new DisposableStack()
|
|
63
64
|
|
|
64
65
|
constructor(opts: WOFPostalCityAliasLookupOpts) {
|
|
65
66
|
if (opts.database) {
|
|
66
67
|
this.#db = opts.database
|
|
67
|
-
this.#ownsDB = false
|
|
68
68
|
} else if (opts.databasePath) {
|
|
69
|
-
this.#db = new
|
|
70
|
-
this.#ownsDB = true
|
|
69
|
+
this.#db = this.#resources.use(new DatabaseClient<PostalCityAliasDatabase>(opts.databasePath, { readOnly: true }))
|
|
71
70
|
} else {
|
|
72
71
|
throw new Error("WOFPostalCityAliasLookup needs `databasePath` or `database`")
|
|
73
72
|
}
|
|
74
|
-
|
|
75
|
-
// `#kdb` wraps `#db` for the typed query; close() owns the raw handle directly (sync).
|
|
76
|
-
this.#kdb = new DatabaseClient<PostalCityAliasDatabase>({ database: this.#db })
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
/**
|
|
@@ -85,7 +81,7 @@ export class WOFPostalCityAliasLookup {
|
|
|
85
81
|
|
|
86
82
|
if (!pc) return []
|
|
87
83
|
|
|
88
|
-
const rows = await this.#
|
|
84
|
+
const rows = await this.#db
|
|
89
85
|
.selectFrom("postal_city_alias")
|
|
90
86
|
.select(["postal_city", "geo_locality", "n"])
|
|
91
87
|
.where("postcode", "=", pc)
|
|
@@ -95,9 +91,7 @@ export class WOFPostalCityAliasLookup {
|
|
|
95
91
|
return rows.map((r) => ({ postalCity: String(r.postal_city), geoLocality: String(r.geo_locality), n: Number(r.n) }))
|
|
96
92
|
}
|
|
97
93
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.#db.close()
|
|
101
|
-
}
|
|
94
|
+
[Symbol.dispose](): void {
|
|
95
|
+
this.#resources[Symbol.dispose]()
|
|
102
96
|
}
|
|
103
97
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { sql, type Kysely } from "kysely"
|
|
22
22
|
|
|
23
|
-
import type { NameKey } from "
|
|
23
|
+
import type { NameKey } from "#street/normalize"
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* One postal-city → geo-locality edge, keyed exactly by `(name_key, postcode)`. The probe returns the geographic
|
|
@@ -55,7 +55,7 @@ export interface PostalCityCandidateDatabase {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* The table name the lookup probes (existence-
|
|
58
|
+
* The table name the lookup probes (existence-restricted, so an old candidate.db without it is byte-stable).
|
|
59
59
|
*/
|
|
60
60
|
export const POSTAL_CITY_CANDIDATE_TABLE = "postal_city_candidate"
|
|
61
61
|
|
|
@@ -4,22 +4,24 @@
|
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
6
|
* SQLite-backed postcode lookup for the postcode anchor (#240). A thin exact-match resolver over
|
|
7
|
-
* one or more `postalcode-*.db`
|
|
7
|
+
* one or more `postalcode-*.db` extracts (the `spr` schema built by `build-unified-wof --placetypes
|
|
8
8
|
* postalcode`, then centroid-backfilled by `scripts/backfill-postcode-centroids.ts`).
|
|
9
9
|
*
|
|
10
10
|
* This is the production implementation of the `PostcodeResolver` interface consumed by
|
|
11
11
|
* `@mailwoman/neural`'s `extractPostcodeAnchors`. It is deliberately dumb: an indexed exact-match
|
|
12
|
-
* on the postcode string across every
|
|
12
|
+
* on the postcode string across every extract, unioned. No FTS, no ranking, no proximity — the
|
|
13
13
|
* anchor only needs "does this string exist as a postcode, in which countries, near where". A
|
|
14
|
-
* future WASM build swaps this for an FST-backed resolver behind the same `lookup()`
|
|
14
|
+
* future WASM build swaps this for an FST-backed resolver behind the same `lookup()` interface.
|
|
15
15
|
*
|
|
16
|
-
* Why multiple
|
|
17
|
-
* query to ONE
|
|
18
|
-
* single query could only ever hit one country's
|
|
19
|
-
* countries to build its country posterior, so it queries each
|
|
16
|
+
* Why multiple extracts instead of the multi-extract `WOFSQLitePlaceLookup`: that resolver routes a
|
|
17
|
+
* query to ONE extract by placetype, but every postcode extract shares `placetype='postalcode'`, so a
|
|
18
|
+
* single query could only ever hit one country's extract. The anchor needs the union across
|
|
19
|
+
* countries to build its country posterior, so it queries each extract directly.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
23
|
+
|
|
24
|
+
import type { WOFDatabase } from "#schema"
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* A gazetteer hit. `lat`/`lon` of 0 means the postcode is known but has no centroid (no admin parent).
|
|
@@ -34,19 +36,19 @@ const LOOKUP_SQL =
|
|
|
34
36
|
"SELECT country, latitude AS lat, longitude AS lon FROM spr WHERE name = ? AND placetype = 'postalcode' AND is_current != 0"
|
|
35
37
|
|
|
36
38
|
export class WOFPostcodeLookup {
|
|
37
|
-
readonly #dbs:
|
|
38
|
-
readonly #stmts: ReturnType<
|
|
39
|
+
readonly #dbs: DatabaseClient<WOFDatabase>[]
|
|
40
|
+
readonly #stmts: ReturnType<DatabaseClient["prepare"]>[]
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
|
-
* Open each
|
|
43
|
+
* Open each extract read-only and prepare its exact-match statement.
|
|
42
44
|
*/
|
|
43
45
|
constructor(dbPaths: readonly string[]) {
|
|
44
|
-
this.#dbs = dbPaths.map((p) => new
|
|
46
|
+
this.#dbs = dbPaths.map((p) => new DatabaseClient<WOFDatabase>(p, { readOnly: true }))
|
|
45
47
|
this.#stmts = this.#dbs.map((db) => db.prepare(LOOKUP_SQL))
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
|
-
* Exact-match the postcode across every
|
|
51
|
+
* Exact-match the postcode across every extract and union the rows.
|
|
50
52
|
*/
|
|
51
53
|
lookup(postcode: string): PostcodePlace[] {
|
|
52
54
|
const out: PostcodePlace[] = []
|
|
@@ -60,9 +62,9 @@ export class WOFPostcodeLookup {
|
|
|
60
62
|
return out
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
[Symbol.dispose](): void {
|
|
64
66
|
for (const db of this.#dbs) {
|
|
65
|
-
db.
|
|
67
|
+
db.destroy()
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
}
|