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