text-to-map 1.0.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/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/bin/address-points-import-only.d.ts +1 -0
- package/dist/bin/address-points-import-only.js +14 -0
- package/dist/bin/address-points.d.ts +1 -0
- package/dist/bin/address-points.js +14 -0
- package/dist/bin/clear-all.d.ts +1 -0
- package/dist/bin/clear-all.js +5 -0
- package/dist/bin/generate-syntax-diagrams.d.ts +1 -0
- package/dist/bin/generate-syntax-diagrams.js +19 -0
- package/dist/bin/parse-ordinance.d.ts +1 -0
- package/dist/bin/parse-ordinance.js +20 -0
- package/dist/bin/schools.d.ts +1 -0
- package/dist/bin/schools.js +8 -0
- package/dist/bin/streets.d.ts +1 -0
- package/dist/bin/streets.js +14 -0
- package/dist/db/address-points.d.ts +38 -0
- package/dist/db/address-points.js +312 -0
- package/dist/db/db.d.ts +23 -0
- package/dist/db/db.js +90 -0
- package/dist/db/founders.d.ts +9 -0
- package/dist/db/founders.js +191 -0
- package/dist/db/meta.d.ts +3 -0
- package/dist/db/meta.js +17 -0
- package/dist/db/schools.d.ts +6 -0
- package/dist/db/schools.js +61 -0
- package/dist/db/street-sync.d.ts +5 -0
- package/dist/db/street-sync.js +18 -0
- package/dist/db/types.d.ts +34 -0
- package/dist/db/types.js +12 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/open-data-sync/address-points.d.ts +4 -0
- package/dist/open-data-sync/address-points.js +73 -0
- package/dist/open-data-sync/schools.d.ts +3 -0
- package/dist/open-data-sync/schools.js +308 -0
- package/dist/open-data-sync/streets.d.ts +2 -0
- package/dist/open-data-sync/streets.js +77 -0
- package/dist/smd-to-csv/json-to-csv.d.ts +1 -0
- package/dist/smd-to-csv/json-to-csv.js +153 -0
- package/dist/smd-to-csv/ordinance-to-csv-rules.d.ts +1 -0
- package/dist/smd-to-csv/ordinance-to-csv-rules.js +31 -0
- package/dist/smd-to-csv/txt-to-json.d.ts +1 -0
- package/dist/smd-to-csv/txt-to-json.js +102 -0
- package/dist/street-markdown/municipality.d.ts +5 -0
- package/dist/street-markdown/municipality.js +44 -0
- package/dist/street-markdown/roman-numerals.d.ts +1 -0
- package/dist/street-markdown/roman-numerals.js +67 -0
- package/dist/street-markdown/smd-line-parser.d.ts +4 -0
- package/dist/street-markdown/smd-line-parser.js +29 -0
- package/dist/street-markdown/smd-parser.d.ts +21 -0
- package/dist/street-markdown/smd-parser.js +343 -0
- package/dist/street-markdown/smd.d.ts +9 -0
- package/dist/street-markdown/smd.js +182 -0
- package/dist/street-markdown/token-definition.d.ts +23 -0
- package/dist/street-markdown/token-definition.js +154 -0
- package/dist/street-markdown/types.d.ts +83 -0
- package/dist/street-markdown/types.js +18 -0
- package/dist/utils/addressBuilder.d.ts +8 -0
- package/dist/utils/addressBuilder.js +101 -0
- package/dist/utils/atom.d.ts +2 -0
- package/dist/utils/atom.js +65 -0
- package/dist/utils/helpers.d.ts +34 -0
- package/dist/utils/helpers.js +157 -0
- package/package.json +82 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { MunicipalityType } from "./types";
|
|
2
|
+
import { getDb, insertAutoincrementRow, insertMultipleRows } from "./db";
|
|
3
|
+
import { extractMunicipalityName, findClosestString } from "../utils/helpers";
|
|
4
|
+
const cityTypeCode = 261;
|
|
5
|
+
const cityDistrictTypeCode = 263;
|
|
6
|
+
export const insertFounders = (founders) => {
|
|
7
|
+
const db = getDb();
|
|
8
|
+
const selectCityStatement = db.prepare(`SELECT c.name, c.code FROM school s
|
|
9
|
+
JOIN school_location l ON s.izo = l.school_izo
|
|
10
|
+
JOIN address_point a ON l.address_point_id = a.id
|
|
11
|
+
JOIN city c ON a.city_code = c.code
|
|
12
|
+
WHERE s.izo = ?
|
|
13
|
+
LIMIT 1`);
|
|
14
|
+
const selectDistrictStatement = db.prepare(`SELECT d.name, d.code FROM school s
|
|
15
|
+
JOIN school_location l ON s.izo = l.school_izo
|
|
16
|
+
JOIN address_point a ON l.address_point_id = a.id
|
|
17
|
+
JOIN city_district d ON a.city_district_code = d.code
|
|
18
|
+
WHERE s.izo = ?
|
|
19
|
+
LIMIT 1`);
|
|
20
|
+
let insertedFounders = 0;
|
|
21
|
+
const schoolFounderConnectionData = [];
|
|
22
|
+
founders.forEach((founder) => {
|
|
23
|
+
if (founder.municipalityType !== MunicipalityType.City &&
|
|
24
|
+
founder.municipalityType !== MunicipalityType.District) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const municipalityName = extractMunicipalityName(founder);
|
|
28
|
+
// check if the extracted municipality name is the same as in all the schools' locations
|
|
29
|
+
let allEqual = true;
|
|
30
|
+
let municipalityCode = "";
|
|
31
|
+
founder.schools.forEach((school) => {
|
|
32
|
+
const result = (founder.municipalityType === MunicipalityType.City
|
|
33
|
+
? selectCityStatement
|
|
34
|
+
: selectDistrictStatement).get(school.izo);
|
|
35
|
+
if (!result) {
|
|
36
|
+
console.log(`izo: ${school.izo}, extracted: ${municipalityName}, RUIAN: UNDEFINED`);
|
|
37
|
+
allEqual = false;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const { name, code } = result;
|
|
41
|
+
municipalityCode = code;
|
|
42
|
+
if (name !== municipalityName) {
|
|
43
|
+
console.log(`izo: ${school.izo}, extracted: ${municipalityName}, RUIAN: ${name}`);
|
|
44
|
+
allEqual = false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (!allEqual) {
|
|
49
|
+
// here we could try to find the correct municipality by searching for the name in the DB
|
|
50
|
+
// this would solve the case of one school in the whole Czech Republic that is located outside
|
|
51
|
+
// its founder municipality - too much work for now
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const founderId = insertAutoincrementRow([
|
|
55
|
+
founder.name,
|
|
56
|
+
founder.ico,
|
|
57
|
+
String(founder.originalType),
|
|
58
|
+
founder.municipalityType === MunicipalityType.City
|
|
59
|
+
? municipalityCode
|
|
60
|
+
: null,
|
|
61
|
+
founder.municipalityType === MunicipalityType.City
|
|
62
|
+
? null
|
|
63
|
+
: municipalityCode,
|
|
64
|
+
], "founder", ["name", "ico", "founder_type_code", "city_code", "city_district_code"]);
|
|
65
|
+
if (founderId !== null) {
|
|
66
|
+
insertedFounders++;
|
|
67
|
+
founder.schools.forEach((school) => {
|
|
68
|
+
schoolFounderConnectionData.push([school.izo, founderId]);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
const insertedConnections = insertMultipleRows(schoolFounderConnectionData, "school_founder", ["school_izo", "founder_id"]);
|
|
73
|
+
return insertedFounders + insertedConnections;
|
|
74
|
+
};
|
|
75
|
+
export const findFounder = (name) => {
|
|
76
|
+
const errors = [];
|
|
77
|
+
const db = getDb();
|
|
78
|
+
const exactMatchStatement = db.prepare(`SELECT f.id, f.name, f.ico, f.founder_type_code, f.city_code, f.city_district_code FROM founder f
|
|
79
|
+
LEFT JOIN city c ON c.code = f.city_code
|
|
80
|
+
LEFT JOIN city_district d ON d.code = f.city_district_code
|
|
81
|
+
WHERE f.name = ? OR c.name = ? OR d.name = ?`);
|
|
82
|
+
const result = exactMatchStatement.get(name, name, name);
|
|
83
|
+
if (result) {
|
|
84
|
+
return { founder: resultToFounder(result), errors };
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const allFounderNames = getAllFounderNames();
|
|
88
|
+
const namesList = allFounderNames
|
|
89
|
+
.map((row) => row.founderName)
|
|
90
|
+
.concat(allFounderNames.map((row) => row.municipalityName));
|
|
91
|
+
const bestMatch = findClosestString(name, namesList);
|
|
92
|
+
const bestMatchRow = allFounderNames.find((foundersNames) => foundersNames.founderName === bestMatch ||
|
|
93
|
+
foundersNames.municipalityName === bestMatch);
|
|
94
|
+
errors.push(`No exact match for founder "${name}", using "${bestMatch}" instead.`);
|
|
95
|
+
const findByIdStatement = db.prepare(`SELECT f.id, f.name, f.ico, f.founder_type_code, f.city_code, f.city_district_code FROM founder f
|
|
96
|
+
WHERE f.id = ?`);
|
|
97
|
+
return {
|
|
98
|
+
founder: resultToFounder(findByIdStatement.get(bestMatchRow.id)),
|
|
99
|
+
errors,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
let cachedCityCode = null;
|
|
104
|
+
let cityCodeFounder = null;
|
|
105
|
+
export const getFounderCityCode = (founder) => {
|
|
106
|
+
const db = getDb();
|
|
107
|
+
if (founder.municipalityType === MunicipalityType.District) {
|
|
108
|
+
if (cityCodeFounder !== founder) {
|
|
109
|
+
const founderStatement = db.prepare(`
|
|
110
|
+
SELECT city_code
|
|
111
|
+
FROM city_district
|
|
112
|
+
WHERE code = ?
|
|
113
|
+
`);
|
|
114
|
+
cachedCityCode = founderStatement.get(founder.cityOrDistrictCode).city_code;
|
|
115
|
+
}
|
|
116
|
+
return cachedCityCode;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
return founder.cityOrDistrictCode;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const resultToFounder = (result) => {
|
|
123
|
+
return {
|
|
124
|
+
name: result.name,
|
|
125
|
+
ico: result.ico,
|
|
126
|
+
originalType: result.founder_type_code,
|
|
127
|
+
municipalityType: result.founder_type_code === cityTypeCode
|
|
128
|
+
? MunicipalityType.City
|
|
129
|
+
: MunicipalityType.District,
|
|
130
|
+
cityOrDistrictCode: result.city_code || result.city_district_code,
|
|
131
|
+
schools: getSchoolsByFounderId(parseInt(result.id)),
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
const getSchoolsByFounderId = (founderId) => {
|
|
135
|
+
const db = getDb();
|
|
136
|
+
const statement = db.prepare(`SELECT s.izo, s.name, s.capacity, sl.address_point_id FROM school s
|
|
137
|
+
JOIN school_founder sf ON s.izo = sf.school_izo
|
|
138
|
+
JOIN school_location sl ON s.izo = sl.school_izo
|
|
139
|
+
WHERE sf.founder_id = ?`);
|
|
140
|
+
return statement.all(founderId).map((row) => ({
|
|
141
|
+
izo: String(row.izo),
|
|
142
|
+
name: String(row.name),
|
|
143
|
+
capacity: parseInt(row.capacity),
|
|
144
|
+
locations: [
|
|
145
|
+
{
|
|
146
|
+
addressPointId: parseInt(row.address_point_id),
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
}));
|
|
150
|
+
};
|
|
151
|
+
const getAllFounderNames = () => {
|
|
152
|
+
const db = getDb();
|
|
153
|
+
const statement = db.prepare(`SELECT f.id, f.name AS founder_name, c.name AS city_name, d.name AS city_district_name FROM founder f
|
|
154
|
+
LEFT JOIN city c ON c.code = f.city_code
|
|
155
|
+
LEFT JOIN city_district d ON d.code = f.city_district_code`);
|
|
156
|
+
const result = statement.all();
|
|
157
|
+
return result.map((row) => ({
|
|
158
|
+
id: parseInt(row.id),
|
|
159
|
+
founderName: String(row.founder_name),
|
|
160
|
+
municipalityName: String(row.city_name ? row.city_name : row.city_district_name),
|
|
161
|
+
}));
|
|
162
|
+
};
|
|
163
|
+
export const findMunicipalityByNameAndType = (name, type) => {
|
|
164
|
+
const errors = [];
|
|
165
|
+
const db = getDb();
|
|
166
|
+
const exactMatchStatement = db.prepare(`SELECT code FROM ${type === MunicipalityType.City ? "city" : "city_district"} WHERE name = ?`);
|
|
167
|
+
const result = exactMatchStatement.get(name);
|
|
168
|
+
if (result) {
|
|
169
|
+
return { municipality: { code: result.code, type }, errors };
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const allNames = getAllMunicipalityNames(type);
|
|
173
|
+
const namesList = allNames.map((row) => row.name);
|
|
174
|
+
const bestMatch = findClosestString(name, namesList);
|
|
175
|
+
const bestMatchRow = allNames.find((municipality) => municipality.name === bestMatch);
|
|
176
|
+
errors.push(`No exact match for municipality "${name}", using "${bestMatch}" instead.`);
|
|
177
|
+
return {
|
|
178
|
+
municipality: { code: bestMatchRow.code, type },
|
|
179
|
+
errors,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const getAllMunicipalityNames = (type) => {
|
|
184
|
+
const db = getDb();
|
|
185
|
+
const statement = db.prepare(`SELECT name, code FROM ${type === MunicipalityType.City ? "city" : "city_district"}`);
|
|
186
|
+
const result = statement.all();
|
|
187
|
+
return result.map((row) => ({
|
|
188
|
+
name: row.name,
|
|
189
|
+
code: row.code,
|
|
190
|
+
}));
|
|
191
|
+
};
|
package/dist/db/meta.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getDb } from "./db";
|
|
2
|
+
export const getMetaValue = (key) => {
|
|
3
|
+
const db = getDb();
|
|
4
|
+
const statement = db.prepare("SELECT value FROM meta WHERE key = ?");
|
|
5
|
+
return statement.pluck().get(key);
|
|
6
|
+
};
|
|
7
|
+
export const setMetaValue = (key, value) => {
|
|
8
|
+
const db = getDb();
|
|
9
|
+
if (getMetaValue(key) === undefined) {
|
|
10
|
+
const statement = db.prepare("INSERT INTO meta (key, value) VALUES (?, ?)");
|
|
11
|
+
return statement.run(key, value.toString());
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
const statement = db.prepare("UPDATE meta SET value = ? WHERE key = ?");
|
|
15
|
+
return statement.run(value.toString(), key);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getDb, insertMultipleRows } from "./db";
|
|
2
|
+
import { findClosestString } from "../utils/helpers";
|
|
3
|
+
export const insertSchools = (schools, doNotClearTable = false) => {
|
|
4
|
+
if (!doNotClearTable) {
|
|
5
|
+
const db = getDb();
|
|
6
|
+
db.exec("DELETE FROM school_location");
|
|
7
|
+
db.exec("DELETE FROM school_founder");
|
|
8
|
+
db.exec("DELETE FROM school_location");
|
|
9
|
+
db.exec("DELETE FROM founder");
|
|
10
|
+
db.exec("DELETE FROM school");
|
|
11
|
+
db.exec("DELETE FROM sqlite_sequence WHERE name='school_location' OR name='founder' OR name='school_founder'");
|
|
12
|
+
}
|
|
13
|
+
const insertedSchools = insertMultipleRows(schools.map((school) => [
|
|
14
|
+
school.izo,
|
|
15
|
+
school.name,
|
|
16
|
+
school.capacity.toString(),
|
|
17
|
+
]), "school", ["izo", "name", "capacity"]);
|
|
18
|
+
// const locations = schools.flatMap((school) => {
|
|
19
|
+
// const uniqueAddressPoints = [
|
|
20
|
+
// ...new Set(school.locations.map((location) => location.addressPointId)),
|
|
21
|
+
// ];
|
|
22
|
+
// return uniqueAddressPoints.map((addressPoint) => [
|
|
23
|
+
// school.izo,
|
|
24
|
+
// addressPoint.toString(),
|
|
25
|
+
// ]);
|
|
26
|
+
// });
|
|
27
|
+
const locations = schools
|
|
28
|
+
.filter((school) => school.locations.length > 0)
|
|
29
|
+
.map((school) => [
|
|
30
|
+
school.izo,
|
|
31
|
+
school.locations[0].addressPointId.toString(),
|
|
32
|
+
]);
|
|
33
|
+
let insertedLocations = 0;
|
|
34
|
+
// @todo prevent FK errors (address point might not exist, maybe even school?) - or maybe the DB wasn't fresh
|
|
35
|
+
// plus filter out duplicit locations (same address id + izo)
|
|
36
|
+
locations.forEach((location) => {
|
|
37
|
+
try {
|
|
38
|
+
insertedLocations += insertMultipleRows([location], "school_location", ["school_izo", "address_point_id"], false);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.log(`Cannot add location with RUIAN code ${location[1]} (school IZO = ${location[0]}): code does not exist.`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return insertedSchools + insertedLocations;
|
|
45
|
+
};
|
|
46
|
+
export const findSchool = (name, schools) => {
|
|
47
|
+
if (schools.length === 0) {
|
|
48
|
+
return { school: null, errors: ["No schools for this founder."] };
|
|
49
|
+
}
|
|
50
|
+
let school = null;
|
|
51
|
+
const errors = [];
|
|
52
|
+
school = schools.find((school) => school.name === name);
|
|
53
|
+
if (school) {
|
|
54
|
+
return { school, errors };
|
|
55
|
+
}
|
|
56
|
+
const namesList = schools.map((school) => school.name);
|
|
57
|
+
const bestMatch = findClosestString(name, namesList);
|
|
58
|
+
school = schools.find((school) => bestMatch === school.name);
|
|
59
|
+
errors.push(`No exact match for school "${name}", using "${bestMatch}" instead.`);
|
|
60
|
+
return { school, errors };
|
|
61
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { DbfStreet } from "./types";
|
|
2
|
+
export declare const setStreetAsSynced: (streetFeedUrl: string) => void;
|
|
3
|
+
export declare const getAllSyncedStreets: () => Set<string>;
|
|
4
|
+
export declare const deleteStreets: (streetUrls: string[]) => void;
|
|
5
|
+
export declare const insertStreetsFromDbf: (data: DbfStreet[]) => number;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { deleteMultipleRows, getDb, insertMultipleRows } from "./db";
|
|
2
|
+
export const setStreetAsSynced = (streetFeedUrl) => {
|
|
3
|
+
const db = getDb();
|
|
4
|
+
db.prepare("INSERT OR IGNORE INTO street_sync (feed_url) VALUES (?)").run(streetFeedUrl);
|
|
5
|
+
};
|
|
6
|
+
export const getAllSyncedStreets = () => {
|
|
7
|
+
const db = getDb();
|
|
8
|
+
return new Set(db
|
|
9
|
+
.prepare("SELECT * FROM street_sync")
|
|
10
|
+
.all()
|
|
11
|
+
.map((row) => row.feed_url));
|
|
12
|
+
};
|
|
13
|
+
export const deleteStreets = (streetUrls) => {
|
|
14
|
+
deleteMultipleRows(streetUrls, "street_sync", "feed_url");
|
|
15
|
+
};
|
|
16
|
+
export const insertStreetsFromDbf = (data) => {
|
|
17
|
+
return insertMultipleRows(data.map((street) => [street.KOD, street.OBEC_KOD, street.NAZEV]), "street", ["code", "city_code", "name"]);
|
|
18
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface SchoolLocation {
|
|
2
|
+
id?: number;
|
|
3
|
+
schoolIzo?: number;
|
|
4
|
+
addressPointId: number;
|
|
5
|
+
}
|
|
6
|
+
export interface School {
|
|
7
|
+
name: string;
|
|
8
|
+
izo: string;
|
|
9
|
+
capacity: number;
|
|
10
|
+
locations: SchoolLocation[];
|
|
11
|
+
}
|
|
12
|
+
export interface Founder {
|
|
13
|
+
name: string;
|
|
14
|
+
ico: string;
|
|
15
|
+
originalType?: number;
|
|
16
|
+
municipalityType: MunicipalityType;
|
|
17
|
+
cityOrDistrictCode?: number;
|
|
18
|
+
schools: School[];
|
|
19
|
+
}
|
|
20
|
+
export declare enum MunicipalityType {
|
|
21
|
+
City = 0,
|
|
22
|
+
District = 1,
|
|
23
|
+
Other = 2
|
|
24
|
+
}
|
|
25
|
+
export interface Municipality {
|
|
26
|
+
type: MunicipalityType;
|
|
27
|
+
code: number;
|
|
28
|
+
}
|
|
29
|
+
export declare const founderToMunicipality: (founder: Founder) => Municipality;
|
|
30
|
+
export interface DbfStreet {
|
|
31
|
+
KOD: string;
|
|
32
|
+
NAZEV: string;
|
|
33
|
+
OBEC_KOD: string;
|
|
34
|
+
}
|
package/dist/db/types.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export var MunicipalityType;
|
|
2
|
+
(function (MunicipalityType) {
|
|
3
|
+
MunicipalityType[MunicipalityType["City"] = 0] = "City";
|
|
4
|
+
MunicipalityType[MunicipalityType["District"] = 1] = "District";
|
|
5
|
+
MunicipalityType[MunicipalityType["Other"] = 2] = "Other";
|
|
6
|
+
})(MunicipalityType || (MunicipalityType = {}));
|
|
7
|
+
export const founderToMunicipality = (founder) => {
|
|
8
|
+
return {
|
|
9
|
+
type: founder.municipalityType,
|
|
10
|
+
code: founder.cityOrDistrictCode,
|
|
11
|
+
};
|
|
12
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { downloadAndImportAllLatestAddressPoints, importAllLatestAddressPoints, deleteDb } from "./open-data-sync/address-points";
|
|
2
|
+
export { downloadAndImportAllSchools, deleteSchoolsXmlFile } from "./open-data-sync/schools";
|
|
3
|
+
export { downloadAndImportAllStreets } from "./open-data-sync/streets";
|
|
4
|
+
export { parseOrdinanceToAddressPoints } from "./street-markdown/smd";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { downloadAndImportAllLatestAddressPoints, importAllLatestAddressPoints, deleteDb } from "./open-data-sync/address-points";
|
|
2
|
+
export { downloadAndImportAllSchools, deleteSchoolsXmlFile } from "./open-data-sync/schools";
|
|
3
|
+
export { downloadAndImportAllStreets } from "./open-data-sync/streets";
|
|
4
|
+
export { parseOrdinanceToAddressPoints } from "./street-markdown/smd";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { OpenDataSyncOptions } from "../utils/helpers";
|
|
2
|
+
export declare const downloadAndImportAllLatestAddressPoints: (options?: OpenDataSyncOptions) => Promise<void>;
|
|
3
|
+
export declare const importAllLatestAddressPoints: (options?: OpenDataSyncOptions) => Promise<void>;
|
|
4
|
+
export declare const deleteDb: (options?: OpenDataSyncOptions) => void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import fetch from "node-fetch";
|
|
11
|
+
import { createWriteStream, createReadStream, rmSync, readdirSync, existsSync, } from "fs";
|
|
12
|
+
import { pipeline } from "stream/promises";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import AdmZip from "adm-zip";
|
|
15
|
+
import { parse } from "csv-parse";
|
|
16
|
+
import iconv from "iconv-lite";
|
|
17
|
+
import { prepareOptions, initDb, } from "../utils/helpers";
|
|
18
|
+
import { commitAddressPoints, importParsedLine } from "../db/address-points";
|
|
19
|
+
import { getLatestUrlFromAtomFeed } from "../utils/atom";
|
|
20
|
+
const downloadAndUnzip = (url, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
+
const zipFilePath = join(options.tmpDir, options.addressPointsZipFileName);
|
|
22
|
+
console.log("Downloading a large ZIP file with RUIAN data (~65 MB)...");
|
|
23
|
+
const response = yield fetch(url);
|
|
24
|
+
if (response.status !== 200) {
|
|
25
|
+
throw new Error(`The ZIP file could not be downloaded. HTTP Code: ${response.status}`);
|
|
26
|
+
}
|
|
27
|
+
yield pipeline(response.body, createWriteStream(zipFilePath));
|
|
28
|
+
console.log("Finished downloading.");
|
|
29
|
+
const zip = new AdmZip(zipFilePath);
|
|
30
|
+
console.log(`Starting to unzip CSV files to '${options.tmpDir}'`);
|
|
31
|
+
zip.extractAllTo(options.tmpDir, true);
|
|
32
|
+
console.log("Unzip completed.");
|
|
33
|
+
rmSync(zipFilePath);
|
|
34
|
+
console.log("Removed the ZIP file.");
|
|
35
|
+
});
|
|
36
|
+
const importDataToDb = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
const extractionFolder = getExtractionFolder(options);
|
|
38
|
+
const files = readdirSync(extractionFolder);
|
|
39
|
+
let total = 0;
|
|
40
|
+
let next = 0;
|
|
41
|
+
console.log("Initiating import of RUIAN data to search DB (~3 million rows to be imported).");
|
|
42
|
+
initDb(options);
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
const parseStream = parse({ delimiter: ";", fromLine: 2 }).on("data", (data) => {
|
|
45
|
+
total += importParsedLine(data);
|
|
46
|
+
if (total - next >= 100000) {
|
|
47
|
+
next += 100000;
|
|
48
|
+
console.log(`Total imported rows: ${next}`);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
yield pipeline(createReadStream(join(extractionFolder, file)), iconv.decodeStream("win1250"), parseStream);
|
|
52
|
+
total += commitAddressPoints();
|
|
53
|
+
}
|
|
54
|
+
console.log(`Import completed. Total imported rows: ${total}`);
|
|
55
|
+
});
|
|
56
|
+
const getExtractionFolder = (options) => join(options.tmpDir, options.addressPointsCsvFolderName);
|
|
57
|
+
export const downloadAndImportAllLatestAddressPoints = (options = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
|
+
const completeOptions = prepareOptions(options);
|
|
59
|
+
const datasetFeedLink = yield getLatestUrlFromAtomFeed(completeOptions.addressPointsAtomUrl);
|
|
60
|
+
const zipUrl = yield getLatestUrlFromAtomFeed(datasetFeedLink);
|
|
61
|
+
yield downloadAndUnzip(zipUrl, completeOptions);
|
|
62
|
+
yield importDataToDb(completeOptions);
|
|
63
|
+
});
|
|
64
|
+
export const importAllLatestAddressPoints = (options = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
|
+
const completeOptions = prepareOptions(options);
|
|
66
|
+
yield importDataToDb(completeOptions);
|
|
67
|
+
});
|
|
68
|
+
export const deleteDb = (options = {}) => {
|
|
69
|
+
const completeOptions = prepareOptions(options);
|
|
70
|
+
if (existsSync(completeOptions.dbFilePath)) {
|
|
71
|
+
rmSync(completeOptions.dbFilePath);
|
|
72
|
+
}
|
|
73
|
+
};
|