@hebcal/geo-sqlite 3.6.2 → 3.7.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 +113 -18
- package/dist/index.mjs +113 -18
- package/package.json +1 -1
- package/zips-dummy.sql +3 -0
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/geo-sqlite v3.
|
|
1
|
+
/*! @hebcal/geo-sqlite v3.7.0 */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
@@ -57,13 +57,71 @@ FROM ZIPCodes_Primary
|
|
|
57
57
|
WHERE ZipCode LIKE ?
|
|
58
58
|
ORDER BY Population DESC
|
|
59
59
|
LIMIT 10`;
|
|
60
|
+
const ZIP_FULLTEXT_COMPLETE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
61
|
+
FROM ZIPCodes_CityFullText
|
|
62
|
+
WHERE CityMixedCase MATCH ?
|
|
63
|
+
ORDER BY Population DESC
|
|
64
|
+
LIMIT 15`;
|
|
60
65
|
const GEONAME_COMPLETE_SQL = `SELECT geonameid, asciiname, admin1, country,
|
|
61
66
|
population, latitude, longitude, timezone
|
|
62
67
|
FROM geoname_fulltext
|
|
63
68
|
WHERE longname MATCH ?
|
|
64
69
|
GROUP BY geonameid
|
|
65
70
|
ORDER BY population DESC
|
|
66
|
-
LIMIT
|
|
71
|
+
LIMIT 15`;
|
|
72
|
+
const stateNames = {
|
|
73
|
+
'AK': 'Alaska',
|
|
74
|
+
'AL': 'Alabama',
|
|
75
|
+
'AR': 'Arkansas',
|
|
76
|
+
'AZ': 'Arizona',
|
|
77
|
+
'CA': 'California',
|
|
78
|
+
'CO': 'Colorado',
|
|
79
|
+
'CT': 'Connecticut',
|
|
80
|
+
'DC': 'Washington, D.C.',
|
|
81
|
+
'DE': 'Delaware',
|
|
82
|
+
'FL': 'Florida',
|
|
83
|
+
'GA': 'Georgia',
|
|
84
|
+
'HI': 'Hawaii',
|
|
85
|
+
'IA': 'Iowa',
|
|
86
|
+
'ID': 'Idaho',
|
|
87
|
+
'IL': 'Illinois',
|
|
88
|
+
'IN': 'Indiana',
|
|
89
|
+
'KS': 'Kansas',
|
|
90
|
+
'KY': 'Kentucky',
|
|
91
|
+
'LA': 'Louisiana',
|
|
92
|
+
'MA': 'Massachusetts',
|
|
93
|
+
'MD': 'Maryland',
|
|
94
|
+
'ME': 'Maine',
|
|
95
|
+
'MI': 'Michigan',
|
|
96
|
+
'MN': 'Minnesota',
|
|
97
|
+
'MO': 'Missouri',
|
|
98
|
+
'MS': 'Mississippi',
|
|
99
|
+
'MT': 'Montana',
|
|
100
|
+
'NC': 'North Carolina',
|
|
101
|
+
'ND': 'North Dakota',
|
|
102
|
+
'NE': 'Nebraska',
|
|
103
|
+
'NH': 'New Hampshire',
|
|
104
|
+
'NJ': 'New Jersey',
|
|
105
|
+
'NM': 'New Mexico',
|
|
106
|
+
'NV': 'Nevada',
|
|
107
|
+
'NY': 'New York',
|
|
108
|
+
'OH': 'Ohio',
|
|
109
|
+
'OK': 'Oklahoma',
|
|
110
|
+
'OR': 'Oregon',
|
|
111
|
+
'PA': 'Pennsylvania',
|
|
112
|
+
'RI': 'Rhode Island',
|
|
113
|
+
'SC': 'South Carolina',
|
|
114
|
+
'SD': 'South Dakota',
|
|
115
|
+
'TN': 'Tennessee',
|
|
116
|
+
'TX': 'Texas',
|
|
117
|
+
'UT': 'Utah',
|
|
118
|
+
'VA': 'Virginia',
|
|
119
|
+
'VT': 'Vermont',
|
|
120
|
+
'WA': 'Washington',
|
|
121
|
+
'WI': 'Wisconsin',
|
|
122
|
+
'WV': 'West Virginia',
|
|
123
|
+
'WY': 'Wyoming'
|
|
124
|
+
};
|
|
67
125
|
/** Wrapper around sqlite databases */
|
|
68
126
|
|
|
69
127
|
class GeoDb {
|
|
@@ -218,6 +276,28 @@ class GeoDb {
|
|
|
218
276
|
return null;
|
|
219
277
|
}
|
|
220
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* @private
|
|
281
|
+
* @param {any[]} res
|
|
282
|
+
* @return {Object[]}
|
|
283
|
+
*/
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
static zipResultToObj(res) {
|
|
287
|
+
const obj = {
|
|
288
|
+
id: String(res.ZipCode),
|
|
289
|
+
value: `${res.CityMixedCase}, ${res.State} ${res.ZipCode}`,
|
|
290
|
+
admin1: res.State,
|
|
291
|
+
asciiname: res.CityMixedCase,
|
|
292
|
+
country: 'United States',
|
|
293
|
+
latitude: res.Latitude,
|
|
294
|
+
longitude: res.Longitude,
|
|
295
|
+
timezone: core.Location.getUsaTzid(res.State, res.TimeZone, res.DayLightSaving),
|
|
296
|
+
population: res.Population,
|
|
297
|
+
geo: 'zip'
|
|
298
|
+
};
|
|
299
|
+
return obj;
|
|
300
|
+
}
|
|
221
301
|
/**
|
|
222
302
|
* Generates autocomplete results based on a query string
|
|
223
303
|
* @param {string} qraw
|
|
@@ -235,34 +315,23 @@ class GeoDb {
|
|
|
235
315
|
this.zipCompStmt = this.zipsDb.prepare(ZIP_COMPLETE_SQL);
|
|
236
316
|
}
|
|
237
317
|
|
|
238
|
-
return this.zipCompStmt.all(qraw + '%').map(
|
|
239
|
-
const obj = {
|
|
240
|
-
id: String(res.ZipCode),
|
|
241
|
-
value: `${res.CityMixedCase}, ${res.State} ${res.ZipCode}`,
|
|
242
|
-
admin1: res.State,
|
|
243
|
-
asciiname: res.CityMixedCase,
|
|
244
|
-
country: 'United States',
|
|
245
|
-
latitude: res.Latitude,
|
|
246
|
-
longitude: res.Longitude,
|
|
247
|
-
timezone: core.Location.getUsaTzid(res.State, res.TimeZone, res.DayLightSaving),
|
|
248
|
-
population: res.Population,
|
|
249
|
-
geo: 'zip'
|
|
250
|
-
};
|
|
251
|
-
return obj;
|
|
252
|
-
});
|
|
318
|
+
return this.zipCompStmt.all(qraw + '%').map(GeoDb.zipResultToObj);
|
|
253
319
|
} else {
|
|
254
320
|
if (!this.geonamesCompStmt) {
|
|
255
321
|
this.geonamesCompStmt = this.geonamesDb.prepare(GEONAME_COMPLETE_SQL);
|
|
256
322
|
}
|
|
257
323
|
|
|
258
324
|
qraw = qraw.replace(/\"/g, '""');
|
|
259
|
-
|
|
325
|
+
const geoRows = this.geonamesCompStmt.all(`"${qraw}*"`);
|
|
326
|
+
const geoMatches = geoRows.map(res => {
|
|
260
327
|
const country = res.country || '';
|
|
261
328
|
const admin1 = res.admin1 || '';
|
|
262
329
|
const obj = {
|
|
263
330
|
id: res.geonameid,
|
|
264
331
|
value: core.Location.geonameCityDescr(res.asciiname, admin1, country),
|
|
265
332
|
asciiname: res.asciiname,
|
|
333
|
+
admin1,
|
|
334
|
+
country,
|
|
266
335
|
latitude: res.latitude,
|
|
267
336
|
longitude: res.longitude,
|
|
268
337
|
timezone: res.timezone,
|
|
@@ -281,6 +350,32 @@ class GeoDb {
|
|
|
281
350
|
obj.tokens = Array.from(new Set(res.asciiname.split(' ').concat(admin1.split(' '), country.split(' '))));
|
|
282
351
|
return obj;
|
|
283
352
|
});
|
|
353
|
+
|
|
354
|
+
if (!this.zipFulltextCompStmt) {
|
|
355
|
+
this.zipFulltextCompStmt = this.zipsDb.prepare(ZIP_FULLTEXT_COMPLETE_SQL);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const zipRows = this.zipFulltextCompStmt.all(`"${qraw}*"`);
|
|
359
|
+
const zipMatches = zipRows.map(GeoDb.zipResultToObj);
|
|
360
|
+
const map = new Map();
|
|
361
|
+
|
|
362
|
+
for (const obj of zipMatches) {
|
|
363
|
+
const key = [obj.asciiname, stateNames[obj.admin1], obj.country].join('|');
|
|
364
|
+
|
|
365
|
+
if (!map.has(key)) {
|
|
366
|
+
map.set(key, obj);
|
|
367
|
+
}
|
|
368
|
+
} // GeoNames takes priority over USA ZIP code matches
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
for (const obj of geoMatches) {
|
|
372
|
+
const key = [obj.asciiname, obj.admin1, obj.country].join('|');
|
|
373
|
+
map.set(key, obj);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const values = Array.from(map.values());
|
|
377
|
+
values.sort((a, b) => b.population - a.population);
|
|
378
|
+
return values.slice(0, 10);
|
|
284
379
|
}
|
|
285
380
|
}
|
|
286
381
|
/** Reads entire ZIP database and caches in-memory */
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/geo-sqlite v3.
|
|
1
|
+
/*! @hebcal/geo-sqlite v3.7.0 */
|
|
2
2
|
import Database from 'better-sqlite3';
|
|
3
3
|
import { Location, Locale } from '@hebcal/core';
|
|
4
4
|
import pino from 'pino';
|
|
@@ -45,13 +45,71 @@ FROM ZIPCodes_Primary
|
|
|
45
45
|
WHERE ZipCode LIKE ?
|
|
46
46
|
ORDER BY Population DESC
|
|
47
47
|
LIMIT 10`;
|
|
48
|
+
const ZIP_FULLTEXT_COMPLETE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
49
|
+
FROM ZIPCodes_CityFullText
|
|
50
|
+
WHERE CityMixedCase MATCH ?
|
|
51
|
+
ORDER BY Population DESC
|
|
52
|
+
LIMIT 15`;
|
|
48
53
|
const GEONAME_COMPLETE_SQL = `SELECT geonameid, asciiname, admin1, country,
|
|
49
54
|
population, latitude, longitude, timezone
|
|
50
55
|
FROM geoname_fulltext
|
|
51
56
|
WHERE longname MATCH ?
|
|
52
57
|
GROUP BY geonameid
|
|
53
58
|
ORDER BY population DESC
|
|
54
|
-
LIMIT
|
|
59
|
+
LIMIT 15`;
|
|
60
|
+
const stateNames = {
|
|
61
|
+
'AK': 'Alaska',
|
|
62
|
+
'AL': 'Alabama',
|
|
63
|
+
'AR': 'Arkansas',
|
|
64
|
+
'AZ': 'Arizona',
|
|
65
|
+
'CA': 'California',
|
|
66
|
+
'CO': 'Colorado',
|
|
67
|
+
'CT': 'Connecticut',
|
|
68
|
+
'DC': 'Washington, D.C.',
|
|
69
|
+
'DE': 'Delaware',
|
|
70
|
+
'FL': 'Florida',
|
|
71
|
+
'GA': 'Georgia',
|
|
72
|
+
'HI': 'Hawaii',
|
|
73
|
+
'IA': 'Iowa',
|
|
74
|
+
'ID': 'Idaho',
|
|
75
|
+
'IL': 'Illinois',
|
|
76
|
+
'IN': 'Indiana',
|
|
77
|
+
'KS': 'Kansas',
|
|
78
|
+
'KY': 'Kentucky',
|
|
79
|
+
'LA': 'Louisiana',
|
|
80
|
+
'MA': 'Massachusetts',
|
|
81
|
+
'MD': 'Maryland',
|
|
82
|
+
'ME': 'Maine',
|
|
83
|
+
'MI': 'Michigan',
|
|
84
|
+
'MN': 'Minnesota',
|
|
85
|
+
'MO': 'Missouri',
|
|
86
|
+
'MS': 'Mississippi',
|
|
87
|
+
'MT': 'Montana',
|
|
88
|
+
'NC': 'North Carolina',
|
|
89
|
+
'ND': 'North Dakota',
|
|
90
|
+
'NE': 'Nebraska',
|
|
91
|
+
'NH': 'New Hampshire',
|
|
92
|
+
'NJ': 'New Jersey',
|
|
93
|
+
'NM': 'New Mexico',
|
|
94
|
+
'NV': 'Nevada',
|
|
95
|
+
'NY': 'New York',
|
|
96
|
+
'OH': 'Ohio',
|
|
97
|
+
'OK': 'Oklahoma',
|
|
98
|
+
'OR': 'Oregon',
|
|
99
|
+
'PA': 'Pennsylvania',
|
|
100
|
+
'RI': 'Rhode Island',
|
|
101
|
+
'SC': 'South Carolina',
|
|
102
|
+
'SD': 'South Dakota',
|
|
103
|
+
'TN': 'Tennessee',
|
|
104
|
+
'TX': 'Texas',
|
|
105
|
+
'UT': 'Utah',
|
|
106
|
+
'VA': 'Virginia',
|
|
107
|
+
'VT': 'Vermont',
|
|
108
|
+
'WA': 'Washington',
|
|
109
|
+
'WI': 'Wisconsin',
|
|
110
|
+
'WV': 'West Virginia',
|
|
111
|
+
'WY': 'Wyoming'
|
|
112
|
+
};
|
|
55
113
|
/** Wrapper around sqlite databases */
|
|
56
114
|
|
|
57
115
|
class GeoDb {
|
|
@@ -206,6 +264,28 @@ class GeoDb {
|
|
|
206
264
|
return null;
|
|
207
265
|
}
|
|
208
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* @private
|
|
269
|
+
* @param {any[]} res
|
|
270
|
+
* @return {Object[]}
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
static zipResultToObj(res) {
|
|
275
|
+
const obj = {
|
|
276
|
+
id: String(res.ZipCode),
|
|
277
|
+
value: `${res.CityMixedCase}, ${res.State} ${res.ZipCode}`,
|
|
278
|
+
admin1: res.State,
|
|
279
|
+
asciiname: res.CityMixedCase,
|
|
280
|
+
country: 'United States',
|
|
281
|
+
latitude: res.Latitude,
|
|
282
|
+
longitude: res.Longitude,
|
|
283
|
+
timezone: Location.getUsaTzid(res.State, res.TimeZone, res.DayLightSaving),
|
|
284
|
+
population: res.Population,
|
|
285
|
+
geo: 'zip'
|
|
286
|
+
};
|
|
287
|
+
return obj;
|
|
288
|
+
}
|
|
209
289
|
/**
|
|
210
290
|
* Generates autocomplete results based on a query string
|
|
211
291
|
* @param {string} qraw
|
|
@@ -223,34 +303,23 @@ class GeoDb {
|
|
|
223
303
|
this.zipCompStmt = this.zipsDb.prepare(ZIP_COMPLETE_SQL);
|
|
224
304
|
}
|
|
225
305
|
|
|
226
|
-
return this.zipCompStmt.all(qraw + '%').map(
|
|
227
|
-
const obj = {
|
|
228
|
-
id: String(res.ZipCode),
|
|
229
|
-
value: `${res.CityMixedCase}, ${res.State} ${res.ZipCode}`,
|
|
230
|
-
admin1: res.State,
|
|
231
|
-
asciiname: res.CityMixedCase,
|
|
232
|
-
country: 'United States',
|
|
233
|
-
latitude: res.Latitude,
|
|
234
|
-
longitude: res.Longitude,
|
|
235
|
-
timezone: Location.getUsaTzid(res.State, res.TimeZone, res.DayLightSaving),
|
|
236
|
-
population: res.Population,
|
|
237
|
-
geo: 'zip'
|
|
238
|
-
};
|
|
239
|
-
return obj;
|
|
240
|
-
});
|
|
306
|
+
return this.zipCompStmt.all(qraw + '%').map(GeoDb.zipResultToObj);
|
|
241
307
|
} else {
|
|
242
308
|
if (!this.geonamesCompStmt) {
|
|
243
309
|
this.geonamesCompStmt = this.geonamesDb.prepare(GEONAME_COMPLETE_SQL);
|
|
244
310
|
}
|
|
245
311
|
|
|
246
312
|
qraw = qraw.replace(/\"/g, '""');
|
|
247
|
-
|
|
313
|
+
const geoRows = this.geonamesCompStmt.all(`"${qraw}*"`);
|
|
314
|
+
const geoMatches = geoRows.map(res => {
|
|
248
315
|
const country = res.country || '';
|
|
249
316
|
const admin1 = res.admin1 || '';
|
|
250
317
|
const obj = {
|
|
251
318
|
id: res.geonameid,
|
|
252
319
|
value: Location.geonameCityDescr(res.asciiname, admin1, country),
|
|
253
320
|
asciiname: res.asciiname,
|
|
321
|
+
admin1,
|
|
322
|
+
country,
|
|
254
323
|
latitude: res.latitude,
|
|
255
324
|
longitude: res.longitude,
|
|
256
325
|
timezone: res.timezone,
|
|
@@ -269,6 +338,32 @@ class GeoDb {
|
|
|
269
338
|
obj.tokens = Array.from(new Set(res.asciiname.split(' ').concat(admin1.split(' '), country.split(' '))));
|
|
270
339
|
return obj;
|
|
271
340
|
});
|
|
341
|
+
|
|
342
|
+
if (!this.zipFulltextCompStmt) {
|
|
343
|
+
this.zipFulltextCompStmt = this.zipsDb.prepare(ZIP_FULLTEXT_COMPLETE_SQL);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const zipRows = this.zipFulltextCompStmt.all(`"${qraw}*"`);
|
|
347
|
+
const zipMatches = zipRows.map(GeoDb.zipResultToObj);
|
|
348
|
+
const map = new Map();
|
|
349
|
+
|
|
350
|
+
for (const obj of zipMatches) {
|
|
351
|
+
const key = [obj.asciiname, stateNames[obj.admin1], obj.country].join('|');
|
|
352
|
+
|
|
353
|
+
if (!map.has(key)) {
|
|
354
|
+
map.set(key, obj);
|
|
355
|
+
}
|
|
356
|
+
} // GeoNames takes priority over USA ZIP code matches
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
for (const obj of geoMatches) {
|
|
360
|
+
const key = [obj.asciiname, obj.admin1, obj.country].join('|');
|
|
361
|
+
map.set(key, obj);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const values = Array.from(map.values());
|
|
365
|
+
values.sort((a, b) => b.population - a.population);
|
|
366
|
+
return values.slice(0, 10);
|
|
272
367
|
}
|
|
273
368
|
}
|
|
274
369
|
/** Reads entire ZIP database and caches in-memory */
|
package/package.json
CHANGED