@hebcal/geo-sqlite 4.9.1 → 4.9.3
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 +48 -130
- package/dist/index.mjs +48 -130
- package/package.json +11 -5
- package/readme.txt +0 -141
- /package/bin/{build-geonames-sqlite.cjs → build-geonames-sqlite} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/geo-sqlite v4.9.
|
|
1
|
+
/*! @hebcal/geo-sqlite v4.9.3 */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var Database = require('better-sqlite3');
|
|
@@ -18,10 +18,7 @@ let a=[["\0","","","","","","","","\b","\t","\n","\v","\f","\r","","","
|
|
|
18
18
|
* @return {string}
|
|
19
19
|
*/
|
|
20
20
|
function munge(s) {
|
|
21
|
-
return s.toLowerCase()
|
|
22
|
-
.replace(/'/g, '')
|
|
23
|
-
.replace(/ /g, '')
|
|
24
|
-
.replace(/\+/g, '');
|
|
21
|
+
return s.toLowerCase().replace(/'/g, '').replace(/ /g, '').replace(/\+/g, '');
|
|
25
22
|
}
|
|
26
23
|
|
|
27
24
|
const GEONAME_SQL = `SELECT
|
|
@@ -39,7 +36,6 @@ LEFT JOIN country c on g.country = c.iso
|
|
|
39
36
|
LEFT JOIN admin1 a on g.country||'.'||g.admin1 = a.key
|
|
40
37
|
WHERE g.geonameid = ?
|
|
41
38
|
`;
|
|
42
|
-
|
|
43
39
|
const GEONAME_ALL_SQL = `SELECT
|
|
44
40
|
g.geonameid as geonameid,
|
|
45
41
|
g.name as name,
|
|
@@ -55,33 +51,25 @@ FROM geoname g
|
|
|
55
51
|
LEFT JOIN country c on g.country = c.iso
|
|
56
52
|
LEFT JOIN admin1 a on g.country||'.'||g.admin1 = a.key
|
|
57
53
|
`;
|
|
58
|
-
|
|
59
54
|
const ZIPCODE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
60
55
|
FROM ZIPCodes_Primary WHERE ZipCode = ?`;
|
|
61
|
-
|
|
62
56
|
const ZIPCODE_ALL_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
63
57
|
FROM ZIPCodes_Primary`;
|
|
64
|
-
|
|
65
58
|
const ZIP_COMPLETE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
66
59
|
FROM ZIPCodes_Primary
|
|
67
60
|
WHERE ZipCode LIKE ?
|
|
68
61
|
ORDER BY Population DESC
|
|
69
62
|
LIMIT 10`;
|
|
70
|
-
|
|
71
|
-
const ZIP_FULLTEXT_COMPLETE_SQL =
|
|
72
|
-
`SELECT ZipCode
|
|
63
|
+
const ZIP_FULLTEXT_COMPLETE_SQL = `SELECT ZipCode
|
|
73
64
|
FROM ZIPCodes_CityFullText5
|
|
74
65
|
WHERE ZIPCodes_CityFullText5 MATCH ?
|
|
75
66
|
ORDER BY Population DESC
|
|
76
67
|
LIMIT 20`;
|
|
77
|
-
|
|
78
|
-
const GEONAME_COMPLETE_SQL =
|
|
79
|
-
`SELECT geonameid, longname, city, admin1, country
|
|
68
|
+
const GEONAME_COMPLETE_SQL = `SELECT geonameid, longname, city, admin1, country
|
|
80
69
|
FROM geoname_fulltext
|
|
81
70
|
WHERE geoname_fulltext MATCH ?
|
|
82
71
|
ORDER BY population DESC
|
|
83
72
|
LIMIT 20`;
|
|
84
|
-
|
|
85
73
|
const stateNames = {
|
|
86
74
|
'AK': 'Alaska',
|
|
87
75
|
'AL': 'Alabama',
|
|
@@ -133,7 +121,7 @@ const stateNames = {
|
|
|
133
121
|
'WA': 'Washington',
|
|
134
122
|
'WI': 'Wisconsin',
|
|
135
123
|
'WV': 'West Virginia',
|
|
136
|
-
'WY': 'Wyoming'
|
|
124
|
+
'WY': 'Wyoming'
|
|
137
125
|
};
|
|
138
126
|
|
|
139
127
|
/** Wrapper around sqlite databases */
|
|
@@ -146,9 +134,13 @@ class GeoDb {
|
|
|
146
134
|
constructor(logger, zipsFilename, geonamesFilename) {
|
|
147
135
|
this.logger = logger;
|
|
148
136
|
if (logger) logger.info(`GeoDb: opening ${zipsFilename}...`);
|
|
149
|
-
this.zipsDb = new Database(zipsFilename, {
|
|
137
|
+
this.zipsDb = new Database(zipsFilename, {
|
|
138
|
+
fileMustExist: true
|
|
139
|
+
});
|
|
150
140
|
if (logger) logger.info(`GeoDb: opening ${geonamesFilename}...`);
|
|
151
|
-
this.geonamesDb = new Database(geonamesFilename, {
|
|
141
|
+
this.geonamesDb = new Database(geonamesFilename, {
|
|
142
|
+
fileMustExist: true
|
|
143
|
+
});
|
|
152
144
|
this.zipStmt = this.zipsDb.prepare(ZIPCODE_SQL);
|
|
153
145
|
/** @type {Map<string, Location>} */
|
|
154
146
|
this.zipCache = new Map();
|
|
@@ -294,15 +286,7 @@ class GeoDb {
|
|
|
294
286
|
const country = result.country || '';
|
|
295
287
|
const admin1 = result.admin1 || '';
|
|
296
288
|
const cityDescr = GeoDb.geonameCityDescr(result.name, admin1, country);
|
|
297
|
-
const location = new core.Location(
|
|
298
|
-
result.latitude,
|
|
299
|
-
result.longitude,
|
|
300
|
-
result.cc == 'IL',
|
|
301
|
-
result.timezone,
|
|
302
|
-
cityDescr,
|
|
303
|
-
result.cc,
|
|
304
|
-
geonameid,
|
|
305
|
-
);
|
|
289
|
+
const location = new core.Location(result.latitude, result.longitude, result.cc == 'IL', result.timezone, cityDescr, result.cc, geonameid);
|
|
306
290
|
location.geo = 'geoname';
|
|
307
291
|
location.geonameid = geonameid;
|
|
308
292
|
location.asciiname = result.asciiname;
|
|
@@ -354,7 +338,7 @@ class GeoDb {
|
|
|
354
338
|
longitude: res.Longitude,
|
|
355
339
|
timezone: core.Location.getUsaTzid(res.State, res.TimeZone, res.DayLightSaving),
|
|
356
340
|
population: res.Population,
|
|
357
|
-
geo: 'zip'
|
|
341
|
+
geo: 'zip'
|
|
358
342
|
};
|
|
359
343
|
return obj;
|
|
360
344
|
}
|
|
@@ -365,7 +349,7 @@ class GeoDb {
|
|
|
365
349
|
* @param {boolean} latlong
|
|
366
350
|
* @return {Object[]}
|
|
367
351
|
*/
|
|
368
|
-
autoComplete(qraw, latlong=false) {
|
|
352
|
+
autoComplete(qraw, latlong = false) {
|
|
369
353
|
qraw = qraw.trim();
|
|
370
354
|
if (qraw.length === 0) {
|
|
371
355
|
return [];
|
|
@@ -392,7 +376,7 @@ class GeoDb {
|
|
|
392
376
|
geoRows.push(row);
|
|
393
377
|
}
|
|
394
378
|
}
|
|
395
|
-
const geoMatches = geoRows.map(
|
|
379
|
+
const geoMatches = geoRows.map(res => {
|
|
396
380
|
const loc = this.lookupGeoname(res.geonameid);
|
|
397
381
|
return this.geonameLocToAutocomplete(loc, res);
|
|
398
382
|
});
|
|
@@ -400,7 +384,7 @@ class GeoDb {
|
|
|
400
384
|
this.zipFulltextCompStmt = this.zipsDb.prepare(ZIP_FULLTEXT_COMPLETE_SQL);
|
|
401
385
|
}
|
|
402
386
|
const zipRows = this.zipFulltextCompStmt.all(`{longname} : "${qraw}" *`);
|
|
403
|
-
const zipMatches = zipRows.map(
|
|
387
|
+
const zipMatches = zipRows.map(res => {
|
|
404
388
|
const loc = this.lookupZip(res.ZipCode);
|
|
405
389
|
return GeoDb.zipLocToAutocomplete(loc);
|
|
406
390
|
});
|
|
@@ -438,7 +422,7 @@ class GeoDb {
|
|
|
438
422
|
latitude: loc.latitude,
|
|
439
423
|
longitude: loc.longitude,
|
|
440
424
|
timezone: loc.getTzid(),
|
|
441
|
-
geo: 'geoname'
|
|
425
|
+
geo: 'geoname'
|
|
442
426
|
};
|
|
443
427
|
if (loc.population) {
|
|
444
428
|
obj.population = loc.population;
|
|
@@ -475,7 +459,7 @@ class GeoDb {
|
|
|
475
459
|
longitude: loc.longitude,
|
|
476
460
|
timezone: loc.getTzid(),
|
|
477
461
|
population: loc.population,
|
|
478
|
-
geo: 'zip'
|
|
462
|
+
geo: 'zip'
|
|
479
463
|
};
|
|
480
464
|
}
|
|
481
465
|
|
|
@@ -551,11 +535,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
551
535
|
logger.info(`Opening ${dbFilename}`);
|
|
552
536
|
const db = new Database(dbFilename);
|
|
553
537
|
db.pragma('journal_mode = MEMORY');
|
|
554
|
-
|
|
555
|
-
doSql(logger, db,
|
|
556
|
-
`DROP TABLE IF EXISTS country`,
|
|
557
|
-
|
|
558
|
-
`CREATE TABLE country (
|
|
538
|
+
doSql(logger, db, `DROP TABLE IF EXISTS country`, `CREATE TABLE country (
|
|
559
539
|
ISO TEXT PRIMARY KEY,
|
|
560
540
|
ISO3 TEXT NOT NULL,
|
|
561
541
|
IsoNumeric TEXT NOT NULL,
|
|
@@ -575,14 +555,9 @@ async function buildGeonamesSqlite(opts) {
|
|
|
575
555
|
geonameid INT NOT NULL,
|
|
576
556
|
neighbours TEXT NOT NULL,
|
|
577
557
|
EquivalentFipsCode TEXT NOT NULL
|
|
578
|
-
)
|
|
579
|
-
);
|
|
558
|
+
);`);
|
|
580
559
|
await doFile(logger, db, countryInfotxt, 'country', 19);
|
|
581
|
-
|
|
582
|
-
doSql(logger, db,
|
|
583
|
-
`DROP TABLE IF EXISTS geoname`,
|
|
584
|
-
|
|
585
|
-
`CREATE TABLE geoname (
|
|
560
|
+
doSql(logger, db, `DROP TABLE IF EXISTS geoname`, `CREATE TABLE geoname (
|
|
586
561
|
geonameid int PRIMARY KEY,
|
|
587
562
|
name nvarchar(200),
|
|
588
563
|
asciiname nvarchar(200),
|
|
@@ -601,48 +576,32 @@ async function buildGeonamesSqlite(opts) {
|
|
|
601
576
|
elevation int,
|
|
602
577
|
gtopo30 int,
|
|
603
578
|
timezone nvarchar(40),
|
|
604
|
-
moddate date)
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
const truncateAlternateNames = (a) => {
|
|
579
|
+
moddate date);`);
|
|
580
|
+
const truncateAlternateNames = a => {
|
|
608
581
|
a[3] = '';
|
|
609
582
|
return true;
|
|
610
583
|
};
|
|
611
584
|
await doFile(logger, db, cities5000txt, 'geoname', 19, truncateAlternateNames);
|
|
612
585
|
await doFile(logger, db, citiesPatch, 'geoname', 19, truncateAlternateNames);
|
|
613
|
-
await doFile(logger, db, ILtxt, 'geoname', 19,
|
|
586
|
+
await doFile(logger, db, ILtxt, 'geoname', 19, a => {
|
|
614
587
|
a[3] = '';
|
|
615
588
|
return a[6] == 'P' && (a[7] == 'PPL' || a[7] == 'STLMT');
|
|
616
589
|
});
|
|
617
|
-
|
|
618
|
-
doSql(logger, db,
|
|
619
|
-
`DROP TABLE IF EXISTS admin1`,
|
|
620
|
-
|
|
621
|
-
`CREATE TABLE admin1 (
|
|
590
|
+
doSql(logger, db, `DROP TABLE IF EXISTS admin1`, `CREATE TABLE admin1 (
|
|
622
591
|
key TEXT PRIMARY KEY,
|
|
623
592
|
name nvarchar(200) NOT NULL,
|
|
624
593
|
asciiname nvarchar(200) NOT NULL,
|
|
625
594
|
geonameid int NOT NULL
|
|
626
|
-
)
|
|
627
|
-
);
|
|
628
|
-
|
|
595
|
+
);`);
|
|
629
596
|
await doFile(logger, db, admin1CodesASCIItxt, 'admin1', 4);
|
|
630
597
|
|
|
631
598
|
// fix inconsistencies with the USA capitol
|
|
632
|
-
doSql(logger, db,
|
|
633
|
-
`UPDATE geoname
|
|
599
|
+
doSql(logger, db, `UPDATE geoname
|
|
634
600
|
SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
|
|
635
|
-
WHERE geonameid = 4140963;`,
|
|
636
|
-
|
|
637
|
-
`UPDATE admin1
|
|
601
|
+
WHERE geonameid = 4140963;`, `UPDATE admin1
|
|
638
602
|
SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
|
|
639
|
-
WHERE key = 'US.DC'
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
doSql(logger, db,
|
|
643
|
-
`DROP TABLE IF EXISTS alternatenames`,
|
|
644
|
-
|
|
645
|
-
`CREATE TABLE alternatenames (
|
|
603
|
+
WHERE key = 'US.DC';`);
|
|
604
|
+
doSql(logger, db, `DROP TABLE IF EXISTS alternatenames`, `CREATE TABLE alternatenames (
|
|
646
605
|
id int PRIMARY KEY,
|
|
647
606
|
geonameid int NOT NULL,
|
|
648
607
|
isolanguage varchar(7),
|
|
@@ -653,10 +612,8 @@ async function buildGeonamesSqlite(opts) {
|
|
|
653
612
|
isHistoric tinyint,
|
|
654
613
|
periodFrom NULL,
|
|
655
614
|
periodTo NULL
|
|
656
|
-
)
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
await doFile(logger, db, ILalternate, 'alternatenames', 10, (a) => {
|
|
615
|
+
);`);
|
|
616
|
+
await doFile(logger, db, ILalternate, 'alternatenames', 10, a => {
|
|
660
617
|
const firstchar = a[3][0];
|
|
661
618
|
if (a[2] === 'he' && (firstchar < '\u05D0' || firstchar > '\u05EA')) {
|
|
662
619
|
a[2] = 'en';
|
|
@@ -684,35 +641,16 @@ async function buildGeonamesSqlite(opts) {
|
|
|
684
641
|
});
|
|
685
642
|
|
|
686
643
|
// remove duplicates from alternatenames
|
|
687
|
-
doSql(logger, db,
|
|
688
|
-
`DROP TABLE IF EXISTS altnames`,
|
|
689
|
-
|
|
690
|
-
`CREATE TABLE altnames
|
|
644
|
+
doSql(logger, db, `DROP TABLE IF EXISTS altnames`, `CREATE TABLE altnames
|
|
691
645
|
AS SELECT geonameid, isolanguage, name
|
|
692
646
|
FROM alternatenames
|
|
693
647
|
GROUP BY 1, 2, 3
|
|
694
|
-
|
|
695
|
-
);
|
|
696
|
-
|
|
697
|
-
doSql(logger, db,
|
|
698
|
-
`update admin1 set name='',asciiname='' where key like 'PS.%';`,
|
|
699
|
-
`update country set country = '' where iso = 'PS';`,
|
|
700
|
-
`delete from geoname where geonameid = 7303419;`,
|
|
701
|
-
);
|
|
702
|
-
|
|
703
|
-
doSql(logger, db,
|
|
704
|
-
`DROP TABLE IF EXISTS geoname_fulltext`,
|
|
705
|
-
|
|
706
|
-
`CREATE VIRTUAL TABLE geoname_fulltext
|
|
648
|
+
`);
|
|
649
|
+
doSql(logger, db, `update admin1 set name='',asciiname='' where key like 'PS.%';`, `update country set country = '' where iso = 'PS';`, `delete from geoname where geonameid = 7303419;`);
|
|
650
|
+
doSql(logger, db, `DROP TABLE IF EXISTS geoname_fulltext`, `CREATE VIRTUAL TABLE geoname_fulltext
|
|
707
651
|
USING fts5(geonameid UNINDEXED, longname, population, city, admin1, country);
|
|
708
|
-
`,
|
|
709
|
-
|
|
710
|
-
`DROP TABLE IF EXISTS geoname_non_ascii`,
|
|
711
|
-
|
|
712
|
-
`CREATE TABLE geoname_non_ascii AS
|
|
713
|
-
SELECT geonameid FROM geoname WHERE asciiname <> name`,
|
|
714
|
-
|
|
715
|
-
`INSERT INTO geoname_fulltext
|
|
652
|
+
`, `DROP TABLE IF EXISTS geoname_non_ascii`, `CREATE TABLE geoname_non_ascii AS
|
|
653
|
+
SELECT geonameid FROM geoname WHERE asciiname <> name`, `INSERT INTO geoname_fulltext
|
|
716
654
|
SELECT g.geonameid,
|
|
717
655
|
g.asciiname||', '||a.asciiname||', '||c.Country,
|
|
718
656
|
g.population,
|
|
@@ -723,9 +661,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
723
661
|
AND g.country <> 'IL'
|
|
724
662
|
AND g.country <> 'GB'
|
|
725
663
|
AND g.country||'.'||g.admin1 = a.key
|
|
726
|
-
`,
|
|
727
|
-
|
|
728
|
-
`INSERT INTO geoname_fulltext
|
|
664
|
+
`, `INSERT INTO geoname_fulltext
|
|
729
665
|
SELECT g.geonameid,
|
|
730
666
|
g.asciiname||', '||a.asciiname||', USA',
|
|
731
667
|
g.population,
|
|
@@ -733,9 +669,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
733
669
|
FROM geoname g, admin1 a
|
|
734
670
|
WHERE g.country = 'US'
|
|
735
671
|
AND g.country||'.'||g.admin1 = a.key
|
|
736
|
-
`,
|
|
737
|
-
|
|
738
|
-
`INSERT INTO geoname_fulltext
|
|
672
|
+
`, `INSERT INTO geoname_fulltext
|
|
739
673
|
SELECT g.geonameid,
|
|
740
674
|
g.asciiname||', '||a.asciiname||', UK',
|
|
741
675
|
g.population,
|
|
@@ -743,18 +677,14 @@ async function buildGeonamesSqlite(opts) {
|
|
|
743
677
|
FROM geoname g, admin1 a
|
|
744
678
|
WHERE g.country = 'GB'
|
|
745
679
|
AND g.country||'.'||g.admin1 = a.key
|
|
746
|
-
`,
|
|
747
|
-
|
|
748
|
-
`INSERT INTO geoname_fulltext
|
|
680
|
+
`, `INSERT INTO geoname_fulltext
|
|
749
681
|
SELECT g.geonameid,
|
|
750
682
|
g.asciiname||', Israel',
|
|
751
683
|
g.population,
|
|
752
684
|
g.asciiname,NULL,'Israel'
|
|
753
685
|
FROM geoname g
|
|
754
686
|
WHERE g.country = 'IL'
|
|
755
|
-
`,
|
|
756
|
-
|
|
757
|
-
`INSERT INTO geoname_fulltext
|
|
687
|
+
`, `INSERT INTO geoname_fulltext
|
|
758
688
|
SELECT g.geonameid,
|
|
759
689
|
g.asciiname||', '||c.Country,
|
|
760
690
|
g.population,
|
|
@@ -762,9 +692,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
762
692
|
FROM geoname g, country c
|
|
763
693
|
WHERE g.country = c.ISO
|
|
764
694
|
AND (g.admin1 = '' OR g.admin1 = '00')
|
|
765
|
-
`,
|
|
766
|
-
|
|
767
|
-
`INSERT INTO geoname_fulltext
|
|
695
|
+
`, `INSERT INTO geoname_fulltext
|
|
768
696
|
SELECT g.geonameid,
|
|
769
697
|
g.name||', '||a.name||', '||c.Country,
|
|
770
698
|
g.population,
|
|
@@ -773,9 +701,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
773
701
|
WHERE gna.geonameid = g.geonameid
|
|
774
702
|
AND g.country = c.ISO
|
|
775
703
|
AND g.country||'.'||g.admin1 = a.key
|
|
776
|
-
`,
|
|
777
|
-
|
|
778
|
-
`INSERT INTO geoname_fulltext
|
|
704
|
+
`, `INSERT INTO geoname_fulltext
|
|
779
705
|
SELECT g.geonameid,
|
|
780
706
|
alt.name||', ישראל',
|
|
781
707
|
g.population,
|
|
@@ -784,9 +710,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
784
710
|
WHERE g.country = 'IL'
|
|
785
711
|
AND alt.isolanguage = 'he'
|
|
786
712
|
AND g.geonameid = alt.geonameid
|
|
787
|
-
`,
|
|
788
|
-
|
|
789
|
-
`INSERT INTO geoname_fulltext
|
|
713
|
+
`, `INSERT INTO geoname_fulltext
|
|
790
714
|
SELECT g.geonameid,
|
|
791
715
|
alt.name||', Israel',
|
|
792
716
|
g.population,
|
|
@@ -795,11 +719,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
795
719
|
WHERE g.country = 'IL'
|
|
796
720
|
AND alt.isolanguage = 'en'
|
|
797
721
|
AND g.geonameid = alt.geonameid
|
|
798
|
-
`,
|
|
799
|
-
|
|
800
|
-
'VACUUM',
|
|
801
|
-
);
|
|
802
|
-
|
|
722
|
+
`, 'VACUUM');
|
|
803
723
|
return new Promise((resolve, reject) => {
|
|
804
724
|
try {
|
|
805
725
|
logger.info(`Closing ${dbFilename}`);
|
|
@@ -847,11 +767,11 @@ async function doFile(logger, db, infile, tableName, expectedFields, callback) {
|
|
|
847
767
|
try {
|
|
848
768
|
const rl = readline.createInterface({
|
|
849
769
|
input: fs.createReadStream(infile),
|
|
850
|
-
crlfDelay: Infinity
|
|
770
|
+
crlfDelay: Infinity
|
|
851
771
|
});
|
|
852
772
|
let num = 0;
|
|
853
773
|
let accepted = 0;
|
|
854
|
-
rl.on('line',
|
|
774
|
+
rl.on('line', line => {
|
|
855
775
|
num++;
|
|
856
776
|
if (line[0] == '#') {
|
|
857
777
|
return;
|
|
@@ -870,13 +790,11 @@ async function doFile(logger, db, infile, tableName, expectedFields, callback) {
|
|
|
870
790
|
stmt.run(a);
|
|
871
791
|
accepted++;
|
|
872
792
|
});
|
|
873
|
-
|
|
874
793
|
rl.on('close', () => {
|
|
875
794
|
logger.info(`Inserted ${accepted} / ${num} into ${tableName} from ${infile}`);
|
|
876
795
|
stmt = null;
|
|
877
796
|
db.exec('COMMIT');
|
|
878
797
|
});
|
|
879
|
-
|
|
880
798
|
return resolve(events.once(rl, 'close'));
|
|
881
799
|
} catch (err) {
|
|
882
800
|
logger.error(err);
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/geo-sqlite v4.9.
|
|
1
|
+
/*! @hebcal/geo-sqlite v4.9.3 */
|
|
2
2
|
import Database from 'better-sqlite3';
|
|
3
3
|
import { Location, Locale } from '@hebcal/core';
|
|
4
4
|
import '@hebcal/cities';
|
|
@@ -16,10 +16,7 @@ let a=[["\0","","","","","","","","\b","\t","\n","\v","\f","\r","","","
|
|
|
16
16
|
* @return {string}
|
|
17
17
|
*/
|
|
18
18
|
function munge(s) {
|
|
19
|
-
return s.toLowerCase()
|
|
20
|
-
.replace(/'/g, '')
|
|
21
|
-
.replace(/ /g, '')
|
|
22
|
-
.replace(/\+/g, '');
|
|
19
|
+
return s.toLowerCase().replace(/'/g, '').replace(/ /g, '').replace(/\+/g, '');
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
const GEONAME_SQL = `SELECT
|
|
@@ -37,7 +34,6 @@ LEFT JOIN country c on g.country = c.iso
|
|
|
37
34
|
LEFT JOIN admin1 a on g.country||'.'||g.admin1 = a.key
|
|
38
35
|
WHERE g.geonameid = ?
|
|
39
36
|
`;
|
|
40
|
-
|
|
41
37
|
const GEONAME_ALL_SQL = `SELECT
|
|
42
38
|
g.geonameid as geonameid,
|
|
43
39
|
g.name as name,
|
|
@@ -53,33 +49,25 @@ FROM geoname g
|
|
|
53
49
|
LEFT JOIN country c on g.country = c.iso
|
|
54
50
|
LEFT JOIN admin1 a on g.country||'.'||g.admin1 = a.key
|
|
55
51
|
`;
|
|
56
|
-
|
|
57
52
|
const ZIPCODE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
58
53
|
FROM ZIPCodes_Primary WHERE ZipCode = ?`;
|
|
59
|
-
|
|
60
54
|
const ZIPCODE_ALL_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
61
55
|
FROM ZIPCodes_Primary`;
|
|
62
|
-
|
|
63
56
|
const ZIP_COMPLETE_SQL = `SELECT ZipCode,CityMixedCase,State,Latitude,Longitude,TimeZone,DayLightSaving,Population
|
|
64
57
|
FROM ZIPCodes_Primary
|
|
65
58
|
WHERE ZipCode LIKE ?
|
|
66
59
|
ORDER BY Population DESC
|
|
67
60
|
LIMIT 10`;
|
|
68
|
-
|
|
69
|
-
const ZIP_FULLTEXT_COMPLETE_SQL =
|
|
70
|
-
`SELECT ZipCode
|
|
61
|
+
const ZIP_FULLTEXT_COMPLETE_SQL = `SELECT ZipCode
|
|
71
62
|
FROM ZIPCodes_CityFullText5
|
|
72
63
|
WHERE ZIPCodes_CityFullText5 MATCH ?
|
|
73
64
|
ORDER BY Population DESC
|
|
74
65
|
LIMIT 20`;
|
|
75
|
-
|
|
76
|
-
const GEONAME_COMPLETE_SQL =
|
|
77
|
-
`SELECT geonameid, longname, city, admin1, country
|
|
66
|
+
const GEONAME_COMPLETE_SQL = `SELECT geonameid, longname, city, admin1, country
|
|
78
67
|
FROM geoname_fulltext
|
|
79
68
|
WHERE geoname_fulltext MATCH ?
|
|
80
69
|
ORDER BY population DESC
|
|
81
70
|
LIMIT 20`;
|
|
82
|
-
|
|
83
71
|
const stateNames = {
|
|
84
72
|
'AK': 'Alaska',
|
|
85
73
|
'AL': 'Alabama',
|
|
@@ -131,7 +119,7 @@ const stateNames = {
|
|
|
131
119
|
'WA': 'Washington',
|
|
132
120
|
'WI': 'Wisconsin',
|
|
133
121
|
'WV': 'West Virginia',
|
|
134
|
-
'WY': 'Wyoming'
|
|
122
|
+
'WY': 'Wyoming'
|
|
135
123
|
};
|
|
136
124
|
|
|
137
125
|
/** Wrapper around sqlite databases */
|
|
@@ -144,9 +132,13 @@ class GeoDb {
|
|
|
144
132
|
constructor(logger, zipsFilename, geonamesFilename) {
|
|
145
133
|
this.logger = logger;
|
|
146
134
|
if (logger) logger.info(`GeoDb: opening ${zipsFilename}...`);
|
|
147
|
-
this.zipsDb = new Database(zipsFilename, {
|
|
135
|
+
this.zipsDb = new Database(zipsFilename, {
|
|
136
|
+
fileMustExist: true
|
|
137
|
+
});
|
|
148
138
|
if (logger) logger.info(`GeoDb: opening ${geonamesFilename}...`);
|
|
149
|
-
this.geonamesDb = new Database(geonamesFilename, {
|
|
139
|
+
this.geonamesDb = new Database(geonamesFilename, {
|
|
140
|
+
fileMustExist: true
|
|
141
|
+
});
|
|
150
142
|
this.zipStmt = this.zipsDb.prepare(ZIPCODE_SQL);
|
|
151
143
|
/** @type {Map<string, Location>} */
|
|
152
144
|
this.zipCache = new Map();
|
|
@@ -292,15 +284,7 @@ class GeoDb {
|
|
|
292
284
|
const country = result.country || '';
|
|
293
285
|
const admin1 = result.admin1 || '';
|
|
294
286
|
const cityDescr = GeoDb.geonameCityDescr(result.name, admin1, country);
|
|
295
|
-
const location = new Location(
|
|
296
|
-
result.latitude,
|
|
297
|
-
result.longitude,
|
|
298
|
-
result.cc == 'IL',
|
|
299
|
-
result.timezone,
|
|
300
|
-
cityDescr,
|
|
301
|
-
result.cc,
|
|
302
|
-
geonameid,
|
|
303
|
-
);
|
|
287
|
+
const location = new Location(result.latitude, result.longitude, result.cc == 'IL', result.timezone, cityDescr, result.cc, geonameid);
|
|
304
288
|
location.geo = 'geoname';
|
|
305
289
|
location.geonameid = geonameid;
|
|
306
290
|
location.asciiname = result.asciiname;
|
|
@@ -352,7 +336,7 @@ class GeoDb {
|
|
|
352
336
|
longitude: res.Longitude,
|
|
353
337
|
timezone: Location.getUsaTzid(res.State, res.TimeZone, res.DayLightSaving),
|
|
354
338
|
population: res.Population,
|
|
355
|
-
geo: 'zip'
|
|
339
|
+
geo: 'zip'
|
|
356
340
|
};
|
|
357
341
|
return obj;
|
|
358
342
|
}
|
|
@@ -363,7 +347,7 @@ class GeoDb {
|
|
|
363
347
|
* @param {boolean} latlong
|
|
364
348
|
* @return {Object[]}
|
|
365
349
|
*/
|
|
366
|
-
autoComplete(qraw, latlong=false) {
|
|
350
|
+
autoComplete(qraw, latlong = false) {
|
|
367
351
|
qraw = qraw.trim();
|
|
368
352
|
if (qraw.length === 0) {
|
|
369
353
|
return [];
|
|
@@ -390,7 +374,7 @@ class GeoDb {
|
|
|
390
374
|
geoRows.push(row);
|
|
391
375
|
}
|
|
392
376
|
}
|
|
393
|
-
const geoMatches = geoRows.map(
|
|
377
|
+
const geoMatches = geoRows.map(res => {
|
|
394
378
|
const loc = this.lookupGeoname(res.geonameid);
|
|
395
379
|
return this.geonameLocToAutocomplete(loc, res);
|
|
396
380
|
});
|
|
@@ -398,7 +382,7 @@ class GeoDb {
|
|
|
398
382
|
this.zipFulltextCompStmt = this.zipsDb.prepare(ZIP_FULLTEXT_COMPLETE_SQL);
|
|
399
383
|
}
|
|
400
384
|
const zipRows = this.zipFulltextCompStmt.all(`{longname} : "${qraw}" *`);
|
|
401
|
-
const zipMatches = zipRows.map(
|
|
385
|
+
const zipMatches = zipRows.map(res => {
|
|
402
386
|
const loc = this.lookupZip(res.ZipCode);
|
|
403
387
|
return GeoDb.zipLocToAutocomplete(loc);
|
|
404
388
|
});
|
|
@@ -436,7 +420,7 @@ class GeoDb {
|
|
|
436
420
|
latitude: loc.latitude,
|
|
437
421
|
longitude: loc.longitude,
|
|
438
422
|
timezone: loc.getTzid(),
|
|
439
|
-
geo: 'geoname'
|
|
423
|
+
geo: 'geoname'
|
|
440
424
|
};
|
|
441
425
|
if (loc.population) {
|
|
442
426
|
obj.population = loc.population;
|
|
@@ -473,7 +457,7 @@ class GeoDb {
|
|
|
473
457
|
longitude: loc.longitude,
|
|
474
458
|
timezone: loc.getTzid(),
|
|
475
459
|
population: loc.population,
|
|
476
|
-
geo: 'zip'
|
|
460
|
+
geo: 'zip'
|
|
477
461
|
};
|
|
478
462
|
}
|
|
479
463
|
|
|
@@ -549,11 +533,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
549
533
|
logger.info(`Opening ${dbFilename}`);
|
|
550
534
|
const db = new Database(dbFilename);
|
|
551
535
|
db.pragma('journal_mode = MEMORY');
|
|
552
|
-
|
|
553
|
-
doSql(logger, db,
|
|
554
|
-
`DROP TABLE IF EXISTS country`,
|
|
555
|
-
|
|
556
|
-
`CREATE TABLE country (
|
|
536
|
+
doSql(logger, db, `DROP TABLE IF EXISTS country`, `CREATE TABLE country (
|
|
557
537
|
ISO TEXT PRIMARY KEY,
|
|
558
538
|
ISO3 TEXT NOT NULL,
|
|
559
539
|
IsoNumeric TEXT NOT NULL,
|
|
@@ -573,14 +553,9 @@ async function buildGeonamesSqlite(opts) {
|
|
|
573
553
|
geonameid INT NOT NULL,
|
|
574
554
|
neighbours TEXT NOT NULL,
|
|
575
555
|
EquivalentFipsCode TEXT NOT NULL
|
|
576
|
-
)
|
|
577
|
-
);
|
|
556
|
+
);`);
|
|
578
557
|
await doFile(logger, db, countryInfotxt, 'country', 19);
|
|
579
|
-
|
|
580
|
-
doSql(logger, db,
|
|
581
|
-
`DROP TABLE IF EXISTS geoname`,
|
|
582
|
-
|
|
583
|
-
`CREATE TABLE geoname (
|
|
558
|
+
doSql(logger, db, `DROP TABLE IF EXISTS geoname`, `CREATE TABLE geoname (
|
|
584
559
|
geonameid int PRIMARY KEY,
|
|
585
560
|
name nvarchar(200),
|
|
586
561
|
asciiname nvarchar(200),
|
|
@@ -599,48 +574,32 @@ async function buildGeonamesSqlite(opts) {
|
|
|
599
574
|
elevation int,
|
|
600
575
|
gtopo30 int,
|
|
601
576
|
timezone nvarchar(40),
|
|
602
|
-
moddate date)
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const truncateAlternateNames = (a) => {
|
|
577
|
+
moddate date);`);
|
|
578
|
+
const truncateAlternateNames = a => {
|
|
606
579
|
a[3] = '';
|
|
607
580
|
return true;
|
|
608
581
|
};
|
|
609
582
|
await doFile(logger, db, cities5000txt, 'geoname', 19, truncateAlternateNames);
|
|
610
583
|
await doFile(logger, db, citiesPatch, 'geoname', 19, truncateAlternateNames);
|
|
611
|
-
await doFile(logger, db, ILtxt, 'geoname', 19,
|
|
584
|
+
await doFile(logger, db, ILtxt, 'geoname', 19, a => {
|
|
612
585
|
a[3] = '';
|
|
613
586
|
return a[6] == 'P' && (a[7] == 'PPL' || a[7] == 'STLMT');
|
|
614
587
|
});
|
|
615
|
-
|
|
616
|
-
doSql(logger, db,
|
|
617
|
-
`DROP TABLE IF EXISTS admin1`,
|
|
618
|
-
|
|
619
|
-
`CREATE TABLE admin1 (
|
|
588
|
+
doSql(logger, db, `DROP TABLE IF EXISTS admin1`, `CREATE TABLE admin1 (
|
|
620
589
|
key TEXT PRIMARY KEY,
|
|
621
590
|
name nvarchar(200) NOT NULL,
|
|
622
591
|
asciiname nvarchar(200) NOT NULL,
|
|
623
592
|
geonameid int NOT NULL
|
|
624
|
-
)
|
|
625
|
-
);
|
|
626
|
-
|
|
593
|
+
);`);
|
|
627
594
|
await doFile(logger, db, admin1CodesASCIItxt, 'admin1', 4);
|
|
628
595
|
|
|
629
596
|
// fix inconsistencies with the USA capitol
|
|
630
|
-
doSql(logger, db,
|
|
631
|
-
`UPDATE geoname
|
|
597
|
+
doSql(logger, db, `UPDATE geoname
|
|
632
598
|
SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
|
|
633
|
-
WHERE geonameid = 4140963;`,
|
|
634
|
-
|
|
635
|
-
`UPDATE admin1
|
|
599
|
+
WHERE geonameid = 4140963;`, `UPDATE admin1
|
|
636
600
|
SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
|
|
637
|
-
WHERE key = 'US.DC'
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
doSql(logger, db,
|
|
641
|
-
`DROP TABLE IF EXISTS alternatenames`,
|
|
642
|
-
|
|
643
|
-
`CREATE TABLE alternatenames (
|
|
601
|
+
WHERE key = 'US.DC';`);
|
|
602
|
+
doSql(logger, db, `DROP TABLE IF EXISTS alternatenames`, `CREATE TABLE alternatenames (
|
|
644
603
|
id int PRIMARY KEY,
|
|
645
604
|
geonameid int NOT NULL,
|
|
646
605
|
isolanguage varchar(7),
|
|
@@ -651,10 +610,8 @@ async function buildGeonamesSqlite(opts) {
|
|
|
651
610
|
isHistoric tinyint,
|
|
652
611
|
periodFrom NULL,
|
|
653
612
|
periodTo NULL
|
|
654
|
-
)
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
await doFile(logger, db, ILalternate, 'alternatenames', 10, (a) => {
|
|
613
|
+
);`);
|
|
614
|
+
await doFile(logger, db, ILalternate, 'alternatenames', 10, a => {
|
|
658
615
|
const firstchar = a[3][0];
|
|
659
616
|
if (a[2] === 'he' && (firstchar < '\u05D0' || firstchar > '\u05EA')) {
|
|
660
617
|
a[2] = 'en';
|
|
@@ -682,35 +639,16 @@ async function buildGeonamesSqlite(opts) {
|
|
|
682
639
|
});
|
|
683
640
|
|
|
684
641
|
// remove duplicates from alternatenames
|
|
685
|
-
doSql(logger, db,
|
|
686
|
-
`DROP TABLE IF EXISTS altnames`,
|
|
687
|
-
|
|
688
|
-
`CREATE TABLE altnames
|
|
642
|
+
doSql(logger, db, `DROP TABLE IF EXISTS altnames`, `CREATE TABLE altnames
|
|
689
643
|
AS SELECT geonameid, isolanguage, name
|
|
690
644
|
FROM alternatenames
|
|
691
645
|
GROUP BY 1, 2, 3
|
|
692
|
-
|
|
693
|
-
);
|
|
694
|
-
|
|
695
|
-
doSql(logger, db,
|
|
696
|
-
`update admin1 set name='',asciiname='' where key like 'PS.%';`,
|
|
697
|
-
`update country set country = '' where iso = 'PS';`,
|
|
698
|
-
`delete from geoname where geonameid = 7303419;`,
|
|
699
|
-
);
|
|
700
|
-
|
|
701
|
-
doSql(logger, db,
|
|
702
|
-
`DROP TABLE IF EXISTS geoname_fulltext`,
|
|
703
|
-
|
|
704
|
-
`CREATE VIRTUAL TABLE geoname_fulltext
|
|
646
|
+
`);
|
|
647
|
+
doSql(logger, db, `update admin1 set name='',asciiname='' where key like 'PS.%';`, `update country set country = '' where iso = 'PS';`, `delete from geoname where geonameid = 7303419;`);
|
|
648
|
+
doSql(logger, db, `DROP TABLE IF EXISTS geoname_fulltext`, `CREATE VIRTUAL TABLE geoname_fulltext
|
|
705
649
|
USING fts5(geonameid UNINDEXED, longname, population, city, admin1, country);
|
|
706
|
-
`,
|
|
707
|
-
|
|
708
|
-
`DROP TABLE IF EXISTS geoname_non_ascii`,
|
|
709
|
-
|
|
710
|
-
`CREATE TABLE geoname_non_ascii AS
|
|
711
|
-
SELECT geonameid FROM geoname WHERE asciiname <> name`,
|
|
712
|
-
|
|
713
|
-
`INSERT INTO geoname_fulltext
|
|
650
|
+
`, `DROP TABLE IF EXISTS geoname_non_ascii`, `CREATE TABLE geoname_non_ascii AS
|
|
651
|
+
SELECT geonameid FROM geoname WHERE asciiname <> name`, `INSERT INTO geoname_fulltext
|
|
714
652
|
SELECT g.geonameid,
|
|
715
653
|
g.asciiname||', '||a.asciiname||', '||c.Country,
|
|
716
654
|
g.population,
|
|
@@ -721,9 +659,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
721
659
|
AND g.country <> 'IL'
|
|
722
660
|
AND g.country <> 'GB'
|
|
723
661
|
AND g.country||'.'||g.admin1 = a.key
|
|
724
|
-
`,
|
|
725
|
-
|
|
726
|
-
`INSERT INTO geoname_fulltext
|
|
662
|
+
`, `INSERT INTO geoname_fulltext
|
|
727
663
|
SELECT g.geonameid,
|
|
728
664
|
g.asciiname||', '||a.asciiname||', USA',
|
|
729
665
|
g.population,
|
|
@@ -731,9 +667,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
731
667
|
FROM geoname g, admin1 a
|
|
732
668
|
WHERE g.country = 'US'
|
|
733
669
|
AND g.country||'.'||g.admin1 = a.key
|
|
734
|
-
`,
|
|
735
|
-
|
|
736
|
-
`INSERT INTO geoname_fulltext
|
|
670
|
+
`, `INSERT INTO geoname_fulltext
|
|
737
671
|
SELECT g.geonameid,
|
|
738
672
|
g.asciiname||', '||a.asciiname||', UK',
|
|
739
673
|
g.population,
|
|
@@ -741,18 +675,14 @@ async function buildGeonamesSqlite(opts) {
|
|
|
741
675
|
FROM geoname g, admin1 a
|
|
742
676
|
WHERE g.country = 'GB'
|
|
743
677
|
AND g.country||'.'||g.admin1 = a.key
|
|
744
|
-
`,
|
|
745
|
-
|
|
746
|
-
`INSERT INTO geoname_fulltext
|
|
678
|
+
`, `INSERT INTO geoname_fulltext
|
|
747
679
|
SELECT g.geonameid,
|
|
748
680
|
g.asciiname||', Israel',
|
|
749
681
|
g.population,
|
|
750
682
|
g.asciiname,NULL,'Israel'
|
|
751
683
|
FROM geoname g
|
|
752
684
|
WHERE g.country = 'IL'
|
|
753
|
-
`,
|
|
754
|
-
|
|
755
|
-
`INSERT INTO geoname_fulltext
|
|
685
|
+
`, `INSERT INTO geoname_fulltext
|
|
756
686
|
SELECT g.geonameid,
|
|
757
687
|
g.asciiname||', '||c.Country,
|
|
758
688
|
g.population,
|
|
@@ -760,9 +690,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
760
690
|
FROM geoname g, country c
|
|
761
691
|
WHERE g.country = c.ISO
|
|
762
692
|
AND (g.admin1 = '' OR g.admin1 = '00')
|
|
763
|
-
`,
|
|
764
|
-
|
|
765
|
-
`INSERT INTO geoname_fulltext
|
|
693
|
+
`, `INSERT INTO geoname_fulltext
|
|
766
694
|
SELECT g.geonameid,
|
|
767
695
|
g.name||', '||a.name||', '||c.Country,
|
|
768
696
|
g.population,
|
|
@@ -771,9 +699,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
771
699
|
WHERE gna.geonameid = g.geonameid
|
|
772
700
|
AND g.country = c.ISO
|
|
773
701
|
AND g.country||'.'||g.admin1 = a.key
|
|
774
|
-
`,
|
|
775
|
-
|
|
776
|
-
`INSERT INTO geoname_fulltext
|
|
702
|
+
`, `INSERT INTO geoname_fulltext
|
|
777
703
|
SELECT g.geonameid,
|
|
778
704
|
alt.name||', ישראל',
|
|
779
705
|
g.population,
|
|
@@ -782,9 +708,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
782
708
|
WHERE g.country = 'IL'
|
|
783
709
|
AND alt.isolanguage = 'he'
|
|
784
710
|
AND g.geonameid = alt.geonameid
|
|
785
|
-
`,
|
|
786
|
-
|
|
787
|
-
`INSERT INTO geoname_fulltext
|
|
711
|
+
`, `INSERT INTO geoname_fulltext
|
|
788
712
|
SELECT g.geonameid,
|
|
789
713
|
alt.name||', Israel',
|
|
790
714
|
g.population,
|
|
@@ -793,11 +717,7 @@ async function buildGeonamesSqlite(opts) {
|
|
|
793
717
|
WHERE g.country = 'IL'
|
|
794
718
|
AND alt.isolanguage = 'en'
|
|
795
719
|
AND g.geonameid = alt.geonameid
|
|
796
|
-
`,
|
|
797
|
-
|
|
798
|
-
'VACUUM',
|
|
799
|
-
);
|
|
800
|
-
|
|
720
|
+
`, 'VACUUM');
|
|
801
721
|
return new Promise((resolve, reject) => {
|
|
802
722
|
try {
|
|
803
723
|
logger.info(`Closing ${dbFilename}`);
|
|
@@ -845,11 +765,11 @@ async function doFile(logger, db, infile, tableName, expectedFields, callback) {
|
|
|
845
765
|
try {
|
|
846
766
|
const rl = readline.createInterface({
|
|
847
767
|
input: fs.createReadStream(infile),
|
|
848
|
-
crlfDelay: Infinity
|
|
768
|
+
crlfDelay: Infinity
|
|
849
769
|
});
|
|
850
770
|
let num = 0;
|
|
851
771
|
let accepted = 0;
|
|
852
|
-
rl.on('line',
|
|
772
|
+
rl.on('line', line => {
|
|
853
773
|
num++;
|
|
854
774
|
if (line[0] == '#') {
|
|
855
775
|
return;
|
|
@@ -868,13 +788,11 @@ async function doFile(logger, db, infile, tableName, expectedFields, callback) {
|
|
|
868
788
|
stmt.run(a);
|
|
869
789
|
accepted++;
|
|
870
790
|
});
|
|
871
|
-
|
|
872
791
|
rl.on('close', () => {
|
|
873
792
|
logger.info(`Inserted ${accepted} / ${num} into ${tableName} from ${infile}`);
|
|
874
793
|
stmt = null;
|
|
875
794
|
db.exec('COMMIT');
|
|
876
795
|
});
|
|
877
|
-
|
|
878
796
|
return resolve(events.once(rl, 'close'));
|
|
879
797
|
} catch (err) {
|
|
880
798
|
logger.error(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hebcal/geo-sqlite",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.3",
|
|
4
4
|
"author": "Michael J. Radwin (https://github.com/mjradwin)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hebcal"
|
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
"description": "Hebcal ES6 interface to GeoNames and USA ZIP code SQLite databases",
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"module": "./dist/index.mjs",
|
|
11
|
-
"type": "module",
|
|
12
11
|
"bin": {
|
|
13
|
-
"build-geonames-sqlite": "bin/build-geonames-sqlite
|
|
12
|
+
"build-geonames-sqlite": "bin/build-geonames-sqlite",
|
|
14
13
|
"download-and-make-dbs": "bin/download-and-make-dbs"
|
|
15
14
|
},
|
|
16
15
|
"repository": {
|
|
@@ -31,7 +30,7 @@
|
|
|
31
30
|
"dependencies": {
|
|
32
31
|
"@hebcal/cities": "^3.2.0",
|
|
33
32
|
"@hebcal/core": "^4.3.0",
|
|
34
|
-
"better-sqlite3": "^8.5.
|
|
33
|
+
"better-sqlite3": "^8.5.0",
|
|
35
34
|
"pino": "^8.15.0",
|
|
36
35
|
"pino-pretty": "^10.2.0",
|
|
37
36
|
"transliteration": "^2.3.5"
|
|
@@ -42,11 +41,18 @@
|
|
|
42
41
|
"readme": "npx jsdoc2md dist/index.js",
|
|
43
42
|
"test": "ava"
|
|
44
43
|
},
|
|
44
|
+
"ava": {
|
|
45
|
+
"require": ["@babel/register"]
|
|
46
|
+
},
|
|
45
47
|
"license": "BSD-2-Clause",
|
|
46
48
|
"devDependencies": {
|
|
49
|
+
"@babel/core": "^7.22.10",
|
|
50
|
+
"@babel/preset-env": "^7.22.10",
|
|
51
|
+
"@babel/register": "^7.22.5",
|
|
52
|
+
"@rollup/plugin-babel": "^6.0.3",
|
|
47
53
|
"@rollup/plugin-commonjs": "^25.0.4",
|
|
48
54
|
"@rollup/plugin-json": "^6.0.0",
|
|
49
|
-
"@rollup/plugin-node-resolve": "^15.
|
|
55
|
+
"@rollup/plugin-node-resolve": "^15.1.0",
|
|
50
56
|
"ava": "^5.3.1",
|
|
51
57
|
"eslint": "^8.47.0",
|
|
52
58
|
"eslint-config-google": "^0.14.0",
|
package/readme.txt
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
Readme for GeoNames Gazetteer extract files
|
|
3
|
-
|
|
4
|
-
============================================================================================================
|
|
5
|
-
|
|
6
|
-
This work is licensed under a Creative Commons Attribution 4.0 License,
|
|
7
|
-
see https://creativecommons.org/licenses/by/4.0/
|
|
8
|
-
The Data is provided "as is" without warranty or any representation of accuracy, timeliness or completeness.
|
|
9
|
-
|
|
10
|
-
The data format is tab-delimited text in utf8 encoding.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Files :
|
|
14
|
-
-------
|
|
15
|
-
XX.zip : features for country with iso code XX, see 'geoname' table for columns. 'no-country' for features not belonging to a country.
|
|
16
|
-
allCountries.zip : all countries combined in one file, see 'geoname' table for columns
|
|
17
|
-
cities500.zip : all cities with a population > 500 or seats of adm div down to PPLA4 (ca 185.000), see 'geoname' table for columns
|
|
18
|
-
cities1000.zip : all cities with a population > 1000 or seats of adm div down to PPLA3 (ca 130.000), see 'geoname' table for columns
|
|
19
|
-
cities5000.zip : all cities with a population > 5000 or PPLA (ca 50.000), see 'geoname' table for columns
|
|
20
|
-
cities15000.zip : all cities with a population > 15000 or capitals (ca 25.000), see 'geoname' table for columns
|
|
21
|
-
alternateNamesV2.zip : alternate names with language codes and geonameId, file with iso language codes, with new columns from and to
|
|
22
|
-
alternateNames.zip : obsolete use V2, this file does not have the new columns to and from and will be removed in the future
|
|
23
|
-
admin1CodesASCII.txt : names in English for admin divisions. Columns: code, name, name ascii, geonameid
|
|
24
|
-
admin2Codes.txt : names for administrative subdivision 'admin2 code' (UTF8), Format : concatenated codes <tab>name <tab> asciiname <tab> geonameId
|
|
25
|
-
iso-languagecodes.txt : iso 639 language codes, as used for alternate names in file alternateNames.zip
|
|
26
|
-
featureCodes.txt : name and description for feature classes and feature codes
|
|
27
|
-
timeZones.txt : countryCode, timezoneId, gmt offset on 1st of January, dst offset to gmt on 1st of July (of the current year), rawOffset without DST
|
|
28
|
-
countryInfo.txt : country information : iso codes, fips codes, languages, capital ,...
|
|
29
|
-
see the geonames webservices for additional country information,
|
|
30
|
-
bounding box : http://api.geonames.org/countryInfo?
|
|
31
|
-
country names in different languages : http:/api.geonames.org/countryInfoCSV?lang=it
|
|
32
|
-
modifications-<date>.txt : all records modified on the previous day, the date is in yyyy-MM-dd format. You can use this file to daily synchronize your own geonames database.
|
|
33
|
-
deletes-<date>.txt : all records deleted on the previous day, format : geonameId <tab> name <tab> comment.
|
|
34
|
-
|
|
35
|
-
alternateNamesModifications-<date>.txt : all alternate names modified on the previous day,
|
|
36
|
-
alternateNamesDeletes-<date>.txt : all alternate names deleted on the previous day, format : alternateNameId <tab> geonameId <tab> name <tab> comment.
|
|
37
|
-
userTags.zip : user tags , format : geonameId <tab> tag.
|
|
38
|
-
hierarchy.zip : parentId, childId, type. The type 'ADM' stands for the admin hierarchy modeled by the admin1-4 codes. The other entries are entered with the user interface. The relation toponym-adm hierarchy is not included in the file, it can instead be built from the admincodes of the toponym.
|
|
39
|
-
adminCode5.zip : the new adm5 column is not yet exported in the other files (in order to not break import scripts). Instead it is availabe as separate file.
|
|
40
|
-
columns: geonameId,adm5code
|
|
41
|
-
|
|
42
|
-
The main 'geoname' table has the following fields :
|
|
43
|
-
---------------------------------------------------
|
|
44
|
-
geonameid : integer id of record in geonames database
|
|
45
|
-
name : name of geographical point (utf8) varchar(200)
|
|
46
|
-
asciiname : name of geographical point in plain ascii characters, varchar(200)
|
|
47
|
-
alternatenames : alternatenames, comma separated, ascii names automatically transliterated, convenience attribute from alternatename table, varchar(10000)
|
|
48
|
-
latitude : latitude in decimal degrees (wgs84)
|
|
49
|
-
longitude : longitude in decimal degrees (wgs84)
|
|
50
|
-
feature class : see http://www.geonames.org/export/codes.html, char(1)
|
|
51
|
-
feature code : see http://www.geonames.org/export/codes.html, varchar(10)
|
|
52
|
-
country code : ISO-3166 2-letter country code, 2 characters
|
|
53
|
-
cc2 : alternate country codes, comma separated, ISO-3166 2-letter country code, 200 characters
|
|
54
|
-
admin1 code : fipscode (subject to change to iso code), see exceptions below, see file admin1Codes.txt for display names of this code; varchar(20)
|
|
55
|
-
admin2 code : code for the second administrative division, a county in the US, see file admin2Codes.txt; varchar(80)
|
|
56
|
-
admin3 code : code for third level administrative division, varchar(20)
|
|
57
|
-
admin4 code : code for fourth level administrative division, varchar(20)
|
|
58
|
-
population : bigint (8 byte int)
|
|
59
|
-
elevation : in meters, integer
|
|
60
|
-
dem : digital elevation model, srtm3 or gtopo30, average elevation of 3''x3'' (ca 90mx90m) or 30''x30'' (ca 900mx900m) area in meters, integer. srtm processed by cgiar/ciat.
|
|
61
|
-
timezone : the iana timezone id (see file timeZone.txt) varchar(40)
|
|
62
|
-
modification date : date of last modification in yyyy-MM-dd format
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
AdminCodes:
|
|
66
|
-
Most adm1 are FIPS codes. ISO codes are used for US, CH, BE and ME. UK and Greece are using an additional level between country and fips code. The code '00' stands for general features where no specific adm1 code is defined.
|
|
67
|
-
The corresponding admin feature is found with the same countrycode and adminX codes and the respective feature code ADMx.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
The table 'alternate names' :
|
|
72
|
-
-----------------------------
|
|
73
|
-
alternateNameId : the id of this alternate name, int
|
|
74
|
-
geonameid : geonameId referring to id in table 'geoname', int
|
|
75
|
-
isolanguage : iso 639 language code 2- or 3-characters; 4-characters 'post' for postal codes and 'iata','icao' and faac for airport codes, fr_1793 for French Revolution names, abbr for abbreviation, link to a website (mostly to wikipedia), wkdt for the wikidataid, varchar(7)
|
|
76
|
-
alternate name : alternate name or name variant, varchar(400)
|
|
77
|
-
isPreferredName : '1', if this alternate name is an official/preferred name
|
|
78
|
-
isShortName : '1', if this is a short name like 'California' for 'State of California'
|
|
79
|
-
isColloquial : '1', if this alternate name is a colloquial or slang term. Example: 'Big Apple' for 'New York'.
|
|
80
|
-
isHistoric : '1', if this alternate name is historic and was used in the past. Example 'Bombay' for 'Mumbai'.
|
|
81
|
-
from : from period when the name was used
|
|
82
|
-
to : to period when the name was used
|
|
83
|
-
|
|
84
|
-
Remark : the field 'alternatenames' in the table 'geoname' is a short version of the 'alternatenames' table without links and postal codes but with ascii transliterations. You probably don't need both.
|
|
85
|
-
If you don't need to know the language of a name variant, the field 'alternatenames' will be sufficient. If you need to know the language
|
|
86
|
-
of a name variant, then you will need to load the table 'alternatenames' and you can drop the column in the geoname table.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Boundaries:
|
|
92
|
-
Simplified country boundaries are available in two slightly different formats:
|
|
93
|
-
shapes_simplified_low:
|
|
94
|
-
geonameId: The geonameId of the feature
|
|
95
|
-
geoJson: The boundary in geoJson format
|
|
96
|
-
|
|
97
|
-
shapes_simplified_low.json:
|
|
98
|
-
similar to the abovementioned file, but fully in geojson format. The geonameId is a feature property in the geojson string.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
Statistics on the number of features per country and the feature class and code distributions : http://www.geonames.org/statistics/
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Continent codes :
|
|
105
|
-
AF : Africa geonameId=6255146
|
|
106
|
-
AS : Asia geonameId=6255147
|
|
107
|
-
EU : Europe geonameId=6255148
|
|
108
|
-
NA : North America geonameId=6255149
|
|
109
|
-
OC : Oceania geonameId=6255151
|
|
110
|
-
SA : South America geonameId=6255150
|
|
111
|
-
AN : Antarctica geonameId=6255152
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
feature classes:
|
|
115
|
-
A: country, state, region,...
|
|
116
|
-
H: stream, lake, ...
|
|
117
|
-
L: parks,area, ...
|
|
118
|
-
P: city, village,...
|
|
119
|
-
R: road, railroad
|
|
120
|
-
S: spot, building, farm
|
|
121
|
-
T: mountain,hill,rock,...
|
|
122
|
-
U: undersea
|
|
123
|
-
V: forest,heath,...
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
If you find errors or miss important places, please do use the wiki-style edit interface on our website
|
|
127
|
-
https://www.geonames.org to correct inaccuracies and to add new records.
|
|
128
|
-
Thanks in the name of the geonames community for your valuable contribution.
|
|
129
|
-
|
|
130
|
-
Data Sources:
|
|
131
|
-
https://www.geonames.org/data-sources.html
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
More Information is also available in the geonames faq :
|
|
135
|
-
|
|
136
|
-
https://forum.geonames.org/gforum/forums/show/6.page
|
|
137
|
-
|
|
138
|
-
The forum : https://forum.geonames.org
|
|
139
|
-
|
|
140
|
-
or the google group : https://groups.google.com/group/geonames
|
|
141
|
-
|
|
File without changes
|