@vizabi/reader-ddfcsv 4.2.0 → 4.3.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.
- package/dist/reader-ddfcsv-polyfill.js +1 -1
- package/dist/reader-ddfcsv-polyfill.js.map +1 -1
- package/dist/reader-ddfcsv.js +7 -1
- package/dist/reader-ddfcsv.js.map +1 -1
- package/lib/src/ddf-csv.d.ts +1 -0
- package/lib/src/ddf-csv.js +20 -7
- package/lib/src/ddf-csv.js.map +1 -1
- package/lib/src/ddfcsv-reader.js +1 -1
- package/lib/src/interfaces.d.ts +1 -0
- package/lib/src/resource-selection-optimizer/in-clause-under-conjunction.d.ts +2 -2
- package/lib/src/resource-selection-optimizer/in-clause-under-conjunction.js +17 -42
- package/lib/src/resource-selection-optimizer/in-clause-under-conjunction.js.map +1 -1
- package/lib/src/resource-selection-optimizer/index.d.ts +1 -1
- package/lib/src/resource-selection-optimizer/index.js +2 -2
- package/lib/src/resource-selection-optimizer/index.js.map +1 -1
- package/lib-web/src/ddf-csv.d.ts +1 -0
- package/lib-web/src/ddf-csv.js +277 -378
- package/lib-web/src/ddf-csv.js.map +1 -1
- package/lib-web/src/ddfcsv-error.js +8 -12
- package/lib-web/src/ddfcsv-error.js.map +1 -1
- package/lib-web/src/ddfcsv-reader.js +81 -123
- package/lib-web/src/ddfcsv-reader.js.map +1 -1
- package/lib-web/src/file-readers/frontend-file-reader.js +13 -16
- package/lib-web/src/file-readers/frontend-file-reader.js.map +1 -1
- package/lib-web/src/file-readers/github-path-adapter.js +5 -5
- package/lib-web/src/file-readers/github-path-adapter.js.map +1 -1
- package/lib-web/src/index-web.js +2 -2
- package/lib-web/src/index-web.js.map +1 -1
- package/lib-web/src/interfaces.d.ts +1 -0
- package/lib-web/src/resource-selection-optimizer/in-clause-under-conjunction.d.ts +2 -2
- package/lib-web/src/resource-selection-optimizer/in-clause-under-conjunction.js +164 -368
- package/lib-web/src/resource-selection-optimizer/in-clause-under-conjunction.js.map +1 -1
- package/lib-web/src/resource-selection-optimizer/index.d.ts +1 -1
- package/lib-web/src/resource-selection-optimizer/index.js +6 -6
- package/lib-web/src/resource-selection-optimizer/index.js.map +1 -1
- package/package.json +3 -2
- package/src/ddf-csv.ts +22 -17
- package/src/interfaces.ts +1 -0
- package/src/resource-selection-optimizer/in-clause-under-conjunction.ts +16 -45
- package/src/resource-selection-optimizer/index.ts +2 -2
- package/tsconfig-web.json +1 -1
package/lib-web/src/ddf-csv.js
CHANGED
|
@@ -1,48 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ddfCsvReader = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var d3_time_format_1 = require("d3-time-format");
|
|
14
|
-
var isValidNumeric = function (val) { return typeof val !== 'number' && !val ? false : true; };
|
|
4
|
+
const includes = require("lodash.includes");
|
|
5
|
+
const isEmpty = require("lodash.isempty");
|
|
6
|
+
const stripBom = require("strip-bom");
|
|
7
|
+
const resource_selection_optimizer_1 = require("./resource-selection-optimizer");
|
|
8
|
+
const ddfcsv_error_1 = require("./ddfcsv-error");
|
|
9
|
+
const ddf_query_validator_1 = require("ddf-query-validator");
|
|
10
|
+
const Papa = require("papaparse");
|
|
11
|
+
const d3_time_format_1 = require("d3-time-format");
|
|
12
|
+
const isValidNumeric = val => typeof val !== 'number' && !val ? false : true;
|
|
15
13
|
function ddfCsvReader(logger) {
|
|
16
|
-
|
|
14
|
+
const internalConcepts = [
|
|
17
15
|
{ concept: 'concept', concept_type: 'string', domain: null },
|
|
18
16
|
{ concept: 'concept_type', concept_type: 'string', domain: null }
|
|
19
17
|
];
|
|
20
|
-
|
|
21
|
-
['$and',
|
|
22
|
-
['$or',
|
|
23
|
-
['$not',
|
|
24
|
-
['$nor',
|
|
25
|
-
['$eq',
|
|
26
|
-
['$ne',
|
|
27
|
-
['$gt',
|
|
28
|
-
['$gte',
|
|
29
|
-
['$lt',
|
|
30
|
-
['$lte',
|
|
31
|
-
['$in',
|
|
32
|
-
['$nin',
|
|
18
|
+
const operators = new Map([
|
|
19
|
+
['$and', (row, predicates) => predicates.every(p => applyFilterRow(row, p))],
|
|
20
|
+
['$or', (row, predicates) => predicates.some(p => applyFilterRow(row, p))],
|
|
21
|
+
['$not', (row, predicate) => !applyFilterRow(row, predicate)],
|
|
22
|
+
['$nor', (row, predicates) => !predicates.some(p => applyFilterRow(row, p))],
|
|
23
|
+
['$eq', (rowValue, filterValue) => rowValue == filterValue],
|
|
24
|
+
['$ne', (rowValue, filterValue) => rowValue != filterValue],
|
|
25
|
+
['$gt', (rowValue, filterValue) => isValidNumeric(rowValue) && rowValue > filterValue],
|
|
26
|
+
['$gte', (rowValue, filterValue) => isValidNumeric(rowValue) && rowValue >= filterValue],
|
|
27
|
+
['$lt', (rowValue, filterValue) => isValidNumeric(rowValue) && rowValue < filterValue],
|
|
28
|
+
['$lte', (rowValue, filterValue) => isValidNumeric(rowValue) && rowValue <= filterValue],
|
|
29
|
+
['$in', (rowValue, filterValue) => filterValue.has(rowValue)],
|
|
30
|
+
['$nin', (rowValue, filterValue) => !filterValue.has(rowValue)],
|
|
33
31
|
]);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
const keyValueLookup = new Map();
|
|
33
|
+
const resourcesLookup = new Map();
|
|
34
|
+
let optimalFilesSet = [];
|
|
35
|
+
let datapackage;
|
|
36
|
+
let datapackagePromise;
|
|
38
37
|
function loadDataPackage(baseOptions) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return new Promise(
|
|
38
|
+
const datapackagePath = (0, ddf_query_validator_1.getFilePath)(baseOptions.basePath);
|
|
39
|
+
const { debug, error } = baseOptions.diagnostic.prepareDiagnosticFor('loadDataPackage');
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
42
41
|
if (datapackage) {
|
|
43
42
|
return resolve(datapackage);
|
|
44
43
|
}
|
|
45
|
-
baseOptions.fileReader.readText(datapackagePath,
|
|
44
|
+
baseOptions.fileReader.readText(datapackagePath, (err, data) => {
|
|
46
45
|
if (err) {
|
|
47
46
|
error('file reading', err);
|
|
48
47
|
return reject(new ddfcsv_error_1.DdfCsvError(ddfcsv_error_1.FILE_READING_ERROR, err, datapackagePath));
|
|
@@ -62,83 +61,58 @@ function ddfCsvReader(logger) {
|
|
|
62
61
|
});
|
|
63
62
|
});
|
|
64
63
|
}
|
|
65
|
-
function loadConcepts(queryParam, options) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
buildConceptsLookup(concepts, options);
|
|
84
|
-
return [4, reparseConcepts(options)];
|
|
85
|
-
case 3:
|
|
86
|
-
result = _a.sent();
|
|
87
|
-
return [3, 5];
|
|
88
|
-
case 4:
|
|
89
|
-
err_1 = _a.sent();
|
|
90
|
-
error('concepts processing', err_1);
|
|
91
|
-
throw err_1;
|
|
92
|
-
case 5: return [2, result];
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
});
|
|
64
|
+
async function loadConcepts(queryParam, options) {
|
|
65
|
+
const { error } = options.diagnostic.prepareDiagnosticFor('loadConcepts');
|
|
66
|
+
setConceptsLookup(internalConcepts, options);
|
|
67
|
+
const conceptQuery = {
|
|
68
|
+
select: { key: ['concept'], value: ['concept_type', 'domain'] },
|
|
69
|
+
from: 'concepts'
|
|
70
|
+
};
|
|
71
|
+
let result;
|
|
72
|
+
try {
|
|
73
|
+
const concepts = await queryData(conceptQuery, options);
|
|
74
|
+
buildConceptsLookup(concepts, options);
|
|
75
|
+
result = await reparseConcepts(options);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
error('concepts processing', err);
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
96
82
|
}
|
|
97
83
|
function buildConceptsLookup(concepts, options) {
|
|
98
|
-
|
|
99
|
-
.filter(
|
|
100
|
-
.map(
|
|
84
|
+
const entitySetMembershipConcepts = concepts
|
|
85
|
+
.filter(concept => concept.concept_type === 'entity_set')
|
|
86
|
+
.map(concept => ({
|
|
101
87
|
concept: 'is--' + concept.concept,
|
|
102
88
|
concept_type: 'boolean',
|
|
103
89
|
domain: null
|
|
104
|
-
})
|
|
90
|
+
}));
|
|
105
91
|
concepts = concepts
|
|
106
92
|
.concat(entitySetMembershipConcepts)
|
|
107
93
|
.concat(internalConcepts);
|
|
108
94
|
setConceptsLookup(concepts, options);
|
|
109
95
|
}
|
|
110
|
-
function reparseConcepts(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
['
|
|
114
|
-
['measure', function (str) { return parseFloat(str); }]
|
|
96
|
+
function reparseConcepts({ conceptsLookup }) {
|
|
97
|
+
const parsingFunctions = new Map([
|
|
98
|
+
['boolean', (str) => str === 'true' || str === 'TRUE'],
|
|
99
|
+
['measure', (str) => parseFloat(str)]
|
|
115
100
|
]);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return resource.data.then(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
resourceConcepts.forEach(
|
|
122
|
-
|
|
123
|
-
|
|
101
|
+
const resources = getResources(['concept']);
|
|
102
|
+
const resourceUpdates = [...resources].map(resource => {
|
|
103
|
+
return resource.data.then(response => {
|
|
104
|
+
const resourceConcepts = Object.keys(response.data[0]);
|
|
105
|
+
const parsingConcepts = new Map();
|
|
106
|
+
resourceConcepts.forEach(concept => {
|
|
107
|
+
const type = conceptsLookup.get(concept).concept_type;
|
|
108
|
+
const fn = parsingFunctions.get(type);
|
|
124
109
|
if (fn) {
|
|
125
110
|
parsingConcepts.set(concept, fn);
|
|
126
111
|
}
|
|
127
112
|
});
|
|
128
|
-
return response.data.forEach(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
for (var parsingConcepts_1 = tslib_1.__values(parsingConcepts), parsingConcepts_1_1 = parsingConcepts_1.next(); !parsingConcepts_1_1.done; parsingConcepts_1_1 = parsingConcepts_1.next()) {
|
|
132
|
-
var _b = tslib_1.__read(parsingConcepts_1_1.value, 2), concept = _b[0], parseFn = _b[1];
|
|
133
|
-
row[concept] = parseFn(row[concept]);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
137
|
-
finally {
|
|
138
|
-
try {
|
|
139
|
-
if (parsingConcepts_1_1 && !parsingConcepts_1_1.done && (_a = parsingConcepts_1.return)) _a.call(parsingConcepts_1);
|
|
140
|
-
}
|
|
141
|
-
finally { if (e_1) throw e_1.error; }
|
|
113
|
+
return response.data.forEach(row => {
|
|
114
|
+
for (const [concept, parseFn] of parsingConcepts) {
|
|
115
|
+
row[concept] = parseFn(row[concept]);
|
|
142
116
|
}
|
|
143
117
|
});
|
|
144
118
|
});
|
|
@@ -147,84 +121,61 @@ function ddfCsvReader(logger) {
|
|
|
147
121
|
}
|
|
148
122
|
function setConceptsLookup(concepts, options) {
|
|
149
123
|
options.conceptsLookup.clear();
|
|
150
|
-
concepts.forEach(
|
|
151
|
-
}
|
|
152
|
-
function query(queryParam, baseOptions) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return [4, (0, ddf_query_validator_1.validateQueryDefinitions)(queryParam, baseOptions)];
|
|
173
|
-
case 5:
|
|
174
|
-
_c.sent();
|
|
175
|
-
if (!(0, ddf_query_validator_1.isSchemaQuery)(queryParam)) return [3, 7];
|
|
176
|
-
return [4, querySchema(queryParam, baseOptions)];
|
|
177
|
-
case 6:
|
|
178
|
-
data = _c.sent();
|
|
179
|
-
return [3, 11];
|
|
180
|
-
case 7:
|
|
181
|
-
appropriatePlugin = (0, resource_selection_optimizer_1.getAppropriatePlugin)(queryParam, baseOptions);
|
|
182
|
-
if (!appropriatePlugin) return [3, 9];
|
|
183
|
-
optimalFilesSet = [];
|
|
184
|
-
return [4, appropriatePlugin.getRecommendedFilesSet()];
|
|
185
|
-
case 8:
|
|
186
|
-
files = _c.sent();
|
|
187
|
-
optimalFilesSet = files;
|
|
188
|
-
queryParam.optimalFilesSet = [].concat(files, queryParam.optimalFilesSet);
|
|
189
|
-
warning('get custom optimal files list by a plugin', optimalFilesSet);
|
|
190
|
-
_c.label = 9;
|
|
191
|
-
case 9: return [4, queryData(queryParam, baseOptions)];
|
|
192
|
-
case 10:
|
|
193
|
-
data = _c.sent();
|
|
194
|
-
_c.label = 11;
|
|
195
|
-
case 11: return [3, 13];
|
|
196
|
-
case 12:
|
|
197
|
-
err_2 = _c.sent();
|
|
198
|
-
error('general query error', err_2);
|
|
199
|
-
throw err_2;
|
|
200
|
-
case 13: return [2, data];
|
|
124
|
+
concepts.forEach(row => options.conceptsLookup.set(row.concept, row));
|
|
125
|
+
}
|
|
126
|
+
async function query(queryParam, baseOptions) {
|
|
127
|
+
const { warning, error } = baseOptions.diagnostic.prepareDiagnosticFor('query');
|
|
128
|
+
let data;
|
|
129
|
+
try {
|
|
130
|
+
await (0, ddf_query_validator_1.validateQueryStructure)(queryParam, baseOptions);
|
|
131
|
+
baseOptions.datapackage = await (datapackagePromise || (datapackagePromise = loadDataPackage(baseOptions)));
|
|
132
|
+
baseOptions.resourcesLookup = resourcesLookup;
|
|
133
|
+
await loadConcepts(queryParam, baseOptions);
|
|
134
|
+
await (0, ddf_query_validator_1.validateQueryDefinitions)(queryParam, baseOptions);
|
|
135
|
+
if ((0, ddf_query_validator_1.isSchemaQuery)(queryParam)) {
|
|
136
|
+
data = await querySchema(queryParam, baseOptions);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const appropriatePlugin = (0, resource_selection_optimizer_1.getAppropriatePlugin)(this, queryParam, baseOptions);
|
|
140
|
+
if (appropriatePlugin) {
|
|
141
|
+
optimalFilesSet = [];
|
|
142
|
+
const files = await appropriatePlugin.getRecommendedFilesSet();
|
|
143
|
+
optimalFilesSet = files;
|
|
144
|
+
queryParam.optimalFilesSet = [].concat(files, queryParam.optimalFilesSet);
|
|
145
|
+
warning('get custom optimal files list by a plugin', optimalFilesSet);
|
|
201
146
|
}
|
|
202
|
-
|
|
203
|
-
|
|
147
|
+
data = await queryData(queryParam, baseOptions);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
error('general query error', err);
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
return data;
|
|
204
155
|
}
|
|
205
156
|
function queryData(queryParam, options) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
157
|
+
const { debug } = options.diagnostic.prepareDiagnosticFor('queryData');
|
|
158
|
+
const { select: { key = [], value = [] }, from = '', where = {}, join = {}, order_by = [], language } = queryParam;
|
|
159
|
+
const select = { key, value };
|
|
209
160
|
debug('start all data loading', queryParam);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
161
|
+
const projection = new Set(select.key.concat(select.value));
|
|
162
|
+
const filterFields = getFilterFields(where).filter(field => from === 'entities' || !projection.has(field));
|
|
163
|
+
const resourcesPromise = loadResources(select.key, [...select.value, ...filterFields], language, options, queryParam);
|
|
164
|
+
const joinsPromise = getJoinFilters(join, queryParam, options);
|
|
165
|
+
const entitySetFilterPromise = getEntitySetFilter(select.key, queryParam, options);
|
|
215
166
|
return Promise.all([resourcesPromise, entitySetFilterPromise, joinsPromise])
|
|
216
|
-
.then(
|
|
217
|
-
var _b = tslib_1.__read(_a, 3), resourceResponses = _b[0], entitySetFilter = _b[1], joinFilters = _b[2];
|
|
167
|
+
.then(([resourceResponses, entitySetFilter, joinFilters]) => {
|
|
218
168
|
debug('finish all data loading', queryParam);
|
|
219
|
-
|
|
220
|
-
|
|
169
|
+
const whereResolved = processWhere(where, joinFilters);
|
|
170
|
+
const filter = mergeFilters(entitySetFilter, whereResolved);
|
|
221
171
|
debug('dataTables processing', queryParam);
|
|
222
|
-
|
|
223
|
-
.map(
|
|
172
|
+
const dataTables = resourceResponses
|
|
173
|
+
.map(response => processResourceResponse(response, select, filterFields, options));
|
|
224
174
|
debug('queryResult processing', queryParam);
|
|
225
|
-
|
|
226
|
-
.
|
|
227
|
-
.map(
|
|
175
|
+
const queryResult = joinData(select.key, 'overwrite', ...dataTables)
|
|
176
|
+
.filter(row => applyFilterRow(row, filter))
|
|
177
|
+
.map(row => fillMissingValues(row, projection))
|
|
178
|
+
.map(row => projectRow(row, projection));
|
|
228
179
|
debug('result ordering', queryParam);
|
|
229
180
|
orderData(queryResult, order_by);
|
|
230
181
|
debug('final result is ready', queryParam);
|
|
@@ -232,21 +183,20 @@ function ddfCsvReader(logger) {
|
|
|
232
183
|
});
|
|
233
184
|
}
|
|
234
185
|
function parseTime(result, options) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
timeConcepts.forEach(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
result.forEach(function (row) {
|
|
186
|
+
const conceptsLookup = options.conceptsLookup;
|
|
187
|
+
const concepts = Object.keys(result[0] || {});
|
|
188
|
+
const timeConcepts = concepts.map(c => conceptsLookup.get(c) || {}).filter(co => co.concept_type == 'time');
|
|
189
|
+
timeConcepts.forEach(({ concept }) => {
|
|
190
|
+
const parse = getTimeParser(concept, options);
|
|
191
|
+
result.forEach(row => {
|
|
242
192
|
row[concept] = parse(row[concept]);
|
|
243
193
|
});
|
|
244
194
|
});
|
|
245
195
|
return result;
|
|
246
196
|
}
|
|
247
197
|
function getTimeParser(concept, options) {
|
|
248
|
-
|
|
249
|
-
|
|
198
|
+
const { error } = options.diagnostic.prepareDiagnosticFor('queryData');
|
|
199
|
+
const parsers = {
|
|
250
200
|
year: (0, d3_time_format_1.utcParse)('%Y'),
|
|
251
201
|
month: (0, d3_time_format_1.utcParse)('%Y-%m'),
|
|
252
202
|
day: (0, d3_time_format_1.utcParse)('%Y%m%d'),
|
|
@@ -257,8 +207,8 @@ function ddfCsvReader(logger) {
|
|
|
257
207
|
quarter: (0, d3_time_format_1.utcParse)('%Yq%q')
|
|
258
208
|
};
|
|
259
209
|
function tryParse(str) {
|
|
260
|
-
for (
|
|
261
|
-
|
|
210
|
+
for (const i in parsers) {
|
|
211
|
+
const dateObject = parsers[i](str);
|
|
262
212
|
if (dateObject) {
|
|
263
213
|
return dateObject;
|
|
264
214
|
}
|
|
@@ -271,29 +221,28 @@ function ddfCsvReader(logger) {
|
|
|
271
221
|
}
|
|
272
222
|
if (!parsers[concept]) {
|
|
273
223
|
error('No time parser found for time concept: ' + concept);
|
|
274
|
-
return
|
|
224
|
+
return str => str;
|
|
275
225
|
}
|
|
276
226
|
return parsers[concept];
|
|
277
227
|
}
|
|
278
|
-
function orderData(data, orderBy) {
|
|
279
|
-
if (orderBy === void 0) { orderBy = []; }
|
|
228
|
+
function orderData(data, orderBy = []) {
|
|
280
229
|
if (orderBy.length === 0) {
|
|
281
230
|
return;
|
|
282
231
|
}
|
|
283
|
-
|
|
232
|
+
const orderNormalized = orderBy.map(orderPart => {
|
|
284
233
|
if (typeof orderPart === 'string') {
|
|
285
234
|
return { concept: orderPart, direction: 1 };
|
|
286
235
|
}
|
|
287
236
|
else {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
return { concept
|
|
237
|
+
const concept = Object.keys(orderPart)[0];
|
|
238
|
+
const direction = (orderPart[concept] === 'asc' ? 1 : -1);
|
|
239
|
+
return { concept, direction };
|
|
291
240
|
}
|
|
292
241
|
});
|
|
293
|
-
|
|
294
|
-
data.sort(
|
|
295
|
-
for (
|
|
296
|
-
|
|
242
|
+
const n = orderNormalized.length;
|
|
243
|
+
data.sort((a, b) => {
|
|
244
|
+
for (let i = 0; i < n; i++) {
|
|
245
|
+
const order = orderNormalized[i];
|
|
297
246
|
if (a[order.concept] < b[order.concept]) {
|
|
298
247
|
return -1 * order.direction;
|
|
299
248
|
}
|
|
@@ -305,11 +254,11 @@ function ddfCsvReader(logger) {
|
|
|
305
254
|
});
|
|
306
255
|
}
|
|
307
256
|
function processWhere(where, joinFilters) {
|
|
308
|
-
|
|
309
|
-
for (
|
|
310
|
-
|
|
257
|
+
const result = {};
|
|
258
|
+
for (const field in where) {
|
|
259
|
+
const fieldValue = where[field];
|
|
311
260
|
if (includes(['$and', '$or', '$nor'], field)) {
|
|
312
|
-
result[field] = fieldValue.map(
|
|
261
|
+
result[field] = fieldValue.map(subFilter => processWhere(subFilter, joinFilters));
|
|
313
262
|
}
|
|
314
263
|
else if (field === '$in' || field === '$nin') {
|
|
315
264
|
result[field] = new Set(fieldValue);
|
|
@@ -326,62 +275,44 @@ function ddfCsvReader(logger) {
|
|
|
326
275
|
}
|
|
327
276
|
return result;
|
|
328
277
|
}
|
|
329
|
-
function mergeFilters() {
|
|
330
|
-
|
|
331
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
332
|
-
filters[_i] = arguments[_i];
|
|
333
|
-
}
|
|
334
|
-
return filters.reduce(function (a, b) {
|
|
278
|
+
function mergeFilters(...filters) {
|
|
279
|
+
return filters.reduce((a, b) => {
|
|
335
280
|
a.$and.push(b);
|
|
336
281
|
return a;
|
|
337
282
|
}, { $and: [] });
|
|
338
283
|
}
|
|
339
284
|
function querySchema(queryParam, baseOptions) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
debug(
|
|
343
|
-
return baseOptions.datapackage.ddfSchema[collectionPar].map(
|
|
344
|
-
var primaryKey = _a.primaryKey, value = _a.value;
|
|
345
|
-
return ({ key: primaryKey, value: value });
|
|
346
|
-
});
|
|
285
|
+
const { debug, error } = baseOptions.diagnostic.prepareDiagnosticFor('query');
|
|
286
|
+
const getSchemaFromCollection = collectionPar => {
|
|
287
|
+
debug(`get schema for collection ${collectionPar}`);
|
|
288
|
+
return baseOptions.datapackage.ddfSchema[collectionPar].map(({ primaryKey, value }) => ({ key: primaryKey, value }));
|
|
347
289
|
};
|
|
348
|
-
|
|
290
|
+
const collection = queryParam.from.split('.')[0];
|
|
349
291
|
if (baseOptions.datapackage.ddfSchema[collection]) {
|
|
350
292
|
return getSchemaFromCollection(collection);
|
|
351
293
|
}
|
|
352
294
|
else if (collection === '*') {
|
|
353
295
|
return Object.keys(baseOptions.datapackage.ddfSchema)
|
|
354
296
|
.map(getSchemaFromCollection)
|
|
355
|
-
.reduce(
|
|
297
|
+
.reduce((a, b) => a.concat(b));
|
|
356
298
|
}
|
|
357
299
|
else {
|
|
358
|
-
|
|
300
|
+
const message = `No valid collection (${collection}) for schema query`;
|
|
359
301
|
error(message);
|
|
360
302
|
throwError(new ddfcsv_error_1.DdfCsvError(ddfcsv_error_1.DDF_ERROR, message));
|
|
361
303
|
}
|
|
362
304
|
}
|
|
363
305
|
function fillMissingValues(row, projection) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
var field = projection_1_1.value;
|
|
368
|
-
if (typeof row[field] === 'undefined') {
|
|
369
|
-
row[field] = null;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
374
|
-
finally {
|
|
375
|
-
try {
|
|
376
|
-
if (projection_1_1 && !projection_1_1.done && (_a = projection_1.return)) _a.call(projection_1);
|
|
306
|
+
for (const field of projection) {
|
|
307
|
+
if (typeof row[field] === 'undefined') {
|
|
308
|
+
row[field] = null;
|
|
377
309
|
}
|
|
378
|
-
finally { if (e_2) throw e_2.error; }
|
|
379
310
|
}
|
|
380
311
|
return row;
|
|
381
312
|
}
|
|
382
313
|
function applyFilterRow(row, filter) {
|
|
383
|
-
return Object.keys(filter).every(
|
|
384
|
-
|
|
314
|
+
return Object.keys(filter).every(filterKey => {
|
|
315
|
+
const operator = operators.get(filterKey);
|
|
385
316
|
if (operator) {
|
|
386
317
|
return operator(row, filter[filterKey]);
|
|
387
318
|
}
|
|
@@ -394,80 +325,65 @@ function ddfCsvReader(logger) {
|
|
|
394
325
|
});
|
|
395
326
|
}
|
|
396
327
|
function getJoinFilters(join, queryParam, options) {
|
|
397
|
-
return Promise.all(Object.keys(join).map(
|
|
398
|
-
.then(
|
|
328
|
+
return Promise.all(Object.keys(join).map(joinID => getJoinFilter(joinID, join[joinID], queryParam, options)))
|
|
329
|
+
.then(results => results.reduce(mergeObjects, {}));
|
|
399
330
|
}
|
|
400
331
|
function mergeObjects(a, b) {
|
|
401
332
|
return Object.assign(a, b);
|
|
402
333
|
}
|
|
403
334
|
function getJoinFilter(joinID, join, queryParam, options) {
|
|
404
|
-
var _a;
|
|
405
335
|
if (options.conceptsLookup.get(join.key).concept_type === 'time') {
|
|
406
|
-
return Promise.resolve(
|
|
336
|
+
return Promise.resolve({ [joinID]: join.where });
|
|
407
337
|
}
|
|
408
338
|
else {
|
|
409
339
|
return query({
|
|
410
340
|
select: { key: [join.key] },
|
|
411
341
|
where: join.where,
|
|
412
342
|
from: options.conceptsLookup.has(join.key) ? 'entities' : 'concepts'
|
|
413
|
-
}, Object.assign({ joinID
|
|
414
|
-
.then(
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
_b),
|
|
422
|
-
_a);
|
|
423
|
-
});
|
|
343
|
+
}, Object.assign({ joinID }, options))
|
|
344
|
+
.then(result => ({
|
|
345
|
+
[joinID]: {
|
|
346
|
+
[join.key]: {
|
|
347
|
+
$in: new Set(result.map(row => row[join.key]))
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}));
|
|
424
351
|
}
|
|
425
352
|
}
|
|
426
353
|
function getFilterFields(filter) {
|
|
427
|
-
|
|
428
|
-
for (
|
|
354
|
+
const fields = [];
|
|
355
|
+
for (const field in filter) {
|
|
429
356
|
if (includes(['$and', '$or', '$not', '$nor'], field)) {
|
|
430
|
-
filter[field].map(getFilterFields).forEach(
|
|
357
|
+
filter[field].map(getFilterFields).forEach(subFields => fields.push(...subFields));
|
|
431
358
|
}
|
|
432
359
|
else {
|
|
433
360
|
fields.push(field);
|
|
434
361
|
}
|
|
435
362
|
}
|
|
436
|
-
return
|
|
363
|
+
return [...new Set(fields)];
|
|
437
364
|
}
|
|
438
365
|
function filterConceptsByType(conceptTypes, queryKey, options) {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
var concept = options.conceptsLookup.get(conceptString);
|
|
446
|
-
if (includes(conceptTypes, concept.concept_type)) {
|
|
447
|
-
concepts.push(concept);
|
|
448
|
-
}
|
|
366
|
+
const conceptStrings = queryKey || Array.from(options.conceptsLookup.keys());
|
|
367
|
+
const concepts = [];
|
|
368
|
+
for (const conceptString of conceptStrings) {
|
|
369
|
+
const concept = options.conceptsLookup.get(conceptString);
|
|
370
|
+
if (includes(conceptTypes, concept.concept_type)) {
|
|
371
|
+
concepts.push(concept);
|
|
449
372
|
}
|
|
450
373
|
}
|
|
451
|
-
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
452
|
-
finally {
|
|
453
|
-
try {
|
|
454
|
-
if (conceptStrings_1_1 && !conceptStrings_1_1.done && (_a = conceptStrings_1.return)) _a.call(conceptStrings_1);
|
|
455
|
-
}
|
|
456
|
-
finally { if (e_3) throw e_3.error; }
|
|
457
|
-
}
|
|
458
374
|
return concepts;
|
|
459
375
|
}
|
|
460
376
|
function getEntityConceptRenameMap(queryKey, resourceKey, options) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
377
|
+
const resourceKeySet = new Set(resourceKey);
|
|
378
|
+
const entityConceptTypes = ['entity_set', 'entity_domain'];
|
|
379
|
+
const queryEntityConcepts = filterConceptsByType(entityConceptTypes, queryKey, options);
|
|
464
380
|
if (queryEntityConcepts.length === 0) {
|
|
465
381
|
return new Map();
|
|
466
382
|
}
|
|
467
|
-
|
|
383
|
+
const allEntityConcepts = filterConceptsByType(entityConceptTypes, null, options);
|
|
468
384
|
return queryEntityConcepts
|
|
469
|
-
.map(
|
|
470
|
-
.filter(
|
|
385
|
+
.map(concept => allEntityConcepts
|
|
386
|
+
.filter(lookupConcept => {
|
|
471
387
|
if (concept.concept_type === 'entity_set') {
|
|
472
388
|
return resourceKeySet.has(lookupConcept.concept) &&
|
|
473
389
|
lookupConcept.concept !== concept.concept &&
|
|
@@ -480,114 +396,86 @@ function ddfCsvReader(logger) {
|
|
|
480
396
|
lookupConcept.domain === concept.concept;
|
|
481
397
|
}
|
|
482
398
|
})
|
|
483
|
-
.reduce(
|
|
399
|
+
.reduce((map, aliasConcept) => map.set(aliasConcept.concept, concept.concept), new Map())).reduce((mapA, mapB) => new Map([...mapA, ...mapB]), new Map());
|
|
484
400
|
}
|
|
485
401
|
function getEntitySetFilter(conceptStrings, queryParam, options) {
|
|
486
|
-
|
|
487
|
-
.map(
|
|
402
|
+
const promises = filterConceptsByType(['entity_set'], conceptStrings, options)
|
|
403
|
+
.map(concept => query({
|
|
488
404
|
select: { key: [concept.domain], value: ['is--' + concept.concept] },
|
|
489
405
|
from: 'entities'
|
|
490
|
-
}, Object.assign({},
|
|
491
|
-
.then(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
}); });
|
|
501
|
-
return Promise.all(promises).then(function (results) {
|
|
502
|
-
return results.reduce(function (a, b) { return Object.assign(a, b); }, {});
|
|
406
|
+
}, Object.assign({}, options))
|
|
407
|
+
.then(result => ({
|
|
408
|
+
[concept.concept]: {
|
|
409
|
+
$in: new Set(result
|
|
410
|
+
.filter(row => row['is--' + concept.concept])
|
|
411
|
+
.map(row => row[concept.domain]))
|
|
412
|
+
}
|
|
413
|
+
})));
|
|
414
|
+
return Promise.all(promises).then(results => {
|
|
415
|
+
return results.reduce((a, b) => Object.assign(a, b), {});
|
|
503
416
|
});
|
|
504
417
|
}
|
|
505
418
|
function getResources(key, value) {
|
|
506
419
|
if (!value || value.length === 0 || key[0] === value) {
|
|
507
|
-
return new Set(
|
|
508
|
-
|
|
509
|
-
|
|
420
|
+
return new Set([...keyValueLookup
|
|
421
|
+
.get(createKeyString(key))
|
|
422
|
+
.values()
|
|
423
|
+
].reduce((a, b) => a.concat(b)));
|
|
510
424
|
}
|
|
511
425
|
if (Array.isArray(value)) {
|
|
512
426
|
return value
|
|
513
|
-
.map(
|
|
514
|
-
.reduce(
|
|
427
|
+
.map(singleValue => getResources(key, singleValue))
|
|
428
|
+
.reduce((resultSet, resources) => new Set([...resultSet, ...resources]), new Set());
|
|
515
429
|
}
|
|
516
|
-
|
|
430
|
+
let oneKeyOneValueResourcesArray = keyValueLookup
|
|
517
431
|
.get(createKeyString(key))
|
|
518
432
|
.get(value);
|
|
519
433
|
if (oneKeyOneValueResourcesArray) {
|
|
520
434
|
oneKeyOneValueResourcesArray = oneKeyOneValueResourcesArray
|
|
521
|
-
.filter(
|
|
435
|
+
.filter(v => isEmpty(optimalFilesSet) || includes(optimalFilesSet, v.path));
|
|
522
436
|
}
|
|
523
437
|
return new Set(oneKeyOneValueResourcesArray);
|
|
524
438
|
}
|
|
525
439
|
function processResourceResponse(response, select, filterFields, options) {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
440
|
+
const resourcePK = response.resource.schema.primaryKey;
|
|
441
|
+
const resourceProjection = new Set([...resourcePK, ...select.value, ...filterFields]);
|
|
442
|
+
const renameMap = getEntityConceptRenameMap(select.key, resourcePK, options);
|
|
529
443
|
return response.data
|
|
530
|
-
.map(
|
|
531
|
-
.map(
|
|
444
|
+
.map(row => projectRow(row, resourceProjection))
|
|
445
|
+
.map(row => renameHeaderRow(row, renameMap));
|
|
532
446
|
}
|
|
533
447
|
function loadResources(key, value, language, options, queryParam) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
debug('resources list by query', { queryParam
|
|
537
|
-
return Promise.all(
|
|
448
|
+
const { debug } = options.diagnostic.prepareDiagnosticFor('loadResource');
|
|
449
|
+
const resources = getResources(key, value);
|
|
450
|
+
debug('resources list by query', { queryParam, resources: [...resources] });
|
|
451
|
+
return Promise.all([...resources].map(resource => loadResource(resource, language, options)));
|
|
538
452
|
}
|
|
539
453
|
function projectRow(row, projectionSet) {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
var concept = _c.value;
|
|
545
|
-
if (projectionSet.has(concept)) {
|
|
546
|
-
result[concept] = row[concept];
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
551
|
-
finally {
|
|
552
|
-
try {
|
|
553
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
454
|
+
const result = {};
|
|
455
|
+
for (const concept of Object.keys(row)) {
|
|
456
|
+
if (projectionSet.has(concept)) {
|
|
457
|
+
result[concept] = row[concept];
|
|
554
458
|
}
|
|
555
|
-
finally { if (e_4) throw e_4.error; }
|
|
556
459
|
}
|
|
557
460
|
return result;
|
|
558
461
|
}
|
|
559
462
|
function renameHeaderRow(row, renameMap) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
for (var _b = tslib_1.__values(Object.keys(row)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
564
|
-
var concept = _c.value;
|
|
565
|
-
result[renameMap.get(concept) || concept] = row[concept];
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
569
|
-
finally {
|
|
570
|
-
try {
|
|
571
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
572
|
-
}
|
|
573
|
-
finally { if (e_5) throw e_5.error; }
|
|
463
|
+
const result = {};
|
|
464
|
+
for (const concept of Object.keys(row)) {
|
|
465
|
+
result[renameMap.get(concept) || concept] = row[concept];
|
|
574
466
|
}
|
|
575
467
|
return result;
|
|
576
468
|
}
|
|
577
|
-
function joinData(key, joinMode) {
|
|
578
|
-
var data = [];
|
|
579
|
-
for (var _i = 2; _i < arguments.length; _i++) {
|
|
580
|
-
data[_i - 2] = arguments[_i];
|
|
581
|
-
}
|
|
469
|
+
function joinData(key, joinMode, ...data) {
|
|
582
470
|
if (data.length === 1) {
|
|
583
471
|
return data[0];
|
|
584
472
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
dataPar.forEach(
|
|
588
|
-
|
|
473
|
+
const canonicalKey = key.slice(0).sort();
|
|
474
|
+
const dataMap = data.reduce((result, dataPar) => {
|
|
475
|
+
dataPar.forEach(row => {
|
|
476
|
+
const keyString = canonicalKey.map(concept => row[concept]).join(',');
|
|
589
477
|
if (result.has(keyString)) {
|
|
590
|
-
|
|
478
|
+
const resultRow = result.get(keyString);
|
|
591
479
|
joinRow(resultRow, row, joinMode);
|
|
592
480
|
}
|
|
593
481
|
else {
|
|
@@ -596,7 +484,7 @@ function ddfCsvReader(logger) {
|
|
|
596
484
|
});
|
|
597
485
|
return result;
|
|
598
486
|
}, new Map());
|
|
599
|
-
return
|
|
487
|
+
return [...dataMap.values()];
|
|
600
488
|
}
|
|
601
489
|
function joinRow(resultRow, sourceRow, mode) {
|
|
602
490
|
switch (mode) {
|
|
@@ -604,18 +492,18 @@ function ddfCsvReader(logger) {
|
|
|
604
492
|
Object.assign(resultRow, sourceRow);
|
|
605
493
|
break;
|
|
606
494
|
case 'translation':
|
|
607
|
-
for (
|
|
495
|
+
for (const concept in sourceRow) {
|
|
608
496
|
if (sourceRow[concept] !== '') {
|
|
609
497
|
resultRow[concept] = sourceRow[concept];
|
|
610
498
|
}
|
|
611
499
|
}
|
|
612
500
|
break;
|
|
613
501
|
case 'overwriteWithError':
|
|
614
|
-
for (
|
|
502
|
+
for (const concept in sourceRow) {
|
|
615
503
|
if (resultRow[concept] !== undefined && resultRow[concept] !== sourceRow[concept]) {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
504
|
+
const sourceRowStr = JSON.stringify(sourceRow);
|
|
505
|
+
const resultRowStr = JSON.stringify(resultRow);
|
|
506
|
+
const errStr = `JOIN Error: two resources have different data for "${concept}": ${sourceRowStr},${resultRowStr}`;
|
|
619
507
|
throwError(new ddfcsv_error_1.DdfCsvError(ddfcsv_error_1.DDF_ERROR, errStr));
|
|
620
508
|
}
|
|
621
509
|
else {
|
|
@@ -626,73 +514,75 @@ function ddfCsvReader(logger) {
|
|
|
626
514
|
}
|
|
627
515
|
}
|
|
628
516
|
function throwError(error) {
|
|
629
|
-
|
|
517
|
+
const currentLogger = logger || console;
|
|
630
518
|
currentLogger.error(error.message);
|
|
631
519
|
throw error;
|
|
632
520
|
}
|
|
633
|
-
function createKeyString(key, row) {
|
|
634
|
-
|
|
635
|
-
var canonicalKey = key.slice(0).sort();
|
|
521
|
+
function createKeyString(key, row = false) {
|
|
522
|
+
const canonicalKey = key.slice(0).sort();
|
|
636
523
|
if (!row) {
|
|
637
524
|
return canonicalKey.join(',');
|
|
638
525
|
}
|
|
639
526
|
else {
|
|
640
|
-
return canonicalKey.map(
|
|
527
|
+
return canonicalKey.map(concept => row[concept]).join(',');
|
|
641
528
|
}
|
|
642
529
|
}
|
|
643
530
|
function loadResource(resource, language, options) {
|
|
644
|
-
|
|
645
|
-
|
|
531
|
+
const { warning } = options.diagnostic.prepareDiagnosticFor('loadResource');
|
|
532
|
+
const filePromises = [];
|
|
646
533
|
if (typeof resource.data === 'undefined') {
|
|
647
534
|
resource.data = loadFile(resource.path, options);
|
|
648
535
|
}
|
|
649
536
|
filePromises.push(resource.data);
|
|
650
|
-
|
|
651
|
-
|
|
537
|
+
const languageValid = typeof language !== 'undefined' && includes(getLanguages(options), language);
|
|
538
|
+
const languageLoaded = typeof resource.translations[language] !== 'undefined';
|
|
652
539
|
if (languageValid) {
|
|
653
540
|
if (!languageLoaded) {
|
|
654
|
-
|
|
655
|
-
resource.translations[language] = loadFile(
|
|
656
|
-
.catch(
|
|
657
|
-
warning(
|
|
541
|
+
const translationPath = `lang/${language}/${resource.path}`;
|
|
542
|
+
resource.translations[language] = loadFile(translationPath, options)
|
|
543
|
+
.catch(err => {
|
|
544
|
+
warning(`translation file ${translationPath}`, err);
|
|
658
545
|
return Promise.resolve({});
|
|
659
546
|
});
|
|
660
547
|
}
|
|
661
548
|
filePromises.push(resource.translations[language]);
|
|
662
549
|
}
|
|
663
|
-
return Promise.all(filePromises).then(
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
return { data
|
|
550
|
+
return Promise.all(filePromises).then(fileResponses => {
|
|
551
|
+
const filesData = fileResponses.map(resp => resp.data || []);
|
|
552
|
+
const primaryKey = resource.schema.primaryKey;
|
|
553
|
+
const data = joinData(primaryKey, 'translation', ...filesData);
|
|
554
|
+
return { data, resource };
|
|
668
555
|
});
|
|
669
556
|
}
|
|
670
557
|
function getLanguages(options) {
|
|
671
558
|
if (!options.datapackage.translations) {
|
|
672
559
|
return [];
|
|
673
560
|
}
|
|
674
|
-
return options.datapackage.translations.map(
|
|
561
|
+
return options.datapackage.translations.map(lang => lang.id);
|
|
675
562
|
}
|
|
676
563
|
function loadFile(filePath, options) {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
debug(
|
|
680
|
-
return new Promise(
|
|
681
|
-
options.fileReader.readText(fullFilePath,
|
|
564
|
+
const { debug, error } = options.diagnostic.prepareDiagnosticFor('loadFile');
|
|
565
|
+
const fullFilePath = (0, ddf_query_validator_1.getFilePath)(options.basePath, filePath);
|
|
566
|
+
debug(`start reading "${filePath}"`);
|
|
567
|
+
return new Promise((resolve, reject) => {
|
|
568
|
+
options.fileReader.readText(fullFilePath, (err, data) => {
|
|
682
569
|
if (err) {
|
|
683
|
-
error(
|
|
570
|
+
error(`fail "${filePath}" reading`, err);
|
|
684
571
|
return reject(new ddfcsv_error_1.DdfCsvError(ddfcsv_error_1.FILE_READING_ERROR, err, fullFilePath));
|
|
685
572
|
}
|
|
686
573
|
Papa.parse(stripBom(data), {
|
|
687
574
|
header: true,
|
|
688
575
|
skipEmptyLines: true,
|
|
689
|
-
dynamicTyping:
|
|
690
|
-
|
|
691
|
-
|
|
576
|
+
dynamicTyping: (headerName) => {
|
|
577
|
+
const concept = options.conceptsLookup.get(headerName) || {};
|
|
578
|
+
return !includes(['time', 'string'], concept.concept_type);
|
|
579
|
+
},
|
|
580
|
+
complete: result => {
|
|
581
|
+
debug(`finish reading "${filePath}"`);
|
|
692
582
|
resolve(result);
|
|
693
583
|
},
|
|
694
|
-
error:
|
|
695
|
-
error(
|
|
584
|
+
error: parseErr => {
|
|
585
|
+
error(`fail "${filePath}" parsing`, parseErr);
|
|
696
586
|
reject(new ddfcsv_error_1.DdfCsvError(ddfcsv_error_1.CSV_PARSING_ERROR, parseErr, filePath));
|
|
697
587
|
}
|
|
698
588
|
});
|
|
@@ -703,10 +593,18 @@ function ddfCsvReader(logger) {
|
|
|
703
593
|
if (resourcesLookup.size > 0) {
|
|
704
594
|
return resourcesLookup;
|
|
705
595
|
}
|
|
706
|
-
datapackagePar.resources.forEach(
|
|
596
|
+
datapackagePar.resources.forEach(resource => {
|
|
707
597
|
if (!Array.isArray(resource.schema.primaryKey)) {
|
|
708
598
|
resource.schema.primaryKey = [resource.schema.primaryKey];
|
|
709
599
|
}
|
|
600
|
+
const constraints = resource.schema.fields.reduce((result, field) => {
|
|
601
|
+
var _a;
|
|
602
|
+
if ((_a = field.constraints) === null || _a === void 0 ? void 0 : _a.enum) {
|
|
603
|
+
result[field.name] = field.constraints.enum;
|
|
604
|
+
}
|
|
605
|
+
return result;
|
|
606
|
+
}, {});
|
|
607
|
+
resource.constraints = constraints;
|
|
710
608
|
resource.translations = {};
|
|
711
609
|
resourcesLookup.set(resource.name, resource);
|
|
712
610
|
});
|
|
@@ -716,10 +614,10 @@ function ddfCsvReader(logger) {
|
|
|
716
614
|
if (keyValueLookup.size > 0) {
|
|
717
615
|
return keyValueLookup;
|
|
718
616
|
}
|
|
719
|
-
for (
|
|
720
|
-
datapackagePar.ddfSchema[collection].map(
|
|
721
|
-
|
|
722
|
-
|
|
617
|
+
for (const collection in datapackagePar.ddfSchema) {
|
|
618
|
+
datapackagePar.ddfSchema[collection].map(kvPair => {
|
|
619
|
+
const key = createKeyString(kvPair.primaryKey);
|
|
620
|
+
const resources = kvPair.resources.map(resourceName => resourcesLookup.get(resourceName));
|
|
723
621
|
if (keyValueLookup.has(key)) {
|
|
724
622
|
keyValueLookup.get(key).set(kvPair.value, resources);
|
|
725
623
|
}
|
|
@@ -731,7 +629,8 @@ function ddfCsvReader(logger) {
|
|
|
731
629
|
return keyValueLookup;
|
|
732
630
|
}
|
|
733
631
|
return {
|
|
734
|
-
query
|
|
632
|
+
query,
|
|
633
|
+
loadFile
|
|
735
634
|
};
|
|
736
635
|
}
|
|
737
636
|
exports.ddfCsvReader = ddfCsvReader;
|