@hebcal/geo-sqlite 5.4.0 → 5.5.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 +146 -15
- package/dist/index.js +337 -4
- package/dist/index.mjs +1389 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -33,20 +33,43 @@ db.close();
|
|
|
33
33
|
</dd>
|
|
34
34
|
</dl>
|
|
35
35
|
|
|
36
|
+
## Functions
|
|
37
|
+
|
|
38
|
+
<dl>
|
|
39
|
+
<dt><a href="#buildGeonamesSqlite">buildGeonamesSqlite(opts)</a></dt>
|
|
40
|
+
<dd><p>Builds <code>geonames.sqlite3</code> from files downloaded from geonames.org</p>
|
|
41
|
+
</dd>
|
|
42
|
+
<dt><a href="#doSql">doSql(logger, db, ...sqls)</a></dt>
|
|
43
|
+
<dd></dd>
|
|
44
|
+
<dt><a href="#doFile">doFile(logger, db, infile, tableName, expectedFields, callback)</a></dt>
|
|
45
|
+
<dd></dd>
|
|
46
|
+
</dl>
|
|
36
47
|
|
|
37
48
|
<a name="GeoDb"></a>
|
|
38
49
|
|
|
39
50
|
## GeoDb
|
|
40
51
|
Wrapper around sqlite databases
|
|
41
52
|
|
|
42
|
-
**Kind**: global class
|
|
53
|
+
**Kind**: global class
|
|
43
54
|
|
|
44
55
|
* [GeoDb](#GeoDb)
|
|
45
56
|
* [new GeoDb(logger, zipsFilename, geonamesFilename)](#new_GeoDb_new)
|
|
46
|
-
*
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
* _instance_
|
|
58
|
+
* [.zipCache](#GeoDb+zipCache) : <code>Map.<string, Location></code>
|
|
59
|
+
* [.geonamesCache](#GeoDb+geonamesCache) : <code>Map.<number, Location></code>
|
|
60
|
+
* [.legacyCities](#GeoDb+legacyCities) : <code>Map.<string, number></code>
|
|
61
|
+
* [.countryNames](#GeoDb+countryNames) : <code>Map.<string, string></code>
|
|
62
|
+
* [.close()](#GeoDb+close)
|
|
63
|
+
* [.lookupZip(zip)](#GeoDb+lookupZip) ⇒ <code>Location</code>
|
|
64
|
+
* [.lookupGeoname(geonameid)](#GeoDb+lookupGeoname) ⇒ <code>Location</code>
|
|
65
|
+
* [.lookupLegacyCity(cityName)](#GeoDb+lookupLegacyCity) ⇒ <code>Location</code>
|
|
66
|
+
* [.autoComplete(qraw, latlong)](#GeoDb+autoComplete) ⇒ <code>Array.<Object></code>
|
|
67
|
+
* [.cacheZips()](#GeoDb+cacheZips)
|
|
68
|
+
* [.cacheGeonames()](#GeoDb+cacheGeonames)
|
|
69
|
+
* _static_
|
|
70
|
+
* [.transliterate(source, [options])](#GeoDb.transliterate) ⇒ <code>string</code>
|
|
71
|
+
* [.geonameCityDescr(cityName, admin1, countryName)](#GeoDb.geonameCityDescr) ⇒ <code>string</code>
|
|
72
|
+
* [.version()](#GeoDb.version)
|
|
50
73
|
|
|
51
74
|
<a name="new_GeoDb_new"></a>
|
|
52
75
|
|
|
@@ -54,39 +77,147 @@ Wrapper around sqlite databases
|
|
|
54
77
|
|
|
55
78
|
| Param | Type |
|
|
56
79
|
| --- | --- |
|
|
57
|
-
| logger | <code>any</code> |
|
|
58
|
-
| zipsFilename | <code>string</code> |
|
|
59
|
-
| geonamesFilename | <code>string</code> |
|
|
80
|
+
| logger | <code>any</code> |
|
|
81
|
+
| zipsFilename | <code>string</code> |
|
|
82
|
+
| geonamesFilename | <code>string</code> |
|
|
83
|
+
|
|
84
|
+
<a name="GeoDb+zipCache"></a>
|
|
85
|
+
|
|
86
|
+
### geoDb.zipCache : <code>Map.<string, Location></code>
|
|
87
|
+
**Kind**: instance property of [<code>GeoDb</code>](#GeoDb)
|
|
88
|
+
<a name="GeoDb+geonamesCache"></a>
|
|
60
89
|
|
|
90
|
+
### geoDb.geonamesCache : <code>Map.<number, Location></code>
|
|
91
|
+
**Kind**: instance property of [<code>GeoDb</code>](#GeoDb)
|
|
92
|
+
<a name="GeoDb+legacyCities"></a>
|
|
93
|
+
|
|
94
|
+
### geoDb.legacyCities : <code>Map.<string, number></code>
|
|
95
|
+
**Kind**: instance property of [<code>GeoDb</code>](#GeoDb)
|
|
96
|
+
<a name="GeoDb+countryNames"></a>
|
|
97
|
+
|
|
98
|
+
### geoDb.countryNames : <code>Map.<string, string></code>
|
|
99
|
+
**Kind**: instance property of [<code>GeoDb</code>](#GeoDb)
|
|
61
100
|
<a name="GeoDb+close"></a>
|
|
62
101
|
|
|
63
102
|
### geoDb.close()
|
|
64
103
|
Closes database handles
|
|
65
104
|
|
|
66
|
-
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
105
|
+
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
67
106
|
<a name="GeoDb+lookupZip"></a>
|
|
68
107
|
|
|
69
108
|
### geoDb.lookupZip(zip) ⇒ <code>Location</code>
|
|
70
|
-
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
109
|
+
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
71
110
|
|
|
72
111
|
| Param | Type |
|
|
73
112
|
| --- | --- |
|
|
74
|
-
| zip | <code>string</code> |
|
|
113
|
+
| zip | <code>string</code> |
|
|
75
114
|
|
|
76
115
|
<a name="GeoDb+lookupGeoname"></a>
|
|
77
116
|
|
|
78
117
|
### geoDb.lookupGeoname(geonameid) ⇒ <code>Location</code>
|
|
79
|
-
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
118
|
+
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
80
119
|
|
|
81
120
|
| Param | Type |
|
|
82
121
|
| --- | --- |
|
|
83
|
-
| geonameid | <code>number</code> |
|
|
122
|
+
| geonameid | <code>number</code> |
|
|
84
123
|
|
|
85
124
|
<a name="GeoDb+lookupLegacyCity"></a>
|
|
86
125
|
|
|
87
126
|
### geoDb.lookupLegacyCity(cityName) ⇒ <code>Location</code>
|
|
88
|
-
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
127
|
+
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
128
|
+
|
|
129
|
+
| Param | Type |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| cityName | <code>string</code> |
|
|
132
|
+
|
|
133
|
+
<a name="GeoDb+autoComplete"></a>
|
|
134
|
+
|
|
135
|
+
### geoDb.autoComplete(qraw, latlong) ⇒ <code>Array.<Object></code>
|
|
136
|
+
Generates autocomplete results based on a query string
|
|
137
|
+
|
|
138
|
+
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
139
|
+
|
|
140
|
+
| Param | Type | Default |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| qraw | <code>string</code> | |
|
|
143
|
+
| latlong | <code>boolean</code> | <code>false</code> |
|
|
144
|
+
|
|
145
|
+
<a name="GeoDb+cacheZips"></a>
|
|
146
|
+
|
|
147
|
+
### geoDb.cacheZips()
|
|
148
|
+
Reads entire ZIP database and caches in-memory
|
|
149
|
+
|
|
150
|
+
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
151
|
+
<a name="GeoDb+cacheGeonames"></a>
|
|
152
|
+
|
|
153
|
+
### geoDb.cacheGeonames()
|
|
154
|
+
Reads entire geonames database and caches in-memory
|
|
155
|
+
|
|
156
|
+
**Kind**: instance method of [<code>GeoDb</code>](#GeoDb)
|
|
157
|
+
<a name="GeoDb.transliterate"></a>
|
|
158
|
+
|
|
159
|
+
### GeoDb.transliterate(source, [options]) ⇒ <code>string</code>
|
|
160
|
+
Convenience wrapper of the `transliterate` function from `transliteration` npm package.
|
|
161
|
+
Transliterate the string `source` and return the result.
|
|
162
|
+
|
|
163
|
+
**Kind**: static method of [<code>GeoDb</code>](#GeoDb)
|
|
164
|
+
|
|
165
|
+
| Param | Type |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| source | <code>string</code> |
|
|
168
|
+
| [options] | <code>any</code> |
|
|
169
|
+
|
|
170
|
+
<a name="GeoDb.geonameCityDescr"></a>
|
|
171
|
+
|
|
172
|
+
### GeoDb.geonameCityDescr(cityName, admin1, countryName) ⇒ <code>string</code>
|
|
173
|
+
Builds a city description from geonameid string components
|
|
174
|
+
|
|
175
|
+
**Kind**: static method of [<code>GeoDb</code>](#GeoDb)
|
|
176
|
+
|
|
177
|
+
| Param | Type | Description |
|
|
178
|
+
| --- | --- | --- |
|
|
179
|
+
| cityName | <code>string</code> | e.g. 'Tel Aviv' or 'Chicago' |
|
|
180
|
+
| admin1 | <code>string</code> | e.g. 'England' or 'Massachusetts' |
|
|
181
|
+
| countryName | <code>string</code> | full country name, e.g. 'Israel' or 'United States' |
|
|
182
|
+
|
|
183
|
+
<a name="GeoDb.version"></a>
|
|
184
|
+
|
|
185
|
+
### GeoDb.version()
|
|
186
|
+
Returns the version of the GeoDb package
|
|
187
|
+
|
|
188
|
+
**Kind**: static method of [<code>GeoDb</code>](#GeoDb)
|
|
189
|
+
<a name="buildGeonamesSqlite"></a>
|
|
190
|
+
|
|
191
|
+
## buildGeonamesSqlite(opts)
|
|
192
|
+
Builds `geonames.sqlite3` from files downloaded from geonames.org
|
|
193
|
+
|
|
194
|
+
**Kind**: global function
|
|
195
|
+
|
|
196
|
+
| Param | Type |
|
|
197
|
+
| --- | --- |
|
|
198
|
+
| opts | <code>any</code> |
|
|
199
|
+
|
|
200
|
+
<a name="doSql"></a>
|
|
201
|
+
|
|
202
|
+
## doSql(logger, db, ...sqls)
|
|
203
|
+
**Kind**: global function
|
|
204
|
+
|
|
205
|
+
| Param | Type |
|
|
206
|
+
| --- | --- |
|
|
207
|
+
| logger | <code>pino.Logger</code> |
|
|
208
|
+
| db | <code>Database</code> |
|
|
209
|
+
| ...sqls | <code>string</code> |
|
|
210
|
+
|
|
211
|
+
<a name="doFile"></a>
|
|
212
|
+
|
|
213
|
+
## doFile(logger, db, infile, tableName, expectedFields, callback)
|
|
214
|
+
**Kind**: global function
|
|
89
215
|
|
|
90
216
|
| Param | Type |
|
|
91
217
|
| --- | --- |
|
|
92
|
-
|
|
|
218
|
+
| logger | <code>pino.Logger</code> |
|
|
219
|
+
| db | <code>Database</code> |
|
|
220
|
+
| infile | <code>string</code> |
|
|
221
|
+
| tableName | <code>string</code> |
|
|
222
|
+
| expectedFields | <code>number</code> |
|
|
223
|
+
| callback | <code>function</code> |
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/geo-sqlite v5.
|
|
1
|
+
/*! @hebcal/geo-sqlite v5.5.0 */
|
|
2
2
|
import Database from 'better-sqlite3';
|
|
3
3
|
import { Location, Locale } from '@hebcal/core';
|
|
4
4
|
import '@hebcal/cities';
|
|
@@ -6,6 +6,336 @@ import events from 'events';
|
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
import readline from 'readline';
|
|
8
8
|
|
|
9
|
+
class QuickLRU extends Map {
|
|
10
|
+
#size = 0;
|
|
11
|
+
#cache = new Map();
|
|
12
|
+
#oldCache = new Map();
|
|
13
|
+
#maxSize;
|
|
14
|
+
#maxAge;
|
|
15
|
+
#onEviction;
|
|
16
|
+
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
super();
|
|
19
|
+
|
|
20
|
+
if (!(options.maxSize && options.maxSize > 0)) {
|
|
21
|
+
throw new TypeError('`maxSize` must be a number greater than 0');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (typeof options.maxAge === 'number' && options.maxAge === 0) {
|
|
25
|
+
throw new TypeError('`maxAge` must be a number greater than 0');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.#maxSize = options.maxSize;
|
|
29
|
+
this.#maxAge = options.maxAge || Number.POSITIVE_INFINITY;
|
|
30
|
+
this.#onEviction = options.onEviction;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// For tests.
|
|
34
|
+
get __oldCache() {
|
|
35
|
+
return this.#oldCache;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#emitEvictions(cache) {
|
|
39
|
+
if (typeof this.#onEviction !== 'function') {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const [key, item] of cache) {
|
|
44
|
+
this.#onEviction(key, item.value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#deleteIfExpired(key, item) {
|
|
49
|
+
if (typeof item.expiry === 'number' && item.expiry <= Date.now()) {
|
|
50
|
+
if (typeof this.#onEviction === 'function') {
|
|
51
|
+
this.#onEviction(key, item.value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return this.delete(key);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#getOrDeleteIfExpired(key, item) {
|
|
61
|
+
const deleted = this.#deleteIfExpired(key, item);
|
|
62
|
+
if (deleted === false) {
|
|
63
|
+
return item.value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#getItemValue(key, item) {
|
|
68
|
+
return item.expiry ? this.#getOrDeleteIfExpired(key, item) : item.value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#peek(key, cache) {
|
|
72
|
+
const item = cache.get(key);
|
|
73
|
+
return this.#getItemValue(key, item);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#set(key, value) {
|
|
77
|
+
this.#cache.set(key, value);
|
|
78
|
+
this.#size++;
|
|
79
|
+
|
|
80
|
+
if (this.#size >= this.#maxSize) {
|
|
81
|
+
this.#size = 0;
|
|
82
|
+
this.#emitEvictions(this.#oldCache);
|
|
83
|
+
this.#oldCache = this.#cache;
|
|
84
|
+
this.#cache = new Map();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#moveToRecent(key, item) {
|
|
89
|
+
this.#oldCache.delete(key);
|
|
90
|
+
this.#set(key, item);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
* #entriesAscending() {
|
|
94
|
+
for (const item of this.#oldCache) {
|
|
95
|
+
const [key, value] = item;
|
|
96
|
+
if (!this.#cache.has(key)) {
|
|
97
|
+
const deleted = this.#deleteIfExpired(key, value);
|
|
98
|
+
if (deleted === false) {
|
|
99
|
+
yield item;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const item of this.#cache) {
|
|
105
|
+
const [key, value] = item;
|
|
106
|
+
const deleted = this.#deleteIfExpired(key, value);
|
|
107
|
+
if (deleted === false) {
|
|
108
|
+
yield item;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get(key) {
|
|
114
|
+
if (this.#cache.has(key)) {
|
|
115
|
+
const item = this.#cache.get(key);
|
|
116
|
+
return this.#getItemValue(key, item);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (this.#oldCache.has(key)) {
|
|
120
|
+
const item = this.#oldCache.get(key);
|
|
121
|
+
if (this.#deleteIfExpired(key, item) === false) {
|
|
122
|
+
this.#moveToRecent(key, item);
|
|
123
|
+
return item.value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
set(key, value, {maxAge = this.#maxAge} = {}) {
|
|
129
|
+
const expiry = typeof maxAge === 'number' && maxAge !== Number.POSITIVE_INFINITY
|
|
130
|
+
? (Date.now() + maxAge)
|
|
131
|
+
: undefined;
|
|
132
|
+
|
|
133
|
+
if (this.#cache.has(key)) {
|
|
134
|
+
this.#cache.set(key, {
|
|
135
|
+
value,
|
|
136
|
+
expiry,
|
|
137
|
+
});
|
|
138
|
+
} else {
|
|
139
|
+
this.#set(key, {value, expiry});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
has(key) {
|
|
146
|
+
if (this.#cache.has(key)) {
|
|
147
|
+
return !this.#deleteIfExpired(key, this.#cache.get(key));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (this.#oldCache.has(key)) {
|
|
151
|
+
return !this.#deleteIfExpired(key, this.#oldCache.get(key));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
peek(key) {
|
|
158
|
+
if (this.#cache.has(key)) {
|
|
159
|
+
return this.#peek(key, this.#cache);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (this.#oldCache.has(key)) {
|
|
163
|
+
return this.#peek(key, this.#oldCache);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
expiresIn(key) {
|
|
168
|
+
const item = this.#cache.get(key) ?? this.#oldCache.get(key);
|
|
169
|
+
if (item) {
|
|
170
|
+
return item.expiry ? item.expiry - Date.now() : Number.POSITIVE_INFINITY;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
delete(key) {
|
|
175
|
+
const deleted = this.#cache.delete(key);
|
|
176
|
+
if (deleted) {
|
|
177
|
+
this.#size--;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return this.#oldCache.delete(key) || deleted;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
clear() {
|
|
184
|
+
this.#cache.clear();
|
|
185
|
+
this.#oldCache.clear();
|
|
186
|
+
this.#size = 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
resize(newSize) {
|
|
190
|
+
if (!(newSize && newSize > 0)) {
|
|
191
|
+
throw new TypeError('`maxSize` must be a number greater than 0');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const items = [...this.#entriesAscending()];
|
|
195
|
+
const removeCount = items.length - newSize;
|
|
196
|
+
if (removeCount < 0) {
|
|
197
|
+
this.#cache = new Map(items);
|
|
198
|
+
this.#oldCache = new Map();
|
|
199
|
+
this.#size = items.length;
|
|
200
|
+
} else {
|
|
201
|
+
if (removeCount > 0) {
|
|
202
|
+
this.#emitEvictions(items.slice(0, removeCount));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
this.#oldCache = new Map(items.slice(removeCount));
|
|
206
|
+
this.#cache = new Map();
|
|
207
|
+
this.#size = 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
this.#maxSize = newSize;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
evict(count = 1) {
|
|
214
|
+
const requested = Number(count);
|
|
215
|
+
if (!requested || requested <= 0) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const items = [...this.#entriesAscending()];
|
|
220
|
+
const evictCount = Math.trunc(Math.min(requested, Math.max(items.length - 1, 0)));
|
|
221
|
+
if (evictCount <= 0) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
this.#emitEvictions(items.slice(0, evictCount));
|
|
226
|
+
this.#oldCache = new Map(items.slice(evictCount));
|
|
227
|
+
this.#cache = new Map();
|
|
228
|
+
this.#size = 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
* keys() {
|
|
232
|
+
for (const [key] of this) {
|
|
233
|
+
yield key;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
* values() {
|
|
238
|
+
for (const [, value] of this) {
|
|
239
|
+
yield value;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
* [Symbol.iterator]() {
|
|
244
|
+
for (const item of this.#cache) {
|
|
245
|
+
const [key, value] = item;
|
|
246
|
+
const deleted = this.#deleteIfExpired(key, value);
|
|
247
|
+
if (deleted === false) {
|
|
248
|
+
yield [key, value.value];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
for (const item of this.#oldCache) {
|
|
253
|
+
const [key, value] = item;
|
|
254
|
+
if (!this.#cache.has(key)) {
|
|
255
|
+
const deleted = this.#deleteIfExpired(key, value);
|
|
256
|
+
if (deleted === false) {
|
|
257
|
+
yield [key, value.value];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
* entriesDescending() {
|
|
264
|
+
let items = [...this.#cache];
|
|
265
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
266
|
+
const item = items[i];
|
|
267
|
+
const [key, value] = item;
|
|
268
|
+
const deleted = this.#deleteIfExpired(key, value);
|
|
269
|
+
if (deleted === false) {
|
|
270
|
+
yield [key, value.value];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
items = [...this.#oldCache];
|
|
275
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
276
|
+
const item = items[i];
|
|
277
|
+
const [key, value] = item;
|
|
278
|
+
if (!this.#cache.has(key)) {
|
|
279
|
+
const deleted = this.#deleteIfExpired(key, value);
|
|
280
|
+
if (deleted === false) {
|
|
281
|
+
yield [key, value.value];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
* entriesAscending() {
|
|
288
|
+
for (const [key, value] of this.#entriesAscending()) {
|
|
289
|
+
yield [key, value.value];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
get size() {
|
|
294
|
+
if (!this.#size) {
|
|
295
|
+
return this.#oldCache.size;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
let oldCacheSize = 0;
|
|
299
|
+
for (const key of this.#oldCache.keys()) {
|
|
300
|
+
if (!this.#cache.has(key)) {
|
|
301
|
+
oldCacheSize++;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return Math.min(this.#size + oldCacheSize, this.#maxSize);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
get maxSize() {
|
|
309
|
+
return this.#maxSize;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
get maxAge() {
|
|
313
|
+
return this.#maxAge;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
entries() {
|
|
317
|
+
return this.entriesAscending();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
forEach(callbackFunction, thisArgument = this) {
|
|
321
|
+
for (const [key, value] of this.entriesAscending()) {
|
|
322
|
+
callbackFunction.call(thisArgument, value, key, this);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
get [Symbol.toStringTag]() {
|
|
327
|
+
return 'QuickLRU';
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
toString() {
|
|
331
|
+
return `QuickLRU(${this.size}/${this.maxSize})`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
335
|
+
return this.toString();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
9
339
|
var city2geonameid = {
|
|
10
340
|
"AD-Andorra La Vella":3041563,
|
|
11
341
|
"AE-Abu Dhabi":292968,
|
|
@@ -511,7 +841,7 @@ function munge(s) {
|
|
|
511
841
|
}
|
|
512
842
|
|
|
513
843
|
// DO NOT EDIT THIS AUTO-GENERATED FILE!
|
|
514
|
-
const version = '5.
|
|
844
|
+
const version = '5.5.0';
|
|
515
845
|
|
|
516
846
|
const GEONAME_SQL = `SELECT
|
|
517
847
|
g.name as name,
|
|
@@ -644,10 +974,10 @@ class GeoDb {
|
|
|
644
974
|
this.geonamesDb = new Database(geonamesFilename, {fileMustExist: true});
|
|
645
975
|
this.zipStmt = this.zipsDb.prepare(ZIPCODE_SQL);
|
|
646
976
|
/** @type {Map<string, Location>} */
|
|
647
|
-
this.zipCache = new
|
|
977
|
+
this.zipCache = new QuickLRU({maxSize: 1000});
|
|
648
978
|
this.geonamesStmt = this.geonamesDb.prepare(GEONAME_SQL);
|
|
649
979
|
/** @type {Map<number, Location>} */
|
|
650
|
-
this.geonamesCache = new
|
|
980
|
+
this.geonamesCache = new QuickLRU({maxSize: 1000});
|
|
651
981
|
/** @type {Map<string, number>} */
|
|
652
982
|
this.legacyCities = new Map();
|
|
653
983
|
for (const [name, id] of Object.entries(city2geonameid)) {
|
|
@@ -1015,6 +1345,7 @@ class GeoDb {
|
|
|
1015
1345
|
const start = Date.now();
|
|
1016
1346
|
const stmt = this.zipsDb.prepare(ZIPCODE_ALL_SQL);
|
|
1017
1347
|
const rows = stmt.all();
|
|
1348
|
+
this.zipCache = new Map(); // replace QuickLRU
|
|
1018
1349
|
for (const row of rows) {
|
|
1019
1350
|
const location = this.makeZipLocation(row);
|
|
1020
1351
|
this.zipCache.set(row.ZipCode, location);
|
|
@@ -1028,6 +1359,7 @@ class GeoDb {
|
|
|
1028
1359
|
const start = Date.now();
|
|
1029
1360
|
const stmt = this.geonamesDb.prepare(GEONAME_ALL_SQL);
|
|
1030
1361
|
const rows = stmt.all();
|
|
1362
|
+
this.geonamesCache = new Map(); // replace QuickLRU
|
|
1031
1363
|
for (const row of rows) {
|
|
1032
1364
|
const location = this.makeGeonameLocation(row.geonameid, row);
|
|
1033
1365
|
this.geonamesCache.set(row.geonameid, location);
|
|
@@ -1036,6 +1368,7 @@ class GeoDb {
|
|
|
1036
1368
|
if (this.logger) this.logger.info(`GeoDb: cached ${rows.length} geonames in ${end - start}ms`);
|
|
1037
1369
|
}
|
|
1038
1370
|
|
|
1371
|
+
/** Returns the version of the GeoDb package */
|
|
1039
1372
|
static version() {
|
|
1040
1373
|
return version;
|
|
1041
1374
|
}
|