@vizabi/reader-ddfcsv 4.3.2 → 4.3.3

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.
Files changed (31) hide show
  1. package/dist/reader-ddfcsv-polyfill.js +1 -1
  2. package/dist/reader-ddfcsv-polyfill.js.map +1 -1
  3. package/dist/reader-ddfcsv.js +2 -2
  4. package/dist/reader-ddfcsv.js.map +1 -1
  5. package/lib/src/ddf-csv.d.ts +2 -1
  6. package/lib/src/ddf-csv.js +15 -8
  7. package/lib/src/ddf-csv.js.map +1 -1
  8. package/lib/src/ddfcsv-reader.js +1 -1
  9. package/lib/src/ddfcsv-reader.js.map +1 -1
  10. package/lib/src/resource-selection-optimizer/in-clause-under-conjunction.d.ts +1 -3
  11. package/lib/src/resource-selection-optimizer/in-clause-under-conjunction.js +38 -83
  12. package/lib/src/resource-selection-optimizer/in-clause-under-conjunction.js.map +1 -1
  13. package/lib-web/src/ddf-csv.d.ts +2 -1
  14. package/lib-web/src/ddf-csv.js +15 -8
  15. package/lib-web/src/ddf-csv.js.map +1 -1
  16. package/lib-web/src/ddfcsv-reader.js +1 -1
  17. package/lib-web/src/ddfcsv-reader.js.map +1 -1
  18. package/lib-web/src/resource-selection-optimizer/in-clause-under-conjunction.d.ts +1 -3
  19. package/lib-web/src/resource-selection-optimizer/in-clause-under-conjunction.js +38 -83
  20. package/lib-web/src/resource-selection-optimizer/in-clause-under-conjunction.js.map +1 -1
  21. package/package.json +3 -3
  22. package/src/ddf-csv.ts +13 -9
  23. package/src/ddfcsv-reader.ts +1 -1
  24. package/src/resource-selection-optimizer/in-clause-under-conjunction.ts +39 -101
  25. package/test/definition/datapoints-definition.spec.ts +1 -1
  26. package/test/main.spec.ts +8 -4
  27. package/test/result-fixtures/in-clause-under-conjunction-1.json +100 -100
  28. package/test/result-fixtures/in-clause-under-conjunction-2.json +70169 -70169
  29. package/test/result-fixtures/multi-instances/entities-sg.json +2 -2
  30. package/test/tslint.json +3 -2
  31. package/tslint.json +1 -1
@@ -1,9 +1,7 @@
1
- import * as path from 'path';
2
1
  import * as head from 'lodash.head';
3
2
  import * as values from 'lodash.values';
4
3
  import * as keys from 'lodash.keys';
5
4
  import * as get from 'lodash.get';
6
- import * as flattenDeep from 'lodash.flattendeep';
7
5
  import * as isEmpty from 'lodash.isempty';
8
6
  import * as startsWith from 'lodash.startswith';
9
7
  import * as includes from 'lodash.includes';
@@ -12,8 +10,6 @@ import { DdfCsvError } from '../ddfcsv-error';
12
10
  import { IDatapackage, IResourceSelectionOptimizer, IResourceRead, IBaseReaderOptions } from '../interfaces';
13
11
  import { QueryFeature, featureDetectors, IQuery } from 'ddf-query-validator';
14
12
 
15
- const Papa = require('papaparse');
16
-
17
13
  const WHERE_KEYWORD = 'where';
18
14
  const JOIN_KEYWORD = 'join';
19
15
  const KEY_IN = '$in';
@@ -21,10 +17,6 @@ const KEY_NIN = '$nin';
21
17
  const KEY_AND = '$and';
22
18
  const KEY_OR = '$or';
23
19
 
24
- const getFirstConditionClause = clause => head(values(clause));
25
- const getFirstKey = obj => head(keys(obj));
26
- const isOneKeyBased = obj => keys(obj).length === 1;
27
-
28
20
  export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
29
21
  private flow: any = {};
30
22
  private fileReader: IResourceRead;
@@ -44,11 +36,7 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
44
36
  isMatched(): boolean {
45
37
  this.flow.joinObject = get(this.query, JOIN_KEYWORD);
46
38
 
47
- const relatedFeatures = compact(featureDetectors.map(detector => detector(this.query, this.conceptsLookup)));
48
-
49
- return this.query.from === "datapoints";
50
- // return includes(relatedFeatures, QueryFeature.WhereClauseBasedOnConjunction) &&
51
- // includes(relatedFeatures, QueryFeature.ConjunctionPartFromWhereClauseCorrespondsToJoin);
39
+ return this.query.from === "datapoints" && this.flow.joinObject;
52
40
  }
53
41
 
54
42
  async getRecommendedFilesSet(): Promise<string[]> {
@@ -59,7 +47,8 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
59
47
 
60
48
  let result;
61
49
  try {
62
- this.collectProcessableClauses();
50
+ this.flow.processableClauses = await this.collectProcessableClauses();
51
+ if (!this.flow.processableClauses) return [];
63
52
  this.collectEntityFilesNames();
64
53
  const data = await this.collectEntities();
65
54
  this.fillEntityValuesHash(data);
@@ -80,24 +69,26 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
80
69
  }
81
70
  }
82
71
 
83
- private collectProcessableClauses(): InClauseUnderConjunction {
84
- const joinKeys = keys(this.flow.joinObject);
85
-
86
- this.flow.processableClauses = [];
72
+ private collectProcessableClauses(): Promise<any> {
73
+ const joinKeys = keys(this.flow.joinObject).filter(
74
+ key => ["entity_domain", "entity_set"].includes(this.options.conceptsLookup.get(key.slice(1))?.concept_type));
75
+ if (!joinKeys.length) return Promise.resolve(false);
87
76
 
88
- for (const joinKey of joinKeys) {
77
+ return Promise.all(joinKeys.map(joinKey => {
78
+ const key = this.flow.joinObject[joinKey].key;
89
79
  const where = get(this.flow.joinObject, `${joinKey}.${WHERE_KEYWORD}`, {});
90
80
 
91
- if (this.singleAndField(where)) {
92
- this.flow.processableClauses.push(...flattenDeep(where[KEY_AND].map(el => this.getProcessableClauses(el))));
93
- } else if (this.singleOrField(where)) {
94
- this.flow.processableClauses.push(...flattenDeep(where[KEY_OR].map(el => this.getProcessableClauses(el))));
95
- } else {
96
- this.flow.processableClauses.push(...this.getProcessableClauses(where));
97
- }
98
- }
81
+ return this.parent.queryData({
82
+ select: { key: [key] },
83
+ where,
84
+ from: this.options.conceptsLookup.has(key) ? 'entities' : 'concepts'
85
+ }, Object.assign({ joinID: joinKey }, this.options))
86
+ .then(result => ({
87
+ key,
88
+ entities: new Set(result.map(row => row[ key ]))
89
+ }));
90
+ }));
99
91
 
100
- return this;
101
92
  }
102
93
 
103
94
  private collectEntityFilesNames(): InClauseUnderConjunction {
@@ -107,15 +98,15 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
107
98
 
108
99
  for (const schemaResourceRecord of this.datapackage.ddfSchema.entities) {
109
100
  for (const clause of this.flow.processableClauses) {
110
- const primaryKey = getFirstKey(clause);
101
+ const key = clause.key;
111
102
 
112
- if (head(schemaResourceRecord.primaryKey) === primaryKey) {
103
+ if (head(schemaResourceRecord.primaryKey) === key) {
113
104
  for (const resourceName of schemaResourceRecord.resources) {
114
105
  const resource = this.options.resourcesLookup.get(resourceName);
115
106
 
116
107
  this.flow.entityResources.add(resource);
117
108
  this.flow.entityFilesNames.add(resource.path);
118
- this.flow.fileNameToPrimaryKeyHash.set(resource.path, primaryKey);
109
+ this.flow.fileNameToPrimaryKeyHash.set(resource.path, key);
119
110
  }
120
111
  }
121
112
  }
@@ -162,30 +153,14 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
162
153
  }
163
154
 
164
155
  private getFilesGroupsQueryClause(): InClauseUnderConjunction {
165
- const getEntitiesExcept = (entityValuesToExclude: string[]): string[] => {
166
- const result = [];
167
-
168
- for (const entityKey of this.flow.entityValueToDomainHash.keys()) {
169
- if (!includes(entityValuesToExclude, entityKey)) {
170
- result.push(entityKey);
171
- }
172
- }
173
-
174
- return result;
175
- };
176
156
  const filesGroupsByClause = new Map();
177
157
 
178
158
  for (const clause of this.flow.processableClauses) {
179
159
  const filesGroupByClause = {
180
- entities: this.flow.entityFilesNames,
181
- datapoints: new Set(),
182
- concepts: new Set()
160
+ datapoints: new Set()
183
161
  };
184
- const firstConditionClause = getFirstConditionClause(clause);
185
- const entityValuesFromClause = firstConditionClause[KEY_IN] || getEntitiesExcept(firstConditionClause[KEY_NIN]);
186
162
 
187
- for (const entityValueFromClause of entityValuesFromClause) {
188
- //filesGroupByClause.entities.add(this.flow.entityValueToFileHash.get(entityValueFromClause));
163
+ for (const entityValueFromClause of clause.entities) {
189
164
 
190
165
  const entitiesByQuery = this.flow.entityValueToDomainHash.get(entityValueFromClause);
191
166
 
@@ -194,13 +169,12 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
194
169
  for (const resourceName of schemaResourceRecord.resources) {
195
170
  if (includes(schemaResourceRecord.primaryKey, entityByQuery)) {
196
171
  const resource = this.options.resourcesLookup.get(resourceName);
197
- const constraint = resource.constraints[entityByQuery];
172
+ const constraint = resource.constraints?.[entityByQuery];
198
173
  if ( constraint ) {
199
174
  if (constraint.includes(entityValueFromClause)) {
200
175
  filesGroupByClause.datapoints.add(resource.path);
201
176
  }
202
- }
203
- else {
177
+ } else {
204
178
  filesGroupByClause.datapoints.add(resource.path);
205
179
  }
206
180
  }
@@ -209,13 +183,7 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
209
183
  }
210
184
  }
211
185
 
212
- for (const schemaResourceRecord of this.datapackage.ddfSchema.concepts) {
213
- for (const resourceName of schemaResourceRecord.resources) {
214
- filesGroupByClause.concepts.add(this.options.resourcesLookup.get(resourceName).path);
215
- }
216
- }
217
-
218
- filesGroupsByClause.set(clause, filesGroupByClause);
186
+ filesGroupsByClause.set(clause.key, filesGroupByClause);
219
187
  }
220
188
 
221
189
  this.flow.filesGroupsByClause = filesGroupsByClause;
@@ -224,59 +192,29 @@ export class InClauseUnderConjunction implements IResourceSelectionOptimizer {
224
192
  }
225
193
 
226
194
  private getOptimalFilesGroup(): string[] {
227
- const clauseKeys = this.flow.filesGroupsByClause.keys();
228
195
 
229
- let appropriateClauseKey;
230
- let appropriateClauseSize;
231
-
232
- for (const key of clauseKeys) {
233
- const size = this.flow.filesGroupsByClause.get(key).datapoints.size +
234
- this.flow.filesGroupsByClause.get(key).entities.size +
235
- this.flow.filesGroupsByClause.get(key).concepts.size;
196
+ const entities = this.flow.entityFilesNames;
236
197
 
237
- if (!appropriateClauseKey || size < appropriateClauseSize) {
238
- appropriateClauseKey = key;
239
- appropriateClauseSize = size;
198
+ const concepts = new Set();
199
+ for (const schemaResourceRecord of this.datapackage.ddfSchema.concepts) {
200
+ for (const resourceName of schemaResourceRecord.resources) {
201
+ concepts.add(this.options.resourcesLookup.get(resourceName).path);
240
202
  }
241
203
  }
242
204
 
243
- if (!this.flow.filesGroupsByClause.get(appropriateClauseKey)) {
244
- return [];
245
- }
246
-
247
- return [
248
- ...Array.from(this.flow.filesGroupsByClause.get(appropriateClauseKey).concepts),
249
- ...Array.from(this.flow.filesGroupsByClause.get(appropriateClauseKey).entities),
250
- ...Array.from(this.flow.filesGroupsByClause.get(appropriateClauseKey).datapoints)
251
- ] as string[];
252
- }
253
-
254
- private getProcessableClauses(clause) {
255
- const result = [];
256
- const clauseKeys = keys(clause);
205
+ const clauseKeys = this.flow.filesGroupsByClause.keys();
206
+ let datapoints = Array.from(this.flow.filesGroupsByClause.get(clauseKeys.next().value).datapoints);
257
207
 
258
208
  for (const key of clauseKeys) {
259
- if (!startsWith(key, '$') && isOneKeyBased(clause[key])) {
260
- // attention! this functionality process only first clause
261
- // for example, { geo: { '$in': ['world'] } }
262
- // in this example { geo: { '$in': ['world'] }, foo: { '$in': ['bar', 'baz'] } }]
263
- // foo: { '$in': ['bar', 'baz'] } will NOT be processed
264
- const conditionKey = head(keys(clause[key]));
265
-
266
- if (conditionKey === KEY_IN || conditionKey === KEY_NIN) {
267
- result.push(clause);
268
- }
269
- }
209
+ datapoints = this.intersectArray(datapoints, Array.from(this.flow.filesGroupsByClause.get(key).datapoints));
270
210
  }
271
211
 
272
- return result;
212
+ return [...Array.from(concepts), ...Array.from(entities)].concat(datapoints) as string[];
273
213
  }
274
214
 
275
- private singleAndField(clause): boolean {
276
- return isOneKeyBased(clause) && !!get(clause, KEY_AND);
277
- }
278
215
 
279
- private singleOrField(clause): boolean {
280
- return isOneKeyBased(clause) && !!get(clause, KEY_OR);
216
+ private intersectArray(array1, array2) {
217
+ return array1.filter(value => array2.includes(value));
281
218
  }
219
+
282
220
  }
@@ -232,7 +232,7 @@ describe('Datapoints definition errors in query', () => {
232
232
  where: {
233
233
  country_code: {
234
234
  $in: [
235
- '900'
235
+ 900
236
236
  ]
237
237
  }
238
238
  }
package/test/main.spec.ts CHANGED
@@ -127,8 +127,10 @@ describe('General errors in ddfcsv reader', () => {
127
127
 
128
128
  expect(error.file).to.equal(expectedPath);
129
129
  expect(error.name).to.equal('DdfCsvError');
130
- expect(error.message).to.equal(`JSON parsing error [filepath: ${expectedPath}]. Unexpected token ( in JSON at position 0.`);
131
- expect(error.details).to.equal('Unexpected token ( in JSON at position 0');
130
+ expect(error.message).to.equal(`JSON parsing error [filepath: ${expectedPath}]. Unexpected token '(', "(
131
+ "nam"... is not valid JSON.`);
132
+ expect(error.details).to.equal(`Unexpected token '(', "(
133
+ "nam"... is not valid JSON`);
132
134
  }
133
135
  });
134
136
  });
@@ -245,8 +247,10 @@ describe('General errors in ddfcsv reader', () => {
245
247
 
246
248
  expect(error.file).to.equal(expectedPath);
247
249
  expect(error.name).to.equal('DdfCsvError');
248
- expect(error.message).to.equal(`JSON parsing error [filepath: ${expectedPath}]. Unexpected token ( in JSON at position 0.`);
249
- expect(error.details).to.equal('Unexpected token ( in JSON at position 0');
250
+ expect(error.message).to.equal(`JSON parsing error [filepath: ${expectedPath}]. Unexpected token '(', "(
251
+ "nam"... is not valid JSON.`);
252
+ expect(error.details).to.equal(`Unexpected token '(', "(
253
+ "nam"... is not valid JSON`);
250
254
  }
251
255
  });
252
256
  });