@hebcal/geo-sqlite 5.10.5 → 5.11.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/dist/index.js CHANGED
@@ -1,1483 +1,4 @@
1
- /*! @hebcal/geo-sqlite v5.10.5 */
2
- import { DatabaseSync } from 'node:sqlite';
3
- import fs$1, { existsSync } from 'node:fs';
4
- import QuickLRU from 'quick-lru';
5
- import { Location, Locale } from '@hebcal/core';
6
- import '@hebcal/cities';
7
- import { transliterate } from 'transliteration';
8
- import events from 'events';
9
- import fs from 'fs';
10
- import readline from 'readline';
11
-
12
- var city2geonameid = {
13
- "AD-Andorra La Vella":3041563,
14
- "AE-Abu Dhabi":292968,
15
- "AE-Dubai":292223,
16
- "AF-Kabul":1138958,
17
- "AI-The Valley":3573374,
18
- "AL-Tirana":3183875,
19
- "AM-Yerevan":616052,
20
- "AO-Luanda":2240449,
21
- "AR-Buenos Aires":3435910,
22
- "AR-Cordoba":3860259,
23
- "AR-Rosario":3838583,
24
- "AS-Pago Pago":5881576,
25
- "AT-Vienna":2761369,
26
- "AU-Adelaide":2078025,
27
- "AU-Brisbane":2174003,
28
- "AU-Canberra":2172517,
29
- "AU-Gold Coast":2165087,
30
- "AU-Hobart":2163355,
31
- "AU-Melbourne":2158177,
32
- "AU-Perth":2063523,
33
- "AU-Sydney":2147714,
34
- "AW-Oranjestad":3577154,
35
- "AZ-Baku":587084,
36
- "Ashdod":295629,
37
- "Atlanta":4180439,
38
- "Austin":4671654,
39
- "BA-Sarajevo":3191281,
40
- "BB-Bridgetown":3374036,
41
- "BD-Chittagong":1205733,
42
- "BD-Dhaka":1185241,
43
- "BD-Khulna":1336135,
44
- "BE-Brussels":2800866,
45
- "BF-Ouagadougou":2357048,
46
- "BG-Sofia":727011,
47
- "BH-Manama":290340,
48
- "BI-Bujumbura":425378,
49
- "BJ-Porto-novo":2392087,
50
- "BM-Hamilton":3573197,
51
- "BN-Bandar Seri Begawan":1820906,
52
- "BO-La Paz":3911925,
53
- "BO-Santa Cruz de la Sierra":3904906,
54
- "BR-Belo Horizonte":3470127,
55
- "BR-Brasilia":3469058,
56
- "BR-Fortaleza":3399415,
57
- "BR-Rio de Janeiro":3451190,
58
- "BR-Salvador":3450554,
59
- "BR-Sao Paulo":3448439,
60
- "BS-Nassau":3571824,
61
- "BT-Thimphu":1252416,
62
- "BW-Gaborone":933773,
63
- "BY-Minsk":625144,
64
- "BZ-Belmopan":3582672,
65
- "Baghdad":98182,
66
- "Baltimore":4347778,
67
- "Be'er Sheva":295530,
68
- "Beer Sheva":295530,
69
- "Bene Beraq":295514,
70
- "IL-Bene Beraq":295514,
71
- "Berlin":2950159,
72
- "Bnei Brak":295514,
73
- "Bogota":3688689,
74
- "Boston":4930956,
75
- "Buenos Aires":3435910,
76
- "Buffalo":5110629,
77
- "CA-Calgary":5913490,
78
- "CA-Edmonton":5946768,
79
- "CA-Halifax":6324729,
80
- "CA-Mississauga":6075357,
81
- "CA-Montreal":6077243,
82
- "CA-Ottawa":6094817,
83
- "CA-Quebec City":6325494,
84
- "CA-Regina":6119109,
85
- "CA-Saskatoon":6141256,
86
- "CA-St. John's-05":6324733,
87
- "CA-Toronto":6167865,
88
- "CA-Vancouver":6173331,
89
- "CA-Victoria":6174041,
90
- "CA-Winnipeg":6183235,
91
- "CD-Kinshasa":2314302,
92
- "CD-Lubumbashi":922704,
93
- "CF-Bangui":2389853,
94
- "CG-Brazzaville":2260535,
95
- "CH-Bern":2661552,
96
- "CH-Geneva":2660646,
97
- "CH-Zurich":2657896,
98
- "CI-Abidjan":2293538,
99
- "CI-Yamoussoukro":2279755,
100
- "CK-Avarua":4035715,
101
- "CL-Santiago":3871336,
102
- "CM-Douala":2232593,
103
- "CM-Yaounde":2220957,
104
- "CN-Beijing":1816670,
105
- "CN-Chengdu":1815286,
106
- "CN-Chongqing":1814906,
107
- "CN-Guangzhou":1809858,
108
- "CN-Harbin":2037013,
109
- "CN-Kaifeng":1804879,
110
- "CN-Lanzhou":1804430,
111
- "CN-Nanchong":1800146,
112
- "CN-Nanjing":1799962,
113
- "CN-Puyang":1798422,
114
- "CN-Shanghai":1796236,
115
- "CN-Shenyang":2034937,
116
- "CN-Shenzhen":1795565,
117
- "CN-Shiyan":1794903,
118
- "CN-Tai'an":1793724,
119
- "CN-Tianjin":1792947,
120
- "CN-Wuhan":1791247,
121
- "CN-Xi'an":1790630,
122
- "CN-Yueyang":1927639,
123
- "CN-Zhumadian":1783873,
124
- "CO-Barranquilla":3689147,
125
- "CO-Bogota":3688689,
126
- "CO-Bogotá":3688689,
127
- "CO-Cali":3687925,
128
- "CO-Medellin":3674962,
129
- "CR-San Jose":3621849,
130
- "CR-San José":3621849,
131
- "CR-San José":3621849,
132
- "CU-Havana":3553478,
133
- "CV-Praia":3374333,
134
- "CW-Willemstad":3513090,
135
- "CY-Nicosia":146268,
136
- "CZ-Prague":3067696,
137
- "Chicago":4887398,
138
- "Cincinnati":4508722,
139
- "Cleveland":5150529,
140
- "DE-Berlin":2950159,
141
- "DE-Hamburg":2911298,
142
- "DE-Munich":2867714,
143
- "DK-Copenhagen":2618425,
144
- "DM-Roseau":3575635,
145
- "DO-Santiago de los Caballeros":3492914,
146
- "DO-Santo Domingo":3492908,
147
- "DZ-Algiers":2507480,
148
- "Dallas":4684888,
149
- "Denver":5419384,
150
- "Detroit":4990729,
151
- "EC-Guayaquil":3657509,
152
- "EC-Quito":3652462,
153
- "EE-Tallinn":588409,
154
- "EG-Al Jizah":360995,
155
- "EG-Alexandria":361058,
156
- "EG-Cairo":360630,
157
- "ER-Asmara":343300,
158
- "ES-Barcelona":3128760,
159
- "ES-Madrid":3117735,
160
- "ET-Addis Ababa":344979,
161
- "Eilat":295277,
162
- "FI-Helsinki":658225,
163
- "FJ-Suva":2198148,
164
- "FK-Stanley":3426691,
165
- "FO-Tórshavn":2611396,
166
- "FR-Marseilles":2995469,
167
- "FR-Paris":2988507,
168
- "GA-Libreville":2399697,
169
- "GB-Belfast":2655984,
170
- "GB-Birmingham":2655603,
171
- "GB-Bristol":2654675,
172
- "GB-Cardiff":2653822,
173
- "GB-Edinburgh":2650225,
174
- "GB-Glasgow":2648579,
175
- "GB-Leeds":2644688,
176
- "GB-Liverpool":2644210,
177
- "GB-London":2643743,
178
- "GB-Manchester":2643123,
179
- "GB-Sheffield":2638077,
180
- "GE-Tbilisi":611717,
181
- "GH-Accra":2306104,
182
- "GH-Kumasi":2298890,
183
- "GI-Gibraltar":2411585,
184
- "GL-Nuuk":3421319,
185
- "GM-Banjul":2413876,
186
- "GN-Camayenne":2422488,
187
- "GN-Conakry":2422465,
188
- "GQ-Malabo":2309527,
189
- "GR-Athens":264371,
190
- "GT-Guatemala City":3598132,
191
- "GW-Bissau":2374775,
192
- "GY-Georgetown":3378644,
193
- "Gibraltar":2411585,
194
- "HK-Hong Kong":1819729,
195
- "HN-Tegucigalpa":3600949,
196
- "HR-Zagreb":3186886,
197
- "HT-Port-au-Prince":3718426,
198
- "HU-Budapest":3054643,
199
- "Haifa":294801,
200
- "Hawaii":5856195,
201
- "Houston":4699066,
202
- "ID-Bandung":1650357,
203
- "ID-Bekasi":1649378,
204
- "ID-Depok":1645518,
205
- "ID-Jakarta":1642911,
206
- "ID-Makassar":1622786,
207
- "ID-Medan":1214520,
208
- "ID-Palembang":1633070,
209
- "ID-Semarang":1627896,
210
- "ID-South Tangerang":8581443,
211
- "ID-Surabaya":1625822,
212
- "ID-Tangerang":1625084,
213
- "IE-Dublin":2964574,
214
- "IL-Ashdod":295629,
215
- "IL-Ashkelon":295620,
216
- "IL-Ashqelon":295620,
217
- "IL-Bat Yam":295548,
218
- "IL-Be'er Sheva":295530,
219
- "IL-Beer Sheva":295530,
220
- "IL-Beit Shemesh":295432,
221
- "IL-Bet Shemesh":295432,
222
- "IL-Bnei Brak":295514,
223
- "IL-Eilat":295277,
224
- "IL-Hadera":294946,
225
- "IL-Haifa":294801,
226
- "IL-Herzliya":294778,
227
- "IL-Herzliyya":294778,
228
- "IL-Holon":294751,
229
- "IL-Jerusalem":281184,
230
- "IL-Kfar Saba":294514,
231
- "IL-Lod":294421,
232
- "IL-Modiin":282926,
233
- "IL-Nazareth":294098,
234
- "IL-Netanya":294071,
235
- "IL-Petach Tikvah":293918,
236
- "IL-Petah Tikvah":293918,
237
- "IL-Petah Tiqwa":293918,
238
- "IL-Ra'anana":293807,
239
- "IL-Raanana":293807,
240
- "IL-Ramat Gan":293788,
241
- "IL-Ramla":293768,
242
- "IL-Rishon LeZion":293703,
243
- "IL-Rishon Leziyyon":293703,
244
- "IL-Tel Aviv":293397,
245
- "IL-Tiberias":293322,
246
- "IM-Douglas":3042237,
247
- "IN-Ahmadabad":1279233,
248
- "IN-Bangalore":1277333,
249
- "IN-Bombay":1275339,
250
- "IN-Calcutta":1275004,
251
- "IN-Chennai":1264527,
252
- "IN-Cochin":1273874,
253
- "IN-Hyderabad":1269843,
254
- "IN-Jaipur":1269515,
255
- "IN-Kanpur":1267995,
256
- "IN-New Delhi":1261481,
257
- "IN-Pune":1259229,
258
- "IN-Surat":1255364,
259
- "IQ-Baghdad":98182,
260
- "IR-Tehran":112931,
261
- "IS-Reykjavik":3413829,
262
- "IS-Reykjavík":3413829,
263
- "IT-Milano":3173435,
264
- "IT-Rome":3169070,
265
- "JM-Kingston":3489854,
266
- "JO-Amman":250441,
267
- "JP-Kobe-shi":1859171,
268
- "JP-Kyoto":1857910,
269
- "JP-Nagoya-shi":1856057,
270
- "JP-Osaka-shi":1853909,
271
- "JP-Sapporo":2128295,
272
- "JP-Tokyo":1850147,
273
- "Jerusalem":281184,
274
- "Johannesburg":993800,
275
- "KE-Nairobi":184745,
276
- "KG-Bishkek":1528675,
277
- "KH-Phnom Penh":1821306,
278
- "KM-Moroni":921772,
279
- "KN-Basseterre":3575551,
280
- "KP-Pyongyang":1871859,
281
- "KR-Busan":1838524,
282
- "KR-Seoul":1835848,
283
- "KW-Kuwait":285787,
284
- "KY-George Town":3580661,
285
- "KZ-Almaty":1526384,
286
- "KZ-Astana":1526273,
287
- "Kiev":703448,
288
- "LA-Vientiane":1651944,
289
- "LB-Beirut":276781,
290
- "LC-Castries":3576812,
291
- "LI-Vaduz":3042030,
292
- "LR-Monrovia":2274895,
293
- "LS-Maseru":932505,
294
- "LT-Vilnius":593116,
295
- "LU-Luxemburg":2960316,
296
- "LV-Riga":456172,
297
- "LY-Tripoli":2210247,
298
- "La Paz":3911925,
299
- "Livingston":5100572,
300
- "London":2643743,
301
- "Los Angeles":5368361,
302
- "MA-Casablanca":2553604,
303
- "MA-Rabat":2538475,
304
- "MD-Chisinau":618426,
305
- "ME-Podgorica":3193044,
306
- "MG-Antananarivo":1070940,
307
- "MK-Skopje":785842,
308
- "ML-Bamako":2460596,
309
- "MM-Mandalay":1311874,
310
- "MM-Rangoon":1298824,
311
- "MN-Ulaanbaatar":2028462,
312
- "MP-Saipan":7828758,
313
- "MR-Nouakchott":2377450,
314
- "MS-Plymouth":3578069,
315
- "MT-Valletta":2562305,
316
- "MU-Port Louis":934154,
317
- "MW-Lilongwe":927967,
318
- "MX-Cancun":3531673,
319
- "MX-Guadalajara":4005539,
320
- "MX-Iztapalapa":3526683,
321
- "MX-Mazatlan":3996322,
322
- "MX-Mexico City":3530597,
323
- "MX-Monterrey":3995465,
324
- "MX-Puerto Vallarta":3991328,
325
- "MX-Tijuana":3981609,
326
- "MY-Kota Bharu":1736376,
327
- "MY-Kuala Lumpur":1735161,
328
- "MZ-Maputo":1040652,
329
- "Melbourne":2158177,
330
- "Mexico City":3530597,
331
- "Miami":4164138,
332
- "Montreal":6077243,
333
- "Moscow":524901,
334
- "NA-Windhoek":3352136,
335
- "NC-Noumea":2139521,
336
- "NC-Nouméa":2139521,
337
- "NE-Niamey":2440485,
338
- "NG-Abuja":2352778,
339
- "NG-Lagos":2332459,
340
- "NI-Managua":3617763,
341
- "NL-Amsterdam":2759794,
342
- "NO-Oslo":3143244,
343
- "NP-Kathmandu":1283240,
344
- "NU-Alofi":4036284,
345
- "NZ-Auckland":2193733,
346
- "NZ-Christchurch":2192362,
347
- "NZ-Wellington":2179537,
348
- "New York":5128581,
349
- "OM-Muscat":287286,
350
- "Omaha":5074472,
351
- "Ottawa":6094817,
352
- "PA-Panama City":3703443,
353
- "PE-Lima":3936456,
354
- "PF-Papeete":4033936,
355
- "PG-Port Moresby":2088122,
356
- "PH-Manila":1701668,
357
- "PK-Islamabad":1176615,
358
- "PK-Karachi":1174872,
359
- "PL-Warsaw":756135,
360
- "PR-San Juan":4568127,
361
- "PT-Lisbon":2267057,
362
- "PY-Asuncion":3439389,
363
- "Panama City":3703443,
364
- "Paris":2988507,
365
- "Petach Tikvah":293918,
366
- "Petah Tikvah":293918,
367
- "Petah Tikva":293918,
368
- "Petah Tiqwa":293918,
369
- "Petaẖ Tiqwa":293918,
370
- "Philadelphia":4560349,
371
- "Phoenix":5308655,
372
- "Pittsburgh":5206379,
373
- "QA-Doha":290030,
374
- "RO-Bucharest":683506,
375
- "RS-Belgrade":792680,
376
- "RU-Moscow":524901,
377
- "RU-Novosibirsk":1496747,
378
- "RU-Saint Petersburg":498817,
379
- "RU-Yekaterinburg":1486209,
380
- "RW-Kigali":202061,
381
- "Ra'anana":293807,
382
- "SA-Jeddah":105343,
383
- "SA-Mecca":104515,
384
- "SA-Medina":109223,
385
- "SA-Riyadh":108410,
386
- "SB-Honiara":2108502,
387
- "SC-Victoria":241131,
388
- "SD-Khartoum":379252,
389
- "SD-Omdurman":365137,
390
- "SE-Stockholm":2673730,
391
- "SG-Singapore":1880252,
392
- "SH-Jamestown":3370903,
393
- "SI-Ljubljana":3196359,
394
- "SK-Bratislava":3060972,
395
- "SL-Freetown":2408770,
396
- "SN-Dakar":2253354,
397
- "SO-Mogadishu":53654,
398
- "SR-Paramaribo":3383330,
399
- "ST-Sao Tome":2410763,
400
- "ST-São Tomé":2410763,
401
- "SV-San Salvador":3583361,
402
- "SY-Aleppo":170063,
403
- "SY-Damascus":170654,
404
- "SZ-Mbabane":934985,
405
- "Saint Louis":4407066,
406
- "Saint Petersburg":498817,
407
- "San Francisco":5391959,
408
- "Seattle":5809844,
409
- "Sydney":2147714,
410
- "TC-Cockburn Town":3576994,
411
- "TD-Ndjamena":2427123,
412
- "TG-Lome":2365267,
413
- "TG-Lomé":2365267,
414
- "TH-Bangkok":1609350,
415
- "TJ-Dushanbe":1221874,
416
- "TM-Ashgabat":162183,
417
- "TN-Tunis":2464470,
418
- "TR-Adana":325363,
419
- "TR-Ankara":323786,
420
- "TR-Bursa":750269,
421
- "TR-Istanbul":745044,
422
- "TR-Izmir":311046,
423
- "TV-Funafuti":2110394,
424
- "TW-Kaohsiung":1673820,
425
- "TW-Taipei":1668341,
426
- "TZ-Dar es Salaam":160263,
427
- "TZ-Dodoma":160196,
428
- "Tel Aviv":293397,
429
- "Tiberias":293322,
430
- "Toronto":6167865,
431
- "UA-Kharkiv":706483,
432
- "UA-Kiev":703448,
433
- "UG-Kampala":232422,
434
- "US-Atlanta-GA":4180439,
435
- "US-Austin-TX":4671654,
436
- "US-Baltimore-MD":4347778,
437
- "US-Boston-MA":4930956,
438
- "US-Buffalo-NY":5110629,
439
- "US-Chicago-IL":4887398,
440
- "US-Cincinnati-OH":4508722,
441
- "US-Cleveland-OH":5150529,
442
- "US-Columbus-OH":4509177,
443
- "US-Dallas-TX":4684888,
444
- "US-Denver-CO":5419384,
445
- "US-Detroit-MI":4990729,
446
- "US-Hartford-CT":4835797,
447
- "US-Honolulu-HI":5856195,
448
- "US-Houston-TX":4699066,
449
- "US-Lakewood-NJ":5100280,
450
- "US-Las Vegas-NV":5506956,
451
- "US-Livingston-NY":5100572,
452
- "US-Los Angeles-CA":5368361,
453
- "US-Memphis-TN":4641239,
454
- "US-Miami-FL":4164138,
455
- "US-Milwaukee-WI":5263045,
456
- "US-Monsey-NY":5127315,
457
- "US-New Haven-CT":4839366,
458
- "US-New York-NY":5128581,
459
- "US-Omaha-NE":5074472,
460
- "US-Orlando-FL":4167147,
461
- "US-Passaic-NJ":5102443,
462
- "US-Philadelphia-PA":4560349,
463
- "US-Phoenix-AZ":5308655,
464
- "US-Pittsburgh-PA":5206379,
465
- "US-Portland-OR":5746545,
466
- "US-Providence-RI":5224151,
467
- "US-Richmond-VA":4781708,
468
- "US-Rochester-NY":5134086,
469
- "US-Saint Louis-MO":4407066,
470
- "US-Saint Paul-MN":5045360,
471
- "US-San Diego-CA":5391811,
472
- "US-San Francisco-CA":5391959,
473
- "US-Seattle-WA":5809844,
474
- "US-Silver Spring-MD":4369596,
475
- "US-Teaneck-NJ":5105262,
476
- "US-Washington-DC":4140963,
477
- "US-White Plains-NY":5144336,
478
- "UY-Montevideo":3441575,
479
- "UZ-Tashkent":1512569,
480
- "VC-Kingstown":3577887,
481
- "VE-Caracas":3646738,
482
- "VE-Maracaibo":3633009,
483
- "VE-Maracay":3632998,
484
- "VE-Valencia":3625549,
485
- "VG-Road Town":3577430,
486
- "VN-Hanoi":1581130,
487
- "VN-Ho Chi Minh City":1566083,
488
- "Vancouver":6173331,
489
- "WS-Apia":4035413,
490
- "Washington DC":4140963,
491
- "White Plains":5144336,
492
- "YE-Sanaa":71137,
493
- "YT-Mamoudzou":921815,
494
- "ZA-Cape Town":3369157,
495
- "ZA-Durban":1007311,
496
- "ZA-Johannesburg":993800,
497
- "ZA-Pretoria":964137,
498
- "ZM-Lusaka":909137,
499
- "ZW-Harare":890299
500
- };
501
-
502
- /**
503
- * @private
504
- * @param {string} s
505
- * @return {string}
506
- */
507
- function munge(s) {
508
- return s.toLowerCase()
509
- .replace(/'/g, '')
510
- .replace(/ /g, '')
511
- .replace(/\+/g, '');
512
- }
513
-
514
- // DO NOT EDIT THIS AUTO-GENERATED FILE!
515
- const version = '5.10.5';
516
-
517
- const GEONAME_SQL = `SELECT
518
- g.name as name,
519
- g.asciiname as asciiname,
520
- g.country as cc,
521
- c.country as country,
522
- a.asciiname as admin1,
523
- g.latitude as latitude,
524
- g.longitude as longitude,
525
- g.population as population,
526
- g.gtopo30 as elevation,
527
- g.timezone as timezone
528
- FROM geoname g
529
- LEFT JOIN country c on g.country = c.iso
530
- LEFT JOIN admin1 a on g.country||'.'||g.admin1 = a.key
531
- WHERE g.geonameid = ?
532
- `;
533
-
534
- const GEONAME_ALL_SQL = `SELECT
535
- g.geonameid as geonameid,
536
- g.name as name,
537
- g.asciiname as asciiname,
538
- g.country as cc,
539
- c.country as country,
540
- a.asciiname as admin1,
541
- g.latitude as latitude,
542
- g.longitude as longitude,
543
- g.population as population,
544
- g.gtopo30 as elevation,
545
- g.timezone as timezone
546
- FROM geoname g
547
- LEFT JOIN country c on g.country = c.iso
548
- LEFT JOIN admin1 a on g.country||'.'||g.admin1 = a.key
549
- `;
550
-
551
- const ZIPCODE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,Elevation,
552
- TimeZone,DayLightSaving,Population
553
- FROM ZIPCodes_Primary WHERE ZipCode = ?`;
554
-
555
- const ZIPCODE_ALL_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,Elevation,
556
- TimeZone,DayLightSaving,Population
557
- FROM ZIPCodes_Primary`;
558
-
559
- const ZIP_COMPLETE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
560
- FROM ZIPCodes_Primary
561
- WHERE ZipCode >= ? AND ZipCode < ?
562
- ORDER BY Population DESC
563
- LIMIT 10`;
564
-
565
- const ZIP_FULLTEXT_COMPLETE_SQL =
566
- `SELECT ZipCode
567
- FROM ZIPCodes_CityFullText5
568
- WHERE ZIPCodes_CityFullText5 MATCH ?
569
- ORDER BY Population DESC
570
- LIMIT 20`;
571
-
572
- const GEONAME_COMPLETE_SQL =
573
- `SELECT geonameid, longname, city, admin1, country
574
- FROM geoname_fulltext
575
- WHERE geoname_fulltext MATCH ?
576
- ORDER BY population DESC
577
- LIMIT 20`;
578
-
579
- const stateNames = {
580
- 'AK': 'Alaska',
581
- 'AL': 'Alabama',
582
- 'AR': 'Arkansas',
583
- 'AZ': 'Arizona',
584
- 'CA': 'California',
585
- 'CO': 'Colorado',
586
- 'CT': 'Connecticut',
587
- 'DC': 'Washington, D.C.',
588
- 'DE': 'Delaware',
589
- 'FL': 'Florida',
590
- 'GA': 'Georgia',
591
- 'HI': 'Hawaii',
592
- 'IA': 'Iowa',
593
- 'ID': 'Idaho',
594
- 'IL': 'Illinois',
595
- 'IN': 'Indiana',
596
- 'KS': 'Kansas',
597
- 'KY': 'Kentucky',
598
- 'LA': 'Louisiana',
599
- 'MA': 'Massachusetts',
600
- 'MD': 'Maryland',
601
- 'ME': 'Maine',
602
- 'MI': 'Michigan',
603
- 'MN': 'Minnesota',
604
- 'MO': 'Missouri',
605
- 'MS': 'Mississippi',
606
- 'MT': 'Montana',
607
- 'NC': 'North Carolina',
608
- 'ND': 'North Dakota',
609
- 'NE': 'Nebraska',
610
- 'NH': 'New Hampshire',
611
- 'NJ': 'New Jersey',
612
- 'NM': 'New Mexico',
613
- 'NV': 'Nevada',
614
- 'NY': 'New York',
615
- 'OH': 'Ohio',
616
- 'OK': 'Oklahoma',
617
- 'OR': 'Oregon',
618
- 'PA': 'Pennsylvania',
619
- 'RI': 'Rhode Island',
620
- 'SC': 'South Carolina',
621
- 'SD': 'South Dakota',
622
- 'TN': 'Tennessee',
623
- 'TX': 'Texas',
624
- 'UT': 'Utah',
625
- 'VA': 'Virginia',
626
- 'VT': 'Vermont',
627
- 'WA': 'Washington',
628
- 'WI': 'Wisconsin',
629
- 'WV': 'West Virginia',
630
- 'WY': 'Wyoming',
631
- };
632
-
633
- /** Wrapper around sqlite databases */
634
- class GeoDb {
635
- /**
636
- * @param {any} logger
637
- * @param {string} zipsFilename
638
- * @param {string} geonamesFilename
639
- * @param {any} options
640
- */
641
- constructor(logger, zipsFilename, geonamesFilename, options) {
642
- this.logger = logger;
643
- if (logger) logger.info(`GeoDb: opening ${zipsFilename}...`);
644
- if (!existsSync(zipsFilename)) {
645
- throw new Error(`GeoDb: ${zipsFilename} does not exist`);
646
- }
647
- this.zipsDb = new DatabaseSync(zipsFilename);
648
- if (logger) logger.info(`GeoDb: opening ${geonamesFilename}...`);
649
- if (!existsSync(geonamesFilename)) {
650
- throw new Error(`GeoDb: ${geonamesFilename} does not exist`);
651
- }
652
- this.geonamesDb = new DatabaseSync(geonamesFilename);
653
- this.zipStmt = this.zipsDb.prepare(ZIPCODE_SQL);
654
- const zipsCacheSize = options?.zipsCacheSize || 150;
655
- /** @type {Map<string, Location>} */
656
- this.zipCache = new QuickLRU({maxSize: zipsCacheSize});
657
- this.geonamesStmt = this.geonamesDb.prepare(GEONAME_SQL);
658
- const geonamesCacheSize = options?.geonamesCacheSize || 750;
659
- /** @type {Map<number, Location>} */
660
- this.geonamesCache = new QuickLRU({maxSize: geonamesCacheSize});
661
- /** @type {Map<string, number>} */
662
- this.legacyCities = new Map();
663
- for (const [name, id] of Object.entries(city2geonameid)) {
664
- this.legacyCities.set(munge(name), id);
665
- }
666
- const stmt = this.geonamesDb.prepare(`SELECT ISO, Country FROM country WHERE Country <> ''`);
667
- const rows = stmt.all();
668
- const map = new Map();
669
- for (const row of rows) {
670
- map.set(row.ISO, row.Country);
671
- }
672
- /** @type {Map<string, string>} */
673
- this.countryNames = map;
674
- if (logger) logger.info(`GeoDb: ${map.size} countries, ${this.legacyCities.size} legacy cities`);
675
- }
676
-
677
- /** Closes database handles */
678
- close() {
679
- this.zipStmt = undefined;
680
- this.geonamesStmt = undefined;
681
- this.zipsDb.close();
682
- this.zipsDb = undefined;
683
- this.geonamesDb.close();
684
- this.geonamesDb = undefined;
685
- }
686
-
687
- /**
688
- * @private
689
- * @param {string} s
690
- * @return {string}
691
- */
692
- static munge(s) {
693
- return munge(s);
694
- }
695
-
696
- /**
697
- * @param {string} zip
698
- * @return {Location}
699
- */
700
- lookupZip(zip) {
701
- const zip5 = zip.trim().substring(0, 5);
702
- const found = this.zipCache.get(zip5);
703
- if (found !== undefined) return found;
704
- const result = this.zipStmt.get(zip5);
705
- if (!result) {
706
- if (this.logger) this.logger.warn(`GeoDb: unknown zipcode=${zip5}`);
707
- this.zipCache.set(zip5, null);
708
- return null;
709
- }
710
- result.ZipCode = String(zip5);
711
- const location = this.makeZipLocation(result);
712
- this.zipCache.set(zip5, location);
713
- return location;
714
- }
715
-
716
- /**
717
- * @private
718
- * @param {any} result
719
- * @return {Location}
720
- */
721
- makeZipLocation(result) {
722
- const zip = result.ZipCode;
723
- const tz = result.TimeZone;
724
- const tzid = Location.getUsaTzid(result.State, +tz, result.DayLightSaving);
725
- const cityDescr = `${result.CityMixedCase}, ${result.State} ${zip}`;
726
- const elevation = result?.Elevation > 0 ? result.Elevation : 0;
727
- const location = new Location(result.Latitude, result.Longitude, false, tzid, cityDescr,
728
- 'US', zip, elevation);
729
- location.admin1 = location.state = result.State;
730
- location.stateName = stateNames[location.state];
731
- location.geo = 'zip';
732
- location.zip = zip;
733
- location.population = result.Population;
734
- return location;
735
- }
736
-
737
- /**
738
- * @param {number} geonameid
739
- * @return {Location}
740
- */
741
- lookupGeoname(geonameid) {
742
- geonameid = +geonameid;
743
- if (!geonameid) return null;
744
- if (geonameid === 293396) {
745
- geonameid = 293397;
746
- }
747
- const found = this.geonamesCache.get(geonameid);
748
- if (found !== undefined) return found;
749
- const result = this.geonamesStmt.get(geonameid);
750
- if (!result) {
751
- if (this.logger) this.logger.warn(`GeoDb: unknown geonameid=${geonameid}`);
752
- this.geonamesCache.set(geonameid, null);
753
- return null;
754
- }
755
- const location = this.makeGeonameLocation(geonameid, result);
756
- this.geonamesCache.set(geonameid, location);
757
- return location;
758
- }
759
-
760
- /**
761
- * Convenience wrapper of the `transliterate` function from `transliteration` npm package.
762
- * Transliterate the string `source` and return the result.
763
- * @param {string} source
764
- * @param {any} [options]
765
- * @return {string}
766
- */
767
- static transliterate(source, options) {
768
- return transliterate(source, options);
769
- }
770
-
771
- /**
772
- * Builds a city description from geonameid string components
773
- * @param {string} cityName e.g. 'Tel Aviv' or 'Chicago'
774
- * @param {string} admin1 e.g. 'England' or 'Massachusetts'
775
- * @param {string} countryName full country name, e.g. 'Israel' or 'United States'
776
- * @return {string}
777
- */
778
- static geonameCityDescr(cityName, admin1, countryName) {
779
- if (countryName === 'United States') countryName = 'USA';
780
- if (countryName === 'United Kingdom') countryName = 'UK';
781
- let cityDescr = cityName;
782
- if (countryName !== 'Israel' && admin1 && !admin1.includes(cityName)) {
783
- const tlitCityName = transliterate(cityName);
784
- const tlitAdmin1 = transliterate(admin1);
785
- if (!tlitAdmin1.includes(tlitCityName)) {
786
- cityDescr += ', ' + admin1;
787
- }
788
- }
789
- if (countryName) {
790
- cityDescr += ', ' + countryName;
791
- }
792
- return cityDescr;
793
- }
794
-
795
- /**
796
- * @private
797
- * @param {number} geonameid
798
- * @param {any} result
799
- * @return {Location}
800
- */
801
- makeGeonameLocation(geonameid, result) {
802
- const country = result.country || '';
803
- const admin1 = result.admin1 || '';
804
- const cityDescr = GeoDb.geonameCityDescr(result.name, admin1, country);
805
- const elevation = result?.elevation > 0 ? result.elevation : 0;
806
- const location = new Location(
807
- result.latitude,
808
- result.longitude,
809
- result.cc === 'IL',
810
- result.timezone,
811
- cityDescr,
812
- result.cc,
813
- geonameid,
814
- elevation,
815
- );
816
- location.geo = 'geoname';
817
- location.geonameid = geonameid;
818
- location.asciiname = result.asciiname;
819
- if (admin1) {
820
- location.admin1 = admin1;
821
- }
822
- if (result.population) {
823
- location.population = result.population;
824
- }
825
- return location;
826
- }
827
-
828
- /**
829
- * @param {string} cityName
830
- * @return {Location}
831
- */
832
- lookupLegacyCity(cityName) {
833
- const name = munge(cityName);
834
- const geonameid = this.legacyCities.get(name);
835
- if (geonameid) {
836
- return this.lookupGeoname(geonameid);
837
- } else {
838
- const location = Location.lookup(cityName);
839
- if (location) {
840
- return location;
841
- }
842
- if (this.logger) this.logger.warn(`GeoDb: unknown city=${cityName}`);
843
- return null;
844
- }
845
- }
846
-
847
- /**
848
- * @private
849
- * @param {any[]} res
850
- * @return {Object[]}
851
- */
852
- static zipResultToObj(res) {
853
- const obj = {
854
- id: String(res.ZipCode),
855
- value: `${res.CityMixedCase}, ${res.State} ${res.ZipCode}`,
856
- admin1: res.State,
857
- asciiname: res.CityMixedCase,
858
- country: 'United States',
859
- cc: 'US',
860
- latitude: res.Latitude,
861
- longitude: res.Longitude,
862
- timezone: Location.getUsaTzid(res.State, res.TimeZone, res.DayLightSaving),
863
- population: res.Population,
864
- geo: 'zip',
865
- };
866
- if (res.Elevation && res.Elevation > 0) {
867
- obj.elevation = res.Elevation;
868
- }
869
- return obj;
870
- }
871
-
872
- /**
873
- * Generates autocomplete results based on a query string
874
- * @param {string} qraw
875
- * @param {boolean} latlong
876
- * @return {Object[]}
877
- */
878
- autoComplete(qraw, latlong=false) {
879
- qraw = qraw.trim();
880
- if (qraw.length === 0) {
881
- return [];
882
- }
883
- const firstCharCode = qraw.charCodeAt(0);
884
- if (firstCharCode >= 48 && firstCharCode <= 57) {
885
- // special-case PK query instead of full-table scan
886
- if (GeoDb.is5DigitZip(qraw)) {
887
- const loc = this.lookupZip(qraw);
888
- return loc ? [GeoDb.zipLocToAutocomplete(loc)] : [];
889
- }
890
- if (!this.zipCompStmt) {
891
- this.zipCompStmt = this.zipsDb.prepare(ZIP_COMPLETE_SQL);
892
- }
893
- // this is a ZIP code prefix, a string with 1-4 digits
894
- const zipA = qraw.substring(0, 5);
895
- const zipB = zipA === '9' ? 'A' :String(+zipA + 1).padStart(zipA.length, '0');
896
- return this.zipCompStmt.all(zipA, zipB).map(GeoDb.zipResultToObj);
897
- } else {
898
- if (!this.geonamesCompStmt) {
899
- this.geonamesCompStmt = this.geonamesDb.prepare(GEONAME_COMPLETE_SQL);
900
- }
901
- qraw = qraw.replaceAll('"', '""');
902
- const geoRows0 = this.geonamesCompStmt.all(`{longname} : "${qraw}" *`);
903
- const ids = new Set();
904
- const geoRows = [];
905
- for (const row of geoRows0) {
906
- const id = row.geonameid;
907
- if (!ids.has(id)) {
908
- ids.add(id);
909
- geoRows.push(row);
910
- }
911
- }
912
- const geoMatches = geoRows.map((res) => {
913
- const loc = this.lookupGeoname(res.geonameid);
914
- return this.geonameLocToAutocomplete(loc, res);
915
- });
916
- if (!this.zipFulltextCompStmt) {
917
- this.zipFulltextCompStmt = this.zipsDb.prepare(ZIP_FULLTEXT_COMPLETE_SQL);
918
- }
919
- const zipRows = this.zipFulltextCompStmt.all(`{longname} : "${qraw}" *`);
920
- const zipMatches = zipRows.map((res) => {
921
- const loc = this.lookupZip(res.ZipCode);
922
- return GeoDb.zipLocToAutocomplete(loc);
923
- });
924
- const values = this.mergeZipGeo(zipMatches, geoMatches);
925
- values.sort((a, b) => b.population - a.population);
926
- const topN = values.slice(0, 12);
927
- if (!latlong) {
928
- for (const val of topN) {
929
- delete val.latitude;
930
- delete val.longitude;
931
- delete val.timezone;
932
- delete val.population;
933
- }
934
- }
935
- return topN;
936
- }
937
- }
938
-
939
- /**
940
- * @private
941
- * @param {Location} loc
942
- * @param {any} res
943
- * @return {any}
944
- */
945
- geonameLocToAutocomplete(loc, res) {
946
- const cc = loc.getCountryCode();
947
- const country = res.country || this.countryNames.get(cc) || '';
948
- const admin1 = res.admin || loc.admin1 || '';
949
- const obj = {
950
- id: res.geonameid,
951
- value: loc.getName(),
952
- admin1,
953
- country,
954
- cc,
955
- latitude: loc.latitude,
956
- longitude: loc.longitude,
957
- timezone: loc.getTzid(),
958
- geo: 'geoname',
959
- };
960
- if (loc.population) {
961
- obj.population = loc.population;
962
- }
963
- if (res.city !== loc.asciiname) {
964
- obj.name = res.city;
965
- }
966
- if (loc.asciiname) {
967
- obj.asciiname = loc.asciiname;
968
- }
969
- if (country) {
970
- obj.country = country;
971
- }
972
- if (admin1) {
973
- obj.admin1 = admin1;
974
- }
975
- return obj;
976
- }
977
-
978
- /**
979
- * @private
980
- * @param {Location} loc
981
- * @return {any}
982
- */
983
- static zipLocToAutocomplete(loc) {
984
- return {
985
- id: loc.zip,
986
- value: loc.getName(),
987
- admin1: loc.admin1,
988
- asciiname: loc.getShortName(),
989
- country: 'United States',
990
- cc: 'US',
991
- latitude: loc.latitude,
992
- longitude: loc.longitude,
993
- timezone: loc.getTzid(),
994
- population: loc.population,
995
- geo: 'zip',
996
- };
997
- }
998
-
999
- /**
1000
- * GeoNames matches takes priority over USA ZIP code matches
1001
- * @private
1002
- * @param {any[]} zipMatches
1003
- * @param {any[]} geoMatches
1004
- * @return {any[]}
1005
- */
1006
- mergeZipGeo(zipMatches, geoMatches) {
1007
- const zlen = zipMatches.length;
1008
- const glen = geoMatches.length;
1009
- if (zlen && !glen) {
1010
- return zipMatches;
1011
- } else if (glen && !zlen) {
1012
- return geoMatches;
1013
- }
1014
- const map = new Map();
1015
- for (const obj of zipMatches) {
1016
- const key = [obj.asciiname, stateNames[obj.admin1], obj.cc].join('|');
1017
- if (!map.has(key)) {
1018
- map.set(key, obj);
1019
- }
1020
- }
1021
- for (const obj of geoMatches) {
1022
- const key = [obj.asciiname, obj.admin1, obj.cc].join('|');
1023
- map.set(key, obj);
1024
- }
1025
- return Array.from(map.values());
1026
- }
1027
-
1028
- /** Reads entire ZIP database and caches in-memory */
1029
- cacheZips() {
1030
- const start = Date.now();
1031
- const stmt = this.zipsDb.prepare(ZIPCODE_ALL_SQL);
1032
- const rows = stmt.all();
1033
- this.zipCache = new Map(); // replace QuickLRU
1034
- for (const row of rows) {
1035
- const location = this.makeZipLocation(row);
1036
- this.zipCache.set(row.ZipCode, location);
1037
- }
1038
- const end = Date.now();
1039
- if (this.logger) this.logger.info(`GeoDb: cached ${rows.length} ZIP codes in ${end - start}ms`);
1040
- }
1041
-
1042
- /** Reads entire geonames database and caches in-memory */
1043
- cacheGeonames() {
1044
- const start = Date.now();
1045
- const stmt = this.geonamesDb.prepare(GEONAME_ALL_SQL);
1046
- const rows = stmt.all();
1047
- this.geonamesCache = new Map(); // replace QuickLRU
1048
- for (const row of rows) {
1049
- const location = this.makeGeonameLocation(row.geonameid, row);
1050
- this.geonamesCache.set(row.geonameid, location);
1051
- }
1052
- const end = Date.now();
1053
- if (this.logger) this.logger.info(`GeoDb: cached ${rows.length} geonames in ${end - start}ms`);
1054
- }
1055
-
1056
- /** Returns the version of the GeoDb package */
1057
- static version() {
1058
- return version;
1059
- }
1060
-
1061
- /**
1062
- * @param {string} str
1063
- * @return {boolean}
1064
- */
1065
- static is5DigitZip(str) {
1066
- if (typeof str !== 'string') {
1067
- return false;
1068
- }
1069
- const s = str.trim();
1070
- if (s.length < 5) {
1071
- return false;
1072
- }
1073
- for (let i = 0; i < 5; i++) {
1074
- if (s.charCodeAt(i) > 57 || s.charCodeAt(i) < 48) {
1075
- return false;
1076
- }
1077
- }
1078
- return true;
1079
- }
1080
- }
1081
-
1082
- /* eslint-disable no-multi-spaces */
1083
-
1084
- const fcodeKeep = {
1085
- PPL: true, // populated place: a city, town, village, or other agglomeration of
1086
- PPLA: true, // seat of a first-order administrative division (PPLC takes precedence over PPLA)
1087
- PPLA2: true, // seat of a second-order administrative division
1088
- PPLA3: true, // seat of a third-order administrative division
1089
- PPLC: true, // capital of a political entity
1090
- // an area similar to a locality but with a small group of dwellings or other buildings
1091
- PPLG: true, // seat of government of a political entity
1092
- PPLL: true, // populated locality
1093
- // cities, towns, villages, or other agglomerations of buildings where people live and work
1094
- PPLS: true, // populated places
1095
- PPLX: true, // section of populated place
1096
- STLMT: true, // israeli settlement
1097
- };
1098
-
1099
- /**
1100
- * Builds `geonames.sqlite3` from files downloaded from geonames.org
1101
- * @param {any} opts
1102
- */
1103
- async function buildGeonamesSqlite(opts) {
1104
- const dbFilename = opts.dbFilename;
1105
- const countryInfotxt = opts.countryInfotxt;
1106
- const cities5000txt = opts.cities5000txt;
1107
- const citiesPatch = opts.citiesPatch;
1108
- const admin1CodesASCIItxt = opts.admin1CodesASCIItxt;
1109
- const ILtxt = opts.ILtxt;
1110
- const ILalternate = opts.ILalternate;
1111
- const logger = opts.logger;
1112
- logger.info(`Opening ${dbFilename}`);
1113
- const db = new DatabaseSync(dbFilename);
1114
- db.exec('PRAGMA journal_mode = MEMORY');
1115
-
1116
- doSql(logger, db,
1117
- `DROP TABLE IF EXISTS country`,
1118
-
1119
- `CREATE TABLE country (
1120
- ISO TEXT PRIMARY KEY,
1121
- ISO3 TEXT NOT NULL,
1122
- IsoNumeric TEXT NOT NULL,
1123
- fips TEXT NOT NULL,
1124
- Country TEXT NOT NULL,
1125
- Capital TEXT NOT NULL,
1126
- Area INT NOT NULL,
1127
- Population INT NOT NULL,
1128
- Continent TEXT NOT NULL,
1129
- tld TEXT NOT NULL,
1130
- CurrencyCode TEXT NOT NULL,
1131
- CurrencyName TEXT NOT NULL,
1132
- Phone TEXT NOT NULL,
1133
- PostalCodeFormat TEXT,
1134
- PostalCodeRegex TEXT,
1135
- Languages TEXT NOT NULL,
1136
- geonameid INT NOT NULL,
1137
- neighbours TEXT NOT NULL,
1138
- EquivalentFipsCode TEXT NOT NULL
1139
- );`,
1140
- );
1141
- await doFile(logger, db, countryInfotxt, 'country', 19);
1142
-
1143
- doSql(logger, db,
1144
- `DROP TABLE IF EXISTS geoname`,
1145
-
1146
- `CREATE TABLE geoname (
1147
- geonameid int PRIMARY KEY,
1148
- name nvarchar(200),
1149
- asciiname nvarchar(200),
1150
- alternatenames nvarchar(4000),
1151
- latitude decimal(18,15),
1152
- longitude decimal(18,15),
1153
- fclass nchar(1),
1154
- fcode nvarchar(10),
1155
- country nvarchar(2),
1156
- cc2 nvarchar(60),
1157
- admin1 nvarchar(20),
1158
- admin2 nvarchar(80),
1159
- admin3 nvarchar(20),
1160
- admin4 nvarchar(20),
1161
- population int,
1162
- elevation int,
1163
- gtopo30 int,
1164
- timezone nvarchar(40),
1165
- moddate date);`,
1166
- );
1167
-
1168
- const truncateAlternateNames = (a) => {
1169
- a[3] = '';
1170
- return true;
1171
- };
1172
- const minPopulation = opts.population;
1173
- const citiesFilter = (a) => {
1174
- if (!a[17]) {
1175
- return false; // require a non-empty iana timezone id
1176
- }
1177
- const fcode = a[7];
1178
- logger.debug(a[0], a[1], fcode);
1179
- if (!fcodeKeep[fcode]) {
1180
- return false;
1181
- }
1182
- if (minPopulation) {
1183
- const population = a[14];
1184
- if (fcode === 'PPL' && population && population < minPopulation) {
1185
- return false;
1186
- }
1187
- }
1188
- a[3] = '';
1189
- return true;
1190
- };
1191
- await doFile(logger, db, cities5000txt, 'geoname', 19, citiesFilter);
1192
- await doFile(logger, db, citiesPatch, 'geoname', 19, truncateAlternateNames);
1193
- await doFile(logger, db, ILtxt, 'geoname', 19, (a) => {
1194
- a[3] = '';
1195
- return a[6] == 'P' && fcodeKeep[a[7]];
1196
- });
1197
-
1198
- doSql(logger, db,
1199
- `DROP TABLE IF EXISTS admin1`,
1200
-
1201
- `CREATE TABLE admin1 (
1202
- key TEXT PRIMARY KEY,
1203
- name nvarchar(200) NOT NULL,
1204
- asciiname nvarchar(200) NOT NULL,
1205
- geonameid int NOT NULL
1206
- );`,
1207
- );
1208
-
1209
- await doFile(logger, db, admin1CodesASCIItxt, 'admin1', 4);
1210
-
1211
- // fix inconsistencies with the USA capitol
1212
- doSql(logger, db,
1213
- `UPDATE geoname
1214
- SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
1215
- WHERE geonameid = 4140963;`,
1216
-
1217
- `UPDATE admin1
1218
- SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
1219
- WHERE key = 'US.DC';`,
1220
- );
1221
-
1222
- doSql(logger, db,
1223
- `DROP TABLE IF EXISTS alternatenames`,
1224
-
1225
- `CREATE TABLE alternatenames (
1226
- id int PRIMARY KEY,
1227
- geonameid int NOT NULL,
1228
- isolanguage varchar(7),
1229
- name varchar(400),
1230
- isPreferredName tinyint,
1231
- isShortName tinyint,
1232
- isColloquial tinyint,
1233
- isHistoric tinyint,
1234
- periodFrom NULL,
1235
- periodTo NULL
1236
- );`,
1237
- );
1238
-
1239
- await doFile(logger, db, ILalternate, 'alternatenames', 10, (a) => {
1240
- const firstchar = a[3][0];
1241
- if (a[2] === 'he' && (firstchar < '\u05D0' || firstchar > '\u05EA')) {
1242
- a[2] = 'en';
1243
- }
1244
- if (a[2] === 'he' || a[2] === 'en') {
1245
- if (a[2] === 'he') {
1246
- a[3] = a[3].replace(/‘/g, '׳');
1247
- a[3] = a[3].replace(/’/g, '׳');
1248
- a[3] = a[3].replace(/'/g, '׳');
1249
- a[3] = Locale.hebrewStripNikkud(a[3]);
1250
- } else {
1251
- a[3] = a[3].replace(/‘/g, '\'');
1252
- a[3] = a[3].replace(/’/g, '\'');
1253
- a[3] = a[3].replace(/Ḥ/g, 'Ch');
1254
- a[3] = a[3].replace(/H̱/g, 'Ch');
1255
- a[3] = a[3].replace(/ẖ/g, 'ch');
1256
- a[3] = a[3].replace(/Ẕ/g, 'Tz');
1257
- a[3] = a[3].replace(/ẕ/g, 'tz');
1258
- a[3] = a[3].replace(/ā/g, 'a');
1259
- a[3] = a[3].replace(/é/g, 'e');
1260
- }
1261
- return true;
1262
- }
1263
- return false;
1264
- });
1265
-
1266
- // remove duplicates from alternatenames
1267
- doSql(logger, db,
1268
- `DROP TABLE IF EXISTS altnames`,
1269
-
1270
- `CREATE TABLE altnames
1271
- AS SELECT geonameid, isolanguage, name
1272
- FROM alternatenames
1273
- GROUP BY 1, 2, 3
1274
- `,
1275
- );
1276
-
1277
- doSql(logger, db,
1278
- // `update admin1 set name='',asciiname='' where key like 'PS.%';`,
1279
- // `update country set country = '' where iso = 'PS';`,
1280
- `delete from geoname where country = 'PS' and admin1 = 'GZ';`,
1281
- `delete from geoname where geonameid = 7303419;`,
1282
- `update geoname set country = 'IL' where country = 'PS' and admin1 = 'WE';`,
1283
- );
1284
-
1285
- doSql(logger, db,
1286
- `DROP TABLE IF EXISTS geoname_fulltext`,
1287
-
1288
- `CREATE VIRTUAL TABLE geoname_fulltext
1289
- USING fts5(geonameid UNINDEXED, longname, population, city, admin1, country);
1290
- `,
1291
-
1292
- `DROP TABLE IF EXISTS geoname_non_ascii`,
1293
-
1294
- `CREATE TABLE geoname_non_ascii AS
1295
- SELECT geonameid FROM geoname WHERE asciiname <> name`,
1296
-
1297
- `INSERT INTO geoname_fulltext
1298
- SELECT g.geonameid,
1299
- g.asciiname||', '||a.asciiname||', '||c.Country,
1300
- g.population,
1301
- g.asciiname,a.asciiname,c.Country
1302
- FROM geoname g, admin1 a, country c
1303
- WHERE g.country = c.ISO
1304
- AND g.country <> 'US'
1305
- AND g.country <> 'IL'
1306
- AND g.country <> 'GB'
1307
- AND g.country||'.'||g.admin1 = a.key
1308
- `,
1309
-
1310
- `INSERT INTO geoname_fulltext
1311
- SELECT g.geonameid,
1312
- g.asciiname||', '||a.asciiname||', USA',
1313
- g.population,
1314
- g.asciiname,a.asciiname,'United States'
1315
- FROM geoname g, admin1 a
1316
- WHERE g.country = 'US'
1317
- AND g.country||'.'||g.admin1 = a.key
1318
- `,
1319
-
1320
- `INSERT INTO geoname_fulltext
1321
- SELECT g.geonameid,
1322
- g.asciiname||', '||a.asciiname||', UK',
1323
- g.population,
1324
- g.asciiname,a.asciiname,'UK'
1325
- FROM geoname g, admin1 a
1326
- WHERE g.country = 'GB'
1327
- AND g.country||'.'||g.admin1 = a.key
1328
- `,
1329
-
1330
- `INSERT INTO geoname_fulltext
1331
- SELECT g.geonameid,
1332
- g.asciiname||', Israel',
1333
- g.population,
1334
- g.asciiname,NULL,'Israel'
1335
- FROM geoname g
1336
- WHERE g.country = 'IL'
1337
- `,
1338
-
1339
- `INSERT INTO geoname_fulltext
1340
- SELECT g.geonameid,
1341
- g.asciiname||', '||c.Country,
1342
- g.population,
1343
- g.asciiname,NULL,c.Country
1344
- FROM geoname g, country c
1345
- WHERE g.country = c.ISO
1346
- AND (g.admin1 = '' OR g.admin1 = '00')
1347
- `,
1348
-
1349
- `INSERT INTO geoname_fulltext
1350
- SELECT g.geonameid,
1351
- g.name||', '||a.name||', '||c.Country,
1352
- g.population,
1353
- g.name,a.name,c.Country
1354
- FROM geoname_non_ascii gna, geoname g, admin1 a, country c
1355
- WHERE gna.geonameid = g.geonameid
1356
- AND g.country = c.ISO
1357
- AND g.country||'.'||g.admin1 = a.key
1358
- `,
1359
-
1360
- `INSERT INTO geoname_fulltext
1361
- SELECT g.geonameid,
1362
- alt.name||', ישראל',
1363
- g.population,
1364
- alt.name,NULL,'ישראל'
1365
- FROM geoname g, altnames alt
1366
- WHERE g.country = 'IL'
1367
- AND alt.isolanguage = 'he'
1368
- AND g.geonameid = alt.geonameid
1369
- `,
1370
-
1371
- `INSERT INTO geoname_fulltext
1372
- SELECT g.geonameid,
1373
- alt.name||', Israel',
1374
- g.population,
1375
- alt.name,NULL,'Israel'
1376
- FROM geoname g, altnames alt
1377
- WHERE g.country = 'IL'
1378
- AND alt.isolanguage = 'en'
1379
- AND g.geonameid = alt.geonameid
1380
- `,
1381
-
1382
- 'VACUUM',
1383
- );
1384
-
1385
- return new Promise((resolve, reject) => {
1386
- try {
1387
- logger.info(`Closing ${dbFilename}`);
1388
- db.close();
1389
- logger.info('buildGeonamesSqlite finished');
1390
- resolve(true);
1391
- } catch (err) {
1392
- logger.error(err);
1393
- reject(err);
1394
- }
1395
- });
1396
- }
1397
-
1398
- /**
1399
- * @param {pino.Logger} logger
1400
- * @param {Database} db
1401
- * @param {...string} sqls
1402
- */
1403
- function doSql(logger, db, ...sqls) {
1404
- for (let i = 0; i < sqls.length; i++) {
1405
- logger.info(sqls[i]);
1406
- db.exec(sqls[i]);
1407
- }
1408
- }
1409
-
1410
- /**
1411
- * @param {pino.Logger} logger
1412
- * @param {Database} db
1413
- * @param {string} infile
1414
- * @param {string} tableName
1415
- * @param {number} expectedFields
1416
- * @param {Function} callback
1417
- */
1418
- async function doFile(logger, db, infile, tableName, expectedFields, callback) {
1419
- return new Promise((resolve, reject) => {
1420
- logger.info(`${infile} => ${tableName}`);
1421
- db.exec('BEGIN');
1422
- let sql = `INSERT OR IGNORE INTO ${tableName} VALUES (?`;
1423
- for (let i = 0; i < expectedFields - 1; i++) {
1424
- sql += ',?';
1425
- }
1426
- sql += ')';
1427
- logger.info(sql);
1428
- let stmt = db.prepare(sql);
1429
- try {
1430
- const rl = readline.createInterface({
1431
- input: fs.createReadStream(infile),
1432
- crlfDelay: Infinity,
1433
- });
1434
- let num = 0;
1435
- let accepted = 0;
1436
- rl.on('line', (line) => {
1437
- num++;
1438
- if (line[0] == '#') {
1439
- return;
1440
- }
1441
- const a = line.split('\t');
1442
- if (a.length != expectedFields) {
1443
- logger.warn(`${infile}:${num}: got ${a.length} fields (expected ${expectedFields})`);
1444
- return;
1445
- }
1446
- if (callback) {
1447
- const accept = callback(a);
1448
- if (!accept) {
1449
- return;
1450
- }
1451
- }
1452
- stmt.run(...a);
1453
- accepted++;
1454
- });
1455
-
1456
- rl.on('close', () => {
1457
- logger.info(`Inserted ${accepted} / ${num} into ${tableName} from ${infile}`);
1458
- stmt = null;
1459
- db.exec('COMMIT');
1460
- });
1461
-
1462
- return resolve(events.once(rl, 'close'));
1463
- } catch (err) {
1464
- logger.error(err);
1465
- return reject(err);
1466
- }
1467
- });
1468
- }
1469
-
1470
- /**
1471
- * Builds `zips.sqlite3` from the bundled zips-dummy.sql schema file
1472
- * @param {string} dbFilename path to the output SQLite database file
1473
- * @param {string} sqlFile path to the SQL schema file
1474
- */
1475
- function makeZipsSqlite(dbFilename, sqlFile) {
1476
- const sql = fs$1.readFileSync(sqlFile, 'utf8');
1477
- const db = new DatabaseSync(dbFilename);
1478
- console.log(sql);
1479
- db.exec(sql);
1480
- db.close();
1481
- }
1482
-
1483
- export { GeoDb, buildGeonamesSqlite, makeZipsSqlite };
1
+ export { GeoDb } from './geodb.js';
2
+ export { buildGeonamesSqlite } from './build-geonames-sqlite.js';
3
+ export { makeZipsSqlite } from './make-zips-sqlite.js';
4
+ //# sourceMappingURL=index.js.map