@sis-cc/dotstatsuite-components 9.3.5 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +8 -3
- package/lib/rules/src/table/factories/getCells.js +22 -4
- package/lib/rules/src/table/factories/getLayoutWithFlags.js +32 -5
- package/lib/rules/src/table/factories/getTableData.js +9 -2
- package/lib/rules/src/table/preparators/prepareData.js +37 -2
- package/lib/rules/src/v8-transformer.js +5 -9
- package/lib/rules2/src/constants.js +7 -0
- package/lib/rules2/src/getAdvAttrSeriesAtCoordinates.js +39 -0
- package/lib/rules2/src/getAdvancedAttributes.js +126 -0
- package/lib/rules2/src/getMetadataCoordinates.js +38 -0
- package/lib/rules2/src/getMetadataStructureFromData.js +23 -0
- package/lib/rules2/src/getSidebarData.js +76 -0
- package/lib/rules2/src/hasCellMetadata.js +19 -0
- package/lib/rules2/src/hasLayoutEntryMetadata.js +18 -0
- package/lib/rules2/src/index.js +47 -0
- package/lib/rules2/src/parseMetadataSeries.js +83 -0
- package/lib/rules2/src/refineMetadataCoordinates.js +34 -0
- package/lib/rules2/src/sdmx3.0DataFormatPatch.js +20 -0
- package/lib/viewer/src/chart.js +48 -41
- package/lib/viewer/src/index.js +76 -56
- package/package.json +9 -10
- package/src/index.js +2 -0
- package/src/rules/src/table/factories/getCells.js +13 -4
- package/src/rules/src/table/factories/getLayoutWithFlags.js +36 -10
- package/src/rules/src/table/factories/getTableData.js +12 -3
- package/src/rules/src/table/preparators/prepareData.js +45 -4
- package/src/rules/src/v8-transformer.js +3 -8
- package/src/rules2/src/constants.js +2 -0
- package/src/rules2/src/getAdvAttrSeriesAtCoordinates.js +29 -0
- package/src/rules2/src/getAdvancedAttributes.js +113 -0
- package/src/rules2/src/getMetadataCoordinates.js +37 -0
- package/src/rules2/src/getMetadataStructureFromData.js +17 -0
- package/src/rules2/src/getSidebarData.js +73 -0
- package/src/rules2/src/hasCellMetadata.js +11 -0
- package/src/rules2/src/hasLayoutEntryMetadata.js +9 -0
- package/src/rules2/src/index.js +8 -0
- package/src/rules2/src/parseMetadataSeries.js +80 -0
- package/src/rules2/src/refineMetadataCoordinates.js +27 -0
- package/src/rules2/src/sdmx3.0DataFormatPatch.js +9 -0
- package/src/viewer/src/chart.js +15 -14
- package/src/viewer/src/index.js +35 -26
- package/test/advanced-attributes-parsing-perf.test.js +16 -0
- package/test/getCells.test.js +7 -5
- package/test/getDataflowAdvancedAttributes.test.js +32 -0
- package/test/getLayoutDataWithFlags.test.js +22 -12
- package/test/getMetadataCoordinates.test.js +0 -0
- package/test/getSeriesAdvancedAttributes.test.js +30 -0
- package/test/getSidebarData.test.js +116 -0
- package/test/getSubtitleFlags.test.js +1 -1
- package/test/getTableData.test.js +2 -1
- package/test/metadata-parsing-perf.test.js +487 -0
- package/test/mocks/OECD_SNA_TABLE1_1.0_-_AUS_V_metadata.json +152 -0
- package/test/mocks/large_metadata_series.json +701 -0
- package/test/mocks/observations-advanced-attributes.json +55382 -0
- package/test/parseMetadataSeries.test.js +55 -0
- package/test/prepareData.test.js +2 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as R from 'ramda';
|
|
2
2
|
import { getFlags } from './getCells';
|
|
3
3
|
import { dimensionValueDisplay } from '../../dimension-utils';
|
|
4
|
+
import { hasCellMetadata } from '../../../../rules2/src/hasCellMetadata';
|
|
4
5
|
|
|
5
6
|
export const getLayoutSerieAttributes = (layoutSerie, seriesAttributes) => {
|
|
6
7
|
const length = R.length(layoutSerie);
|
|
@@ -72,15 +73,39 @@ const getSerieKey = R.pipe(R.reduce(
|
|
|
72
73
|
[]
|
|
73
74
|
), R.join(':'));
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
[
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
const getCoordinates = (data, unitsId) => R.reduce(
|
|
77
|
+
(acc, entry) => {
|
|
78
|
+
const dimId = R.path(['dimension', 'id'], entry);
|
|
79
|
+
const valId = R.path(['value', 'id'], entry);
|
|
80
|
+
if (dimId === unitsId) {
|
|
81
|
+
return acc;
|
|
82
|
+
}
|
|
83
|
+
return R.assoc(dimId, valId, acc);
|
|
84
|
+
},
|
|
85
|
+
{},
|
|
86
|
+
data
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
export const getLayoutDataWithFlags = (seriesAttributes, display, customAttributes, metadataCoordinates, unitsId) => {
|
|
90
|
+
const regularAttrsIds = R.concat(customAttributes.flags || [], customAttributes.footnotes || []);
|
|
91
|
+
const formatSublayout = (getAttributes, supplData = []) => data => {
|
|
92
|
+
const attributes = getAttributes(data);
|
|
93
|
+
const key = getSerieKey(data);
|
|
94
|
+
const cells = getSublayoutDataCells(display, customAttributes)(data);
|
|
95
|
+
const flags = getFlagsFromSeriesAttributes(display, customAttributes)(attributes);
|
|
96
|
+
const coordinates = getCoordinates(R.concat(supplData, data), unitsId);
|
|
97
|
+
const hasMetadata = hasCellMetadata(metadataCoordinates, coordinates);
|
|
98
|
+
const advancedAttributesSeries = R.isNil(attributes)
|
|
99
|
+
? {}
|
|
100
|
+
: R.filter(
|
|
101
|
+
serie => !R.isEmpty(R.omit(regularAttrsIds, R.propOr({}, 'attributes', serie))),
|
|
102
|
+
attributes
|
|
103
|
+
);
|
|
104
|
+
const hasAdvancedAttributes = !R.isEmpty(advancedAttributesSeries);
|
|
105
|
+
const sideProps = hasMetadata || hasAdvancedAttributes ? { hasAdvancedAttributes, hasMetadata, coordinates } : null;
|
|
106
|
+
|
|
107
|
+
return ({ data: cells, key, flags, sideProps });
|
|
108
|
+
};
|
|
84
109
|
|
|
85
110
|
return R.evolve({
|
|
86
111
|
headerData: R.map(formatSublayout(data => getLayoutSerieAttributes(data, seriesAttributes))),
|
|
@@ -91,7 +116,8 @@ export const getLayoutDataWithFlags = (seriesAttributes, display, customAttribut
|
|
|
91
116
|
return ([
|
|
92
117
|
formatSublayout(() => sectionAttributes)(sectionSerie),
|
|
93
118
|
R.map(
|
|
94
|
-
formatSublayout(rowData => getLayoutSerieAttributes(R.concat(sectionSerie, rowData), R.omit(R.keys(sectionAttributes), seriesAttributes))
|
|
119
|
+
formatSublayout(rowData => getLayoutSerieAttributes(R.concat(sectionSerie, rowData), R.omit(R.keys(sectionAttributes), seriesAttributes)),
|
|
120
|
+
sectionSerie)
|
|
95
121
|
)(R.last(sectionData))
|
|
96
122
|
]);
|
|
97
123
|
}
|
|
@@ -13,6 +13,7 @@ import { cleanUnitsInLayoutData } from '../units/cleanUnitsInLayoutData';
|
|
|
13
13
|
import { getSortedLayoutIndexes } from './getSortedLayoutIndexes';
|
|
14
14
|
import { refineLayoutSize } from './refineLayoutSize';
|
|
15
15
|
import { getLayoutData } from './getLayoutData';
|
|
16
|
+
import { refineMetadataCoordinates } from '../../../../rules2/src/refineMetadataCoordinates';
|
|
16
17
|
|
|
17
18
|
export const getTableProps = ({ data, layoutIds, display, customAttributes, limit, isTimeInverted }) => {
|
|
18
19
|
const seriesAttributes = R.propOr({}, 'seriesAttributes', data);
|
|
@@ -22,6 +23,12 @@ export const getTableProps = ({ data, layoutIds, display, customAttributes, limi
|
|
|
22
23
|
layoutIds
|
|
23
24
|
);
|
|
24
25
|
|
|
26
|
+
const headerDimensionsIds = R.pluck('id',
|
|
27
|
+
R.concat(R.pathOr([], ['units', 'headerUnits'], data), R.values(R.pathOr({}, ['dimensions', 'one'], data)))
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const refinedMetadataCoordinates = refineMetadataCoordinates(data.metadataCoordinates, layoutIds, headerDimensionsIds);
|
|
31
|
+
|
|
25
32
|
const {
|
|
26
33
|
rejectedValueIds,
|
|
27
34
|
unitDimension,
|
|
@@ -45,7 +52,8 @@ export const getTableProps = ({ data, layoutIds, display, customAttributes, limi
|
|
|
45
52
|
unitsDefinitionCodes, unitsSeries, unitsDisplay: unitsLevelDisplay,
|
|
46
53
|
unitDimension, rejectedValueIds, layoutDimsIds
|
|
47
54
|
},
|
|
48
|
-
|
|
55
|
+
refinedMetadataCoordinates.cells,
|
|
56
|
+
data.observationsType,
|
|
49
57
|
);
|
|
50
58
|
|
|
51
59
|
const dimensions = R.mapObjIndexed(
|
|
@@ -89,9 +97,10 @@ export const getTableProps = ({ data, layoutIds, display, customAttributes, limi
|
|
|
89
97
|
unitsDefinitionCodes, unitsIndexes: unitsAttachmentIndexesInLayout,
|
|
90
98
|
partialUnitSerieIndexes, rejectedValueIds, layoutIds
|
|
91
99
|
}),
|
|
92
|
-
getLayoutDataWithFlags(seriesAttributesValues, display, customAttributes),
|
|
93
|
-
cleanUnitsInLayoutData({ unitsDisplay: unitsLevelDisplay, unitsLayoutIndexes: unitsIndexesInLayout })
|
|
100
|
+
getLayoutDataWithFlags(seriesAttributesValues, display, customAttributes, refinedMetadataCoordinates.layout, unitDimension.id),
|
|
101
|
+
cleanUnitsInLayoutData({ unitsDisplay: unitsLevelDisplay, unitsLayoutIndexes: unitsIndexesInLayout }),
|
|
94
102
|
)(layout, R.propOr({}, 'observations', data));
|
|
103
|
+
|
|
95
104
|
return ({
|
|
96
105
|
cells: getCuratedCells({ layout, observations: cells, shape: ['header', 'sections', 'rows'] }),
|
|
97
106
|
layout,
|
|
@@ -21,6 +21,13 @@ import { getDisplay } from '../../preparators/getDisplay';
|
|
|
21
21
|
import { getObservations } from '../../preparators/getObservations';
|
|
22
22
|
import { enhanceObservations } from '../../preparators/enhanceObservations';
|
|
23
23
|
|
|
24
|
+
import { getMetadataCoordinates } from '../../../../rules2/src/getMetadataCoordinates';
|
|
25
|
+
import {
|
|
26
|
+
getDataflowAdvancedAttributes,
|
|
27
|
+
getObservationsAdvancedAttributes,
|
|
28
|
+
getSeriesAdvancedAttributes
|
|
29
|
+
} from '../../../../rules2/src/getAdvancedAttributes';
|
|
30
|
+
|
|
24
31
|
export const prepareData = (sdmxJson, customAttributes, unitsProps={}) => {
|
|
25
32
|
const {
|
|
26
33
|
defaultCodes=[],
|
|
@@ -127,10 +134,42 @@ export const prepareData = (sdmxJson, customAttributes, unitsProps={}) => {
|
|
|
127
134
|
attributesIndexedByIds,
|
|
128
135
|
);
|
|
129
136
|
|
|
130
|
-
const seriesAttributesValues =
|
|
131
|
-
|
|
132
|
-
|
|
137
|
+
const seriesAttributesValues = R.map(
|
|
138
|
+
series => refineSeriesAttributesValues(series, attributesIndexedByIds),
|
|
139
|
+
dimensionsAttributesValues
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const metadataCoordinates = getMetadataCoordinates(sdmxJson);
|
|
143
|
+
const headerAttributesIds = R.concat(attributesIdsIndexedByTargets.dataflow || [], attributesIdsIndexedByTargets.oneValueDimensions || []);
|
|
144
|
+
const headerAttributes = R.pick(headerAttributesIds, attributesIndexedByIds);
|
|
145
|
+
const headerAdvancedAttrIds = R.pipe(
|
|
146
|
+
R.filter(id => !R.includes(id, customAttributes.flags || []) && !R.includes(id, customAttributes.footnotes || [])),
|
|
147
|
+
)(headerAttributesIds);
|
|
148
|
+
|
|
149
|
+
const dataflowAdvancedAttributes = getDataflowAdvancedAttributes(
|
|
150
|
+
headerAttributes,
|
|
151
|
+
oneValueDimensions,
|
|
152
|
+
headerAdvancedAttrIds,
|
|
153
|
+
R.length(dimensions)
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const observationsAdvancedAttributesIds = R.filter(
|
|
157
|
+
id => !R.includes(id, customAttributes.flags || []) && !R.includes(id, customAttributes.footnotes || []),
|
|
158
|
+
attributesIdsIndexedByTargets.observations || []
|
|
133
159
|
);
|
|
160
|
+
const observationsAdvancedAttributes = getObservationsAdvancedAttributes(observations, observationsAdvancedAttributesIds);
|
|
161
|
+
|
|
162
|
+
const seriesAdvancedAttributesIds = R.filter(
|
|
163
|
+
id => !R.includes(id, customAttributes.flags || []) && !R.includes(id, customAttributes.footnotes || []),
|
|
164
|
+
R.concat(attributesIdsIndexedByTargets.series || [], attributesIdsIndexedByTargets.manyValuesDimensions || [])
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const seriesAdvancedAttributes = getSeriesAdvancedAttributes(
|
|
168
|
+
seriesAttributesValues,
|
|
169
|
+
dimensions,
|
|
170
|
+
seriesAdvancedAttributesIds
|
|
171
|
+
);
|
|
172
|
+
|
|
134
173
|
return ({
|
|
135
174
|
dimensions: {
|
|
136
175
|
one: oneValueDimensions,
|
|
@@ -144,11 +183,13 @@ export const prepareData = (sdmxJson, customAttributes, unitsProps={}) => {
|
|
|
144
183
|
unitsAttachmentSeriesIds,
|
|
145
184
|
unitsSeries,
|
|
146
185
|
},
|
|
186
|
+
metadataCoordinates,
|
|
187
|
+
advancedAttributes: { ...dataflowAdvancedAttributes, ...observationsAdvancedAttributes, ...seriesAdvancedAttributes },
|
|
147
188
|
observations,
|
|
148
189
|
observationsType: getObservationsType(sdmxJson.data),
|
|
149
190
|
dataflowAttributes,
|
|
150
191
|
dataflowName: R.path(['data', 'structure', 'name'], sdmxJson),
|
|
151
192
|
seriesAttributes: R.props(seriesAttributesIds, attributesIndexedByIds),
|
|
152
|
-
seriesAttributesValues
|
|
193
|
+
seriesAttributesValues: seriesAttributesValues.series || {}
|
|
153
194
|
});
|
|
154
195
|
};
|
|
@@ -95,22 +95,17 @@ export const dataTransformer = (dataNew, options = {}) => {
|
|
|
95
95
|
const getAttrObservations = R.propOr([], 'observation');
|
|
96
96
|
const attrObservations = getAttrObservations(attributes);
|
|
97
97
|
|
|
98
|
-
const getAttrDataset = R.propOr([], 'dataset')
|
|
99
|
-
const attrDataset = getAttrDataset(attributes);
|
|
100
|
-
|
|
101
|
-
const mergeAttr = R.concat(attrDataset, attrObservations);
|
|
102
|
-
|
|
103
98
|
const resAttrObservations = R.map((observation) => ({
|
|
104
99
|
...observation,
|
|
105
100
|
name: getLocalisedProp('names', observation),
|
|
106
|
-
values: getValues(observation.values),
|
|
101
|
+
values: getValues(observation.values || []),
|
|
107
102
|
roles: !R.isNil(observation.role) ? R.head(observation.role) : null,
|
|
108
|
-
}),
|
|
103
|
+
}), attrObservations);
|
|
109
104
|
|
|
110
105
|
const resAttributes = {
|
|
111
106
|
...attributes,
|
|
112
107
|
observation: resAttrObservations,
|
|
113
|
-
}
|
|
108
|
+
};
|
|
114
109
|
|
|
115
110
|
//----------------------------------------------------------------------------------------Dimensions
|
|
116
111
|
const getDimensions = R.propOr({}, 'dimensions');
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
const attribueValueDisplay = (display) => data => {
|
|
4
|
+
if (display === 'code') {
|
|
5
|
+
return R.prop('id', data);
|
|
6
|
+
}
|
|
7
|
+
if (display === 'both') {
|
|
8
|
+
return `${R.prop('id', data)}: ${R.prop('name', data)}`;
|
|
9
|
+
}
|
|
10
|
+
return R.prop('name', data);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const getAdvAttrSeriesAtCoordinates = (coordinates, advancedAttributes, display) => R.pipe(
|
|
14
|
+
R.filter(serie => {
|
|
15
|
+
const mergedCoord = R.mergeLeft(serie.coordinates, coordinates);
|
|
16
|
+
return R.equals(mergedCoord, coordinates);
|
|
17
|
+
}),
|
|
18
|
+
R.map(serie => {
|
|
19
|
+
return R.pipe(
|
|
20
|
+
R.propOr({}, 'attributes'),
|
|
21
|
+
R.values,
|
|
22
|
+
R.map(attribute => ({
|
|
23
|
+
id: attribute.id,
|
|
24
|
+
label: attribueValueDisplay(display)(attribute),
|
|
25
|
+
value: attribueValueDisplay(display)(attribute.value)
|
|
26
|
+
}))
|
|
27
|
+
)(serie);
|
|
28
|
+
}),
|
|
29
|
+
)(advancedAttributes);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
export const getObservationsAdvancedAttributes = (observations, advancedAttributesIds) => R.pipe(
|
|
4
|
+
R.map(obs => ({ attributes: R.pick(advancedAttributesIds, obs.attributes || {}), coordinates: obs.indexedDimValIds || {} })),
|
|
5
|
+
R.filter(entry => !R.isEmpty(entry.attributes))
|
|
6
|
+
)(observations);
|
|
7
|
+
|
|
8
|
+
export const getDataflowAdvancedAttributes = (attributes, dimensions, advancedAttributesIds, dimLength) => {
|
|
9
|
+
const advancedAttributes = R.pick(advancedAttributesIds, attributes);
|
|
10
|
+
const keyTemplate = R.times(R.always(''), dimLength);
|
|
11
|
+
return R.reduce(
|
|
12
|
+
(acc, attribute) => {
|
|
13
|
+
const value = R.head(attribute.values || []);
|
|
14
|
+
const attr = { ...R.pick(['id', 'name'], attribute), value };
|
|
15
|
+
let coordinates = {};
|
|
16
|
+
let key = keyTemplate;
|
|
17
|
+
|
|
18
|
+
if (!R.isEmpty(R.pathOr([], ['relationship', 'dimensions'], attribute))) {
|
|
19
|
+
const attrDimensionsIds = R.pathOr([], ['relationship', 'dimensions'], attribute);
|
|
20
|
+
const attrDimensions = R.props(attrDimensionsIds, dimensions);
|
|
21
|
+
R.forEach(
|
|
22
|
+
dim => {
|
|
23
|
+
const dId = dim.id;
|
|
24
|
+
const dIndex = dim.__index;
|
|
25
|
+
const vId = R.path(['values', 0, 'id'], dim);
|
|
26
|
+
coordinates = { ...coordinates, [dId]: vId };
|
|
27
|
+
key = R.set(R.lensIndex(dIndex), 0)(key);
|
|
28
|
+
},
|
|
29
|
+
attrDimensions
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
key = R.join(':', key);
|
|
34
|
+
return R.over(
|
|
35
|
+
R.lensProp(key),
|
|
36
|
+
entry => R.isNil(entry)
|
|
37
|
+
? ({ attributes: { [attribute.id]: attr }, coordinates })
|
|
38
|
+
: R.over(R.lensProp('attributes'), R.assoc(attribute.id, attr))(entry)
|
|
39
|
+
)(acc);
|
|
40
|
+
},
|
|
41
|
+
{},
|
|
42
|
+
R.values(advancedAttributes)
|
|
43
|
+
)
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
{
|
|
48
|
+
series: {
|
|
49
|
+
'0:0:x:x:x': { attributes: { a2: { id, value } } }
|
|
50
|
+
},
|
|
51
|
+
dimensions: {
|
|
52
|
+
'3:0': { attributes: { a1: { id, value } } },
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export const getSeriesAdvancedAttributes = (seriesAttributes, dimensions, advancedAttributesIds) => {
|
|
59
|
+
const seriesAdvancedAttributes = R.pipe(
|
|
60
|
+
R.propOr({}, 'series'),
|
|
61
|
+
series => R.reduce(
|
|
62
|
+
(acc, key) => {
|
|
63
|
+
const serie = series[key];
|
|
64
|
+
const advancedAttributes = R.pick(advancedAttributesIds, serie.attributes);
|
|
65
|
+
if (R.isEmpty(advancedAttributes)) {
|
|
66
|
+
return acc;
|
|
67
|
+
}
|
|
68
|
+
const splitKey = R.split(':', key);
|
|
69
|
+
const { coordinates, refinedKey } = R.addIndex(R.reduce)(
|
|
70
|
+
(acc, vInd, dInd) => {
|
|
71
|
+
if (vInd === 'x') {
|
|
72
|
+
return ({ ...acc, refinedKey: R.append('', acc.refinedKey) });
|
|
73
|
+
}
|
|
74
|
+
const _refined = R.append(vInd, acc.refinedKey);
|
|
75
|
+
const dim = R.nth(dInd, dimensions);
|
|
76
|
+
const valId = R.path(['values', Number(vInd), 'id'], dim);
|
|
77
|
+
const _coordinates = R.assoc(dim.id, valId, acc.coordinates);
|
|
78
|
+
return ({ coordinates: _coordinates, refinedKey: _refined });
|
|
79
|
+
},
|
|
80
|
+
{ coordinates: {}, refinedKey: [] },
|
|
81
|
+
splitKey
|
|
82
|
+
);
|
|
83
|
+
return R.assoc(R.join(':', refinedKey), { attributes: advancedAttributes, coordinates }, acc);
|
|
84
|
+
},
|
|
85
|
+
{},
|
|
86
|
+
R.keys(series)
|
|
87
|
+
)
|
|
88
|
+
)(seriesAttributes);
|
|
89
|
+
const keyTemplate = R.map(R.always(''), dimensions);
|
|
90
|
+
const dimensionsAdvancedAttributes = R.pipe(
|
|
91
|
+
R.propOr({}, 'dimensions'),
|
|
92
|
+
series => R.reduce(
|
|
93
|
+
(acc, key) => {
|
|
94
|
+
const serie = series[key];
|
|
95
|
+
const advancedAttributes = R.pick(advancedAttributesIds, serie.attributes);
|
|
96
|
+
if (R.isEmpty(advancedAttributes)) {
|
|
97
|
+
return acc;
|
|
98
|
+
}
|
|
99
|
+
const [dInd, vInd] = R.split(':', key);
|
|
100
|
+
const dim = R.nth(Number(dInd), dimensions);
|
|
101
|
+
const valId = R.path(['values', Number(vInd), 'id'], dim);
|
|
102
|
+
const coordinates = { [dim.id]: valId };
|
|
103
|
+
let refinedKey = keyTemplate;
|
|
104
|
+
refinedKey[Number(dInd)] = vInd;
|
|
105
|
+
return R.assoc(R.join(':', refinedKey), { attributes: advancedAttributes, coordinates }, acc);
|
|
106
|
+
},
|
|
107
|
+
{},
|
|
108
|
+
R.keys(series)
|
|
109
|
+
)
|
|
110
|
+
)(seriesAttributes);
|
|
111
|
+
|
|
112
|
+
return R.merge(seriesAdvancedAttributes, dimensionsAdvancedAttributes);
|
|
113
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
export const getMetadataCoordinates = (sdmxJson) => {
|
|
4
|
+
const dimensions = R.pathOr([], ['data', 'structure', 'dimensions', 'observation'], sdmxJson);
|
|
5
|
+
const annotations = R.pathOr([], ['data', 'structure', 'annotations'], sdmxJson);
|
|
6
|
+
const metadataAvailKeys = R.pipe(
|
|
7
|
+
R.pathOr([], ['data', 'dataSets', 0, 'dimensionGroupAttributes']),
|
|
8
|
+
R.map(indexes => R.props(indexes, annotations)),
|
|
9
|
+
R.filter(R.find(R.propEq('type', 'HAS_METADATA'))),
|
|
10
|
+
R.keys
|
|
11
|
+
)(sdmxJson);
|
|
12
|
+
|
|
13
|
+
return R.map(
|
|
14
|
+
key => {
|
|
15
|
+
const indexes = R.split(':', key);
|
|
16
|
+
return R.addIndex(R.reduce)(
|
|
17
|
+
(acc, vIndex, dimIndex) => {
|
|
18
|
+
if (R.isNil(vIndex) || R.isEmpty(vIndex)) {
|
|
19
|
+
return acc;
|
|
20
|
+
}
|
|
21
|
+
const dim = R.nth(dimIndex, dimensions);
|
|
22
|
+
if (R.isNil(dim)) {
|
|
23
|
+
return acc;
|
|
24
|
+
}
|
|
25
|
+
const val = R.path(['values', Number(vIndex)], dim);
|
|
26
|
+
if (R.isNil(val)) {
|
|
27
|
+
return acc;
|
|
28
|
+
}
|
|
29
|
+
return R.assoc(dim.id, val.id, acc);
|
|
30
|
+
},
|
|
31
|
+
{},
|
|
32
|
+
indexes
|
|
33
|
+
);
|
|
34
|
+
},
|
|
35
|
+
metadataAvailKeys
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
export const getDataflowMetadataStructure = sdmxJson => {
|
|
4
|
+
const annotations = R.pathOr([], ['data', 'stucture', 'annotations'], sdmxJson);
|
|
5
|
+
const dataSetAnnotIndexes = R.pathOr([], ['data', 'dataSets', 0, 'annotations'], sdmxJson);
|
|
6
|
+
const dataSetAnnotations = R.props(dataSetAnnotIndexes, annotations);
|
|
7
|
+
const metadataAnnotation = R.find(R.propEq('type', 'METADATA'), dataSetAnnotations);
|
|
8
|
+
if (!metadataAnnotation) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return R.pipe(
|
|
12
|
+
R.propOr('', 'title'),
|
|
13
|
+
R.split('='),
|
|
14
|
+
R.last,
|
|
15
|
+
|
|
16
|
+
)(metadataAnnotation);
|
|
17
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
const dimensionValueDisplay = (display) => data => {
|
|
4
|
+
if (display === 'code') {
|
|
5
|
+
return R.prop('id', data);
|
|
6
|
+
}
|
|
7
|
+
if (display === 'both') {
|
|
8
|
+
return `${R.prop('id', data)}: ${R.prop('name', data)}`;
|
|
9
|
+
}
|
|
10
|
+
return R.prop('name', data);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const sortByCoordinates = (a, b) => {
|
|
14
|
+
const splitACoord = a.splitCoord;
|
|
15
|
+
const splitBCoord = b.splitCoord;
|
|
16
|
+
|
|
17
|
+
const aWeight = R.pipe(R.reject(R.isEmpty), R.length)(splitACoord);
|
|
18
|
+
const bWeight = R.pipe(R.reject(R.isEmpty), R.length)(splitBCoord);
|
|
19
|
+
if (aWeight !== bWeight) {
|
|
20
|
+
return bWeight - aWeight;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let ind = 0;
|
|
24
|
+
while (splitACoord[ind] === splitBCoord[ind]) {
|
|
25
|
+
ind++;
|
|
26
|
+
}
|
|
27
|
+
const _a = R.isEmpty(splitACoord[ind]) ? 0 : Number(splitACoord[ind]);
|
|
28
|
+
const _b = R.isEmpty(splitBCoord[ind]) ? 0 : Number(splitBCoord[ind]);
|
|
29
|
+
return _b - _a;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// options = { display, attributesLabel }
|
|
33
|
+
export const getSidebarData = (attributesSeries, metadataSeries, dataflow, dimensions, options) => {
|
|
34
|
+
const coordinates = R.uniq(R.concat(R.keys(attributesSeries), R.keys(metadataSeries)));
|
|
35
|
+
return R.pipe(
|
|
36
|
+
R.map(coordinate => {
|
|
37
|
+
const attributes = R.prop(coordinate, attributesSeries);
|
|
38
|
+
const metadata = R.prop(coordinate, metadataSeries);
|
|
39
|
+
const children = R.concat(
|
|
40
|
+
R.isNil(attributes) ? [] : [{ id: `${coordinate}-attr`, label: options.attributesLabel, children: attributes }],
|
|
41
|
+
R.isNil(metadata) ? [] : metadata,
|
|
42
|
+
);
|
|
43
|
+
const splitCoord = R.split(':', coordinate);
|
|
44
|
+
let label = null;
|
|
45
|
+
if (R.all(R.isEmpty, splitCoord)) {
|
|
46
|
+
label = dimensionValueDisplay(options.display)(dataflow);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
label = R.pipe(
|
|
50
|
+
R.addIndex(R.reduce)((acc, valIndex, dimIndex) => {
|
|
51
|
+
if (R.isEmpty(valIndex)) {
|
|
52
|
+
return acc;
|
|
53
|
+
}
|
|
54
|
+
const dim = R.nth(dimIndex, dimensions);
|
|
55
|
+
const dimLabel = dimensionValueDisplay(options.display)(dim);
|
|
56
|
+
const value = R.nth(Number(valIndex), dim.values);
|
|
57
|
+
const valLabel = dimensionValueDisplay(options.display)(value);
|
|
58
|
+
return R.append(`${dimLabel}: ${valLabel}`, acc);
|
|
59
|
+
}, []),
|
|
60
|
+
R.join(' - ')
|
|
61
|
+
)(splitCoord);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return ({
|
|
65
|
+
id: coordinate,
|
|
66
|
+
splitCoord,
|
|
67
|
+
label,
|
|
68
|
+
children: R.filter(R.identity, children),
|
|
69
|
+
});
|
|
70
|
+
}),
|
|
71
|
+
R.sort(sortByCoordinates)
|
|
72
|
+
)(coordinates);
|
|
73
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
export const hasCellMetadata = (metadataCoordinates, cellCoordinates) => {
|
|
4
|
+
return R.pipe(
|
|
5
|
+
R.find(coordinates => {
|
|
6
|
+
const mergedCoord = R.mergeLeft(coordinates, cellCoordinates);
|
|
7
|
+
return R.equals(mergedCoord, cellCoordinates);
|
|
8
|
+
}),
|
|
9
|
+
R.complement(R.isNil)
|
|
10
|
+
)(metadataCoordinates);
|
|
11
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export {
|
|
2
|
+
SDMX_3_0_JSON_DATA_FORMAT,
|
|
3
|
+
SDMX_3_0_CSV_DATA_FORMAT
|
|
4
|
+
} from './constants';
|
|
5
|
+
|
|
6
|
+
export { getSidebarData } from './getSidebarData';
|
|
7
|
+
export { parseMetadataSeries } from './parseMetadataSeries';
|
|
8
|
+
export { sdmx_3_0_DataFormatPatch } from './sdmx3.0DataFormatPatch';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
import { getLocalisedName } from '@sis-cc/dotstatsuite-sdmxjs';
|
|
3
|
+
|
|
4
|
+
const dimensionValueDisplay = (locale, display) => data => {
|
|
5
|
+
if (display === 'code') {
|
|
6
|
+
return R.prop('id', data);
|
|
7
|
+
}
|
|
8
|
+
if (display === 'both') {
|
|
9
|
+
return `${R.prop('id', data)}: ${getLocalisedName(locale)(data)}`;
|
|
10
|
+
}
|
|
11
|
+
return getLocalisedName(locale)(data);
|
|
12
|
+
};
|
|
13
|
+
// options = { locale, display, dimensions = [] };
|
|
14
|
+
export const parseMetadataSeries = (metadataJson, options) => {
|
|
15
|
+
const metadataAttributes = R.pathOr([], ['data', 'structures', 0, 'attributes', 'dimensionGroup'], metadataJson);
|
|
16
|
+
const metaAttrLength = R.length(metadataAttributes);
|
|
17
|
+
|
|
18
|
+
if (!metaAttrLength) {
|
|
19
|
+
return ({});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const dimensions = R.pipe(
|
|
23
|
+
R.pathOr([], ['data', 'structures', 0, 'dimensions']),
|
|
24
|
+
({ series = [], observation = [] }) => R.concat(series, observation),
|
|
25
|
+
dims => R.isEmpty(options.dimensions || [])
|
|
26
|
+
? dims
|
|
27
|
+
: R.props(R.pluck('id', options.dimensions), R.indexBy(R.prop('id'), dims))
|
|
28
|
+
)(metadataJson);
|
|
29
|
+
|
|
30
|
+
const metadataSeries = R.pipe(
|
|
31
|
+
R.pathOr({}, ['data', 'dataSets', 0, 'dimensionGroupAttributes']),
|
|
32
|
+
series => R.reduce((acc, serieKey) => {
|
|
33
|
+
const indexes = series[serieKey];
|
|
34
|
+
const metaIndexes = R.take(metaAttrLength, indexes);
|
|
35
|
+
|
|
36
|
+
const evolvedKey = R.pipe(
|
|
37
|
+
R.split(':'),
|
|
38
|
+
R.addIndex(R.map)((vInd, dInd) => {
|
|
39
|
+
if (R.isEmpty(vInd)) {
|
|
40
|
+
return vInd;
|
|
41
|
+
}
|
|
42
|
+
const dim = R.nth(dInd, dimensions);
|
|
43
|
+
const val = R.nth(Number(vInd), dim.values || []);
|
|
44
|
+
|
|
45
|
+
const originalVal = R.find(
|
|
46
|
+
R.propEq('id', val.id),
|
|
47
|
+
)(R.propOr([], 'values', R.nth(dInd, options.dimensions)));
|
|
48
|
+
return R.propOr('', '__index', originalVal);
|
|
49
|
+
}),
|
|
50
|
+
R.join(':')
|
|
51
|
+
)(serieKey)
|
|
52
|
+
|
|
53
|
+
const attributes = R.addIndex(R.reduce)(
|
|
54
|
+
(acc, valueIndex, attrIndex) => {
|
|
55
|
+
if (R.isNil(valueIndex)) {
|
|
56
|
+
return acc;
|
|
57
|
+
}
|
|
58
|
+
const attribute = R.nth(attrIndex, metadataAttributes);
|
|
59
|
+
const label = dimensionValueDisplay(options.locale, options.display)(attribute);
|
|
60
|
+
|
|
61
|
+
const value = R.prop('value', R.nth(valueIndex, attribute.values || []));
|
|
62
|
+
|
|
63
|
+
return R.append({
|
|
64
|
+
id: attribute.id,
|
|
65
|
+
label,
|
|
66
|
+
value: R.is(Object, value) ? R.prop(options.locale, value) : value
|
|
67
|
+
}, acc);
|
|
68
|
+
},
|
|
69
|
+
[],
|
|
70
|
+
metaIndexes
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return R.assoc(evolvedKey, attributes, acc);
|
|
74
|
+
},
|
|
75
|
+
{},
|
|
76
|
+
R.keys(series)
|
|
77
|
+
))(metadataJson);
|
|
78
|
+
|
|
79
|
+
return metadataSeries;
|
|
80
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
export const refineMetadataCoordinates = (metadataCoordinates, layoutIds, headerDimensionsIds) => {
|
|
4
|
+
return R.reduce(
|
|
5
|
+
(acc, coordinates) => {
|
|
6
|
+
const refinedCoord = R.omit(headerDimensionsIds, coordinates);
|
|
7
|
+
if (R.isEmpty(refinedCoord)) {
|
|
8
|
+
return acc;
|
|
9
|
+
}
|
|
10
|
+
const removedHeaderCodes = R.omit(layoutIds.header, refinedCoord);
|
|
11
|
+
if (R.isEmpty(removedHeaderCodes)) {
|
|
12
|
+
return R.over(R.lensProp('layout'), R.append(refinedCoord))(acc);
|
|
13
|
+
}
|
|
14
|
+
const removedSectionCodes = R.omit(layoutIds.sections, refinedCoord);
|
|
15
|
+
if (R.isEmpty(removedSectionCodes)) {
|
|
16
|
+
return R.over(R.lensProp('layout'), R.append(refinedCoord))(acc);
|
|
17
|
+
}
|
|
18
|
+
const removedRowsCodes = R.omit(layoutIds.rows, removedSectionCodes);
|
|
19
|
+
if (R.isEmpty(removedRowsCodes)) {
|
|
20
|
+
return R.over(R.lensProp('layout'), R.append(refinedCoord))(acc);
|
|
21
|
+
}
|
|
22
|
+
return R.over(R.lensProp('cells'), R.append(refinedCoord))(acc);
|
|
23
|
+
},
|
|
24
|
+
{ cells: [], layout: [] },
|
|
25
|
+
metadataCoordinates
|
|
26
|
+
);
|
|
27
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
2
|
+
|
|
3
|
+
export const sdmx_3_0_DataFormatPatch = (sdmxJson) => {
|
|
4
|
+
const dataSet = R.pipe(R.pathOr({}, ['data', 'dataSets']), R.head)(sdmxJson);
|
|
5
|
+
const structureIndex = R.prop('structure', dataSet);
|
|
6
|
+
const structure = R.pipe(R.pathOr([], ['data', 'structures']), R.nth(structureIndex))(sdmxJson);
|
|
7
|
+
|
|
8
|
+
return R.set(R.lensPath(['data', 'structure']), structure)(sdmxJson);
|
|
9
|
+
};
|