@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/README.md +29 -3
- package/bin/make-test-dbs +1 -1
- package/dist/build-geonames-sqlite.d.ts +28 -0
- package/dist/build-geonames-sqlite.js +309 -0
- package/dist/build-geonames-sqlite.js.map +1 -0
- package/dist/city2geonameid.json.d.ts +490 -0
- package/dist/city2geonameid.json.js +490 -0
- package/dist/city2geonameid.json.js.map +1 -0
- package/dist/geodb.d.ts +87 -0
- package/dist/geodb.js +451 -0
- package/dist/geodb.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -1483
- package/dist/index.js.map +1 -0
- package/dist/make-zips-sqlite.d.ts +6 -0
- package/dist/make-zips-sqlite.js +15 -0
- package/dist/make-zips-sqlite.js.map +1 -0
- package/dist/munge.d.ts +6 -0
- package/dist/munge.js +13 -0
- package/dist/munge.js.map +1 -0
- package/dist/pkgVersion.d.ts +1 -0
- package/dist/pkgVersion.js +3 -0
- package/dist/pkgVersion.js.map +1 -0
- package/package.json +26 -30
- package/geo-sqlite.d.ts +0 -161
package/dist/index.js
CHANGED
|
@@ -1,1483 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|