Skip to content

Commit 69e0603

Browse files
Tyler Stewartforstermatth
andauthored
feat: expose array-like methods for searching data (#4)
* feat: expose array-like methods for searching data Instead of limiting an end-user to a string search, enable `predicate` functions to `find` and `filter` values. BREAKING CHANGE: exposed api changed from string search to predicate methods * docs: update readme * feat: data no longer lowercased or characters removed * fix: correct function declaration name Co-authored-by: forstermatth <[email protected]> Co-authored-by: forstermatth <[email protected]>
1 parent dd05a6f commit 69e0603

File tree

7 files changed

+41
-55
lines changed

7 files changed

+41
-55
lines changed

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
{
22
"name": "canadian-city-timezones",
3-
"version": "1.0.0",
3+
"version": "2.0.0",
44
"description": "Searchable timezones for all Canadian cities, towns, townships, villages, hamlets, and municipalities.",
55
"main": "src/index.js",
66
"types": "src/index.d.ts",
77
"files": [
88
"src/index.js",
99
"src/index.d.ts",
10-
"src/util.js",
1110
"src/data.csv"
1211
],
1312
"scripts": {
@@ -20,6 +19,10 @@
2019
"timezones"
2120
],
2221
"author": "trs",
22+
"repository": {
23+
"type": "git",
24+
"url": "https://github.com/autovance/canadian-city-timezones"
25+
},
2326
"license": "MIT",
2427
"devDependencies": {
2528
"csv-parser": "^2.3.3",

readme.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
`npm install canadian-city-timezones`
1212

1313
```ts
14-
import {find, findAll} from 'canadian-city-timezones';
14+
import {find} from 'canadian-city-timezones';
1515

16-
const result = await find('Lethbridge Alberta');
16+
const result = await find((city, province) => city === 'Lethbridge' && province === 'Alberta');
1717
result.city // Lethbridge
1818
result.province // Alberta
1919
result.timezone // America/Edmonton
@@ -24,16 +24,22 @@ result.timezone // America/Edmonton
2424
### Methods
2525

2626
```ts
27-
find(query: string): Promise<TimezoneResult>
27+
find(predicate: (value: TimezoneResult) => boolean): Promise<TimezoneResult | null>
2828
```
2929

30-
Returns the first matching result for the given string.
30+
Returns the first matching result for the given predicate.
3131

3232
```ts
33-
findAll(query: string): Promise<TimezoneResult[]>
33+
filter(predicate: (value: TimezoneResult) => boolean): AsyncGenerator<TimezoneResult>
3434
```
3535

36-
Returns all matching results for the given string.
36+
Yields all matching results for the given predicate.
37+
38+
```ts
39+
values(): AsyncGenerator<TimezoneResult>
40+
```
41+
42+
Yields all values.
3743

3844
### Interfaces
3945

src/generate.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const fetch = require('node-fetch');
88
const csv = require('csv-parser');
99
const geoTz = require('geo-tz');
1010
const removeAccents = require('remove-accents');
11-
const {removeSpecialCharacters} = require('./util');
1211

1312
const mkdirAsync = promisify(mkdir);
1413
const pipelineAsync = promisify(pipeline);
@@ -31,7 +30,7 @@ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3130

3231
async function * getCityData() {
3332
const req = await fetch(CAN_CITY_LIST);
34-
// Download file first as the csv parser would prematurely end being piped it directly
33+
// Download file first as the csv parser would prematurely end being piped in directly
3534
await pipelineAsync(
3635
req.body,
3736
createWriteStream('gc.csv')
@@ -90,8 +89,8 @@ async function * generateData() {
9089
}
9190

9291
yield [
93-
removeSpecialCharacters(cityData.name),
94-
removeSpecialCharacters(cityData.province),
92+
cityData.name,
93+
cityData.province,
9594
timezone
9695
].join(',');
9796

src/index.d.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ declare interface TimezoneResult {
66
timezone: string;
77
}
88

9-
declare function find(query: string): Promise<TimezoneResult>;
9+
declare type Predicate = (data: TimezoneResult) => boolean;
1010

11-
declare function findAll(query: string): Promise<TimezoneResult[]>;
11+
declare function values(): AsyncGenerator<TimezoneResult>;
12+
13+
declare function find(predicate: Predicate): Promise<TimezoneResult | null>;
14+
15+
declare function filter(predicate: Predicate): AsyncGenerator<TimezoneResult>;

src/index.js

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const path = require('path');
22
const {createReadStream} = require('fs');
33
const {createInterface} = require('readline');
4-
const {removeSpecialCharacters} = require('./util');
54

65
const CITY_MAP_DATA = path.join(__dirname, 'data.csv');
76

@@ -28,43 +27,37 @@ async function * getDataIterator() {
2827
}
2928
}
3029

31-
const isPartialMatchFactory = (query) => {
32-
const searchItems = query.split(' ').map((item) => removeSpecialCharacters(item));
33-
34-
return (data) => {
35-
const values = [
36-
data.city,
37-
data.province
38-
];
39-
40-
return searchItems.every((item) => values.join().includes(item));
41-
}
30+
async function* values() {
31+
yield* getDataIterator();
4232
}
4333

44-
async function find(query) {
45-
const isPartialMatch = isPartialMatchFactory(query);
34+
async function find(predicate) {
35+
if (typeof predicate !== 'function') {
36+
throw new TypeError(`${String(predicate)} is not a function`);
37+
}
4638

4739
for await (const data of getDataIterator()) {
48-
if (isPartialMatch(data)) {
40+
if (predicate(data)) {
4941
return data;
5042
}
5143
}
5244
return null;
5345
}
5446

55-
async function findAll(query) {
56-
const isPartialMatch = isPartialMatchFactory(query);
47+
async function* filter(predicate) {
48+
if (typeof predicate !== 'function') {
49+
throw new TypeError(`${String(predicate)} is not a function`);
50+
}
5751

58-
const results = [];
5952
for await (const data of getDataIterator()) {
60-
if (isPartialMatch(data)) {
61-
results.push(data);
53+
if (predicate(data)) {
54+
yield data;
6255
}
6356
}
64-
return results;
6557
}
6658

6759
module.exports = {
60+
values,
6861
find,
69-
findAll
62+
filter
7063
};

src/util.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

test/util.spec.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)