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