@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/lib/address/point/interpolation.ts +45 -39
- package/lib/address/point/schema.ts +17 -40
- package/lib/address/point.ts +316 -0
- package/lib/{address/index.ts → address.ts} +1 -1
- package/lib/ancestry/backfill.ts +20 -86
- package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
- package/lib/build/candidate.ts +122 -174
- package/lib/build/population-corrections.ts +64 -0
- package/lib/build/slim.ts +44 -114
- package/lib/candidate/alias-bags.ts +16 -17
- package/lib/candidate/ancestors/schema.ts +77 -61
- package/lib/candidate/ancestors/sidecar.ts +15 -22
- package/lib/candidate/country-display-names.ts +6 -20
- package/lib/candidate/extract-fold.ts +10 -55
- package/lib/candidate/fts.ts +5 -23
- package/lib/candidate/importance.ts +65 -68
- package/lib/candidate/lookup.ts +124 -415
- package/lib/candidate/name-roles.ts +15 -33
- package/lib/candidate/own-name.ts +35 -32
- package/lib/candidate/place-attrs.ts +20 -13
- package/lib/candidate/schema.ts +29 -65
- package/lib/candidate/scoring.ts +54 -93
- package/lib/capital-schema.ts +21 -17
- package/lib/capitals.ts +29 -27
- package/lib/coincident-roles.ts +85 -55
- package/lib/convention/schema.ts +15 -16
- package/lib/convention.ts +144 -0
- package/lib/coverage-manifest-schema.ts +40 -45
- package/lib/currency-backfill.ts +34 -79
- package/lib/env.ts +1 -1
- package/lib/exact-match.ts +32 -21
- package/lib/extracts.ts +97 -74
- package/lib/fst/autocomplete.ts +54 -37
- package/lib/fst/builder.ts +37 -41
- package/lib/fst/deserialize-web.ts +16 -17
- package/lib/fst/format.ts +41 -23
- package/lib/fst/freshness.ts +43 -120
- package/lib/fst/matcher.ts +7 -5
- package/lib/fst/serialize.ts +54 -74
- package/lib/fst/types.ts +78 -75
- package/lib/{fst/index.ts → fst.ts} +1 -0
- package/lib/fts/query.ts +5 -36
- package/lib/fts.ts +280 -0
- package/lib/geonames/aliases.ts +73 -144
- package/lib/geonames/postal.ts +162 -71
- package/lib/index.ts +9 -8
- package/lib/interpolation.ts +48 -100
- package/lib/lookup.ts +155 -270
- package/lib/name-score.ts +9 -7
- package/lib/nsul/lookup.ts +37 -54
- package/lib/nsul/schema.ts +16 -43
- package/lib/paths.ts +159 -0
- package/lib/place-importance-schema.ts +62 -169
- package/lib/poi/lookup.ts +104 -121
- package/lib/poi/schema.ts +42 -26
- package/lib/polygon-schema.ts +10 -6
- package/lib/postal/city/alias/lookup.ts +22 -40
- package/lib/postal/city/alias/schema.ts +14 -10
- package/lib/postal/city/candidate-schema.ts +26 -20
- package/lib/postcode-point-lookup.ts +8 -27
- package/lib/primary-preference.ts +46 -126
- package/lib/proximity-rerank.ts +44 -33
- package/lib/ranking-weights.ts +105 -78
- package/lib/region-keys.ts +70 -42
- package/lib/reverse.ts +149 -86
- package/lib/schema.ts +73 -50
- package/lib/search-fetch.ts +90 -68
- package/lib/sqlite/convention-source.ts +15 -23
- package/lib/sqlite/utils.ts +19 -22
- package/lib/street/centroid/schema.ts +37 -42
- package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
- package/lib/street/morphology/fst/builder.ts +60 -42
- package/lib/street/morphology/fst/loader.ts +40 -32
- package/lib/street/name-lookup.ts +45 -41
- package/lib/street/normalize.ts +88 -219
- package/lib/street/segment-schema.ts +116 -43
- package/lib/{street/index.ts → street.ts} +1 -1
- package/lib/types.ts +109 -150
- package/lib/unified-schema.ts +29 -29
- package/lib/uprn/existence.ts +30 -19
- package/lib/uprn/lookup.ts +29 -68
- package/lib/uprn/schema.ts +18 -40
- package/lib/weights-overlay-linker.ts +236 -252
- package/out/address/point/interpolation.d.ts +20 -23
- package/out/address/point/interpolation.d.ts.map +1 -1
- package/out/address/point/interpolation.js +42 -39
- package/out/address/point/interpolation.js.map +1 -1
- package/out/address/point/schema.d.ts +12 -35
- package/out/address/point/schema.d.ts.map +1 -1
- package/out/address/point/schema.js +3 -19
- package/out/address/point/schema.js.map +1 -1
- package/out/address/point.d.ts +57 -0
- package/out/address/point.d.ts.map +1 -0
- package/out/address/point.js +206 -0
- package/out/address/point.js.map +1 -0
- package/out/{address/index.js → address.d.ts} +2 -2
- package/out/address.d.ts.map +1 -0
- package/out/{address/index.d.ts → address.js} +2 -2
- package/out/address.js.map +1 -0
- package/out/ancestry/backfill.d.ts +11 -64
- package/out/ancestry/backfill.d.ts.map +1 -1
- package/out/ancestry/backfill.js +14 -74
- package/out/ancestry/backfill.js.map +1 -1
- package/out/ancestry.d.ts +49 -0
- package/out/ancestry.d.ts.map +1 -0
- package/out/ancestry.js +59 -0
- package/out/ancestry.js.map +1 -0
- package/out/build/candidate.d.ts +82 -112
- package/out/build/candidate.d.ts.map +1 -1
- package/out/build/candidate.js +17 -100
- package/out/build/candidate.js.map +1 -1
- package/out/build/population-corrections.d.ts +52 -0
- package/out/build/population-corrections.d.ts.map +1 -0
- package/out/build/population-corrections.js +40 -0
- package/out/build/population-corrections.js.map +1 -0
- package/out/build/slim.d.ts +8 -44
- package/out/build/slim.d.ts.map +1 -1
- package/out/build/slim.js +33 -94
- package/out/build/slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +6 -6
- package/out/candidate/alias-bags.d.ts.map +1 -1
- package/out/candidate/alias-bags.js +16 -17
- package/out/candidate/alias-bags.js.map +1 -1
- package/out/candidate/ancestors/schema.d.ts +73 -57
- package/out/candidate/ancestors/schema.d.ts.map +1 -1
- package/out/candidate/ancestors/schema.js +56 -48
- package/out/candidate/ancestors/schema.js.map +1 -1
- package/out/candidate/ancestors/sidecar.d.ts +3 -8
- package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
- package/out/candidate/ancestors/sidecar.js +15 -22
- package/out/candidate/ancestors/sidecar.js.map +1 -1
- package/out/candidate/country-display-names.d.ts +5 -15
- package/out/candidate/country-display-names.d.ts.map +1 -1
- package/out/candidate/country-display-names.js +6 -20
- package/out/candidate/country-display-names.js.map +1 -1
- package/out/candidate/extract-fold.d.ts +7 -15
- package/out/candidate/extract-fold.d.ts.map +1 -1
- package/out/candidate/extract-fold.js +5 -47
- package/out/candidate/extract-fold.js.map +1 -1
- package/out/candidate/fts.d.ts +5 -23
- package/out/candidate/fts.d.ts.map +1 -1
- package/out/candidate/fts.js +5 -23
- package/out/candidate/fts.js.map +1 -1
- package/out/candidate/importance.d.ts +60 -65
- package/out/candidate/importance.d.ts.map +1 -1
- package/out/candidate/importance.js +56 -63
- package/out/candidate/importance.js.map +1 -1
- package/out/candidate/lookup.d.ts +18 -55
- package/out/candidate/lookup.d.ts.map +1 -1
- package/out/candidate/lookup.js +82 -385
- package/out/candidate/lookup.js.map +1 -1
- package/out/candidate/name-roles.d.ts +9 -21
- package/out/candidate/name-roles.d.ts.map +1 -1
- package/out/candidate/name-roles.js +15 -33
- package/out/candidate/name-roles.js.map +1 -1
- package/out/candidate/own-name.d.ts +23 -25
- package/out/candidate/own-name.d.ts.map +1 -1
- package/out/candidate/own-name.js +35 -32
- package/out/candidate/own-name.js.map +1 -1
- package/out/candidate/place-attrs.d.ts +20 -13
- package/out/candidate/place-attrs.d.ts.map +1 -1
- package/out/candidate/place-attrs.js +4 -5
- package/out/candidate/place-attrs.js.map +1 -1
- package/out/candidate/schema.d.ts +27 -62
- package/out/candidate/schema.d.ts.map +1 -1
- package/out/candidate/schema.js +10 -22
- package/out/candidate/schema.js.map +1 -1
- package/out/candidate/scoring.d.ts +7 -8
- package/out/candidate/scoring.d.ts.map +1 -1
- package/out/candidate/scoring.js +52 -89
- package/out/candidate/scoring.js.map +1 -1
- package/out/capital-schema.d.ts +21 -17
- package/out/capital-schema.d.ts.map +1 -1
- package/out/capital-schema.js +17 -15
- package/out/capital-schema.js.map +1 -1
- package/out/capitals.d.ts +27 -25
- package/out/capitals.d.ts.map +1 -1
- package/out/capitals.js +23 -21
- package/out/capitals.js.map +1 -1
- package/out/coincident-roles.d.ts +60 -43
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +72 -50
- package/out/coincident-roles.js.map +1 -1
- package/out/convention/schema.d.ts +14 -14
- package/out/convention/schema.d.ts.map +1 -1
- package/out/convention/schema.js +6 -4
- package/out/convention/schema.js.map +1 -1
- package/out/convention.d.ts +97 -0
- package/out/convention.d.ts.map +1 -0
- package/out/convention.js +81 -0
- package/out/convention.js.map +1 -0
- package/out/coverage-manifest-schema.d.ts +34 -39
- package/out/coverage-manifest-schema.d.ts.map +1 -1
- package/out/coverage-manifest-schema.js +25 -34
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +16 -38
- package/out/currency-backfill.d.ts.map +1 -1
- package/out/currency-backfill.js +19 -46
- package/out/currency-backfill.js.map +1 -1
- package/out/env.d.ts +1 -1
- package/out/env.js +1 -1
- package/out/exact-match.d.ts +19 -10
- package/out/exact-match.d.ts.map +1 -1
- package/out/exact-match.js +32 -21
- package/out/exact-match.js.map +1 -1
- package/out/extracts.d.ts +66 -55
- package/out/extracts.d.ts.map +1 -1
- package/out/extracts.js +63 -55
- package/out/extracts.js.map +1 -1
- package/out/fst/autocomplete.d.ts +29 -21
- package/out/fst/autocomplete.d.ts.map +1 -1
- package/out/fst/autocomplete.js +39 -28
- package/out/fst/autocomplete.js.map +1 -1
- package/out/fst/builder.d.ts.map +1 -1
- package/out/fst/builder.js +37 -41
- package/out/fst/builder.js.map +1 -1
- package/out/fst/deserialize-web.d.ts +4 -4
- package/out/fst/deserialize-web.d.ts.map +1 -1
- package/out/fst/deserialize-web.js +15 -16
- package/out/fst/deserialize-web.js.map +1 -1
- package/out/fst/format.d.ts +41 -23
- package/out/fst/format.d.ts.map +1 -1
- package/out/fst/format.js +41 -23
- package/out/fst/format.js.map +1 -1
- package/out/fst/freshness.d.ts +19 -81
- package/out/fst/freshness.d.ts.map +1 -1
- package/out/fst/freshness.js +31 -94
- package/out/fst/freshness.js.map +1 -1
- package/out/fst/matcher.d.ts +5 -4
- package/out/fst/matcher.d.ts.map +1 -1
- package/out/fst/matcher.js +2 -2
- package/out/fst/matcher.js.map +1 -1
- package/out/fst/serialize.d.ts +28 -28
- package/out/fst/serialize.d.ts.map +1 -1
- package/out/fst/serialize.js +53 -71
- package/out/fst/serialize.js.map +1 -1
- package/out/fst/types.d.ts +78 -74
- package/out/fst/types.d.ts.map +1 -1
- package/out/fst/types.js +1 -4
- package/out/fst/types.js.map +1 -1
- package/out/{fst/index.js → fst.d.ts} +2 -1
- package/out/fst.d.ts.map +1 -0
- package/out/{fst/index.d.ts → fst.js} +2 -1
- package/out/fst.js.map +1 -0
- package/out/fts/query.d.ts +2 -27
- package/out/fts/query.d.ts.map +1 -1
- package/out/fts/query.js +5 -36
- package/out/fts/query.js.map +1 -1
- package/out/fts.d.ts +126 -0
- package/out/fts.d.ts.map +1 -0
- package/out/fts.js +188 -0
- package/out/fts.js.map +1 -0
- package/out/geonames/aliases.d.ts +26 -62
- package/out/geonames/aliases.d.ts.map +1 -1
- package/out/geonames/aliases.js +45 -117
- package/out/geonames/aliases.js.map +1 -1
- package/out/geonames/postal.d.ts +84 -44
- package/out/geonames/postal.d.ts.map +1 -1
- package/out/geonames/postal.js +115 -73
- package/out/geonames/postal.js.map +1 -1
- package/out/{geonames/index.js → geonames.d.ts} +1 -1
- package/out/geonames.d.ts.map +1 -0
- package/out/{geonames/index.d.ts → geonames.js} +1 -1
- package/out/geonames.js.map +1 -0
- package/out/index.d.ts +9 -8
- package/out/index.d.ts.map +1 -1
- package/out/index.js +6 -5
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +18 -55
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +27 -69
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +23 -51
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +136 -234
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +2 -2
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js +9 -7
- package/out/name-score.js.map +1 -1
- package/out/nsul/lookup.d.ts +33 -34
- package/out/nsul/lookup.d.ts.map +1 -1
- package/out/nsul/lookup.js +26 -40
- package/out/nsul/lookup.js.map +1 -1
- package/out/nsul/schema.d.ts +16 -43
- package/out/nsul/schema.d.ts.map +1 -1
- package/out/nsul/schema.js +9 -35
- package/out/nsul/schema.js.map +1 -1
- package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
- package/out/nsul.d.ts.map +1 -0
- package/out/{nsul/index.js → nsul.js} +1 -1
- package/out/nsul.js.map +1 -0
- package/out/paths.d.ts +124 -0
- package/out/paths.d.ts.map +1 -0
- package/out/paths.js +104 -0
- package/out/paths.js.map +1 -0
- package/out/place-importance-schema.d.ts +51 -143
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +28 -143
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi/lookup.d.ts +40 -47
- package/out/poi/lookup.d.ts.map +1 -1
- package/out/poi/lookup.js +69 -96
- package/out/poi/lookup.js.map +1 -1
- package/out/poi/schema.d.ts +41 -25
- package/out/poi/schema.d.ts.map +1 -1
- package/out/poi/schema.js +25 -17
- package/out/poi/schema.js.map +1 -1
- package/out/{poi/index.js → poi.d.ts} +1 -1
- package/out/poi.d.ts.map +1 -0
- package/out/{poi/index.d.ts → poi.js} +1 -1
- package/out/poi.js.map +1 -0
- package/out/polygon-schema.d.ts +10 -6
- package/out/polygon-schema.d.ts.map +1 -1
- package/out/polygon-schema.js +2 -2
- package/out/polygon-schema.js.map +1 -1
- package/out/postal/city/alias/lookup.d.ts +20 -23
- package/out/postal/city/alias/lookup.d.ts.map +1 -1
- package/out/postal/city/alias/lookup.js +17 -30
- package/out/postal/city/alias/lookup.js.map +1 -1
- package/out/postal/city/alias/schema.d.ts +14 -10
- package/out/postal/city/alias/schema.d.ts.map +1 -1
- package/out/postal/city/alias/schema.js +10 -8
- package/out/postal/city/alias/schema.js.map +1 -1
- package/out/postal/city/candidate-schema.d.ts +25 -19
- package/out/postal/city/candidate-schema.d.ts.map +1 -1
- package/out/postal/city/candidate-schema.js +21 -17
- package/out/postal/city/candidate-schema.js.map +1 -1
- package/out/{postal/index.d.ts → postal.d.ts} +1 -1
- package/out/postal.d.ts.map +1 -0
- package/out/{postal/index.js → postal.js} +1 -1
- package/out/postal.js.map +1 -0
- package/out/postcode-point-lookup.d.ts +6 -24
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +5 -17
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/primary-preference.d.ts +38 -92
- package/out/primary-preference.d.ts.map +1 -1
- package/out/primary-preference.js +15 -99
- package/out/primary-preference.js.map +1 -1
- package/out/proximity-rerank.d.ts +41 -30
- package/out/proximity-rerank.d.ts.map +1 -1
- package/out/proximity-rerank.js +38 -29
- package/out/proximity-rerank.js.map +1 -1
- package/out/ranking-weights.d.ts +98 -64
- package/out/ranking-weights.d.ts.map +1 -1
- package/out/ranking-weights.js +26 -25
- package/out/ranking-weights.js.map +1 -1
- package/out/region-keys.d.ts +50 -31
- package/out/region-keys.d.ts.map +1 -1
- package/out/region-keys.js +68 -40
- package/out/region-keys.js.map +1 -1
- package/out/reverse.d.ts +78 -50
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +98 -61
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +72 -49
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js +4 -5
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +16 -12
- package/out/search-fetch.d.ts.map +1 -1
- package/out/search-fetch.js +83 -63
- package/out/search-fetch.js.map +1 -1
- package/out/sqlite/convention-source.d.ts +12 -16
- package/out/sqlite/convention-source.d.ts.map +1 -1
- package/out/sqlite/convention-source.js +13 -22
- package/out/sqlite/convention-source.js.map +1 -1
- package/out/sqlite/utils.d.ts +19 -19
- package/out/sqlite/utils.d.ts.map +1 -1
- package/out/sqlite/utils.js +14 -15
- package/out/sqlite/utils.js.map +1 -1
- package/out/street/centroid/schema.d.ts +37 -42
- package/out/street/centroid/schema.d.ts.map +1 -1
- package/out/street/centroid/schema.js +9 -21
- package/out/street/centroid/schema.js.map +1 -1
- package/out/street/centroid.d.ts +30 -0
- package/out/street/centroid.d.ts.map +1 -0
- package/out/street/{centroid/index.js → centroid.js} +13 -24
- package/out/street/centroid.js.map +1 -0
- package/out/street/morphology/fst/builder.d.ts +20 -10
- package/out/street/morphology/fst/builder.d.ts.map +1 -1
- package/out/street/morphology/fst/builder.js +44 -34
- package/out/street/morphology/fst/builder.js.map +1 -1
- package/out/street/morphology/fst/loader.d.ts +33 -26
- package/out/street/morphology/fst/loader.d.ts.map +1 -1
- package/out/street/morphology/fst/loader.js +23 -22
- package/out/street/morphology/fst/loader.js.map +1 -1
- package/out/street/name-lookup.d.ts +24 -18
- package/out/street/name-lookup.d.ts.map +1 -1
- package/out/street/name-lookup.js +34 -35
- package/out/street/name-lookup.js.map +1 -1
- package/out/street/normalize.d.ts +35 -136
- package/out/street/normalize.d.ts.map +1 -1
- package/out/street/normalize.js +77 -194
- package/out/street/normalize.js.map +1 -1
- package/out/street/segment-schema.d.ts +79 -39
- package/out/street/segment-schema.d.ts.map +1 -1
- package/out/street/segment-schema.js +71 -21
- package/out/street/segment-schema.js.map +1 -1
- package/out/{street/index.js → street.d.ts} +2 -2
- package/out/street.d.ts.map +1 -0
- package/out/{street/index.d.ts → street.js} +2 -2
- package/out/street.js.map +1 -0
- package/out/types.d.ts +84 -149
- package/out/types.d.ts.map +1 -1
- package/out/types.js +0 -6
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +8 -12
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +29 -29
- package/out/unified-schema.js.map +1 -1
- package/out/uprn/existence.d.ts +28 -17
- package/out/uprn/existence.d.ts.map +1 -1
- package/out/uprn/existence.js +26 -16
- package/out/uprn/existence.js.map +1 -1
- package/out/uprn/lookup.d.ts +14 -44
- package/out/uprn/lookup.d.ts.map +1 -1
- package/out/uprn/lookup.js +21 -57
- package/out/uprn/lookup.js.map +1 -1
- package/out/uprn/schema.d.ts +18 -40
- package/out/uprn/schema.d.ts.map +1 -1
- package/out/uprn/schema.js +10 -32
- package/out/uprn/schema.js.map +1 -1
- package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
- package/out/uprn.d.ts.map +1 -0
- package/out/{uprn/index.js → uprn.js} +1 -1
- package/out/uprn.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +138 -144
- package/out/weights-overlay-linker.d.ts.map +1 -1
- package/out/weights-overlay-linker.js +105 -159
- package/out/weights-overlay-linker.js.map +1 -1
- package/package.json +91 -596
- package/lib/address/point/index.ts +0 -328
- package/lib/convention/index.ts +0 -154
- package/lib/fts/index.ts +0 -361
- package/out/address/index.d.ts.map +0 -1
- package/out/address/index.js.map +0 -1
- package/out/address/point/index.d.ts +0 -53
- package/out/address/point/index.d.ts.map +0 -1
- package/out/address/point/index.js +0 -222
- package/out/address/point/index.js.map +0 -1
- package/out/ancestry/index.d.ts +0 -45
- package/out/ancestry/index.d.ts.map +0 -1
- package/out/ancestry/index.js +0 -55
- package/out/ancestry/index.js.map +0 -1
- package/out/convention/index.d.ts +0 -106
- package/out/convention/index.d.ts.map +0 -1
- package/out/convention/index.js +0 -93
- package/out/convention/index.js.map +0 -1
- package/out/fst/index.d.ts.map +0 -1
- package/out/fst/index.js.map +0 -1
- package/out/fts/index.d.ts +0 -184
- package/out/fts/index.d.ts.map +0 -1
- package/out/fts/index.js +0 -277
- package/out/fts/index.js.map +0 -1
- package/out/geonames/index.d.ts.map +0 -1
- package/out/geonames/index.js.map +0 -1
- package/out/nsul/index.d.ts.map +0 -1
- package/out/nsul/index.js.map +0 -1
- package/out/poi/index.d.ts.map +0 -1
- package/out/poi/index.js.map +0 -1
- package/out/postal/index.d.ts.map +0 -1
- package/out/postal/index.js.map +0 -1
- package/out/street/centroid/index.d.ts +0 -40
- package/out/street/centroid/index.d.ts.map +0 -1
- package/out/street/centroid/index.js.map +0 -1
- package/out/street/index.d.ts.map +0 -1
- package/out/street/index.js.map +0 -1
- package/out/uprn/index.d.ts.map +0 -1
- package/out/uprn/index.js.map +0 -1
- /package/lib/{geonames/index.ts → geonames.ts} +0 -0
- /package/lib/{nsul/index.ts → nsul.ts} +0 -0
- /package/lib/{poi/index.ts → poi.ts} +0 -0
- /package/lib/{postal/index.ts → postal.ts} +0 -0
- /package/lib/{uprn/index.ts → uprn.ts} +0 -0
package/lib/search-fetch.ts
CHANGED
|
@@ -3,43 +3,52 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Fetches FTS5 candidates for fuzzy name matching. It runs the schema-qualified `place_search` match and its
|
|
7
|
+
* population-ordered companion query. Both queries return the raw row shape defined here.
|
|
8
8
|
*
|
|
9
9
|
* Bbox and near-with-radius narrow at the SQL level through SQLite's built-in `rtree`, whose index name and schema
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* whole corpus, so
|
|
10
|
+
* are defined in `fts.ts` beside the FTS5 build. This package uses SQLite's R*Tree instead of SpatiaLite or turf.
|
|
11
|
+
* The R*Tree narrows the search to at most a few hundred candidates per query. Downstream passes work on that set
|
|
12
|
+
* instead of the whole corpus, so exact haversine calculations remain cheap.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { allRows } from "@mailwoman/core/utils"
|
|
16
16
|
import { bboxAround } from "@mailwoman/spatial"
|
|
17
17
|
import type { DatabaseClient, SQLInputValue } from "@mailwoman/sqlite/client"
|
|
18
18
|
|
|
19
|
-
import { PLACE_BBOX_TABLE, PLACE_POPULATION_TABLE } from "#fts
|
|
19
|
+
import { PLACE_BBOX_TABLE, PLACE_POPULATION_TABLE } from "#fts"
|
|
20
20
|
import type { RankingWeights } from "#ranking-weights"
|
|
21
21
|
import type { FindPlaceQuery, WOFPlacetype } from "#types"
|
|
22
22
|
/**
|
|
23
|
-
* Query length at or below which the FTS window is widened.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Query length at or below which the FTS window is widened.
|
|
24
|
+
*
|
|
25
|
+
* A two- or three-character query is almost always a region abbreviation, where the exact match
|
|
26
|
+
* can otherwise fall outside the window behind higher-bm25 partial hits, as "NY" losing to "New York".
|
|
26
27
|
*/
|
|
27
28
|
const SHORT_QUERY_MAX_LENGTH = 3
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
* Over-fetch floor for
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* Over-fetch floor for short (≤3-character) queries.
|
|
32
|
+
*
|
|
33
|
+
* These queries are usually region abbreviations such as "NY" or "VT".
|
|
34
|
+
*
|
|
35
|
+
* An exact-abbrev holder's BM25 is poor (long multilingual alt-name document),
|
|
36
|
+
* so the normal `limit * 4` window can drop it before `exactMatchTiering` promotes
|
|
37
|
+
* it. 200 comfortably covers every same-abbrev region across the 12-country gazetteer
|
|
38
|
+
* (a 2-letter token matches a few dozen regions at most) while staying a cheap region-placetype fetch.
|
|
39
|
+
* See the `#fuzzyNameMatch` over-fetch comment.
|
|
35
40
|
*/
|
|
36
41
|
const SHORT_QUERY_OVERFETCH = 200
|
|
37
42
|
|
|
38
43
|
/**
|
|
39
|
-
* How many rows the population-ordered companion fetch
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
44
|
+
* How many rows the population-ordered companion fetch adds to the candidate pool.
|
|
45
|
+
*
|
|
46
|
+
* Small on purpose.
|
|
47
|
+
* Its only job is to guarantee the famous holders of a name enter the pool at all.
|
|
48
|
+
*
|
|
49
|
+
* For "Paris"-class floods, thousands of small same-name rows fill the BM25 window.
|
|
50
|
+
* A boost inside the BM25-based ORDER BY cannot rescue a candidate whose score is
|
|
51
|
+
* length-poisoned by about 15 points (see the fetch-site comment).
|
|
43
52
|
*/
|
|
44
53
|
const POPULATION_FETCH_LIMIT = 15
|
|
45
54
|
|
|
@@ -49,27 +58,31 @@ export interface RawSearchRow {
|
|
|
49
58
|
placetype: string
|
|
50
59
|
country: string | null
|
|
51
60
|
parent_id: number | null
|
|
52
|
-
rank: number // BM25 (lower = better in SQLite)
|
|
61
|
+
rank: number // BM25 (lower = better in SQLite). We negate to get higher-is-better
|
|
53
62
|
lat: number | null
|
|
54
63
|
lon: number | null
|
|
55
64
|
min_latitude: number | null
|
|
56
65
|
max_latitude: number | null
|
|
57
66
|
min_longitude: number | null
|
|
58
67
|
max_longitude: number | null
|
|
59
|
-
population: number | null // from the place_population aux table
|
|
68
|
+
population: number | null // from the place_population aux table. null when missing
|
|
60
69
|
/**
|
|
61
|
-
* From `place_importance.encyclopedic` when the extract's table
|
|
62
|
-
*
|
|
63
|
-
*
|
|
70
|
+
* From `place_importance.encyclopedic` when the extract's table includes the two-score split columns.
|
|
71
|
+
*
|
|
72
|
+
* NULL means the place has no Wikipedia article, or the extract predates the split.
|
|
73
|
+
* Either case records an absence.
|
|
74
|
+
* The value remains null rather than 0 (ROAD_TO_V9 §2).
|
|
64
75
|
*/
|
|
65
76
|
encyclopedic: number | null
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
/**
|
|
69
|
-
* Fetch the raw candidate rows for a name match on one extract: the BM25-ordered
|
|
70
|
-
* for short queries), plus the population-ordered
|
|
71
|
-
*
|
|
72
|
-
*
|
|
80
|
+
* Fetch the raw candidate rows for a name match on one extract: the BM25-ordered
|
|
81
|
+
* window over `place_search` (widened for short queries), plus the population-ordered
|
|
82
|
+
* companion fetch that keeps the prominent holders of a name pool-complete.
|
|
83
|
+
*
|
|
84
|
+
* `schemaName` is the routed extract's bare schema name, validated at construction,
|
|
85
|
+
* so it is interpolated directly.
|
|
73
86
|
*/
|
|
74
87
|
export function fetchSearchRows<DB>(options: {
|
|
75
88
|
db: DatabaseClient<DB>
|
|
@@ -96,23 +109,26 @@ export function fetchSearchRows<DB>(options: {
|
|
|
96
109
|
weights,
|
|
97
110
|
} = options
|
|
98
111
|
|
|
99
|
-
// Over-fetch so post-scoring
|
|
100
|
-
// region abbreviation like "NY"
|
|
101
|
-
// the
|
|
102
|
-
// so under the normal `limit * 4` window it
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
// postcode signal to disambiguate
|
|
107
|
-
// With a `country` hint every abbrev resolves; bare + no-context lifts 7→10/15 US states.)
|
|
112
|
+
// Over-fetch so post-scoring and exact-match tiering have room to re-rank.
|
|
113
|
+
// Short queries (a 2-3-char region abbreviation like "NY" or "VT") are the danger
|
|
114
|
+
// case the `exactMatchTiering` docstring flags.
|
|
115
|
+
// The exact-abbrev holder's BM25 is poor, so under the normal `limit * 4` window it
|
|
116
|
+
// drops out of the candidate pool before tiering can promote it.
|
|
117
|
+
// A wider window for short queries keeps the exact match available for tiering.
|
|
118
|
+
// Cross-country abbrev collisions ("VT" is both Vermont and Viterbo) still need a country
|
|
119
|
+
// or postcode signal to disambiguate, so this only rescues the window-drop class.
|
|
108
120
|
const ftsLimit =
|
|
109
121
|
query.text.trim().length <= SHORT_QUERY_MAX_LENGTH ? Math.max(limit * 4, SHORT_QUERY_OVERFETCH) : limit * 4
|
|
110
122
|
|
|
111
|
-
// Filter out historical
|
|
112
|
-
// spr table but should never win a contemporary lookup.
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
//
|
|
123
|
+
// Filter out historical, superseded and deprecated places by default.
|
|
124
|
+
// They live in the same spr table but should never win a contemporary lookup.
|
|
125
|
+
// `is_current = 0` is the only WOF value that means "not current", while both
|
|
126
|
+
// `-1` (modern) and `1` (legacy) mean current.
|
|
127
|
+
//
|
|
128
|
+
// The schema-qualified `from` makes the bare `place_search` reference in
|
|
129
|
+
// `match` resolve to the from table.
|
|
130
|
+
// The FTS5 parser requires that resolution.
|
|
131
|
+
// See the extracts.ts header comment.
|
|
116
132
|
const where: string[] = ["place_search MATCH ?", "spr.is_current != 0", "spr.is_deprecated = 0"]
|
|
117
133
|
const params: SQLInputValue[] = [ftsQuery]
|
|
118
134
|
|
|
@@ -131,23 +147,27 @@ export function fetchSearchRows<DB>(options: {
|
|
|
131
147
|
params.push(query.parentID, query.parentID)
|
|
132
148
|
}
|
|
133
149
|
|
|
134
|
-
// Bbox
|
|
135
|
-
// the active extract has the R*Tree
|
|
136
|
-
// filter
|
|
150
|
+
// Bbox and near-with-radius are SQL-level filters via the R*Tree.
|
|
151
|
+
// The join is emitted only when the active extract has the R*Tree.
|
|
152
|
+
// A requested filter on a legacy extract is silently treated as no bbox filter
|
|
153
|
+
// so the query does not crash.
|
|
137
154
|
const extractHasBbox = hasBboxIndex.get(sch) === true
|
|
138
155
|
const useBboxJoin = (query.bbox || query.near?.maxDistanceKm !== undefined) && extractHasBbox
|
|
139
156
|
let joinClause = `JOIN ${sch}.spr ON spr.id = place_search.wof_id`
|
|
140
157
|
|
|
141
158
|
if (useBboxJoin) {
|
|
142
159
|
joinClause += ` JOIN ${sch}.${PLACE_BBOX_TABLE} bbox ON bbox.id = spr.id`
|
|
143
|
-
//
|
|
160
|
+
// aabb intersection.
|
|
161
|
+
// Both bounding-box sides must overlap.
|
|
162
|
+
// The R*Tree checks them in O(log n).
|
|
144
163
|
const filterBox = query.bbox || bboxAround(query.near!.lat, query.near!.lon, query.near!.maxDistanceKm!)
|
|
145
164
|
where.push("bbox.min_lat <= ? AND bbox.max_lat >= ?", "bbox.min_lon <= ? AND bbox.max_lon >= ?")
|
|
146
165
|
params.push(filterBox.maxLat, filterBox.minLat, filterBox.maxLon, filterBox.minLon)
|
|
147
166
|
}
|
|
148
167
|
|
|
149
|
-
//
|
|
150
|
-
//
|
|
168
|
+
// Left join the population aux table when present.
|
|
169
|
+
// If this extract lacks the table, the select omits the population column.
|
|
170
|
+
// The post-scoring loop then uses 0.
|
|
151
171
|
const extractHasPopulation = hasPopulationIndex.get(sch) === true
|
|
152
172
|
|
|
153
173
|
const populationSelect = extractHasPopulation
|
|
@@ -158,31 +178,32 @@ export function fetchSearchRows<DB>(options: {
|
|
|
158
178
|
? `LEFT JOIN ${sch}.${PLACE_POPULATION_TABLE} ON ${PLACE_POPULATION_TABLE}.id = spr.id`
|
|
159
179
|
: ""
|
|
160
180
|
|
|
161
|
-
// The encyclopedic score is
|
|
162
|
-
// appears in the
|
|
163
|
-
// split column, so a pre-split extract emits a literal NULL
|
|
181
|
+
// The encyclopedic score is returned and never ranked on (ROAD_TO_V9 §2).
|
|
182
|
+
// It appears in the select and in no order BY, here or in the companion fetch below.
|
|
183
|
+
// It is conditioned on the split column, so a pre-split extract emits a literal NULL
|
|
184
|
+
// and builds no join at all.
|
|
164
185
|
const { select: encyclopedicSelect, join: encyclopedicJoin } = encyclopedicClauses.get(sch)!
|
|
165
186
|
|
|
166
|
-
// Push the population boost into the
|
|
167
|
-
// (whose long alt-name lists hurt BM25) actually make it into the over-fetch window.
|
|
168
|
-
// post-scoring will still compute the same boost for the final score
|
|
169
|
-
// candidate set is right.
|
|
187
|
+
// Push the population boost into the order BY when the index is available, so famous places
|
|
188
|
+
// (whose long alt-name lists hurt BM25) actually make it into the over-fetch window.
|
|
189
|
+
// The TS post-scoring will still compute the same boost for the final score.
|
|
190
|
+
// This just ensures the candidate set is right.
|
|
170
191
|
//
|
|
171
192
|
// Formula: rank_adjusted = bm25 - populationBoost * min(1.0, log10(1 + pop) / scaleLog10)
|
|
172
193
|
// Lower rank_adjusted = better (matches SQLite's bm25 convention of "more negative = better").
|
|
173
194
|
//
|
|
174
|
-
//
|
|
175
|
-
// bm25 length normalization is polluted by the row's
|
|
176
|
-
// `name` docs read −16.0 (empty alt_names)
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
195
|
+
// Do not reach for bm25 column weights here.
|
|
196
|
+
// FTS5's bm25 length normalization is polluted by the row's total document size,
|
|
197
|
+
// so identical 1-token `name` docs read −16.0 (empty alt_names) against −0.43
|
|
198
|
+
// (2.7 KB alt_names) even with the alt_names column weighted to zero.
|
|
199
|
+
// The population-ordered companion fetch below returns the most populous holder of the name.
|
|
200
|
+
// The post-scoring sort uses population to break ties in the exact tier.
|
|
180
201
|
const orderByExpr = extractHasPopulation
|
|
181
202
|
? `(bm25(place_search) - ? * MIN(1.0, COALESCE(log10(1.0 + ${PLACE_POPULATION_TABLE}.population), 0) / ?))`
|
|
182
203
|
: "bm25(place_search)"
|
|
183
204
|
|
|
184
|
-
// Schema-qualified
|
|
185
|
-
// See extracts.ts header for the failure mode that drove this design.
|
|
205
|
+
// Schema-qualified `from` with a bare-name `match` is required syntax for FTS5 on attached schemas.
|
|
206
|
+
// See the extracts.ts header for the failure mode that drove this design.
|
|
186
207
|
const stmt = db.prepare(`
|
|
187
208
|
SELECT
|
|
188
209
|
spr.id AS id,
|
|
@@ -213,12 +234,13 @@ export function fetchSearchRows<DB>(options: {
|
|
|
213
234
|
|
|
214
235
|
const rawRows = allRows<RawSearchRow>(stmt, ...params)
|
|
215
236
|
|
|
216
|
-
//
|
|
217
|
-
// ("Paris" matches thousands of gap-fill villages) the bm25-based
|
|
218
|
-
// the famous holder
|
|
219
|
-
//
|
|
220
|
-
// prominent holders of a name
|
|
221
|
-
// decides whether they win.
|
|
237
|
+
// Companion fetch: the same `match`, ordered only by population.
|
|
238
|
+
// For name floods ("Paris" matches thousands of gap-fill villages) the bm25-based
|
|
239
|
+
// window above cannot admit the famous holder, because its bm25 is length-poisoned
|
|
240
|
+
// by the row's alias bulk (measured ~15 pts, against a +4.0 boost cap).
|
|
241
|
+
// This fetch includes prominent holders of a name in the candidate pool.
|
|
242
|
+
// The exact-tier sort below decides whether they win.
|
|
243
|
+
// It is skipped without a population index, since there is no column to order by.
|
|
222
244
|
if (extractHasPopulation) {
|
|
223
245
|
const popStmt = db.prepare(`
|
|
224
246
|
SELECT
|
|
@@ -2,46 +2,40 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* `SqliteConventionSource` — a `ConventionSource` backed by the build-from-source convention asset
|
|
7
|
-
* (#290, Direction E). Conventions live in a read-only, provenance-stamped `address_convention`
|
|
8
|
-
* table keyed by WOF polygon id; this source queries them ON DEMAND by id (one indexed lookup,
|
|
9
|
-
* memoized) rather than paging the whole table into memory as a code constant — the deliberate
|
|
10
|
-
* counter to the Pelias "giant dictionary in RAM, no provenance" pattern (see the operator design
|
|
11
|
-
* value in memory `feedback-no-irrelevant-trivia`).
|
|
12
|
-
*
|
|
13
|
-
* The asset is the queryable, distributable artifact; the strategy IMPLEMENTATIONS stay in code. An
|
|
14
|
-
* unknown strategy NAME is surfaced loudly at dispatch (see `lookup.ts`), not silently
|
|
15
|
-
* swallowed.
|
|
16
5
|
*/
|
|
17
6
|
|
|
18
7
|
import { tryParsingJSON } from "@mailwoman/core/json"
|
|
19
8
|
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
20
9
|
|
|
21
|
-
import { ADDRESS_CONVENTION_TABLE, type Convention, type ConventionSource } from "#convention
|
|
10
|
+
import { ADDRESS_CONVENTION_TABLE, type Convention, type ConventionSource } from "#convention"
|
|
22
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Reads per-place address conventions from the convention table in an attached
|
|
14
|
+
* SQLite schema, caching each lookup, including misses.
|
|
15
|
+
*
|
|
16
|
+
* A missing table or unparseable row reads as no convention rather than throwing.
|
|
17
|
+
*/
|
|
23
18
|
export class SqliteConventionSource<DB> implements ConventionSource {
|
|
24
19
|
readonly #db: DatabaseClient<DB>
|
|
25
20
|
readonly #schema: string
|
|
26
|
-
|
|
27
|
-
* Memoize per-id lookups (including misses, as `null`) so a hot ancestor chain is queried once.
|
|
28
|
-
*/
|
|
21
|
+
|
|
29
22
|
readonly #cache = new Map<number, Convention | null>()
|
|
30
23
|
|
|
31
24
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
25
|
+
* Creates a source over an open database that is, or has attached, the convention asset.
|
|
26
|
+
*
|
|
27
|
+
* @param db The open database handle.
|
|
28
|
+
* @param schema The schema that holds the convention table, either `main` or an attached extract's name.
|
|
35
29
|
*/
|
|
36
30
|
constructor(db: DatabaseClient<DB>, schema: string) {
|
|
37
31
|
this.#db = db
|
|
38
32
|
this.#schema = schema
|
|
39
33
|
}
|
|
40
34
|
|
|
41
|
-
get(wofID: number): Convention |
|
|
35
|
+
get(wofID: number): Convention | null {
|
|
42
36
|
const cached = this.#cache.get(wofID)
|
|
43
37
|
|
|
44
|
-
if (cached !== undefined) return cached
|
|
38
|
+
if (cached !== undefined) return cached
|
|
45
39
|
let value: Convention | null = null
|
|
46
40
|
|
|
47
41
|
try {
|
|
@@ -53,13 +47,11 @@ export class SqliteConventionSource<DB> implements ConventionSource {
|
|
|
53
47
|
value = tryParsingJSON<Convention>(row.convention)
|
|
54
48
|
}
|
|
55
49
|
} catch {
|
|
56
|
-
// A missing table → treat as no override (the chain falls back to WORLD_DEFAULT); malformed
|
|
57
|
-
// JSON already nulls out above. The build script validates structure, so this is purely defensive.
|
|
58
50
|
value = null
|
|
59
51
|
}
|
|
60
52
|
|
|
61
53
|
this.#cache.set(wofID, value)
|
|
62
54
|
|
|
63
|
-
return value
|
|
55
|
+
return value
|
|
64
56
|
}
|
|
65
57
|
}
|
package/lib/sqlite/utils.ts
CHANGED
|
@@ -2,25 +2,22 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* Small shared helpers for the SQLite-backed lookups.
|
|
5
|
+
* @file Shared helpers for the SQLite-backed lookups.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
import { allRows, getRow } from "@mailwoman/core/utils"
|
|
10
9
|
import type { DatabaseClient, SQLInputValue } from "@mailwoman/sqlite/client"
|
|
11
10
|
import { hasColumn as columnExists, tableExists } from "@mailwoman/sqlite/introspection"
|
|
12
11
|
|
|
13
|
-
// The row-shape assertion itself lives in `core` so the readers that cannot depend on this package reach the same
|
|
14
|
-
// helper; re-exported here because this module is where this package's readers already look for it.
|
|
15
|
-
|
|
16
12
|
/**
|
|
17
|
-
* A prepared single-row query whose parameter tuple
|
|
18
|
-
*
|
|
13
|
+
* A prepared single-row query whose parameter tuple stays visible to TypeScript.
|
|
14
|
+
*
|
|
15
|
+
* `StatementSync` accepts any `SQLInputValue[]`, which would erase tagged key types at the call site.
|
|
19
16
|
*/
|
|
20
|
-
export type PreparedGet<Parameters extends SQLInputValue[], Row> = (...parameters: Parameters) => Row |
|
|
17
|
+
export type PreparedGet<Parameters extends SQLInputValue[], Row> = (...parameters: Parameters) => Row | null
|
|
21
18
|
|
|
22
19
|
/**
|
|
23
|
-
*
|
|
20
|
+
* Prepares a single-row query with a typed parameter tuple.
|
|
24
21
|
*/
|
|
25
22
|
export function prepareGet<Parameters extends SQLInputValue[], Row, DB>(
|
|
26
23
|
db: DatabaseClient<DB>,
|
|
@@ -32,12 +29,12 @@ export function prepareGet<Parameters extends SQLInputValue[], Row, DB>(
|
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
/**
|
|
35
|
-
*
|
|
32
|
+
* The multi-row counterpart to {@link PreparedGet}.
|
|
36
33
|
*/
|
|
37
34
|
export type PreparedAll<Parameters extends SQLInputValue[], Row> = (...parameters: Parameters) => Row[]
|
|
38
35
|
|
|
39
36
|
/**
|
|
40
|
-
*
|
|
37
|
+
* Prepares a multi-row query with a typed parameter tuple.
|
|
41
38
|
*/
|
|
42
39
|
export function prepareAll<Parameters extends SQLInputValue[], Row, DB>(
|
|
43
40
|
db: DatabaseClient<DB>,
|
|
@@ -49,10 +46,11 @@ export function prepareAll<Parameters extends SQLInputValue[], Row, DB>(
|
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
49
|
+
* Returns true when `name` is a table in the open database.
|
|
50
|
+
* Returns false when the check itself fails.
|
|
51
|
+
*
|
|
52
|
+
* The street-level lookups call it so that an empty extract, such as an interrupted build
|
|
53
|
+
* or a zero-byte file, makes every lookup miss instead of throwing `no such table`.
|
|
56
54
|
*/
|
|
57
55
|
export function hasTable<DB>(db: DatabaseClient<DB>, name: string): boolean {
|
|
58
56
|
try {
|
|
@@ -63,15 +61,14 @@ export function hasTable<DB>(db: DatabaseClient<DB>, name: string): boolean {
|
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
/**
|
|
66
|
-
*
|
|
64
|
+
* Returns true when `table` exists in the open database and has `column`.
|
|
67
65
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* construction and shape the query — `table_info` is a PRAGMA, so it must not sit on a per-query path.
|
|
66
|
+
* An artifact built before a column was added is still valid, so readers call this once
|
|
67
|
+
* at construction and leave the column out of their queries when it is missing.
|
|
68
|
+
* Avoid calling it per query, because it runs a pragma.
|
|
72
69
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
70
|
+
* The pragma does not accept bound parameters, so `table` is interpolated into the SQL.
|
|
71
|
+
* Pass only constants.
|
|
75
72
|
*/
|
|
76
73
|
export function hasColumn<DB>(db: DatabaseClient<DB>, table: string, column: string): boolean {
|
|
77
74
|
try {
|
|
@@ -3,21 +3,7 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* `ban/scripts/build-street-centroid-extract.ts` — the #1042 street-level tier behind "street-only
|
|
8
|
-
* FR queries deserve a street-level answer"). The extract is a `GROUP BY street` roll-up of the
|
|
9
|
-
* sealed rooftop address-point extract: one row per (street, postcode, commune) carrying the street's
|
|
10
|
-
* CENTROID + bounding-box EXTENT + member-point count. No new data source — a derived artifact.
|
|
11
|
-
*
|
|
12
|
-
* Single source of truth for the columns shared by the BUILDER (a positional prepared INSERT for
|
|
13
|
-
* throughput) and the READER ({@link StreetCentroidSqliteLookup}), so a column rename in one is a
|
|
14
|
-
* compile error in the other — the same discipline as `address-point-schema.ts`.
|
|
15
|
-
*
|
|
16
|
-
* Probe scopes (most-selective first): by `postcode`, else by `locality_base` (the
|
|
17
|
-
* arrondissement-stripped commune — see `stripArrondissement`; BAN names Paris/Lyon/Marseille rows
|
|
18
|
-
* per arrondissement, but a query names the base commune). The reader WEIGHTED-aggregates across the
|
|
19
|
-
* matched rows (by `point_count`) so a locality-scope probe returns the street's grand centroid over
|
|
20
|
-
* every postcode/arrondissement it spans.
|
|
6
|
+
* Schema for the street-centroid extract. It groups address-point rows by street.
|
|
21
7
|
*/
|
|
22
8
|
|
|
23
9
|
import type { Kysely } from "kysely"
|
|
@@ -25,30 +11,36 @@ import type { Kysely } from "kysely"
|
|
|
25
11
|
import type { NameKey, StreetKey } from "#street/normalize"
|
|
26
12
|
|
|
27
13
|
/**
|
|
28
|
-
* One
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
14
|
+
* One row per street, postcode and commune.
|
|
15
|
+
*
|
|
16
|
+
* The tuple `(street_norm, postcode, locality_base)` is unique.
|
|
17
|
+
* The reader combines rows by `SUM(lat * point_count) / SUM(point_count)` to get a
|
|
18
|
+
* street's centroid across every postcode and arrondissement it spans.
|
|
19
|
+
*
|
|
20
|
+
* It converts the bounding-box diagonal from the `min_*` and `max_*` columns into `uncertainty_m`.
|
|
32
21
|
*/
|
|
33
22
|
export interface StreetCentroidTable {
|
|
34
23
|
/**
|
|
35
|
-
*
|
|
24
|
+
* The street key from `normalizeStreetForKeyLocale`, which both the builder and the reader use.
|
|
36
25
|
*/
|
|
37
26
|
street_norm: StreetKey
|
|
38
27
|
/**
|
|
39
|
-
* The
|
|
28
|
+
* The postcode of this group, or null when the source row has none.
|
|
40
29
|
*/
|
|
41
30
|
postcode: string | null
|
|
42
31
|
/**
|
|
43
|
-
*
|
|
32
|
+
* The commune key with any arrondissement removed.
|
|
33
|
+
*
|
|
34
|
+
* BAN stores Paris, Lyon and Marseille per arrondissement, but a query usually gives the base commune.
|
|
35
|
+
* The reader uses this column when the query has no postcode.
|
|
44
36
|
*/
|
|
45
37
|
locality_base: NameKey
|
|
46
38
|
/**
|
|
47
|
-
*
|
|
39
|
+
* The mean latitude of the group's member address points.
|
|
48
40
|
*/
|
|
49
41
|
lat: number
|
|
50
42
|
/**
|
|
51
|
-
*
|
|
43
|
+
* The mean longitude of the group's member address points.
|
|
52
44
|
*/
|
|
53
45
|
lon: number
|
|
54
46
|
min_lat: number
|
|
@@ -56,31 +48,32 @@ export interface StreetCentroidTable {
|
|
|
56
48
|
min_lon: number
|
|
57
49
|
max_lon: number
|
|
58
50
|
/**
|
|
59
|
-
*
|
|
51
|
+
* The number of member address points.
|
|
52
|
+
* This value weights the cross-row centroid.
|
|
60
53
|
*/
|
|
61
54
|
point_count: number
|
|
62
55
|
/**
|
|
63
|
-
*
|
|
56
|
+
* One street name as it appeared in the source, kept for display and debugging.
|
|
64
57
|
*/
|
|
65
58
|
street_raw: string
|
|
66
59
|
/**
|
|
67
|
-
*
|
|
60
|
+
* The source register, such as `ban:fr`.
|
|
68
61
|
*/
|
|
69
62
|
source: string
|
|
70
63
|
/**
|
|
71
|
-
* The
|
|
64
|
+
* The data release that the member points came from.
|
|
72
65
|
*/
|
|
73
66
|
release: string
|
|
74
67
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
68
|
+
* The value of `foldStreetSurface(street_raw)`, used by {@link StreetLocalityEvidence}
|
|
69
|
+
* to check that a street name exists.
|
|
70
|
+
*
|
|
71
|
+
* The name-evidence rerank folds the model's street text with the same function, so this
|
|
72
|
+
* column must use `foldStreetSurface` and must not follow the `street_norm` normalizer.
|
|
73
|
+
* The type is a plain string because `foldStreetSurface` differs from the
|
|
74
|
+
* {@link NameKey} fold that other `name_key` columns use.
|
|
80
75
|
*
|
|
81
|
-
*
|
|
82
|
-
* {@link NameKey} one every other `name_key` column carries, and giving it that brand would invite exactly the
|
|
83
|
-
* cross-fold probe the brands exist to stop.
|
|
76
|
+
* A `NameKey` type would allow a probe with the wrong fold.
|
|
84
77
|
*/
|
|
85
78
|
name_key: string
|
|
86
79
|
}
|
|
@@ -93,8 +86,9 @@ export interface StreetCentroidDatabase {
|
|
|
93
86
|
}
|
|
94
87
|
|
|
95
88
|
/**
|
|
96
|
-
* The `street_centroid` columns in
|
|
97
|
-
*
|
|
89
|
+
* The `street_centroid` columns in insert order.
|
|
90
|
+
*
|
|
91
|
+
* The builder derives the placeholders of its positional insert from this list.
|
|
98
92
|
*/
|
|
99
93
|
export const STREET_CENTROID_COLUMNS = [
|
|
100
94
|
"street_norm",
|
|
@@ -114,7 +108,7 @@ export const STREET_CENTROID_COLUMNS = [
|
|
|
114
108
|
] as const
|
|
115
109
|
|
|
116
110
|
/**
|
|
117
|
-
*
|
|
111
|
+
* Creates the `street_centroid` table before the bulk load.
|
|
118
112
|
*/
|
|
119
113
|
export async function createStreetCentroidTable(db: Kysely<StreetCentroidDatabase>): Promise<void> {
|
|
120
114
|
await db.schema
|
|
@@ -137,9 +131,10 @@ export async function createStreetCentroidTable(db: Kysely<StreetCentroidDatabas
|
|
|
137
131
|
}
|
|
138
132
|
|
|
139
133
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
134
|
+
* Creates the postcode and locality indexes that the reader probes, plus `idx_sc_name`.
|
|
135
|
+
*
|
|
136
|
+
* The `idx_sc_name` index serves the unscoped `name_key = ?` lookup.
|
|
137
|
+
* Without it, SQLite would skip-scan `idx_sc_postcode`.
|
|
143
138
|
*/
|
|
144
139
|
export async function createStreetCentroidIndexes(db: Kysely<StreetCentroidDatabase>): Promise<void> {
|
|
145
140
|
await db.schema.createIndex("idx_sc_postcode").on("street_centroid").columns(["postcode", "street_norm"]).execute()
|