@hebcal/geo-sqlite 3.8.0 → 4.0.1

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.
@@ -2,21 +2,22 @@
2
2
 
3
3
  const {buildGeonamesSqlite} = require('@hebcal/geo-sqlite');
4
4
 
5
- if (process.argv.length != 8) {
6
- const infiles = 'countryInfo.txt cities5000.txt cities-patch.txt admin1CodesASCII.txt IL.txt';
5
+ const argv = process.argv.slice(2);
6
+ if (argv.length !== 7) {
7
+ const infiles = 'countryInfo.txt cities5000.txt cities-patch.txt admin1CodesASCII.txt IL.txt IL-alternatenames.txt';
7
8
  console.error(`Usage: build-geonames-sqlite geonames.sqlite3 ${infiles}`);
8
9
  process.exit(1);
9
10
  }
10
11
 
11
- const [dbFilename, countryInfo, cities, citiesPatch, admin1CodesASCII, il] = process.argv.slice(2);
12
-
13
- buildGeonamesSqlite(
14
- dbFilename,
15
- countryInfo,
16
- cities,
17
- citiesPatch,
18
- admin1CodesASCII,
19
- il,
20
- ).then(() => {
12
+ const filenames = {
13
+ dbFilename: argv[0],
14
+ countryInfotxt: argv[1],
15
+ cities5000txt: argv[2],
16
+ citiesPatch: argv[3],
17
+ admin1CodesASCIItxt: argv[4],
18
+ ILtxt: argv[5],
19
+ ILalternate: argv[6],
20
+ };
21
+ buildGeonamesSqlite(filenames).then(() => {
21
22
  console.log('Done!');
22
23
  });
@@ -9,9 +9,13 @@ curl -o $TMPDIR/countryInfo.txt http://download.geonames.org/export/dump/country
9
9
  curl -o $TMPDIR/admin1CodesASCII.txt http://download.geonames.org/export/dump/admin1CodesASCII.txt
10
10
  curl -o $TMPDIR/cities5000.zip http://download.geonames.org/export/dump/cities5000.zip
11
11
  curl -o $TMPDIR/IL.zip http://download.geonames.org/export/dump/IL.zip
12
+ curl -o $TMPDIR/alt-IL.zip http://download.geonames.org/export/dump/alternatenames/IL.zip
12
13
 
13
14
  cd $TMPDIR
14
15
  unzip cities5000.zip
16
+ unzip alt-IL.zip
17
+ mv IL.txt alt-IL.txt
18
+ rm readme.txt
15
19
  unzip IL.zip
16
20
 
17
21
  cd $CURDIR
@@ -23,7 +27,8 @@ $CURDIR/node_modules/.bin/build-geonames-sqlite \
23
27
  $TMPDIR/cities5000.txt \
24
28
  "$CURDIR/node_modules/@hebcal/geo-sqlite/cities-patch.txt" \
25
29
  $TMPDIR/admin1CodesASCII.txt \
26
- $TMPDIR/IL.txt
30
+ $TMPDIR/IL.txt \
31
+ $TMPDIR/alt-IL.txt
27
32
 
28
33
  rm -rf $TMPDIR
29
34
 
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
- /*! @hebcal/geo-sqlite v3.8.0 */
1
+ /*! @hebcal/geo-sqlite v4.0.1 */
2
2
  'use strict';
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var Database = require('better-sqlite3');
7
7
  var core = require('@hebcal/core');
8
+ require('@hebcal/cities');
8
9
  var pino = require('pino');
9
10
  var events = require('events');
10
11
  var fs = require('fs');
@@ -291,6 +292,12 @@ class GeoDb {
291
292
  if (geonameid) {
292
293
  return this.lookupGeoname(geonameid);
293
294
  } else {
295
+ const location = core.Location.lookup(cityName);
296
+
297
+ if (location) {
298
+ return location;
299
+ }
300
+
294
301
  if (this.logger) this.logger.warn(`GeoDb: unknown city=${cityName}`);
295
302
  return null;
296
303
  }
@@ -439,20 +446,25 @@ class GeoDb {
439
446
 
440
447
  /**
441
448
  * Builds `geonames.sqlite3` from files downloaded from geonames.org
442
- * @param {string} dbFilename
443
- * @param {string} countryInfotxt
444
- * @param {string} cities5000txt
445
- * @param {string} citiesPatch
446
- * @param {string} admin1CodesASCIItxt
447
- * @param {string} ILtxt
449
+ * @param {any} opts
448
450
  */
449
451
 
450
- async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, citiesPatch, admin1CodesASCIItxt, ILtxt) {
452
+ async function buildGeonamesSqlite(opts) {
453
+ const dbFilename = opts.dbFilename;
454
+ const countryInfotxt = opts.countryInfotxt;
455
+ const cities5000txt = opts.cities5000txt;
456
+ const citiesPatch = opts.citiesPatch;
457
+ const admin1CodesASCIItxt = opts.admin1CodesASCIItxt;
458
+ const ILtxt = opts.ILtxt;
459
+ const ILalternate = opts.ILalternate;
451
460
  const logger = pino__default["default"]({
452
461
  // level: argv.quiet ? 'warn' : 'info',
453
- prettyPrint: {
454
- translateTime: true,
455
- ignore: 'pid,hostname'
462
+ transport: {
463
+ target: 'pino-pretty',
464
+ options: {
465
+ translateTime: 'SYS:standard',
466
+ ignore: 'pid,hostname'
467
+ }
456
468
  }
457
469
  });
458
470
  const db = new Database__default["default"](dbFilename);
@@ -499,9 +511,16 @@ async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, ci
499
511
  gtopo30 int,
500
512
  timezone nvarchar(40),
501
513
  moddate date);`);
502
- await doFile(logger, db, cities5000txt, 'geoname', 19);
503
- await doFile(logger, db, citiesPatch, 'geoname', 19);
514
+
515
+ const truncateAlternateNames = a => {
516
+ a[3] = '';
517
+ return true;
518
+ };
519
+
520
+ await doFile(logger, db, cities5000txt, 'geoname', 19, truncateAlternateNames);
521
+ await doFile(logger, db, citiesPatch, 'geoname', 19, truncateAlternateNames);
504
522
  await doFile(logger, db, ILtxt, 'geoname', 19, a => {
523
+ a[3] = '';
505
524
  return a[6] == 'P' && (a[7] == 'PPL' || a[7] == 'STLMT');
506
525
  });
507
526
  doSql(logger, db, `DROP TABLE IF EXISTS admin1`, `CREATE TABLE admin1 (
@@ -517,8 +536,41 @@ async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, ci
517
536
  WHERE geonameid = 4140963;`, `UPDATE admin1
518
537
  SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
519
538
  WHERE key = 'US.DC';`);
520
- doSql(logger, db, `DROP TABLE IF EXISTS geoname_he`, `CREATE TABLE geoname_he AS SELECT * FROM geoname LIMIT 0`);
521
- await doFile(logger, db, ILtxt, 'geoname_he', 19, filterPlacesHebrew);
539
+ doSql(logger, db, `DROP TABLE IF EXISTS alternatenames`, `CREATE TABLE alternatenames (
540
+ id int PRIMARY KEY,
541
+ geonameid int NOT NULL,
542
+ isolanguage varchar(7),
543
+ name varchar(400),
544
+ isPreferredName tinyint,
545
+ isShortName tinyint,
546
+ isColloquial tinyint,
547
+ isHistoric tinyint,
548
+ periodFrom NULL,
549
+ periodTo NULL
550
+ );`);
551
+ await doFile(logger, db, ILalternate, 'alternatenames', 10, a => {
552
+ if (a[2] === 'he' || a[2] === 'en') {
553
+ if (a[2] === 'he') {
554
+ a[3] = a[3].replace(/‘/g, '׳');
555
+ a[3] = a[3].replace(/’/g, '׳');
556
+ a[3] = a[3].replace(/\'/g, '׳');
557
+ a[3] = core.Locale.hebrewStripNikkud(a[3]);
558
+ } else {
559
+ a[3] = a[3].replace(/‘/g, '\'');
560
+ a[3] = a[3].replace(/’/g, '\'');
561
+ }
562
+
563
+ return true;
564
+ }
565
+
566
+ return false;
567
+ }); // remove duplicates from alternatenames
568
+
569
+ doSql(logger, db, `DROP TABLE IF EXISTS altnames`, `CREATE TABLE altnames
570
+ AS SELECT geonameid, isolanguage, name
571
+ FROM alternatenames
572
+ GROUP BY 1, 2, 3
573
+ `);
522
574
  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;`);
523
575
  doSql(logger, db, `DROP TABLE IF EXISTS geoname_fulltext`, `CREATE VIRTUAL TABLE geoname_fulltext
524
576
  USING fts3(geonameid int, longname text,
@@ -549,47 +601,23 @@ async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, ci
549
601
  AND g.country = c.ISO
550
602
  AND g.country||'.'||g.admin1 = a.key
551
603
  `, `INSERT INTO geoname_fulltext
552
- SELECT g.geonameid, g.name||', ישראל',
553
- g.name, '', 'ישראל',
604
+ SELECT g.geonameid, alt.name||', ישראל',
605
+ alt.name, '', 'ישראל',
554
606
  g.population, g.latitude, g.longitude, g.timezone
555
- FROM geoname_he g, admin1 a, country c
556
- WHERE g.country = c.ISO
557
- AND g.country||'.'||g.admin1 = a.key
607
+ FROM geoname g, country c, altnames alt
608
+ WHERE g.country = 'IL'
609
+ AND alt.isolanguage = 'he'
610
+ AND g.geonameid = alt.geonameid
558
611
  `);
559
612
  db.close();
560
613
  return Promise.resolve(true);
561
614
  }
562
- /**
563
- * @param {string[]} a
564
- * @return {boolean}
565
- */
566
-
567
- function filterPlacesHebrew(a) {
568
- if (a[6] != 'P' || a[7] != 'PPL' && a[7] != 'STLMT') {
569
- return false;
570
- }
571
-
572
- const alternatenames = a[3].split(',');
573
-
574
- for (const name of alternatenames) {
575
- const firstchar = name[0];
576
-
577
- if (firstchar >= '\u05D0' && firstchar <= '\u05EA') {
578
- a[1] = core.Locale.hebrewStripNikkud(name); // replace 'name' field with Hebrew
579
-
580
- return true;
581
- }
582
- }
583
-
584
- return false;
585
- }
586
615
  /**
587
616
  * @param {pino.Logger} logger
588
617
  * @param {Database} db
589
618
  * @param {...string} sqls
590
619
  */
591
620
 
592
-
593
621
  function doSql(logger, db, ...sqls) {
594
622
  for (let i = 0; i < sqls.length; i++) {
595
623
  logger.info(sqls[i]);
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
- /*! @hebcal/geo-sqlite v3.8.0 */
1
+ /*! @hebcal/geo-sqlite v4.0.1 */
2
2
  import Database from 'better-sqlite3';
3
3
  import { Location, Locale } from '@hebcal/core';
4
+ import '@hebcal/cities';
4
5
  import pino from 'pino';
5
6
  import events from 'events';
6
7
  import fs from 'fs';
@@ -279,6 +280,12 @@ class GeoDb {
279
280
  if (geonameid) {
280
281
  return this.lookupGeoname(geonameid);
281
282
  } else {
283
+ const location = Location.lookup(cityName);
284
+
285
+ if (location) {
286
+ return location;
287
+ }
288
+
282
289
  if (this.logger) this.logger.warn(`GeoDb: unknown city=${cityName}`);
283
290
  return null;
284
291
  }
@@ -427,20 +434,25 @@ class GeoDb {
427
434
 
428
435
  /**
429
436
  * Builds `geonames.sqlite3` from files downloaded from geonames.org
430
- * @param {string} dbFilename
431
- * @param {string} countryInfotxt
432
- * @param {string} cities5000txt
433
- * @param {string} citiesPatch
434
- * @param {string} admin1CodesASCIItxt
435
- * @param {string} ILtxt
437
+ * @param {any} opts
436
438
  */
437
439
 
438
- async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, citiesPatch, admin1CodesASCIItxt, ILtxt) {
440
+ async function buildGeonamesSqlite(opts) {
441
+ const dbFilename = opts.dbFilename;
442
+ const countryInfotxt = opts.countryInfotxt;
443
+ const cities5000txt = opts.cities5000txt;
444
+ const citiesPatch = opts.citiesPatch;
445
+ const admin1CodesASCIItxt = opts.admin1CodesASCIItxt;
446
+ const ILtxt = opts.ILtxt;
447
+ const ILalternate = opts.ILalternate;
439
448
  const logger = pino({
440
449
  // level: argv.quiet ? 'warn' : 'info',
441
- prettyPrint: {
442
- translateTime: true,
443
- ignore: 'pid,hostname'
450
+ transport: {
451
+ target: 'pino-pretty',
452
+ options: {
453
+ translateTime: 'SYS:standard',
454
+ ignore: 'pid,hostname'
455
+ }
444
456
  }
445
457
  });
446
458
  const db = new Database(dbFilename);
@@ -487,9 +499,16 @@ async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, ci
487
499
  gtopo30 int,
488
500
  timezone nvarchar(40),
489
501
  moddate date);`);
490
- await doFile(logger, db, cities5000txt, 'geoname', 19);
491
- await doFile(logger, db, citiesPatch, 'geoname', 19);
502
+
503
+ const truncateAlternateNames = a => {
504
+ a[3] = '';
505
+ return true;
506
+ };
507
+
508
+ await doFile(logger, db, cities5000txt, 'geoname', 19, truncateAlternateNames);
509
+ await doFile(logger, db, citiesPatch, 'geoname', 19, truncateAlternateNames);
492
510
  await doFile(logger, db, ILtxt, 'geoname', 19, a => {
511
+ a[3] = '';
493
512
  return a[6] == 'P' && (a[7] == 'PPL' || a[7] == 'STLMT');
494
513
  });
495
514
  doSql(logger, db, `DROP TABLE IF EXISTS admin1`, `CREATE TABLE admin1 (
@@ -505,8 +524,41 @@ async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, ci
505
524
  WHERE geonameid = 4140963;`, `UPDATE admin1
506
525
  SET name = 'Washington, D.C.', asciiname = 'Washington, D.C.'
507
526
  WHERE key = 'US.DC';`);
508
- doSql(logger, db, `DROP TABLE IF EXISTS geoname_he`, `CREATE TABLE geoname_he AS SELECT * FROM geoname LIMIT 0`);
509
- await doFile(logger, db, ILtxt, 'geoname_he', 19, filterPlacesHebrew);
527
+ doSql(logger, db, `DROP TABLE IF EXISTS alternatenames`, `CREATE TABLE alternatenames (
528
+ id int PRIMARY KEY,
529
+ geonameid int NOT NULL,
530
+ isolanguage varchar(7),
531
+ name varchar(400),
532
+ isPreferredName tinyint,
533
+ isShortName tinyint,
534
+ isColloquial tinyint,
535
+ isHistoric tinyint,
536
+ periodFrom NULL,
537
+ periodTo NULL
538
+ );`);
539
+ await doFile(logger, db, ILalternate, 'alternatenames', 10, a => {
540
+ if (a[2] === 'he' || a[2] === 'en') {
541
+ if (a[2] === 'he') {
542
+ a[3] = a[3].replace(/‘/g, '׳');
543
+ a[3] = a[3].replace(/’/g, '׳');
544
+ a[3] = a[3].replace(/\'/g, '׳');
545
+ a[3] = Locale.hebrewStripNikkud(a[3]);
546
+ } else {
547
+ a[3] = a[3].replace(/‘/g, '\'');
548
+ a[3] = a[3].replace(/’/g, '\'');
549
+ }
550
+
551
+ return true;
552
+ }
553
+
554
+ return false;
555
+ }); // remove duplicates from alternatenames
556
+
557
+ doSql(logger, db, `DROP TABLE IF EXISTS altnames`, `CREATE TABLE altnames
558
+ AS SELECT geonameid, isolanguage, name
559
+ FROM alternatenames
560
+ GROUP BY 1, 2, 3
561
+ `);
510
562
  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;`);
511
563
  doSql(logger, db, `DROP TABLE IF EXISTS geoname_fulltext`, `CREATE VIRTUAL TABLE geoname_fulltext
512
564
  USING fts3(geonameid int, longname text,
@@ -537,47 +589,23 @@ async function buildGeonamesSqlite(dbFilename, countryInfotxt, cities5000txt, ci
537
589
  AND g.country = c.ISO
538
590
  AND g.country||'.'||g.admin1 = a.key
539
591
  `, `INSERT INTO geoname_fulltext
540
- SELECT g.geonameid, g.name||', ישראל',
541
- g.name, '', 'ישראל',
592
+ SELECT g.geonameid, alt.name||', ישראל',
593
+ alt.name, '', 'ישראל',
542
594
  g.population, g.latitude, g.longitude, g.timezone
543
- FROM geoname_he g, admin1 a, country c
544
- WHERE g.country = c.ISO
545
- AND g.country||'.'||g.admin1 = a.key
595
+ FROM geoname g, country c, altnames alt
596
+ WHERE g.country = 'IL'
597
+ AND alt.isolanguage = 'he'
598
+ AND g.geonameid = alt.geonameid
546
599
  `);
547
600
  db.close();
548
601
  return Promise.resolve(true);
549
602
  }
550
- /**
551
- * @param {string[]} a
552
- * @return {boolean}
553
- */
554
-
555
- function filterPlacesHebrew(a) {
556
- if (a[6] != 'P' || a[7] != 'PPL' && a[7] != 'STLMT') {
557
- return false;
558
- }
559
-
560
- const alternatenames = a[3].split(',');
561
-
562
- for (const name of alternatenames) {
563
- const firstchar = name[0];
564
-
565
- if (firstchar >= '\u05D0' && firstchar <= '\u05EA') {
566
- a[1] = Locale.hebrewStripNikkud(name); // replace 'name' field with Hebrew
567
-
568
- return true;
569
- }
570
- }
571
-
572
- return false;
573
- }
574
603
  /**
575
604
  * @param {pino.Logger} logger
576
605
  * @param {Database} db
577
606
  * @param {...string} sqls
578
607
  */
579
608
 
580
-
581
609
  function doSql(logger, db, ...sqls) {
582
610
  for (let i = 0; i < sqls.length; i++) {
583
611
  logger.info(sqls[i]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hebcal/geo-sqlite",
3
- "version": "3.8.0",
3
+ "version": "4.0.1",
4
4
  "author": "Michael J. Radwin (https://github.com/mjradwin)",
5
5
  "keywords": [
6
6
  "hebcal"
@@ -28,10 +28,11 @@
28
28
  "geo-sqlite.d.ts"
29
29
  ],
30
30
  "dependencies": {
31
- "@hebcal/core": "^3.33.2",
31
+ "@hebcal/cities": "^3.1.1",
32
+ "@hebcal/core": "^3.33.3",
32
33
  "better-sqlite3": "^7.5.0",
33
- "pino": "^7.6.4",
34
- "pino-pretty": "^7.5.0"
34
+ "pino": "^7.8.0",
35
+ "pino-pretty": "^7.5.3"
35
36
  },
36
37
  "scripts": {
37
38
  "build": "rollup -c",
@@ -45,34 +46,25 @@
45
46
  ],
46
47
  "require": [
47
48
  "@babel/register",
48
- "@babel/polyfill"
49
+ "regenerator-runtime/runtime"
49
50
  ],
50
- "babel": {
51
- "testOptions": {
52
- "presets": [
53
- "@babel/env"
54
- ]
55
- }
56
- },
57
51
  "inherit": true,
58
52
  "verbose": true
59
53
  },
60
54
  "license": "BSD-2-Clause",
61
55
  "devDependencies": {
62
- "@ava/babel": "^2.0.0",
63
- "@babel/core": "^7.16.12",
64
- "@babel/polyfill": "^7.12.1",
56
+ "@babel/core": "^7.17.5",
65
57
  "@babel/preset-env": "^7.16.11",
66
- "@babel/register": "^7.16.9",
67
- "@rollup/plugin-babel": "^5.3.0",
68
- "@rollup/plugin-commonjs": "^21.0.1",
58
+ "@babel/register": "^7.17.0",
59
+ "@rollup/plugin-babel": "^5.3.1",
60
+ "@rollup/plugin-commonjs": "^21.0.2",
69
61
  "@rollup/plugin-json": "^4.1.0",
70
62
  "@rollup/plugin-node-resolve": "^13.1.3",
71
- "ava": "^3.15.0",
72
- "eslint": "^8.7.0",
63
+ "ava": "^4.0.1",
64
+ "eslint": "^8.10.0",
73
65
  "eslint-config-google": "^0.14.0",
74
- "jsdoc": "^3.6.9",
75
- "jsdoc-to-markdown": "^7.1.0",
76
- "rollup": "^2.66.0"
66
+ "jsdoc": "^3.6.10",
67
+ "jsdoc-to-markdown": "^7.1.1",
68
+ "rollup": "^2.69.0"
77
69
  }
78
70
  }