@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
|
@@ -29,23 +29,23 @@
|
|
|
29
29
|
* (both derive purely from `spr` + `names` — see `fts.ts`). That means `WOFSQLitePlaceLookup`
|
|
30
30
|
* opens the slim DB without any code change — it sees a smaller universe, nothing more.
|
|
31
31
|
*
|
|
32
|
-
* Multi-
|
|
33
|
-
* into the single output DB. The postcode
|
|
34
|
-
* everything else. Empty / missing input paths are skipped (callers pass `""` when a
|
|
32
|
+
* Multi-extract inputs (e.g. admin + postcode) are processed in sequence; selected rows accumulate
|
|
33
|
+
* into the single output DB. The postcode extract contributes only postcodes; admin contributes
|
|
34
|
+
* everything else. Empty / missing input paths are skipped (callers pass `""` when a extract, such
|
|
35
35
|
* as a custom postcode DB, isn't built yet).
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
38
|
+
import { statPath, pathExists } from "@mailwoman/core/fs/readers"
|
|
39
|
+
import { temporaryDirectory } from "@mailwoman/core/fs/temporary"
|
|
40
|
+
import { copyFileTo, removePath } from "@mailwoman/core/fs/writers"
|
|
41
|
+
import { countRows } from "@mailwoman/sqlite"
|
|
42
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
43
|
+
import { sealDatabase } from "@mailwoman/sqlite/sealed-db"
|
|
44
|
+
import { sql } from "kysely"
|
|
45
|
+
import type { Kysely } from "kysely"
|
|
42
46
|
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import { Kysely, sql } from "kysely"
|
|
46
|
-
|
|
47
|
-
import { buildPlaceSearchFTS, PLACE_BBOX_TABLE, PLACE_POPULATION_TABLE, PLACE_SEARCH_TABLE } from "./fts.ts"
|
|
48
|
-
import type { NamesTable, SprTable } from "./schema.ts"
|
|
47
|
+
import { buildPlaceSearchFTS, PLACE_BBOX_TABLE, PLACE_POPULATION_TABLE, PLACE_SEARCH_TABLE } from "#fts/index"
|
|
48
|
+
import type { NamesTable, SprTable, WOFDatabase } from "#schema"
|
|
49
49
|
|
|
50
50
|
export interface BuildSlimOptions {
|
|
51
51
|
/**
|
|
@@ -69,7 +69,7 @@ export interface BuildSlimOptions {
|
|
|
69
69
|
* external `content=`), so once it's built `names` is only the build-time source — the resolver queries
|
|
70
70
|
* `place_search` + `spr` + `place_population` + `coincident_roles` and never reads `names` at runtime. Dropping it is
|
|
71
71
|
* the single biggest size win (~2/3 of the file for a multi-locale build; see #359). A future consumer that needs raw
|
|
72
|
-
* alt-names at runtime should ship a SEPARATE
|
|
72
|
+
* alt-names at runtime should ship a SEPARATE extract rather than re-bloat the hot DB.
|
|
73
73
|
*/
|
|
74
74
|
dropNames?: boolean
|
|
75
75
|
/**
|
|
@@ -149,65 +149,59 @@ export async function buildSlimWOFDatabase(opts: BuildSlimOptions): Promise<Buil
|
|
|
149
149
|
const topLocalities = opts.topLocalitiesPerCountry ?? 1000
|
|
150
150
|
const progress = opts.onProgress ?? (() => {})
|
|
151
151
|
|
|
152
|
-
// Callers pass `""` for
|
|
152
|
+
// Callers pass `""` for extracts that don't exist yet (e.g. a not-yet-built custom postcode DB).
|
|
153
153
|
// Skip empties up front; require every remaining path to exist.
|
|
154
154
|
const inputs = opts.inputs.filter((p) => p.length > 0)
|
|
155
155
|
|
|
156
156
|
if (!inputs.length) throw new Error("no input WOF dbs provided")
|
|
157
157
|
|
|
158
158
|
for (const input of inputs) {
|
|
159
|
-
if (!
|
|
159
|
+
if (!(await pathExists(input))) throw new Error(`input WOF db not found: ${input}`)
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
progress("init", `${inputs.length} input(s) → ${opts.output}`)
|
|
163
163
|
|
|
164
|
-
if (
|
|
165
|
-
|
|
164
|
+
if (await pathExists(opts.output)) {
|
|
165
|
+
await removePath(opts.output)
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// Open the output DB and create the empty schema. We discover the schema from the FIRST input
|
|
169
169
|
// (raw sqlite_master read — Kysely doesn't model that) so the output mirrors source column
|
|
170
170
|
// ordering / types. `CREATE TABLE AS SELECT` flattens types to dynamic, which would break
|
|
171
171
|
// callers that rely on column-affinity behavior.
|
|
172
|
-
const out = new
|
|
172
|
+
const out = new DatabaseClient<BuildSchema>(opts.output)
|
|
173
173
|
let result: BuildSlimResult
|
|
174
174
|
|
|
175
175
|
try {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
throw new Error(`source DB ${inputs[0]} is missing required table '${table}'`)
|
|
196
|
-
}
|
|
176
|
+
using firstSource = new DatabaseClient<WOFDatabase>(inputs[0]!, { readOnly: true })
|
|
177
|
+
|
|
178
|
+
progress("schema", "copying spr / names / place_population schemas from first input")
|
|
179
|
+
|
|
180
|
+
for (const table of COPIED_TABLES) {
|
|
181
|
+
const createSQL = firstSource
|
|
182
|
+
.prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?`)
|
|
183
|
+
.get(table) as { sql?: string } | undefined
|
|
184
|
+
|
|
185
|
+
if (createSQL?.sql) {
|
|
186
|
+
// Raw DDL by design (introspect-and-replay): we exec the SOURCE DB's own CREATE TABLE
|
|
187
|
+
// string read from sqlite_master, so a static Kysely builder can't express it. See AGENTS.md.
|
|
188
|
+
out.exec(createSQL.sql)
|
|
189
|
+
} else if (table === PLACE_POPULATION_TABLE) {
|
|
190
|
+
// Older source builds may predate the aux table — create it empty so the per-source
|
|
191
|
+
// copy + ranking have somewhere to land. Sparse-by-design; missing rows are fine.
|
|
192
|
+
out.exec(PLACE_POPULATION_DDL)
|
|
193
|
+
} else {
|
|
194
|
+
throw new Error(`source DB ${inputs[0]} is missing required table '${table}'`)
|
|
197
195
|
}
|
|
198
|
-
|
|
199
|
-
// PRIMARY KEY on spr.id + place_population.id come from the schemas we copied; an explicit
|
|
200
|
-
// index on names.id helps the per-id INSERT SELECT later.
|
|
201
|
-
out.exec(`CREATE INDEX IF NOT EXISTS names_id_idx ON names(id);`)
|
|
202
|
-
} finally {
|
|
203
|
-
firstSource.close()
|
|
204
196
|
}
|
|
205
197
|
|
|
206
|
-
|
|
198
|
+
// PRIMARY KEY on spr.id + place_population.id come from the schemas we copied; an explicit
|
|
199
|
+
// index on names.id helps the per-id INSERT SELECT later.
|
|
200
|
+
out.exec(`CREATE INDEX IF NOT EXISTS names_id_idx ON names(id);`)
|
|
207
201
|
|
|
208
202
|
// Pull rows from each input.
|
|
209
203
|
for (const inputPath of inputs) {
|
|
210
|
-
await copyFromSource(out,
|
|
204
|
+
await copyFromSource(out, out, inputPath, countries, topLocalities, progress)
|
|
211
205
|
}
|
|
212
206
|
|
|
213
207
|
// Build the resolver virtual tables on the trimmed row set. Both place_search (FTS5) and
|
|
@@ -264,21 +258,21 @@ export async function buildSlimWOFDatabase(opts: BuildSlimOptions): Promise<Buil
|
|
|
264
258
|
|
|
265
259
|
result = {
|
|
266
260
|
outputPath: opts.output,
|
|
267
|
-
outputBytes:
|
|
261
|
+
outputBytes: (await statPath(opts.output)).size,
|
|
268
262
|
rowCounts,
|
|
269
263
|
}
|
|
270
264
|
} finally {
|
|
271
|
-
out.
|
|
265
|
+
await out.destroy()
|
|
272
266
|
}
|
|
273
267
|
|
|
274
268
|
// The sealed-artifact invariant: a built DB is a read-only asset from the moment it exists.
|
|
275
|
-
sealDatabase(opts.output)
|
|
269
|
+
await sealDatabase(opts.output)
|
|
276
270
|
|
|
277
271
|
return result
|
|
278
272
|
}
|
|
279
273
|
|
|
280
274
|
async function copyFromSource(
|
|
281
|
-
out:
|
|
275
|
+
out: DatabaseClient<BuildSchema>,
|
|
282
276
|
kysely: Kysely<BuildSchema>,
|
|
283
277
|
inputPath: string,
|
|
284
278
|
countries: string[],
|
|
@@ -290,134 +284,125 @@ async function copyFromSource(
|
|
|
290
284
|
// ATTACH will still want a writable journal on the side; copying to /tmp dodges that without
|
|
291
285
|
// mutating the canonical files in /mnt/playpen/mailwoman-data/wof/. ATTACH / DETACH stay raw
|
|
292
286
|
// — Kysely doesn't model them.
|
|
293
|
-
|
|
294
|
-
const scratchPath =
|
|
295
|
-
copyFileSync(inputPath, scratchPath)
|
|
287
|
+
await using tmpScratch = await temporaryDirectory("mailwoman-slim-src-")
|
|
288
|
+
const scratchPath = tmpScratch.resolve("src.db")
|
|
296
289
|
|
|
297
|
-
|
|
298
|
-
out.exec(`ATTACH DATABASE '${scratchPath.replaceAll("'", "''")}' AS src;`)
|
|
299
|
-
|
|
300
|
-
try {
|
|
301
|
-
// Does this shard carry the pre-built population aux table? The admin source does; a bare
|
|
302
|
-
// postcode shard might not. The locality ranking + population copy below adapt accordingly.
|
|
303
|
-
const srcHasPopulation = Boolean(
|
|
304
|
-
out.prepare(`SELECT 1 FROM src.sqlite_master WHERE type = 'table' AND name = '${PLACE_POPULATION_TABLE}'`).get()
|
|
305
|
-
)
|
|
290
|
+
await copyFileTo(inputPath, scratchPath)
|
|
306
291
|
|
|
307
|
-
|
|
308
|
-
// "interesting" bit: by declaring `src.spr` / `src.names` / `src.place_population` in
|
|
309
|
-
// `BuildSchema`, Kysely lets us write `selectFrom("src.spr")` with the same column-type
|
|
310
|
-
// checking as the regular schema. SQLite parses the dotted identifier as a schema-name
|
|
311
|
-
// qualifier, so this works directly without any aliasing trick.
|
|
292
|
+
out.exec(`ATTACH DATABASE '${scratchPath.replaceAll("'", "''")}' AS src;`)
|
|
312
293
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
294
|
+
try {
|
|
295
|
+
// Does this extract carry the pre-built population aux table? The admin source does; a bare
|
|
296
|
+
// postcode extract might not. The locality ranking + population copy below adapt accordingly.
|
|
297
|
+
const srcHasPopulation = Boolean(
|
|
298
|
+
out.prepare(`SELECT 1 FROM src.sqlite_master WHERE type = 'table' AND name = '${PLACE_POPULATION_TABLE}'`).get()
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
// The SELECT-INSERT queries below go through Kysely. The cross-schema FROM is the only
|
|
302
|
+
// "interesting" bit: by declaring `src.spr` / `src.names` / `src.place_population` in
|
|
303
|
+
// `BuildSchema`, Kysely lets us write `selectFrom("src.spr")` with the same column-type
|
|
304
|
+
// checking as the regular schema. SQLite parses the dotted identifier as a schema-name
|
|
305
|
+
// qualifier, so this works directly without any aliasing trick.
|
|
306
|
+
|
|
307
|
+
// 1. Ancestor placetypes (country / region / county / etc.) — always-kept.
|
|
308
|
+
progress("country", `${inputPath}: ancestor placetypes in (${countries.join(",")})`)
|
|
309
|
+
|
|
310
|
+
await kysely
|
|
311
|
+
.insertInto("spr")
|
|
312
|
+
.expression((eb) =>
|
|
313
|
+
eb
|
|
314
|
+
.selectFrom("src.spr")
|
|
315
|
+
.selectAll()
|
|
316
|
+
.where("is_current", "!=", 0)
|
|
317
|
+
.where("is_deprecated", "=", 0)
|
|
318
|
+
.where("country", "in", countries)
|
|
319
|
+
.where("placetype", "in", [...ANCESTOR_PLACETYPES])
|
|
320
|
+
)
|
|
321
|
+
.onConflict((oc) => oc.doNothing())
|
|
322
|
+
.execute()
|
|
323
|
+
|
|
324
|
+
// 2. Top-K localities by population. Population lives in the pre-built `place_population`
|
|
325
|
+
// aux table — left-join it so localities without a population row still qualify (sorted
|
|
326
|
+
// last). If the extract has no population table, fall back to a deterministic id ordering.
|
|
327
|
+
progress("locality", `${inputPath}: top-${topLocalities} localities by population`)
|
|
328
|
+
|
|
329
|
+
await kysely
|
|
330
|
+
.insertInto("spr")
|
|
331
|
+
.expression((eb) =>
|
|
332
|
+
eb
|
|
333
|
+
.selectFrom("src.spr as s")
|
|
334
|
+
.$if(srcHasPopulation, (qb) => qb.leftJoin("src.place_population as p", "p.id", "s.id"))
|
|
335
|
+
.selectAll("s")
|
|
336
|
+
.where("s.is_current", "!=", 0)
|
|
337
|
+
.where("s.is_deprecated", "=", 0)
|
|
338
|
+
.where("s.country", "in", countries)
|
|
339
|
+
.where("s.placetype", "=", "locality")
|
|
340
|
+
.orderBy(srcHasPopulation ? sql<number>`COALESCE(p.population, 0)` : sql<number>`s.id`, "desc")
|
|
341
|
+
.limit(topLocalities)
|
|
342
|
+
)
|
|
343
|
+
.onConflict((oc) => oc.doNothing())
|
|
344
|
+
.execute()
|
|
345
|
+
|
|
346
|
+
// 3. All postcodes in scope.
|
|
347
|
+
progress("postcode", `${inputPath}: all postcodes`)
|
|
348
|
+
|
|
349
|
+
await kysely
|
|
350
|
+
.insertInto("spr")
|
|
351
|
+
.expression((eb) =>
|
|
352
|
+
eb
|
|
353
|
+
.selectFrom("src.spr")
|
|
354
|
+
.selectAll()
|
|
355
|
+
.where("is_current", "!=", 0)
|
|
356
|
+
.where("is_deprecated", "=", 0)
|
|
357
|
+
.where("country", "in", countries)
|
|
358
|
+
.where("placetype", "=", "postalcode")
|
|
359
|
+
)
|
|
360
|
+
.onConflict((oc) => oc.doNothing())
|
|
361
|
+
.execute()
|
|
329
362
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
// last). If the shard has no population table, fall back to a deterministic id ordering.
|
|
333
|
-
progress("locality", `${inputPath}: top-${topLocalities} localities by population`)
|
|
363
|
+
// 4. Pull names for the IDs we just selected.
|
|
364
|
+
progress("names", `${inputPath}: names rows for selected IDs`)
|
|
334
365
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
.$if(srcHasPopulation, (qb) => qb.leftJoin("src.place_population as p", "p.id", "s.id"))
|
|
341
|
-
.selectAll("s")
|
|
342
|
-
.where("s.is_current", "!=", 0)
|
|
343
|
-
.where("s.is_deprecated", "=", 0)
|
|
344
|
-
.where("s.country", "in", countries)
|
|
345
|
-
.where("s.placetype", "=", "locality")
|
|
346
|
-
.orderBy(srcHasPopulation ? sql<number>`COALESCE(p.population, 0)` : sql<number>`s.id`, "desc")
|
|
347
|
-
.limit(topLocalities)
|
|
348
|
-
)
|
|
349
|
-
.onConflict((oc) => oc.doNothing())
|
|
350
|
-
.execute()
|
|
366
|
+
await kysely
|
|
367
|
+
.insertInto("names")
|
|
368
|
+
.expression((eb) => eb.selectFrom("src.names").selectAll().where("id", "in", eb.selectFrom("spr").select("id")))
|
|
369
|
+
.onConflict((oc) => oc.doNothing())
|
|
370
|
+
.execute()
|
|
351
371
|
|
|
352
|
-
|
|
353
|
-
|
|
372
|
+
// 5. Pull population rows for the selected IDs (sparse — only the places WOF has a count for).
|
|
373
|
+
if (srcHasPopulation) {
|
|
374
|
+
progress("place_population", `${inputPath}: population rows for selected IDs`)
|
|
354
375
|
|
|
355
376
|
await kysely
|
|
356
|
-
.insertInto("
|
|
377
|
+
.insertInto("place_population")
|
|
357
378
|
.expression((eb) =>
|
|
358
|
-
eb
|
|
359
|
-
.selectFrom("src.spr")
|
|
360
|
-
.selectAll()
|
|
361
|
-
.where("is_current", "!=", 0)
|
|
362
|
-
.where("is_deprecated", "=", 0)
|
|
363
|
-
.where("country", "in", countries)
|
|
364
|
-
.where("placetype", "=", "postalcode")
|
|
379
|
+
eb.selectFrom("src.place_population").selectAll().where("id", "in", eb.selectFrom("spr").select("id"))
|
|
365
380
|
)
|
|
366
381
|
.onConflict((oc) => oc.doNothing())
|
|
367
382
|
.execute()
|
|
383
|
+
}
|
|
368
384
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
)
|
|
387
|
-
.onConflict((oc) => oc.doNothing())
|
|
388
|
-
.execute()
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// 6. Carry the coincident_roles relation (#402) when this source has it (the admin DB), so the
|
|
392
|
-
// slim/demo DB supports dual-role hierarchy completion (on by default). Filtered to surviving
|
|
393
|
-
// spr ids → no orphans. Tiny (~hundreds of rows). `ancestors` is intentionally NOT copied (huge
|
|
394
|
-
// + build-only), so we copy the derived table rather than rebuild it. Raw SQL — conditional +
|
|
395
|
-
// not in the Kysely build schema.
|
|
396
|
-
const relationSchema = out
|
|
397
|
-
.prepare(`SELECT sql FROM src.sqlite_master WHERE type = 'table' AND name = 'coincident_roles'`)
|
|
398
|
-
.get() as { sql?: string } | undefined
|
|
399
|
-
|
|
400
|
-
if (relationSchema?.sql) {
|
|
401
|
-
progress("coincident_roles", `${inputPath}: copying dual-role relation`)
|
|
402
|
-
out.exec(relationSchema.sql.replace(/CREATE TABLE/i, "CREATE TABLE IF NOT EXISTS"))
|
|
403
|
-
|
|
404
|
-
out.exec(
|
|
405
|
-
`INSERT OR IGNORE INTO coincident_roles SELECT * FROM src.coincident_roles
|
|
406
|
-
WHERE admin_id IN (SELECT id FROM spr) AND locality_id IN (SELECT id FROM spr)`
|
|
407
|
-
)
|
|
385
|
+
// 6. Carry the coincident_roles relation (#402) when this source has it (the admin DB), so the
|
|
386
|
+
// slim/demo DB supports dual-role hierarchy completion (on by default). Filtered to surviving
|
|
387
|
+
// spr ids → no orphans. Tiny (~hundreds of rows). `ancestors` is intentionally NOT copied (huge
|
|
388
|
+
// + build-only), so we copy the derived table rather than rebuild it. Raw SQL — conditional +
|
|
389
|
+
// not in the Kysely build schema.
|
|
390
|
+
const relationSchema = out
|
|
391
|
+
.prepare(`SELECT sql FROM src.sqlite_master WHERE type = 'table' AND name = 'coincident_roles'`)
|
|
392
|
+
.get() as { sql?: string } | undefined
|
|
393
|
+
|
|
394
|
+
if (relationSchema?.sql) {
|
|
395
|
+
progress("coincident_roles", `${inputPath}: copying dual-role relation`)
|
|
396
|
+
out.exec(relationSchema.sql.replace(/CREATE TABLE/i, "CREATE TABLE IF NOT EXISTS"))
|
|
397
|
+
|
|
398
|
+
out.exec(
|
|
399
|
+
`INSERT OR IGNORE INTO coincident_roles SELECT * FROM src.coincident_roles
|
|
400
|
+
WHERE admin_id IN (SELECT id FROM spr) AND locality_id IN (SELECT id FROM spr)`
|
|
401
|
+
)
|
|
408
402
|
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
} finally {
|
|
412
|
-
out.exec(`DETACH DATABASE src;`)
|
|
403
|
+
out.exec(`CREATE INDEX IF NOT EXISTS coincident_roles_by_admin ON coincident_roles (admin_id)`)
|
|
413
404
|
}
|
|
414
405
|
} finally {
|
|
415
|
-
|
|
406
|
+
out.exec(`DETACH DATABASE src;`)
|
|
416
407
|
}
|
|
417
408
|
}
|
|
418
|
-
|
|
419
|
-
function countRows(db: DatabaseSync, table: string): number {
|
|
420
|
-
const row = db.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get() as { n?: number } | undefined
|
|
421
|
-
|
|
422
|
-
return Number(row?.n ?? 0)
|
|
423
|
-
}
|
|
@@ -5,19 +5,21 @@
|
|
|
5
5
|
* @file Pass 2 of the candidate build — explode `place_search.alt_names` into distinct alias rows.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
10
|
+
import type { CandidateDatabase } from "#candidate-schema"
|
|
11
|
+
import type { PlaceAttrs, StageRow } from "#candidate/place-attrs"
|
|
12
|
+
import { ALIAS_SEPARATOR } from "#fts/index"
|
|
13
|
+
import type { WOFDatabase } from "#schema"
|
|
14
|
+
import { normalizeLocalityForKey } from "#street/normalize"
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* Pass 2 — explode each place's `place_search.alt_names` bag into distinct-key alias rows (`is_primary = 0`), and count
|
|
16
18
|
* each place's distinct staged keys (primary included) — the gloss detector's key-count signal (#1730).
|
|
17
19
|
*/
|
|
18
20
|
export function explodeAliasBags(
|
|
19
|
-
src:
|
|
20
|
-
out:
|
|
21
|
+
src: DatabaseClient<WOFDatabase>,
|
|
22
|
+
out: DatabaseClient<CandidateDatabase>,
|
|
21
23
|
attrs: Map<number, PlaceAttrs>,
|
|
22
24
|
stageRow: StageRow
|
|
23
25
|
): { nAlias: number; keyCounts: Map<number, number> } {
|
|
@@ -5,11 +5,9 @@
|
|
|
5
5
|
* @file Pass 3b of the candidate build — the containment sidecar (closure rows + interval labels).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
9
9
|
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
import { placetypeDepth } from "../ancestry.ts"
|
|
10
|
+
import { placetypeDepth } from "#ancestry/index"
|
|
13
11
|
import {
|
|
14
12
|
CANDIDATE_ANCESTOR_COLUMNS,
|
|
15
13
|
CANDIDATE_ANCESTOR_TABLE,
|
|
@@ -17,9 +15,10 @@ import {
|
|
|
17
15
|
createCandidateAncestorTable,
|
|
18
16
|
createCandidateIntervalTable,
|
|
19
17
|
MAX_ANCESTOR_DEPTH,
|
|
20
|
-
} from "
|
|
21
|
-
import type { CandidateDatabase } from "
|
|
22
|
-
import type { PlaceAttrs } from "
|
|
18
|
+
} from "#candidate-ancestors-schema"
|
|
19
|
+
import type { CandidateDatabase } from "#candidate-schema"
|
|
20
|
+
import type { PlaceAttrs } from "#candidate/place-attrs"
|
|
21
|
+
import type { WOFDatabase } from "#schema"
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
24
|
* Pass 3b — the ancestors sidecar: closure rows + interval labels (candidate-ancestors-schema.ts owns the encoding
|
|
@@ -27,14 +26,13 @@ import type { PlaceAttrs } from "./place-attrs.ts"
|
|
|
27
26
|
* denormalizing each edge with the parent's name/key from `attrs`, streamed `ORDER BY id` so the clustered `(spr_id,
|
|
28
27
|
* depth)` insert is sorted — the contiguous-leaves discipline of the candidate table itself.
|
|
29
28
|
*
|
|
30
|
-
* Excluded by policy: self rows, and placetypes outside the containment ladder (continent, empire, …: `placetypeDepth`
|
|
31
|
-
*
|
|
32
|
-
*
|
|
29
|
+
* Excluded by policy: self rows, and placetypes outside the containment ladder (continent, empire, …: `placetypeDepth` 0)
|
|
30
|
+
* — they discriminate nothing a consumer of this sidecar checks. An edge to a parent with no current `spr` row has no
|
|
31
|
+
* name to denormalize; it is dropped and counted rather than stored blind.
|
|
33
32
|
*/
|
|
34
33
|
export async function buildAncestorsSidecar(ctx: {
|
|
35
|
-
src:
|
|
36
|
-
out:
|
|
37
|
-
kdb: DatabaseClient<CandidateDatabase>
|
|
34
|
+
src: DatabaseClient<WOFDatabase>
|
|
35
|
+
out: DatabaseClient<CandidateDatabase>
|
|
38
36
|
attrs: Map<number, PlaceAttrs>
|
|
39
37
|
ptID: (pt: string | null) => number
|
|
40
38
|
progress: (phase: string, message: string) => void
|
|
@@ -42,8 +40,8 @@ export async function buildAncestorsSidecar(ctx: {
|
|
|
42
40
|
const { src, out, attrs, ptID, progress } = ctx
|
|
43
41
|
|
|
44
42
|
progress("ancestors", "building containment sidecar (closure rows + interval labels)")
|
|
45
|
-
await createCandidateAncestorTable(ctx.
|
|
46
|
-
await createCandidateIntervalTable(ctx.
|
|
43
|
+
await createCandidateAncestorTable(ctx.out)
|
|
44
|
+
await createCandidateIntervalTable(ctx.out)
|
|
47
45
|
|
|
48
46
|
const insAncestor = out.prepare(
|
|
49
47
|
`INSERT INTO ${CANDIDATE_ANCESTOR_TABLE} VALUES (${CANDIDATE_ANCESTOR_COLUMNS.map(() => "?").join(", ")})`
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
import { enumerateCountryDisplayNames } from "@mailwoman/codex/country"
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
10
|
+
import type { PlaceAttrs, StageRow } from "#candidate/place-attrs"
|
|
11
|
+
import { normalizeLocalityForKey } from "#street/normalize"
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Fold every country surface ICU knows onto that country's candidate row (#1678 thread 1).
|
|
@@ -2,40 +2,43 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
* @file Pass 4 of the candidate build — fold a postcode or locality
|
|
5
|
+
* @file Pass 4 of the candidate build — fold a postcode or locality extract into the staging table.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
9
|
+
import { tableExists } from "@mailwoman/sqlite/introspection"
|
|
9
10
|
|
|
10
|
-
import {
|
|
11
|
-
import type { PlaceAttrs, StageRow } from "
|
|
11
|
+
import type { CandidateDatabase } from "#candidate-schema"
|
|
12
|
+
import type { PlaceAttrs, StageRow } from "#candidate/place-attrs"
|
|
13
|
+
import type { WOFDatabase } from "#schema"
|
|
14
|
+
import { normalizeLocalityForKey } from "#street/normalize"
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
|
-
* Fold ONE
|
|
15
|
-
* off that same
|
|
17
|
+
* Fold ONE extract (`spr` rows at `extractPlacetype` carrying real coordinates) in, then pass 4b: the alias names
|
|
18
|
+
* hanging off that same extract's `names` table.
|
|
16
19
|
*
|
|
17
20
|
* Self-contained by construction — it shares only the staging statement and the code dictionaries with the admin passes
|
|
18
21
|
* above it, and nothing downstream reads anything it produces except the two counters it returns.
|
|
19
22
|
*/
|
|
20
|
-
export function
|
|
23
|
+
export function foldExtract(ctx: {
|
|
21
24
|
/**
|
|
22
|
-
* The staging connection. The
|
|
25
|
+
* The staging connection. The extract itself is opened read-only here and closed before returning.
|
|
23
26
|
*/
|
|
24
|
-
out:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
out: DatabaseClient<CandidateDatabase>
|
|
28
|
+
extractPath: string
|
|
29
|
+
extractPlacetype: "postalcode" | "locality"
|
|
27
30
|
ccID: (code: string | null) => number
|
|
28
31
|
ptID: (pt: string | null) => number
|
|
29
32
|
stageRow: StageRow
|
|
30
33
|
progress: (phase: string, message: string) => void
|
|
31
34
|
}): { primaries: number; aliases: number } {
|
|
32
|
-
const { out,
|
|
35
|
+
const { out, extractPath, extractPlacetype, ccID, ptID, stageRow, progress } = ctx
|
|
33
36
|
|
|
34
|
-
progress(
|
|
37
|
+
progress(extractPlacetype === "postalcode" ? "postcodes" : "localities", `reading ${extractPath}`)
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
const pcPtid = ptID(
|
|
38
|
-
// Per-
|
|
39
|
+
using pc = new DatabaseClient<WOFDatabase>(extractPath, { readOnly: true })
|
|
40
|
+
const pcPtid = ptID(extractPlacetype)
|
|
41
|
+
// Per-extract, not the admin `attrs` map: pass 1 only ever sees the admin DB, so the alias pass
|
|
39
42
|
// below has nothing to join against unless this primary loop records what it staged.
|
|
40
43
|
const pcAttrs = new Map<number, PlaceAttrs>()
|
|
41
44
|
let primaries = 0
|
|
@@ -49,7 +52,7 @@ export function foldShard(ctx: {
|
|
|
49
52
|
min_latitude AS mnlat, min_longitude AS mnlon, max_latitude AS mxlat, max_longitude AS mxlon
|
|
50
53
|
FROM spr WHERE placetype = ? AND latitude != 0 AND longitude != 0`
|
|
51
54
|
)
|
|
52
|
-
.iterate(
|
|
55
|
+
.iterate(extractPlacetype)) {
|
|
53
56
|
const name = String(r.name ?? "")
|
|
54
57
|
const key = normalizeLocalityForKey(name)
|
|
55
58
|
|
|
@@ -91,18 +94,18 @@ export function foldShard(ctx: {
|
|
|
91
94
|
// --- pass 4b: postcode ALIAS names (#1495) ---
|
|
92
95
|
//
|
|
93
96
|
// The delivery-city names GeoNames supplies for a ZIP ("Brooklyn" for 11201) are written into
|
|
94
|
-
// the
|
|
97
|
+
// the extract's `names` table by `postcode/centroid-fills.ts`'s `geonamesNameFill`. Everything
|
|
95
98
|
// downstream of `names` picked them up EXCEPT this build: `fts.ts` unions `spr.name` with every
|
|
96
99
|
// `names` row into `place_search.alt_names`, so the FTS backend resolved "Brooklyn" → 11201
|
|
97
100
|
// while the candidate backend — whose every row IS an exact-tier row — had no key for it at
|
|
98
101
|
// all. Pass 2 does the equivalent fold for admin places, but reads the ADMIN `place_search`,
|
|
99
|
-
// and `attrs` holds admin ids only, so a postcode
|
|
102
|
+
// and `attrs` holds admin ids only, so a postcode extract could never reach it.
|
|
100
103
|
//
|
|
101
104
|
// Same discipline as pass 2: `is_primary = 0` (so `rankByPrimaryPreference` treats it as an
|
|
102
105
|
// alias, not a canonical postcode name), the row stays denormalized onto the POSTCODE's own
|
|
103
106
|
// spr_id/coords/bbox, and the display `name` stays the postcode — resolving "brooklyn" answers
|
|
104
107
|
// with place 11201, it does not rename the place to its delivery city.
|
|
105
|
-
const hasNames = pc
|
|
108
|
+
const hasNames = tableExists(pc, "names")
|
|
106
109
|
|
|
107
110
|
if (hasNames) {
|
|
108
111
|
out.exec("BEGIN")
|
|
@@ -125,13 +128,11 @@ export function foldShard(ctx: {
|
|
|
125
128
|
|
|
126
129
|
out.exec("COMMIT")
|
|
127
130
|
} else {
|
|
128
|
-
// Never a silent zero: real
|
|
129
|
-
// `names`. A
|
|
131
|
+
// Never a silent zero: real extracts come from `createUnifiedSchema`, which always creates
|
|
132
|
+
// `names`. A extract without it has no alias surface to lose, but say so rather than reporting
|
|
130
133
|
// "0 aliases" from a table that was never read.
|
|
131
|
-
progress("postcode-aliases", `${
|
|
134
|
+
progress("postcode-aliases", `${extractPath} has no \`names\` table — no delivery-city aliases to fold`)
|
|
132
135
|
}
|
|
133
136
|
|
|
134
|
-
pc.close()
|
|
135
|
-
|
|
136
137
|
return { primaries, aliases }
|
|
137
138
|
}
|