@mailwoman/resolver-wof-sqlite 9.4.0 → 10.1.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.
Files changed (548) hide show
  1. package/README.md +8 -8
  2. package/lib/address/{point-interpolation.ts → point/interpolation.ts} +40 -38
  3. package/lib/address/point/schema.ts +132 -0
  4. package/lib/address/point.ts +68 -81
  5. package/lib/{address/index.ts → address.ts} +2 -2
  6. package/lib/ancestry/backfill.ts +24 -88
  7. package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
  8. package/lib/build/candidate.ts +608 -0
  9. package/lib/build/population-corrections.ts +64 -0
  10. package/lib/build/slim.ts +338 -0
  11. package/lib/candidate/alias-bags.ts +74 -14
  12. package/lib/candidate/ancestors/schema.ts +211 -0
  13. package/lib/candidate/{ancestors-sidecar.ts → ancestors/sidecar.ts} +17 -24
  14. package/lib/candidate/country-display-names.ts +6 -20
  15. package/lib/candidate/extract-fold.ts +12 -57
  16. package/lib/candidate/fts.ts +28 -0
  17. package/lib/candidate/importance.ts +221 -0
  18. package/lib/candidate/lookup.ts +669 -0
  19. package/lib/candidate/name-roles.ts +16 -34
  20. package/lib/candidate/own-name.ts +34 -31
  21. package/lib/candidate/place-attrs.ts +20 -13
  22. package/lib/candidate/schema.ts +211 -0
  23. package/lib/candidate/scoring.ts +222 -0
  24. package/lib/capital-schema.ts +21 -17
  25. package/lib/capitals.ts +26 -24
  26. package/lib/coincident-roles.ts +74 -55
  27. package/lib/convention/schema.ts +13 -7
  28. package/lib/convention.ts +144 -0
  29. package/lib/coverage-manifest-schema.ts +34 -39
  30. package/lib/currency-backfill.ts +24 -69
  31. package/lib/env.ts +1 -1
  32. package/lib/exact-match.ts +31 -20
  33. package/lib/extracts.ts +96 -73
  34. package/lib/fst/autocomplete.ts +52 -35
  35. package/lib/fst/builder.ts +30 -36
  36. package/lib/fst/deserialize-web.ts +8 -9
  37. package/lib/fst/format.ts +41 -23
  38. package/lib/fst/freshness.ts +17 -95
  39. package/lib/fst/matcher.ts +2 -2
  40. package/lib/fst/serialize.ts +45 -60
  41. package/lib/fst/types.ts +71 -59
  42. package/lib/fts/query.ts +5 -36
  43. package/lib/fts.ts +280 -0
  44. package/lib/geonames/aliases.ts +72 -149
  45. package/lib/geonames/postal.ts +162 -77
  46. package/lib/index.ts +20 -27
  47. package/lib/interpolation.ts +43 -96
  48. package/lib/lookup.ts +137 -257
  49. package/lib/name-score.ts +9 -7
  50. package/lib/nsul/lookup.ts +36 -53
  51. package/lib/nsul/schema.ts +16 -43
  52. package/lib/paths.ts +159 -0
  53. package/lib/place-importance-schema.ts +57 -164
  54. package/lib/poi/lookup.ts +100 -109
  55. package/lib/poi/schema.ts +42 -26
  56. package/lib/polygon-schema.ts +10 -6
  57. package/lib/postal/city/alias/lookup.ts +79 -0
  58. package/lib/postal/{city-alias-schema.ts → city/alias/schema.ts} +14 -10
  59. package/lib/postal/{city-candidate-schema.ts → city/candidate-schema.ts} +26 -20
  60. package/lib/postal.ts +9 -0
  61. package/lib/postcode-point-lookup.ts +9 -19
  62. package/lib/primary-preference.ts +45 -125
  63. package/lib/proximity-rerank.ts +43 -32
  64. package/lib/ranking-weights.ts +98 -76
  65. package/lib/region-keys.ts +68 -40
  66. package/lib/reverse.ts +108 -72
  67. package/lib/schema.ts +74 -42
  68. package/lib/search-fetch.ts +90 -68
  69. package/lib/sqlite/convention-source.ts +57 -0
  70. package/lib/sqlite/utils.ts +79 -0
  71. package/lib/street/centroid/schema.ts +149 -0
  72. package/lib/street/centroid.ts +16 -25
  73. package/lib/street/{morphology-fst-builder.ts → morphology/fst/builder.ts} +56 -41
  74. package/lib/street/{morphology-fst-loader.ts → morphology/fst/loader.ts} +36 -29
  75. package/lib/street/name-lookup.ts +43 -35
  76. package/lib/street/normalize.ts +85 -216
  77. package/lib/street/segment-schema.ts +116 -43
  78. package/lib/{street/index.ts → street.ts} +3 -3
  79. package/lib/types.ts +94 -140
  80. package/lib/unified-schema.ts +29 -29
  81. package/lib/uprn/existence.ts +30 -19
  82. package/lib/uprn/lookup.ts +28 -67
  83. package/lib/uprn/schema.ts +18 -40
  84. package/lib/weights-overlay-linker.ts +204 -232
  85. package/out/address/point/interpolation.d.ts +45 -0
  86. package/out/address/point/interpolation.d.ts.map +1 -0
  87. package/out/address/{point-interpolation.js → point/interpolation.js} +38 -38
  88. package/out/address/point/interpolation.js.map +1 -0
  89. package/out/address/point/schema.d.ts +74 -0
  90. package/out/address/point/schema.d.ts.map +1 -0
  91. package/out/address/{point-schema.js → point/schema.js} +4 -20
  92. package/out/address/point/schema.js.map +1 -0
  93. package/out/address/point.d.ts +24 -21
  94. package/out/address/point.d.ts.map +1 -1
  95. package/out/address/point.js +60 -77
  96. package/out/address/point.js.map +1 -1
  97. package/out/{address/index.js → address.d.ts} +3 -3
  98. package/out/address.d.ts.map +1 -0
  99. package/out/{address/index.d.ts → address.js} +3 -3
  100. package/out/address.js.map +1 -0
  101. package/out/ancestry/backfill.d.ts +11 -64
  102. package/out/ancestry/backfill.d.ts.map +1 -1
  103. package/out/ancestry/backfill.js +18 -76
  104. package/out/ancestry/backfill.js.map +1 -1
  105. package/out/ancestry.d.ts +49 -0
  106. package/out/ancestry.d.ts.map +1 -0
  107. package/out/ancestry.js +59 -0
  108. package/out/ancestry.js.map +1 -0
  109. package/out/build/candidate.d.ts +170 -0
  110. package/out/build/candidate.d.ts.map +1 -0
  111. package/out/{build-candidate.js → build/candidate.js} +33 -102
  112. package/out/build/candidate.js.map +1 -0
  113. package/out/build/population-corrections.d.ts +52 -0
  114. package/out/build/population-corrections.d.ts.map +1 -0
  115. package/out/build/population-corrections.js +40 -0
  116. package/out/build/population-corrections.js.map +1 -0
  117. package/out/build/slim.d.ts +44 -0
  118. package/out/build/slim.d.ts.map +1 -0
  119. package/out/{build-slim.js → build/slim.js} +33 -94
  120. package/out/build/slim.js.map +1 -0
  121. package/out/candidate/alias-bags.d.ts +13 -5
  122. package/out/candidate/alias-bags.d.ts.map +1 -1
  123. package/out/candidate/alias-bags.js +55 -12
  124. package/out/candidate/alias-bags.js.map +1 -1
  125. package/out/candidate/ancestors/schema.d.ts +166 -0
  126. package/out/candidate/ancestors/schema.d.ts.map +1 -0
  127. package/out/candidate/ancestors/schema.js +131 -0
  128. package/out/candidate/ancestors/schema.js.map +1 -0
  129. package/out/candidate/ancestors/sidecar.d.ts +27 -0
  130. package/out/candidate/ancestors/sidecar.d.ts.map +1 -0
  131. package/out/candidate/{ancestors-sidecar.js → ancestors/sidecar.js} +17 -24
  132. package/out/candidate/ancestors/sidecar.js.map +1 -0
  133. package/out/candidate/country-display-names.d.ts +5 -15
  134. package/out/candidate/country-display-names.d.ts.map +1 -1
  135. package/out/candidate/country-display-names.js +6 -20
  136. package/out/candidate/country-display-names.js.map +1 -1
  137. package/out/candidate/extract-fold.d.ts +8 -16
  138. package/out/candidate/extract-fold.d.ts.map +1 -1
  139. package/out/candidate/extract-fold.js +6 -48
  140. package/out/candidate/extract-fold.js.map +1 -1
  141. package/out/candidate/fts.d.ts +19 -0
  142. package/out/candidate/fts.d.ts.map +1 -0
  143. package/out/candidate/fts.js +22 -0
  144. package/out/candidate/fts.js.map +1 -0
  145. package/out/candidate/importance.d.ts +127 -0
  146. package/out/candidate/importance.d.ts.map +1 -0
  147. package/out/candidate/importance.js +162 -0
  148. package/out/candidate/importance.js.map +1 -0
  149. package/out/candidate/lookup.d.ts +36 -0
  150. package/out/candidate/lookup.d.ts.map +1 -0
  151. package/out/candidate/lookup.js +456 -0
  152. package/out/candidate/lookup.js.map +1 -0
  153. package/out/candidate/name-roles.d.ts +10 -22
  154. package/out/candidate/name-roles.d.ts.map +1 -1
  155. package/out/candidate/name-roles.js +15 -33
  156. package/out/candidate/name-roles.js.map +1 -1
  157. package/out/candidate/own-name.d.ts +23 -25
  158. package/out/candidate/own-name.d.ts.map +1 -1
  159. package/out/candidate/own-name.js +34 -31
  160. package/out/candidate/own-name.js.map +1 -1
  161. package/out/candidate/place-attrs.d.ts +20 -13
  162. package/out/candidate/place-attrs.d.ts.map +1 -1
  163. package/out/candidate/place-attrs.js +4 -5
  164. package/out/candidate/place-attrs.js.map +1 -1
  165. package/out/candidate/schema.d.ts +120 -0
  166. package/out/candidate/schema.d.ts.map +1 -0
  167. package/out/{candidate-schema.js → candidate/schema.js} +11 -23
  168. package/out/candidate/schema.js.map +1 -0
  169. package/out/{candidate-scoring.d.ts → candidate/scoring.d.ts} +8 -9
  170. package/out/candidate/scoring.d.ts.map +1 -0
  171. package/out/candidate/scoring.js +157 -0
  172. package/out/candidate/scoring.js.map +1 -0
  173. package/out/capital-schema.d.ts +21 -17
  174. package/out/capital-schema.d.ts.map +1 -1
  175. package/out/capital-schema.js +17 -15
  176. package/out/capital-schema.js.map +1 -1
  177. package/out/capitals.d.ts +26 -24
  178. package/out/capitals.d.ts.map +1 -1
  179. package/out/capitals.js +23 -21
  180. package/out/capitals.js.map +1 -1
  181. package/out/coincident-roles.d.ts +60 -43
  182. package/out/coincident-roles.d.ts.map +1 -1
  183. package/out/coincident-roles.js +61 -50
  184. package/out/coincident-roles.js.map +1 -1
  185. package/out/convention/schema.d.ts +12 -6
  186. package/out/convention/schema.d.ts.map +1 -1
  187. package/out/convention/schema.js +6 -4
  188. package/out/convention/schema.js.map +1 -1
  189. package/out/convention.d.ts +97 -0
  190. package/out/convention.d.ts.map +1 -0
  191. package/out/convention.js +81 -0
  192. package/out/convention.js.map +1 -0
  193. package/out/coverage-manifest-schema.d.ts +33 -38
  194. package/out/coverage-manifest-schema.d.ts.map +1 -1
  195. package/out/coverage-manifest-schema.js +20 -29
  196. package/out/coverage-manifest-schema.js.map +1 -1
  197. package/out/currency-backfill.d.ts +13 -35
  198. package/out/currency-backfill.d.ts.map +1 -1
  199. package/out/currency-backfill.js +12 -39
  200. package/out/currency-backfill.js.map +1 -1
  201. package/out/env.d.ts +2 -2
  202. package/out/env.js +1 -1
  203. package/out/exact-match.d.ts +19 -10
  204. package/out/exact-match.d.ts.map +1 -1
  205. package/out/exact-match.js +31 -20
  206. package/out/exact-match.js.map +1 -1
  207. package/out/extracts.d.ts +65 -54
  208. package/out/extracts.d.ts.map +1 -1
  209. package/out/extracts.js +63 -55
  210. package/out/extracts.js.map +1 -1
  211. package/out/fst/autocomplete.d.ts +28 -20
  212. package/out/fst/autocomplete.d.ts.map +1 -1
  213. package/out/fst/autocomplete.js +38 -27
  214. package/out/fst/autocomplete.js.map +1 -1
  215. package/out/fst/builder.d.ts.map +1 -1
  216. package/out/fst/builder.js +30 -36
  217. package/out/fst/builder.js.map +1 -1
  218. package/out/fst/deserialize-web.d.ts +3 -3
  219. package/out/fst/deserialize-web.d.ts.map +1 -1
  220. package/out/fst/deserialize-web.js +8 -9
  221. package/out/fst/deserialize-web.js.map +1 -1
  222. package/out/fst/format.d.ts +41 -23
  223. package/out/fst/format.d.ts.map +1 -1
  224. package/out/fst/format.js +41 -23
  225. package/out/fst/format.js.map +1 -1
  226. package/out/fst/freshness.d.ts +11 -73
  227. package/out/fst/freshness.d.ts.map +1 -1
  228. package/out/fst/freshness.js +12 -76
  229. package/out/fst/freshness.js.map +1 -1
  230. package/out/fst/matcher.d.ts +1 -1
  231. package/out/fst/matcher.d.ts.map +1 -1
  232. package/out/fst/matcher.js +2 -2
  233. package/out/fst/matcher.js.map +1 -1
  234. package/out/fst/serialize.d.ts +30 -26
  235. package/out/fst/serialize.d.ts.map +1 -1
  236. package/out/fst/serialize.js +44 -58
  237. package/out/fst/serialize.js.map +1 -1
  238. package/out/fst/types.d.ts +71 -59
  239. package/out/fst/types.d.ts.map +1 -1
  240. package/out/fst/types.js +1 -4
  241. package/out/fst/types.js.map +1 -1
  242. package/out/{fst/index.js → fst.d.ts} +1 -1
  243. package/out/fst.d.ts.map +1 -0
  244. package/out/{fst/index.d.ts → fst.js} +1 -1
  245. package/out/fst.js.map +1 -0
  246. package/out/fts/query.d.ts +2 -27
  247. package/out/fts/query.d.ts.map +1 -1
  248. package/out/fts/query.js +5 -36
  249. package/out/fts/query.js.map +1 -1
  250. package/out/fts.d.ts +126 -0
  251. package/out/fts.d.ts.map +1 -0
  252. package/out/fts.js +188 -0
  253. package/out/fts.js.map +1 -0
  254. package/out/geonames/aliases.d.ts +26 -67
  255. package/out/geonames/aliases.d.ts.map +1 -1
  256. package/out/geonames/aliases.js +44 -121
  257. package/out/geonames/aliases.js.map +1 -1
  258. package/out/geonames/postal.d.ts +84 -50
  259. package/out/geonames/postal.d.ts.map +1 -1
  260. package/out/geonames/postal.js +115 -78
  261. package/out/geonames/postal.js.map +1 -1
  262. package/out/{geonames/index.js → geonames.d.ts} +1 -1
  263. package/out/geonames.d.ts.map +1 -0
  264. package/out/{geonames/index.d.ts → geonames.js} +1 -1
  265. package/out/geonames.js.map +1 -0
  266. package/out/index.d.ts +20 -21
  267. package/out/index.d.ts.map +1 -1
  268. package/out/index.js +14 -15
  269. package/out/index.js.map +1 -1
  270. package/out/interpolation.d.ts +15 -52
  271. package/out/interpolation.d.ts.map +1 -1
  272. package/out/interpolation.js +25 -68
  273. package/out/interpolation.js.map +1 -1
  274. package/out/lookup.d.ts +24 -53
  275. package/out/lookup.d.ts.map +1 -1
  276. package/out/lookup.js +117 -223
  277. package/out/lookup.js.map +1 -1
  278. package/out/name-score.d.ts +2 -2
  279. package/out/name-score.d.ts.map +1 -1
  280. package/out/name-score.js +9 -7
  281. package/out/name-score.js.map +1 -1
  282. package/out/nsul/lookup.d.ts +33 -34
  283. package/out/nsul/lookup.d.ts.map +1 -1
  284. package/out/nsul/lookup.js +26 -40
  285. package/out/nsul/lookup.js.map +1 -1
  286. package/out/nsul/schema.d.ts +16 -43
  287. package/out/nsul/schema.d.ts.map +1 -1
  288. package/out/nsul/schema.js +9 -35
  289. package/out/nsul/schema.js.map +1 -1
  290. package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
  291. package/out/nsul.d.ts.map +1 -0
  292. package/out/{nsul/index.js → nsul.js} +1 -1
  293. package/out/nsul.js.map +1 -0
  294. package/out/paths.d.ts +124 -0
  295. package/out/paths.d.ts.map +1 -0
  296. package/out/paths.js +104 -0
  297. package/out/paths.js.map +1 -0
  298. package/out/place-importance-schema.d.ts +49 -141
  299. package/out/place-importance-schema.d.ts.map +1 -1
  300. package/out/place-importance-schema.js +25 -140
  301. package/out/place-importance-schema.js.map +1 -1
  302. package/out/poi/lookup.d.ts +38 -42
  303. package/out/poi/lookup.d.ts.map +1 -1
  304. package/out/poi/lookup.js +67 -90
  305. package/out/poi/lookup.js.map +1 -1
  306. package/out/poi/schema.d.ts +41 -25
  307. package/out/poi/schema.d.ts.map +1 -1
  308. package/out/poi/schema.js +25 -17
  309. package/out/poi/schema.js.map +1 -1
  310. package/out/{poi/index.js → poi.d.ts} +1 -1
  311. package/out/poi.d.ts.map +1 -0
  312. package/out/{poi/index.d.ts → poi.js} +1 -1
  313. package/out/poi.js.map +1 -0
  314. package/out/polygon-schema.d.ts +10 -6
  315. package/out/polygon-schema.d.ts.map +1 -1
  316. package/out/polygon-schema.js +2 -2
  317. package/out/polygon-schema.js.map +1 -1
  318. package/out/postal/{city-alias-lookup.d.ts → city/alias/lookup.d.ts} +22 -25
  319. package/out/postal/city/alias/lookup.d.ts.map +1 -0
  320. package/out/postal/city/alias/lookup.js +49 -0
  321. package/out/postal/city/alias/lookup.js.map +1 -0
  322. package/out/postal/{city-alias-schema.d.ts → city/alias/schema.d.ts} +15 -11
  323. package/out/postal/city/alias/schema.d.ts.map +1 -0
  324. package/out/postal/{city-alias-schema.js → city/alias/schema.js} +11 -9
  325. package/out/postal/city/alias/schema.js.map +1 -0
  326. package/out/postal/city/candidate-schema.d.ts +72 -0
  327. package/out/postal/city/candidate-schema.d.ts.map +1 -0
  328. package/out/postal/city/candidate-schema.js +60 -0
  329. package/out/postal/city/candidate-schema.js.map +1 -0
  330. package/out/postal.d.ts +9 -0
  331. package/out/postal.d.ts.map +1 -0
  332. package/out/postal.js +9 -0
  333. package/out/postal.js.map +1 -0
  334. package/out/postcode-point-lookup.d.ts +9 -19
  335. package/out/postcode-point-lookup.d.ts.map +1 -1
  336. package/out/postcode-point-lookup.js +5 -17
  337. package/out/postcode-point-lookup.js.map +1 -1
  338. package/out/primary-preference.d.ts +39 -93
  339. package/out/primary-preference.d.ts.map +1 -1
  340. package/out/primary-preference.js +13 -97
  341. package/out/primary-preference.js.map +1 -1
  342. package/out/proximity-rerank.d.ts +40 -29
  343. package/out/proximity-rerank.d.ts.map +1 -1
  344. package/out/proximity-rerank.js +38 -29
  345. package/out/proximity-rerank.js.map +1 -1
  346. package/out/ranking-weights.d.ts +91 -62
  347. package/out/ranking-weights.d.ts.map +1 -1
  348. package/out/ranking-weights.js +26 -25
  349. package/out/ranking-weights.js.map +1 -1
  350. package/out/region-keys.d.ts +48 -29
  351. package/out/region-keys.d.ts.map +1 -1
  352. package/out/region-keys.js +68 -40
  353. package/out/region-keys.js.map +1 -1
  354. package/out/reverse.d.ts +75 -50
  355. package/out/reverse.d.ts.map +1 -1
  356. package/out/reverse.js +61 -49
  357. package/out/reverse.js.map +1 -1
  358. package/out/schema.d.ts +74 -42
  359. package/out/schema.d.ts.map +1 -1
  360. package/out/schema.js +4 -5
  361. package/out/schema.js.map +1 -1
  362. package/out/search-fetch.d.ts +16 -12
  363. package/out/search-fetch.d.ts.map +1 -1
  364. package/out/search-fetch.js +83 -63
  365. package/out/search-fetch.js.map +1 -1
  366. package/out/sqlite/convention-source.d.ts +25 -0
  367. package/out/sqlite/convention-source.d.ts.map +1 -0
  368. package/out/sqlite/convention-source.js +48 -0
  369. package/out/sqlite/convention-source.js.map +1 -0
  370. package/out/sqlite/utils.d.ts +45 -0
  371. package/out/sqlite/utils.d.ts.map +1 -0
  372. package/out/sqlite/utils.js +56 -0
  373. package/out/sqlite/utils.js.map +1 -0
  374. package/out/street/centroid/schema.d.ts +100 -0
  375. package/out/street/centroid/schema.d.ts.map +1 -0
  376. package/out/street/centroid/schema.js +66 -0
  377. package/out/street/centroid/schema.js.map +1 -0
  378. package/out/street/centroid.d.ts +9 -19
  379. package/out/street/centroid.d.ts.map +1 -1
  380. package/out/street/centroid.js +11 -22
  381. package/out/street/centroid.js.map +1 -1
  382. package/out/street/{morphology-fst-builder.d.ts → morphology/fst/builder.d.ts} +21 -11
  383. package/out/street/morphology/fst/builder.d.ts.map +1 -0
  384. package/out/street/{morphology-fst-builder.js → morphology/fst/builder.js} +40 -34
  385. package/out/street/morphology/fst/builder.js.map +1 -0
  386. package/out/street/morphology/fst/loader.d.ts +74 -0
  387. package/out/street/morphology/fst/loader.d.ts.map +1 -0
  388. package/out/street/{morphology-fst-loader.js → morphology/fst/loader.js} +21 -21
  389. package/out/street/morphology/fst/loader.js.map +1 -0
  390. package/out/street/name-lookup.d.ts +24 -18
  391. package/out/street/name-lookup.d.ts.map +1 -1
  392. package/out/street/name-lookup.js +32 -31
  393. package/out/street/name-lookup.js.map +1 -1
  394. package/out/street/normalize.d.ts +35 -136
  395. package/out/street/normalize.d.ts.map +1 -1
  396. package/out/street/normalize.js +74 -191
  397. package/out/street/normalize.js.map +1 -1
  398. package/out/street/segment-schema.d.ts +79 -39
  399. package/out/street/segment-schema.d.ts.map +1 -1
  400. package/out/street/segment-schema.js +71 -21
  401. package/out/street/segment-schema.js.map +1 -1
  402. package/out/{street/index.d.ts → street.d.ts} +4 -4
  403. package/out/street.d.ts.map +1 -0
  404. package/out/{street/index.js → street.js} +4 -4
  405. package/out/street.js.map +1 -0
  406. package/out/types.d.ts +69 -138
  407. package/out/types.d.ts.map +1 -1
  408. package/out/types.js +0 -6
  409. package/out/types.js.map +1 -1
  410. package/out/unified-schema.d.ts +8 -12
  411. package/out/unified-schema.d.ts.map +1 -1
  412. package/out/unified-schema.js +29 -29
  413. package/out/unified-schema.js.map +1 -1
  414. package/out/uprn/existence.d.ts +28 -17
  415. package/out/uprn/existence.d.ts.map +1 -1
  416. package/out/uprn/existence.js +26 -16
  417. package/out/uprn/existence.js.map +1 -1
  418. package/out/uprn/lookup.d.ts +14 -44
  419. package/out/uprn/lookup.d.ts.map +1 -1
  420. package/out/uprn/lookup.js +20 -56
  421. package/out/uprn/lookup.js.map +1 -1
  422. package/out/uprn/schema.d.ts +18 -40
  423. package/out/uprn/schema.d.ts.map +1 -1
  424. package/out/uprn/schema.js +10 -32
  425. package/out/uprn/schema.js.map +1 -1
  426. package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
  427. package/out/uprn.d.ts.map +1 -0
  428. package/out/{uprn/index.js → uprn.js} +1 -1
  429. package/out/uprn.js.map +1 -0
  430. package/out/weights-overlay-linker.d.ts +132 -141
  431. package/out/weights-overlay-linker.d.ts.map +1 -1
  432. package/out/weights-overlay-linker.js +86 -154
  433. package/out/weights-overlay-linker.js.map +1 -1
  434. package/package.json +94 -599
  435. package/lib/address/point-schema.ts +0 -155
  436. package/lib/build-candidate.ts +0 -632
  437. package/lib/build-slim.ts +0 -408
  438. package/lib/candidate-ancestors-schema.ts +0 -195
  439. package/lib/candidate-fts.ts +0 -46
  440. package/lib/candidate-importance.ts +0 -224
  441. package/lib/candidate-lookup.ts +0 -977
  442. package/lib/candidate-schema.ts +0 -247
  443. package/lib/candidate-scoring.ts +0 -261
  444. package/lib/convention/index.ts +0 -154
  445. package/lib/fts/index.ts +0 -361
  446. package/lib/postal/city-alias-lookup.ts +0 -97
  447. package/lib/postal/index.ts +0 -9
  448. package/lib/sqlite-convention-source.ts +0 -65
  449. package/lib/sqlite-utils.ts +0 -82
  450. package/lib/street/centroid-schema.ts +0 -154
  451. package/out/address/index.d.ts.map +0 -1
  452. package/out/address/index.js.map +0 -1
  453. package/out/address/point-interpolation.d.ts +0 -49
  454. package/out/address/point-interpolation.d.ts.map +0 -1
  455. package/out/address/point-interpolation.js.map +0 -1
  456. package/out/address/point-schema.d.ts +0 -97
  457. package/out/address/point-schema.d.ts.map +0 -1
  458. package/out/address/point-schema.js.map +0 -1
  459. package/out/ancestry/index.d.ts +0 -45
  460. package/out/ancestry/index.d.ts.map +0 -1
  461. package/out/ancestry/index.js +0 -55
  462. package/out/ancestry/index.js.map +0 -1
  463. package/out/build-candidate.d.ts +0 -184
  464. package/out/build-candidate.d.ts.map +0 -1
  465. package/out/build-candidate.js.map +0 -1
  466. package/out/build-slim.d.ts +0 -80
  467. package/out/build-slim.d.ts.map +0 -1
  468. package/out/build-slim.js.map +0 -1
  469. package/out/candidate/ancestors-sidecar.d.ts +0 -32
  470. package/out/candidate/ancestors-sidecar.d.ts.map +0 -1
  471. package/out/candidate/ancestors-sidecar.js.map +0 -1
  472. package/out/candidate-ancestors-schema.d.ts +0 -150
  473. package/out/candidate-ancestors-schema.d.ts.map +0 -1
  474. package/out/candidate-ancestors-schema.js +0 -123
  475. package/out/candidate-ancestors-schema.js.map +0 -1
  476. package/out/candidate-fts.d.ts +0 -37
  477. package/out/candidate-fts.d.ts.map +0 -1
  478. package/out/candidate-fts.js +0 -40
  479. package/out/candidate-fts.js.map +0 -1
  480. package/out/candidate-importance.d.ts +0 -132
  481. package/out/candidate-importance.d.ts.map +0 -1
  482. package/out/candidate-importance.js +0 -169
  483. package/out/candidate-importance.js.map +0 -1
  484. package/out/candidate-lookup.d.ts +0 -76
  485. package/out/candidate-lookup.d.ts.map +0 -1
  486. package/out/candidate-lookup.js +0 -768
  487. package/out/candidate-lookup.js.map +0 -1
  488. package/out/candidate-schema.d.ts +0 -155
  489. package/out/candidate-schema.d.ts.map +0 -1
  490. package/out/candidate-schema.js.map +0 -1
  491. package/out/candidate-scoring.d.ts.map +0 -1
  492. package/out/candidate-scoring.js +0 -196
  493. package/out/candidate-scoring.js.map +0 -1
  494. package/out/convention/index.d.ts +0 -106
  495. package/out/convention/index.d.ts.map +0 -1
  496. package/out/convention/index.js +0 -93
  497. package/out/convention/index.js.map +0 -1
  498. package/out/fst/index.d.ts.map +0 -1
  499. package/out/fst/index.js.map +0 -1
  500. package/out/fts/index.d.ts +0 -184
  501. package/out/fts/index.d.ts.map +0 -1
  502. package/out/fts/index.js +0 -277
  503. package/out/fts/index.js.map +0 -1
  504. package/out/geonames/index.d.ts.map +0 -1
  505. package/out/geonames/index.js.map +0 -1
  506. package/out/nsul/index.d.ts.map +0 -1
  507. package/out/nsul/index.js.map +0 -1
  508. package/out/poi/index.d.ts.map +0 -1
  509. package/out/poi/index.js.map +0 -1
  510. package/out/postal/city-alias-lookup.d.ts.map +0 -1
  511. package/out/postal/city-alias-lookup.js +0 -62
  512. package/out/postal/city-alias-lookup.js.map +0 -1
  513. package/out/postal/city-alias-schema.d.ts.map +0 -1
  514. package/out/postal/city-alias-schema.js.map +0 -1
  515. package/out/postal/city-candidate-schema.d.ts +0 -66
  516. package/out/postal/city-candidate-schema.d.ts.map +0 -1
  517. package/out/postal/city-candidate-schema.js +0 -56
  518. package/out/postal/city-candidate-schema.js.map +0 -1
  519. package/out/postal/index.d.ts +0 -9
  520. package/out/postal/index.d.ts.map +0 -1
  521. package/out/postal/index.js +0 -9
  522. package/out/postal/index.js.map +0 -1
  523. package/out/sqlite-convention-source.d.ts +0 -29
  524. package/out/sqlite-convention-source.d.ts.map +0 -1
  525. package/out/sqlite-convention-source.js +0 -57
  526. package/out/sqlite-convention-source.js.map +0 -1
  527. package/out/sqlite-utils.d.ts +0 -45
  528. package/out/sqlite-utils.d.ts.map +0 -1
  529. package/out/sqlite-utils.js +0 -57
  530. package/out/sqlite-utils.js.map +0 -1
  531. package/out/street/centroid-schema.d.ts +0 -105
  532. package/out/street/centroid-schema.d.ts.map +0 -1
  533. package/out/street/centroid-schema.js +0 -78
  534. package/out/street/centroid-schema.js.map +0 -1
  535. package/out/street/index.d.ts.map +0 -1
  536. package/out/street/index.js.map +0 -1
  537. package/out/street/morphology-fst-builder.d.ts.map +0 -1
  538. package/out/street/morphology-fst-builder.js.map +0 -1
  539. package/out/street/morphology-fst-loader.d.ts +0 -67
  540. package/out/street/morphology-fst-loader.d.ts.map +0 -1
  541. package/out/street/morphology-fst-loader.js.map +0 -1
  542. package/out/uprn/index.d.ts.map +0 -1
  543. package/out/uprn/index.js.map +0 -1
  544. /package/lib/{fst/index.ts → fst.ts} +0 -0
  545. /package/lib/{geonames/index.ts → geonames.ts} +0 -0
  546. /package/lib/{nsul/index.ts → nsul.ts} +0 -0
  547. /package/lib/{poi/index.ts → poi.ts} +0 -0
  548. /package/lib/{uprn/index.ts → uprn.ts} +0 -0
@@ -0,0 +1,608 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+
7
+ import { COUNTRY_POPULATION } from "@mailwoman/codex/country"
8
+ import { pathExists } from "@mailwoman/core/fs/readers"
9
+ import { removePath } from "@mailwoman/core/fs/writers"
10
+ import { stringifyJSON } from "@mailwoman/core/json"
11
+ import { DatabaseClient } from "@mailwoman/sqlite/client"
12
+ import type { PathBuilderLike } from "path-ts"
13
+
14
+ import { POPULATION_CORRECTIONS } from "#build/population-corrections"
15
+ import { explodeAliasBags } from "#candidate/alias-bags"
16
+ import { buildAncestorsSidecar } from "#candidate/ancestors/sidecar"
17
+ import { stageCountryDisplayNames } from "#candidate/country-display-names"
18
+ import { foldExtract } from "#candidate/extract-fold"
19
+ import { createCandidateFTS } from "#candidate/fts"
20
+ import { IMPORTANCE_JOIN_RADIUS_KM, loadImportanceIndex } from "#candidate/importance"
21
+ import { GLOSS_KEY_THRESHOLD, stampNameRoles } from "#candidate/name-roles"
22
+ import type { PlaceAttrs } from "#candidate/place-attrs"
23
+ import {
24
+ CANDIDATE_COLUMNS,
25
+ createCandidateStagingTables,
26
+ createCandidateTable,
27
+ type CandidateDatabase,
28
+ } from "#candidate/schema"
29
+ import { createCapitalTable } from "#capital-schema"
30
+ import type { CapitalPoint } from "#capitals"
31
+ import { resurrectCurrencyHoles } from "#currency-backfill"
32
+ import type { WOFDatabase } from "#schema"
33
+ import { normalizeLocalityForKey } from "#street/normalize"
34
+
35
+ /**
36
+ * Re-exports the country display-name staging pass from the candidate build's public module.
37
+ */
38
+ export { stageCountryDisplayNames } from "#candidate/country-display-names"
39
+ /**
40
+ * Re-exports the gloss detector's excluded placetypes and default key-count threshold.
41
+ */
42
+ export { GLOSS_EXCLUDED_PLACETYPES, GLOSS_KEY_THRESHOLD } from "#candidate/name-roles"
43
+ /**
44
+ * Re-exports the per-place record that every candidate staging pass writes its rows from.
45
+ */
46
+ export type { PlaceAttrs } from "#candidate/place-attrs"
47
+
48
+ /**
49
+ * Options for {@link buildCandidateTable}.
50
+ */
51
+ export interface BuildCandidateOptions {
52
+ /**
53
+ * The source WOF admin database.
54
+ *
55
+ * It must have the `spr`, `place_population`, `place_search`, `place_abbr` and `ancestors` tables.
56
+ */
57
+ input: PathBuilderLike
58
+
59
+ /**
60
+ * The candidate database to write, replacing any existing file.
61
+ */
62
+ output: PathBuilderLike
63
+
64
+ /**
65
+ * The capital reference entries to store in the artifact's `capital` table.
66
+ *
67
+ * The caller supplies these entries because this published module cannot read repository paths.
68
+ * The builder creates no `capital` table when the caller omits them.
69
+ *
70
+ * The capital loader then falls back to the repository's `capitals-v1.json`.
71
+ */
72
+ capitals?: readonly CapitalPoint[]
73
+
74
+ /**
75
+ * Postcode extract databases whose located `spr` rows become `postalcode` candidate rows.
76
+ *
77
+ * Each extract's `names` table becomes aliases, such as the delivery city "Brooklyn" for 11201.
78
+ */
79
+ postcodes?: readonly PathBuilderLike[]
80
+
81
+ /**
82
+ * Locality extract databases whose located `spr` rows become `locality`
83
+ * candidate rows with zero population.
84
+ *
85
+ * Their `names` tables become non-primary aliases.
86
+ * When an extract's `ancestors` table gives a row's region, the row gets
87
+ * that region's scope and closure rows.
88
+ * Other rows stay unscoped.
89
+ */
90
+ localities?: readonly PathBuilderLike[]
91
+
92
+ /**
93
+ * A WOF admin database with a `place_importance` table supplies the `importance` column.
94
+ *
95
+ * Rows join on name key, country and placetype, then on the nearest centroid.
96
+ * Without this option every row's `importance` is NULL.
97
+ * Consumers treat NULL as unmeasured.
98
+ */
99
+ importance?: PathBuilderLike
100
+
101
+ /**
102
+ * Settings for restoring deprecated WOF places that have no successor and have a GeoNames attestation.
103
+ *
104
+ * A deprecated place is restored only when no live row of the same name lies within 10 km and
105
+ * a GeoNames populated place with the same folded name and at least 1,000 people lies within 10 km.
106
+ * Countries without `<cc>.txt` under `geonamesDir` are skipped and reported.
107
+ */
108
+ currencyBackfill?: {
109
+ geonamesDir: PathBuilderLike
110
+ countries: readonly string[]
111
+
112
+ /**
113
+ * The deprecated placetypes eligible for restoration.
114
+ * The default is `locality`.
115
+ */
116
+ deadPlacetypes?: readonly string[]
117
+ }
118
+
119
+ /**
120
+ * Receives a phase name and a message as each build step runs.
121
+ */
122
+ onProgress?: (phase: string, message: string) => void
123
+
124
+ /**
125
+ * The key-count threshold for the gloss anomaly detector.
126
+ * The default is {@link GLOSS_KEY_THRESHOLD}.
127
+ *
128
+ * Tests override it with a value sized for fixtures.
129
+ */
130
+ glossKeyThreshold?: number
131
+ }
132
+
133
+ /**
134
+ * Row and place counts from each stage of {@link buildCandidateTable}.
135
+ */
136
+ export interface BuildCandidateResult {
137
+ rows: number
138
+ places: number
139
+ primaries: number
140
+ aliases: number
141
+
142
+ /**
143
+ * The count of region aliases dropped because another region in the same
144
+ * country uses the name as its official name.
145
+ *
146
+ * The count is always zero for a source without a `names` table.
147
+ */
148
+ regionOfficialRefused: number
149
+ abbrevs: number
150
+ postcodes: number
151
+
152
+ /**
153
+ * The count of aliases added to postcode rows from the extracts' `names` tables.
154
+ *
155
+ * An extract without a `names` table is reported through `onProgress`.
156
+ */
157
+ postcodeAliases: number
158
+
159
+ /**
160
+ * The count of closure rows written to the `candidate_ancestor` sidecar,
161
+ * including rows from locality extracts.
162
+ */
163
+ ancestorRows: number
164
+
165
+ /**
166
+ * The count of places with at least one closure row.
167
+ */
168
+ ancestorPlaces: number
169
+
170
+ /**
171
+ * The count of places that received a pre/post interval label.
172
+ * It equals the node count of the canonical-parent forest.
173
+ *
174
+ * Containment against a place outside the forest is unknown.
175
+ */
176
+ intervalPlaces: number
177
+
178
+ /**
179
+ * The count of places that received an `importance` score.
180
+ *
181
+ * It is `undefined` when no score source was given.
182
+ */
183
+ importanceScored?: number
184
+
185
+ /**
186
+ * The count of places that matched a scored group by name key, country and placetype
187
+ * but whose nearest scored centroid lay beyond {@link IMPORTANCE_JOIN_RADIUS_KM}.
188
+ *
189
+ * A large change between rebuilds means the score source and the admin source have diverged.
190
+ */
191
+ importanceFiltered?: number
192
+
193
+ /**
194
+ * The count of alias rows the gloss anomaly detector stamped `name_role = 'gloss'`.
195
+ */
196
+ roleGloss: number
197
+
198
+ /**
199
+ * The count of alias rows stamped `name_role = 'abbr'`, which marks a variant in the official language.
200
+ */
201
+ roleAbbr: number
202
+
203
+ /**
204
+ * The count of admin places whose staged key count reached the gloss key threshold.
205
+ * It is the denominator for `keyTailWithRole`.
206
+ */
207
+ keyTailPlaces: number
208
+
209
+ /**
210
+ * The count of places in `keyTailPlaces` with at least one stamped role row.
211
+ */
212
+ keyTailWithRole: number
213
+ }
214
+
215
+ /**
216
+ * Builds the candidate lookup database from a WOF admin database and replaces any existing output.
217
+ * The builder adds an FTS5 trigram index for fuzzy lookup.
218
+ */
219
+ export async function buildCandidateTable(opts: BuildCandidateOptions): Promise<BuildCandidateResult> {
220
+ const progress = opts.onProgress ?? (() => {})
221
+
222
+ if (await pathExists(opts.output)) {
223
+ await removePath(opts.output)
224
+ }
225
+
226
+ using src = new DatabaseClient<WOFDatabase>(opts.input, { readOnly: true })
227
+ using kdb = new DatabaseClient<CandidateDatabase>(opts.output)
228
+
229
+ kdb.exec("PRAGMA page_size=8192; PRAGMA journal_mode=OFF; PRAGMA synchronous=OFF; PRAGMA cache_size=-2000000;")
230
+
231
+ await createCandidateStagingTables(kdb)
232
+
233
+ const ccodes = new Map<string, number>()
234
+ const ptcodes = new Map<string, number>()
235
+
236
+ const ccID = (code: string | null): number => {
237
+ const c = (code || "??").toUpperCase()
238
+ let id = ccodes.get(c)
239
+
240
+ if (id === undefined) {
241
+ id = ccodes.size
242
+ ccodes.set(c, id)
243
+ }
244
+
245
+ return id
246
+ }
247
+
248
+ const ptID = (pt: string | null): number => {
249
+ const p = pt || ""
250
+ let id = ptcodes.get(p)
251
+
252
+ if (id === undefined) {
253
+ id = ptcodes.size
254
+ ptcodes.set(p, id)
255
+ }
256
+
257
+ return id
258
+ }
259
+
260
+ let importance: ReturnType<typeof loadImportanceIndex> | undefined
261
+
262
+ if (opts.importance) {
263
+ progress("importance", `loading place_importance from ${opts.importance}`)
264
+ importance = loadImportanceIndex(opts.importance)
265
+
266
+ progress(
267
+ "importance",
268
+ `${importance.stats.places.toLocaleString()} scored places in ${importance.stats.keys.toLocaleString()} (name, country, placetype) groups` +
269
+ (importance.stats.unkeyable ? `; ${importance.stats.unkeyable.toLocaleString()} unkeyable names skipped` : "")
270
+ )
271
+ } else {
272
+ progress("importance", "no score source given — `importance` will be NULL on every row")
273
+ }
274
+
275
+ progress("region", "loading region ancestry")
276
+ const regionOf = new Map<number, number>()
277
+ let multiRegion = 0
278
+
279
+ for (const r of src
280
+ .prepare(
281
+ "SELECT id, MIN(ancestor_id) AS ancestor_id, COUNT(DISTINCT ancestor_id) AS n" +
282
+ " FROM ancestors WHERE ancestor_placetype='region' GROUP BY id"
283
+ )
284
+ .iterate()) {
285
+ regionOf.set(Number(r.id), Number(r.ancestor_id))
286
+
287
+ if (Number(r.n) > 1) {
288
+ multiRegion++
289
+ }
290
+ }
291
+
292
+ progress(
293
+ "region",
294
+ `${regionOf.size.toLocaleString()} places carry a region` +
295
+ (multiRegion ? ` (${multiRegion.toLocaleString()} carry more than one; stamped with the lowest id)` : "")
296
+ )
297
+
298
+ const insStage = kdb.prepare(`INSERT INTO cand_stage VALUES (${CANDIDATE_COLUMNS.map(() => "?").join(", ")})`)
299
+
300
+ progress("primaries", "indexing place names")
301
+ const attrs = new Map<number, PlaceAttrs>()
302
+ let nPrim = 0
303
+ kdb.exec("BEGIN")
304
+
305
+ for (const r of src
306
+ .prepare(
307
+ `SELECT s.id AS id, s.name AS name, s.placetype AS placetype, s.country AS country,
308
+ s.latitude AS lat, s.longitude AS lon,
309
+ s.min_latitude AS mnlat, s.min_longitude AS mnlon, s.max_latitude AS mxlat, s.max_longitude AS mxlon,
310
+ pp.population AS pop
311
+ FROM spr s LEFT JOIN place_population pp ON pp.id = s.id
312
+ WHERE s.is_current != 0 AND s.is_deprecated = 0`
313
+ )
314
+ .iterate()) {
315
+ const sid = Number(r.id)
316
+ const cid = ccID(r.country as string | null)
317
+ const ptid = ptID(r.placetype as string | null)
318
+ const rid = regionOf.get(sid) ?? 0
319
+
320
+ const wofPop = r.pop === null || r.pop === undefined ? null : Number(r.pop)
321
+
322
+ const pop =
323
+ POPULATION_CORRECTIONS[sid]?.population ??
324
+ (wofPop === null && r.placetype === "country" ? (COUNTRY_POPULATION[String(r.country ?? "")] ?? null) : wofPop)
325
+
326
+ const neg = -Math.log10((pop ?? 0) + 1)
327
+ const name = String(r.name ?? "")
328
+ const pkey = normalizeLocalityForKey(name)
329
+ const lat = r.lat as number
330
+ const lon = r.lon as number
331
+
332
+ const a: PlaceAttrs = {
333
+ cid,
334
+ rid,
335
+ ptid,
336
+ name,
337
+ lat,
338
+ lon,
339
+ mnLat: r.mnlat as number,
340
+ mnLon: r.mnlon as number,
341
+ mxLat: r.mxlat as number,
342
+ mxLon: r.mxlon as number,
343
+ pop,
344
+ neg,
345
+ pkey,
346
+ imp: importance?.find(name, r.country as string | null, r.placetype as string | null, lat, lon) ?? null,
347
+ }
348
+
349
+ attrs.set(sid, a)
350
+
351
+ if (pkey) {
352
+ insStage.run(
353
+ pkey,
354
+ cid,
355
+ rid,
356
+ ptid,
357
+ neg,
358
+ sid,
359
+ name,
360
+ a.lat,
361
+ a.lon,
362
+ a.mnLat,
363
+ a.mnLon,
364
+ a.mxLat,
365
+ a.mxLon,
366
+ pop,
367
+ 1,
368
+ a.imp,
369
+ null
370
+ )
371
+
372
+ nPrim++
373
+ }
374
+ }
375
+
376
+ kdb.exec("COMMIT")
377
+ progress("primaries", `${nPrim.toLocaleString()} primaries; ${attrs.size.toLocaleString()} places`)
378
+
379
+ if (importance) {
380
+ progress(
381
+ "importance",
382
+ `${importance.matched.toLocaleString()} places scored; ` +
383
+ `${importance.refused.toLocaleString()} refused (nearest same-name place > ${IMPORTANCE_JOIN_RADIUS_KM} km away)`
384
+ )
385
+ }
386
+
387
+ const stageRow = (k: string, a: PlaceAttrs, sid: number, isPrimary: number): void => {
388
+ insStage.run(
389
+ k,
390
+ a.cid,
391
+ a.rid,
392
+ a.ptid,
393
+ a.neg,
394
+ sid,
395
+ a.name,
396
+ a.lat,
397
+ a.lon,
398
+ a.mnLat,
399
+ a.mnLon,
400
+ a.mxLat,
401
+ a.mxLon,
402
+ a.pop,
403
+ isPrimary,
404
+ a.imp,
405
+ null
406
+ )
407
+ }
408
+
409
+ progress(
410
+ "country-display-names",
411
+ `${stageCountryDisplayNames({
412
+ attrs,
413
+ iso2ByID: new Map([...ccodes].map(([code, id]) => [id, code])),
414
+ countryPtID: ptID("country"),
415
+ stageRow,
416
+ tx: kdb,
417
+ }).toLocaleString()} country surfaces`
418
+ )
419
+
420
+ if (opts.currencyBackfill) {
421
+ const nBackfill = await resurrectCurrencyHoles({
422
+ src,
423
+ tx: kdb,
424
+ geonamesDir: opts.currencyBackfill.geonamesDir,
425
+ countries: opts.currencyBackfill.countries,
426
+ ...(opts.currencyBackfill.deadPlacetypes ? { deadPlacetypes: opts.currencyBackfill.deadPlacetypes } : {}),
427
+ attrs,
428
+ ccID,
429
+ ptID,
430
+ regionOf,
431
+ importance,
432
+ stageRow,
433
+ progress,
434
+ })
435
+
436
+ progress("currency-backfill", `${nBackfill.toLocaleString()} resurrections staged`)
437
+ } else {
438
+ progress("currency-backfill", "not configured — deprecated-no-successor holes stay dead (#1737)")
439
+ }
440
+
441
+ progress("aliases", "exploding alias bags")
442
+
443
+ const { nAlias, keyCounts, regionOfficialRefused } = explodeAliasBags(src, kdb, attrs, stageRow, {
444
+ regionPlacetypeID: ptID("region"),
445
+ ccID,
446
+ })
447
+
448
+ progress(
449
+ "aliases",
450
+ `${nAlias.toLocaleString()} aliases` +
451
+ (regionOfficialRefused
452
+ ? `; ${regionOfficialRefused.toLocaleString()} region aliases refused as another region's official name`
453
+ : "")
454
+ )
455
+
456
+ let nAbbr = 0
457
+ kdb.exec("BEGIN")
458
+
459
+ for (const r of src.prepare("SELECT id, abbr FROM place_abbr").iterate()) {
460
+ const a = attrs.get(Number(r.id))
461
+
462
+ if (!a) continue
463
+ const k = normalizeLocalityForKey(String(r.abbr ?? ""))
464
+
465
+ if (!k) continue
466
+ stageRow(k, a, Number(r.id), 1)
467
+
468
+ nAbbr++
469
+ }
470
+
471
+ kdb.exec("COMMIT")
472
+ progress("abbrevs", `${nAbbr.toLocaleString()} abbrevs`)
473
+
474
+ const roles = stampNameRoles({
475
+ src,
476
+ out: kdb,
477
+ attrs,
478
+ keyCounts,
479
+ glossThreshold: opts.glossKeyThreshold ?? GLOSS_KEY_THRESHOLD,
480
+ ptcodes,
481
+ ccodes,
482
+ progress,
483
+ })
484
+
485
+ const sidecar = await buildAncestorsSidecar({ src, out: kdb, attrs, ptID, progress })
486
+
487
+ let nPostcode = 0
488
+ let nPostcodeAlias = 0
489
+
490
+ for (const pcDB of opts.postcodes ?? []) {
491
+ const folded = foldExtract({
492
+ out: kdb,
493
+ extractPath: pcDB,
494
+ extractPlacetype: "postalcode",
495
+ ccID,
496
+ ptID,
497
+ stageRow,
498
+ progress,
499
+ })
500
+
501
+ nPostcode += folded.primaries
502
+ nPostcodeAlias += folded.aliases
503
+ }
504
+
505
+ if (nPostcode > 0) {
506
+ progress("postcodes", `${nPostcode.toLocaleString()} postcodes; ${nPostcodeAlias.toLocaleString()} aliases`)
507
+ }
508
+
509
+ let nLocality = 0
510
+ let nLocalityScoped = 0
511
+ let nLocalityAncestor = 0
512
+
513
+ for (const locDB of opts.localities ?? []) {
514
+ const folded = foldExtract({
515
+ out: kdb,
516
+ extractPath: locDB,
517
+ extractPlacetype: "locality",
518
+ ccID,
519
+ ptID,
520
+ stageRow,
521
+ attrs,
522
+ progress,
523
+ })
524
+
525
+ nLocality += folded.primaries
526
+ nLocalityScoped += folded.scoped
527
+ nLocalityAncestor += folded.ancestorRows
528
+ }
529
+
530
+ if (nLocality > 0) {
531
+ progress(
532
+ "localities",
533
+ `${nLocality.toLocaleString()} extract localities folded` +
534
+ (nLocalityScoped
535
+ ? `; ${nLocalityScoped.toLocaleString()} carry a region scope (${nLocalityAncestor.toLocaleString()} closure rows)`
536
+ : "")
537
+ )
538
+ }
539
+
540
+ if (ccodes.size) {
541
+ await kdb
542
+ .insertInto("country_codes")
543
+ .values([...ccodes].map(([code, id]) => ({ id, code })))
544
+ .execute()
545
+ }
546
+
547
+ if (ptcodes.size) {
548
+ await kdb
549
+ .insertInto("placetype_codes")
550
+ .values([...ptcodes].map(([placetype, id]) => ({ id, placetype })))
551
+ .execute()
552
+ }
553
+
554
+ if (opts.capitals?.length) {
555
+ await createCapitalTable<CandidateDatabase>(kdb)
556
+
557
+ await kdb
558
+ .insertInto("capital")
559
+ .values(
560
+ opts.capitals.map((entry) => ({
561
+ country: entry.country,
562
+ latitude: entry.latitude,
563
+ longitude: entry.longitude,
564
+ level: entry.level,
565
+ keys: stringifyJSON(entry.k),
566
+ }))
567
+ )
568
+ .execute()
569
+
570
+ progress("capitals", `${opts.capitals.length.toLocaleString()} capital-reference rows carried in-artifact`)
571
+ }
572
+
573
+ progress("cluster", "building clustered candidate table + VACUUM")
574
+
575
+ const cols = CANDIDATE_COLUMNS.join(", ")
576
+ const keyOrder = CANDIDATE_COLUMNS.slice(0, 6).join(", ")
577
+ await createCandidateTable(kdb)
578
+
579
+ kdb.exec(`INSERT OR IGNORE INTO candidate (${cols}) SELECT ${cols} FROM cand_stage ORDER BY ${keyOrder};`)
580
+ await kdb.schema.dropTable("cand_stage").execute()
581
+
582
+ progress("fts", "building FTS5-trigram fuzzy index")
583
+ createCandidateFTS(kdb)
584
+
585
+ kdb.exec("PRAGMA page_size=8192")
586
+ kdb.exec("VACUUM")
587
+
588
+ const { n: rows } = await kdb
589
+ .selectFrom("candidate")
590
+ .select((eb) => eb.fn.countAll<number>().as("n"))
591
+ .executeTakeFirstOrThrow()
592
+
593
+ return {
594
+ rows,
595
+ places: attrs.size,
596
+ primaries: nPrim,
597
+ aliases: nAlias,
598
+ regionOfficialRefused,
599
+ abbrevs: nAbbr,
600
+ postcodes: nPostcode,
601
+ postcodeAliases: nPostcodeAlias,
602
+ ancestorRows: sidecar.ancestorRows + nLocalityAncestor,
603
+ ancestorPlaces: sidecar.ancestorPlaces + nLocalityScoped,
604
+ intervalPlaces: sidecar.intervalPlaces,
605
+ ...roles,
606
+ ...(importance ? { importanceScored: importance.matched, importanceFiltered: importance.refused } : {}),
607
+ }
608
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file Populations the gazetteer records at a fraction of their size, corrected against the record's own concordance.
6
+ *
7
+ * This file records corrections for review. The build must not rewrite populations from a
8
+ * same-name-parent ratio. The detector cannot distinguish a district's mis-recorded namesake
9
+ * city from a small village with the district name. Both places are real.
10
+ *
11
+ * Each entry identifies one row that a reviewer checked against a second source.
12
+ * The row's own `gn:id` must agree with the coordinates. The GeoNames record must identify the same place.
13
+ *
14
+ * The correction applies to the candidate artifact rather than the admin gazetteer.
15
+ * `place_population` in `admin-global-priority.db` still stores the WOF figure, so a reader going
16
+ * there sees WOF's value and a reader going to `candidate.db` sees the corroborated number. The
17
+ * admin database is a transcription of its source, so correcting it there would make the
18
+ * transcription disagree with what it transcribes.
19
+ */
20
+
21
+ /**
22
+ * One corrected population, with what corroborates it.
23
+ */
24
+ export interface PopulationCorrection {
25
+ /**
26
+ * The GeoNames id from the WOF record's own `concordances` row makes this a
27
+ * correction rather than a substitution.
28
+ *
29
+ * The two sources describe the same place according to WOF.
30
+ */
31
+ geonamesID: string
32
+ population: number
33
+ /**
34
+ * What the gazetteer recorded, kept so a reader can see the size of the
35
+ * disagreement without opening the artifact.
36
+ */
37
+ recorded: number
38
+ /**
39
+ * The place and the reviewer's reading.
40
+ */
41
+ note: string
42
+ }
43
+
44
+ /**
45
+ * WOF id → the corrected population.
46
+ *
47
+ * One entry, because one row has been followed.
48
+ * A second correction requires the same review.
49
+ *
50
+ * Read the row's `gn:id` and confirm the coordinates agree.
51
+ * Then record the second source's value.
52
+ */
53
+ export const POPULATION_CORRECTIONS: Readonly<Record<number, PopulationCorrection>> = {
54
+ 102_030_887: {
55
+ geonamesID: "1278149",
56
+ population: 1_175_116,
57
+ recorded: 19_172,
58
+ note:
59
+ "Aurangabad (Chhatrapati Sambhaji Nagar), Maharashtra. The WOF record sits at 19.870 / 75.349 and GeoNames " +
60
+ "1278149 — the id that record's own concordance names — sits at 19.878 / 75.342, about 1 km apart, classed " +
61
+ "`PPLA2`. WOF's 19,172 against its parent district's 3,701,282 is the 193x ratio that surfaced it; the " +
62
+ "corroborated figure makes the city 32% of its district rather than 0.5% of it.",
63
+ },
64
+ }