diff --git a/SdmxDataParser/build.gradle b/SdmxDataParser/build.gradle index b6bce8d..7536c0a 100644 --- a/SdmxDataParser/build.gradle +++ b/SdmxDataParser/build.gradle @@ -14,6 +14,9 @@ dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' testImplementation 'org.mockito:mockito-core:3.9.0' testImplementation("org.mockito:mockito-junit-jupiter:3.8.0") + testImplementation("org.assertj:assertj-core:${assertj_version}") + testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") + testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") compile project(':SdmxApi') compile project(':SdmxSourceUtil') diff --git a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/JsonDataReaderEngine.java b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/JsonDataReaderEngine.java index 77e0dc5..8dc0083 100644 --- a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/JsonDataReaderEngine.java +++ b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/JsonDataReaderEngine.java @@ -1,7 +1,12 @@ package org.sdmxsource.sdmx.dataparser.engine.reader.json; -import org.slf4j.LoggerFactory; -import org.slf4j.Logger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; import org.sdmxsource.sdmx.api.constants.DATASET_ACTION; import org.sdmxsource.sdmx.api.constants.DATASET_POSITION; import org.sdmxsource.sdmx.api.engine.DataReaderEngine; @@ -17,17 +22,16 @@ import org.sdmxsource.sdmx.api.model.header.DatasetStructureReferenceBean; import org.sdmxsource.sdmx.api.util.ReadableDataLocation; import org.sdmxsource.sdmx.dataparser.engine.reader.AbstractDataReaderEngine; +import org.sdmxsource.sdmx.dataparser.engine.reader.json.StructureIterator.Component; import org.sdmxsource.sdmx.dataparser.engine.reader.json.StructureIterator.JsonDatasetStructuralMetadata; import org.sdmxsource.sdmx.dataparser.model.JsonReader; +import org.sdmxsource.sdmx.sdmxbeans.model.data.KeyValueImpl; import org.sdmxsource.sdmx.sdmxbeans.model.data.KeyableImpl; import org.sdmxsource.sdmx.sdmxbeans.model.data.ObservationImpl; import org.sdmxsource.sdmx.sdmxbeans.model.header.DatasetHeaderBeanImpl; import org.sdmxsource.sdmx.util.date.DateUtil; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The type Json data reader engine. @@ -223,7 +227,7 @@ protected boolean moveNextDatasetInternal() { 504 attached at the data set level. Example: 505 "attributes": [ 0, null, 0 ] */ - List datasetAttributeLinks = jReader.readIntegerArray(); + var datasetAttributeLinks = jReader.readStringArray(); datasetAttributes = decode(datasetAttributeLinks, jsonDatasetStructuralMetadata.getDatasetAttributeList()); } } else { @@ -352,24 +356,25 @@ protected boolean moveNextObservationInternal() { * For Series observations, the reader will be poistioned at the start of the */ protected Observation lazyLoadObservation() { - String obsValue = null; - List attributes = new ArrayList(); - List annotations = new ArrayList(); - List obsAttributes = new ArrayList(); + String obsValue; + List attributes; + List annotations = new ArrayList<>(); + List obsAttributes = new ArrayList<>(); for (int i = 1; i < obsValues.size(); i++) { String obsVal = obsValues.get(i); if (obsVal == null) { continue; } - Integer asInt = Integer.parseInt(obsVal); if (jsonDatasetStructuralMetadata.getObsAttributeList().size() < i) { + int asInt = Integer.parseInt(obsVal); if (jsonDatasetStructuralMetadata.getAnnotationList().size() < asInt + 1) { - LOG.warn("Can not read annotation at index '" + asInt + "' only '" + jsonDatasetStructuralMetadata.getAnnotationList().size() + "' annotations have been reported, so the reported index does not exist"); + LOG.warn("Can not read annotation at index '" + asInt + "' only '" + jsonDatasetStructuralMetadata.getAnnotationList().size() + + "' annotations have been reported, so the reported index does not exist"); } else { annotations.add(jsonDatasetStructuralMetadata.getAnnotationList().get(asInt)); } } else { - obsAttributes.add(asInt); + obsAttributes.add(obsVal); } } attributes = decode(obsAttributes, jsonDatasetStructuralMetadata.getObsAttributeList()); @@ -394,7 +399,7 @@ protected Keyable lazyLoadKey() { if ("annotations".equals(jReader.getCurrentFieldName())) { annotations = decodeAnnotations(jReader.readIntegerArray()); } else if ("attributes".equals(jReader.getCurrentFieldName())) { - attributes = decode(jReader.readIntegerArray(), jsonDatasetStructuralMetadata.getSeriesAttributeList()); + attributes = decode(jReader.readStringArray(), jsonDatasetStructuralMetadata.getSeriesAttributeList()); } } else if (jReader.isStartObject()) { if (jReader.getCurrentFieldName().equals("observations")) { @@ -419,26 +424,33 @@ private AnnotationBean[] decodeAnnotations(List encodedValues) { return annList.toArray(returnArray); } - private List decode(List encodedValues, List> decodeList) { - List returnList = new ArrayList(); + private List decode(List encodedValues, List structureComponents) { + List result = new ArrayList<>(); for (int i = 0; i < encodedValues.size(); i++) { - Integer val = encodedValues.get(i); - if (val != null && decodeList.size() > i) { - KeyValue decoded = decodeList.get(i).get(val); - if (decoded != null) { - returnList.add(decoded); - } + var encodedValue = encodedValues.get(i); + if (encodedValue == null) { + continue; } + + var component = structureComponents.get(i); + var values = component.getValues(); + String code = values.isEmpty() + ? encodedValue + : values.get(Integer.parseInt(encodedValue)); + if (code == null) { + continue; + } + + result.add(new KeyValueImpl(code, component.getId())); } - return returnList; + return result; } - private List decode(String[] encodedValues, List> decodeList) { - List l = new ArrayList(); - for (String str : encodedValues) { - l.add(Integer.parseInt(str)); + private List decode(String[] encodedValues, List decodeList) { + if (ArrayUtils.isEmpty(encodedValues)) { + return Collections.emptyList(); } - return decode(l, decodeList); + return decode(Arrays.asList(encodedValues), decodeList); } @Override diff --git a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/StructureIterator.java b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/StructureIterator.java index 7f4b4bf..3d404a7 100644 --- a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/StructureIterator.java +++ b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/reader/json/StructureIterator.java @@ -1,5 +1,9 @@ package org.sdmxsource.sdmx.dataparser.engine.reader.json; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + import org.sdmxsource.sdmx.api.constants.SDMX_STRUCTURE_TYPE; import org.sdmxsource.sdmx.api.exception.SdmxSemmanticException; import org.sdmxsource.sdmx.api.model.beans.base.AnnotationBean; @@ -8,20 +12,14 @@ import org.sdmxsource.sdmx.api.model.header.DatasetStructureReferenceBean; import org.sdmxsource.sdmx.dataparser.model.JsonReader; import org.sdmxsource.sdmx.dataparser.model.JsonReader.Iterator; -import org.sdmxsource.sdmx.sdmxbeans.model.data.KeyValueImpl; import org.sdmxsource.sdmx.sdmxbeans.model.header.DatasetStructureReferenceBeanImpl; import org.sdmxsource.sdmx.util.beans.reference.StructureReferenceBeanImpl; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * The type Structure iterator. */ public class StructureIterator extends AbstractIterator { - private List componentIterators = new ArrayList(); + private final List componentIterators = new ArrayList<>(); private LEVEL currentLevel = null; private String uri; private boolean inAttributes = false; @@ -45,11 +43,11 @@ public JsonDatasetStructuralMetadata getJsonDatasetStructuralMetadata() { return new JsonDatasetStructuralMetadata(); } - private List> getList(LEVEL lvl) { - List> returnList = new ArrayList>(); - for (ComponentIterator comp : componentIterators) { - if (comp.getLevel() == lvl) { - returnList.add(comp.componentMap); + private List getList(LEVEL lvl) { + List returnList = new ArrayList<>(); + for (ComponentIterator iterator : componentIterators) { + if (iterator.getLevel() == lvl) { + returnList.add(iterator.component); } } return returnList; @@ -140,12 +138,12 @@ private enum LEVEL { */ public class JsonDatasetStructuralMetadata { private DatasetStructureReferenceBean datasetStructureReference; - private List annotationList; - private List> datasetAttributeList; - private List> seriesAttributeList; - private List> obsAttributeList; - private List> seriesList; //Series keys - private List obsIds; //All the concepts at the observation level + private final List annotationList; + private final List datasetAttributeList; + private final List seriesAttributeList; + private final List obsAttributeList; + private List seriesList; //Series keys + private final List obsIds; //All the concepts at the observation level private String dimensionAtObservation; @@ -159,36 +157,30 @@ public JsonDatasetStructuralMetadata() { obsAttributeList = getList(LEVEL.OBS_ATTR); seriesList = getList(LEVEL.SERIES); - Map observationMap = null; - if (seriesList.size() == 0) { + Component observationComponent = null; + if (seriesList.isEmpty()) { //Flat - Observation Concept is last one in list seriesList = getList(LEVEL.OBS); - observationMap = seriesList.get(seriesList.size() - 1); + observationComponent = seriesList.get(seriesList.size() - 1); } else { - ComponentIterator observationComp = null; - for (ComponentIterator comp : componentIterators) { - if (comp.getLevel() == LEVEL.OBS) { - observationComp = comp; + ComponentIterator observationCompIterator = null; + for (ComponentIterator iterator : componentIterators) { + if (iterator.getLevel() == LEVEL.OBS) { + observationCompIterator = iterator; break; } } - if (observationComp != null) { - observationMap = observationComp.componentMap; + if (observationCompIterator != null) { + observationComponent = observationCompIterator.component; } } - if (observationMap == null) { + if (observationComponent == null) { throw new SdmxSemmanticException("Can not read JSON Data Message, missing Observation information in the Structure part of the message"); } - obsIds = new ArrayList(); - for (int i = 0; i < Integer.MAX_VALUE; i++) { - KeyValue kv = observationMap.get(i); - if (kv == null) { - break; - } - dimensionAtObservation = kv.getConcept(); - obsIds.add(kv.getCode()); - } + dimensionAtObservation = observationComponent.id; + obsIds = observationComponent.values; + if (uri != null) { String[] uriSplit = uri.split("/"); @@ -226,7 +218,7 @@ public List getAnnotationList() { * * @return the dataset attribute list */ - public List> getDatasetAttributeList() { + public List getDatasetAttributeList() { return datasetAttributeList; } @@ -235,7 +227,7 @@ public List> getDatasetAttributeList() { * * @return the series attribute list */ - public List> getSeriesAttributeList() { + public List getSeriesAttributeList() { return seriesAttributeList; } @@ -244,7 +236,7 @@ public List> getSeriesAttributeList() { * * @return the obs attribute list */ - public List> getObsAttributeList() { + public List getObsAttributeList() { return obsAttributeList; } @@ -253,7 +245,7 @@ public List> getObsAttributeList() { * * @return the series list */ - public List> getSeriesList() { + public List getSeriesList() { return seriesList; } @@ -276,13 +268,11 @@ public String getDimensionAtObservation() { } } - private class ComponentIterator extends AbstractIterator { - private LEVEL level; - private String id; - private Map componentMap = new HashMap(); + private static class ComponentIterator extends AbstractIterator { + private final LEVEL level; + private Component component; private boolean inValues; - private int pos; /** * Instantiates a new Component iterator. @@ -299,11 +289,10 @@ public ComponentIterator(JsonReader jReader, LEVEL level) { public void next(String fieldName) { if (inValues) { if ("id".equals(fieldName)) { - componentMap.put(pos, new KeyValueImpl(jReader.getValueAsString(), this.id)); - pos++; + component.getValues().add(jReader.getValueAsString()); } } else if ("id".equals(fieldName)) { - this.id = jReader.getValueAsString(); + this.component = new Component(jReader.getValueAsString(), new ArrayList<>()); } } @@ -324,4 +313,42 @@ public LEVEL getLevel() { return level; } } + + static class Component { + + private final String id; + private final List values; + + + public Component(String id, List values) { + this.id = id; + this.values = values; + } + + public String getId() { + return id; + } + + public List getValues() { + return values; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Component)) { + return false; + } + Component that = (Component) o; + return Objects.equals(id, that.id) && Objects.equals(values, that.values); + } + + @Override + public int hashCode() { + return Objects.hash(id, values); + } + } + } diff --git a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/DatasetInfoDataWriterEngine.java b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/DatasetInfoDataWriterEngine.java index c2893ad..7f642a9 100644 --- a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/DatasetInfoDataWriterEngine.java +++ b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/DatasetInfoDataWriterEngine.java @@ -18,6 +18,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Captures all the information about a datasets series and series codes as that are being written @@ -99,6 +100,10 @@ public void writeSeriesKeyValue(String dimensionId, String dimensionValue) { } private void storeComponentValue(String componentId, String componentValue) { + if (!shouldBeIndexed(componentId)) { + return; + } + final Pair, List> codes = codesForComponentMap.get(componentId); if (codes != null) { @@ -114,6 +119,12 @@ private void storeComponentValue(String componentId, String componentValue) { } } + protected boolean shouldBeIndexed(String componentId) { + return currentDSDSuperBean.getCodelistByComponentId(componentId) != null + || Objects.equals(dimensionAtObservation, componentId) + || DimensionBean.TIME_DIMENSION_FIXED_ID.equals(componentId); + } + /** * Gets all dimensions. * @@ -144,5 +155,13 @@ public int getReportedIndex(String concept, String code) { final Integer index = codesForComponentMap.get(concept).getLeft().get(code); return (index == null) ? -1 : index; } + + public String toStringValue(String concept, String code) { + if (code == null) { + return null; + } + int index = getReportedIndex(concept, code); + return index == -1 ? code : Integer.toString(index); + } } diff --git a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/AbstractJsonDataWriter.java b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/AbstractJsonDataWriter.java index 4a5932e..b3a4eb8 100644 --- a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/AbstractJsonDataWriter.java +++ b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/AbstractJsonDataWriter.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * The type Abstract json data writer. @@ -151,7 +152,7 @@ protected void writeDatasetAttributes() throws IOException { LOG.debug("[attributes]"); jsonGenerator.writeArrayFieldStart("attributes"); for (KeyValue dsAttr : datasetAttributes) { - jsonGenerator.writeNumber(super.getReportedIndex(dsAttr.getConcept(), dsAttr.getCode())); + jsonGenerator.writeString(toStringValue(dsAttr.getConcept(), dsAttr.getCode())); } LOG.debug("[/attributes]"); jsonGenerator.writeEndArray(); @@ -161,18 +162,12 @@ protected void writeDatasetAttributes() throws IOException { @Override protected void writeKey(Keyable key) { super.writeKey(key); - StringBuilder sb = new StringBuilder(); - - String delimiter = ""; - for (KeyValue kv : key.getKey()) { - int currentIndex = getReportedIndex(kv.getConcept(), kv.getCode()); - sb.append(delimiter + currentIndex); - delimiter = ":"; - } if (currentKey != null) { - prevKey = currentKey.toString(); + prevKey = currentKey; } - currentKey = sb.toString(); + currentKey = key.getKey().stream() + .map(keyValue -> toStringValue(keyValue.getConcept(), keyValue.getCode())) + .collect(Collectors.joining(":")); } diff --git a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/FlatDataWriter.java b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/FlatDataWriter.java index 8638ddc..0d885d9 100644 --- a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/FlatDataWriter.java +++ b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/FlatDataWriter.java @@ -164,8 +164,7 @@ private void writeJsonObs(Observation obs, String seriesKey) { if (attrValue == null) { jsonGenerator.writeNull(); } else { - int idx = getReportedIndex(attr.getId(), attrValue); - jsonGenerator.writeNumber(idx); + jsonGenerator.writeString(toStringValue(attr.getId(), attrValue)); } } @@ -232,7 +231,7 @@ protected void writeAttributes() throws JsonGenerationException, IOException { LOG.debug("{attributes}"); jsonGenerator.writeObjectFieldStart("attributes"); - jsonGenerator.writeArrayFieldStart("dataset"); + jsonGenerator.writeArrayFieldStart("dataSet"); for (AttributeBean attribute : dsd.getDatasetAttributes()) { ComponentSuperBean attrSb = currentDSDSuperBean.getComponentById(attribute.getId()); writeComponent(attrSb, -1); diff --git a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/SeriesDataWriter.java b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/SeriesDataWriter.java index 93e5d07..18038d2 100644 --- a/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/SeriesDataWriter.java +++ b/SdmxDataParser/src/main/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/SeriesDataWriter.java @@ -1,9 +1,12 @@ package org.sdmxsource.sdmx.dataparser.engine.writer.jsonsupport; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; -import org.slf4j.LoggerFactory; -import org.slf4j.Logger; import org.sdmxsource.sdmx.api.constants.DATASET_ACTION; import org.sdmxsource.sdmx.api.constants.TIME_FORMAT; import org.sdmxsource.sdmx.api.manager.retrieval.SdmxSuperBeanRetrievalManager; @@ -22,11 +25,8 @@ import org.sdmxsource.sdmx.api.model.superbeans.datastructure.DimensionSuperBean; import org.sdmxsource.sdmx.util.date.DateUtil; import org.sdmxsource.util.ObjectUtil; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The type Series data writer. @@ -167,8 +167,7 @@ private void writeSeriesBlock(String currentKey, Keyable series) { if (kv == null) { jsonGenerator.writeNull(); } else { - int reportedIndex = getReportedIndex(kv.getConcept(), kv.getCode()); - jsonGenerator.writeNumber(reportedIndex); + jsonGenerator.writeString(toStringValue(kv.getConcept(), kv.getCode())); } } LOG.debug("[/attributes]"); @@ -222,30 +221,25 @@ private void writeJsonObs(Observation obs, int idx) { jsonGenerator.writeString(obs.getObservationValue()); // Write the attribute values - List obsAttrs = new ArrayList(); + List obsAttrs = new ArrayList<>(); List attr = currentDSDSuperBean.getBuiltFrom().getObservationAttributes(dimensionAtObservation); for (AttributeBean currentAttr : attr) { KeyValue kv = obs.getAttribute(currentAttr.getId()); if (kv == null) { kv = obs.getSeriesKey().getAttribute(currentAttr.getId()); } - String attrValue = kv != null ? kv.getCode() : null; - if (attrValue == null) { - obsAttrs.add(null); - } else { - int index = getReportedIndex(currentAttr.getId(), attrValue); - obsAttrs.add(index); - } + String attrCode = kv != null ? kv.getCode() : null; + obsAttrs.add(toStringValue(currentAttr.getId(), attrCode)); } // Only write out the attributes, if they are not all null and there are no annotations following if (ObjectUtil.validCollection(obsAttrs)) { if (!ObjectUtil.isAllNulls(obsAttrs) || obs.getAnnotations().size() > 0) { - for (Integer attrIdx : obsAttrs) { - if (attrIdx == null) { + for (String attrValue : obsAttrs) { + if (attrValue == null) { jsonGenerator.writeNull(); } else { - jsonGenerator.writeNumber(attrIdx); + jsonGenerator.writeString(attrValue); } } } @@ -404,7 +398,7 @@ protected void writeAttributes() throws JsonGenerationException, IOException { LOG.debug("{attributes}"); jsonGenerator.writeObjectFieldStart("attributes"); - jsonGenerator.writeArrayFieldStart("dataset"); + jsonGenerator.writeArrayFieldStart("dataSet"); for (AttributeBean attribute : dsd.getDatasetAttributes()) { ComponentSuperBean attrSb = currentDSDSuperBean.getComponentById(attribute.getId()); writeComponent(attrSb, -1); diff --git a/SdmxDataParser/src/test/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/ReadWriteEngineTest.java b/SdmxDataParser/src/test/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/ReadWriteEngineTest.java new file mode 100644 index 0000000..c4ee9a7 --- /dev/null +++ b/SdmxDataParser/src/test/java/org/sdmxsource/sdmx/dataparser/engine/writer/jsonsupport/ReadWriteEngineTest.java @@ -0,0 +1,173 @@ +package org.sdmxsource.sdmx.dataparser.engine.writer.jsonsupport; + +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.sdmxsource.sdmx.api.model.beans.datastructure.DimensionBean.TIME_DIMENSION_FIXED_ID; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.constants.DATASET_ACTION; +import org.sdmxsource.sdmx.api.engine.DataReaderEngine; +import org.sdmxsource.sdmx.api.engine.DataWriterEngine; +import org.sdmxsource.sdmx.api.factory.ReadableDataLocationFactory; +import org.sdmxsource.sdmx.api.factory.StructureParserFactory; +import org.sdmxsource.sdmx.api.manager.parse.StructureParsingManager; +import org.sdmxsource.sdmx.api.manager.retrieval.SdmxBeanRetrievalManager; +import org.sdmxsource.sdmx.api.manager.retrieval.SdmxSuperBeanRetrievalManager; +import org.sdmxsource.sdmx.api.model.StructureWorkspace; +import org.sdmxsource.sdmx.api.model.beans.base.AnnotationBean; +import org.sdmxsource.sdmx.api.model.data.KeyValue; +import org.sdmxsource.sdmx.api.model.data.Observation; +import org.sdmxsource.sdmx.api.model.header.DatasetHeaderBean; +import org.sdmxsource.sdmx.api.model.header.DatasetStructureReferenceBean; +import org.sdmxsource.sdmx.dataparser.engine.reader.json.JsonDataReaderEngine; +import org.sdmxsource.sdmx.dataparser.test.Series; +import org.sdmxsource.sdmx.sdmxbeans.model.header.DatasetHeaderBeanImpl; +import org.sdmxsource.sdmx.sdmxbeans.model.header.DatasetStructureReferenceBeanImpl; +import org.sdmxsource.sdmx.structureparser.builder.superbeans.impl.SuperBeansBuilderImpl; +import org.sdmxsource.sdmx.structureparser.manager.parsing.impl.StructureParsingManagerImpl; +import org.sdmxsource.sdmx.structureretrieval.manager.InMemoryRetrievalManager; +import org.sdmxsource.sdmx.structureretrieval.manager.SdmxSuperBeanRetrievalManagerImpl; +import org.sdmxsource.sdmx.util.beans.reference.MaintainableRefBeanImpl; +import org.sdmxsource.util.factory.SdmxSourceReadableDataLocationFactory; + +public class ReadWriteEngineTest { + + private final ReadableDataLocationFactory dataLocationFactory = new SdmxSourceReadableDataLocationFactory(); + private SdmxBeanRetrievalManager sdmxBeanRetrievalManager; + + @Test + public void shouldReadWriteTimeseriesDataset() throws IOException { + var superBeanRetrievalManager = getDataStructureSuperBean("structure/AGENCY_ID_SIMPLE_DF(2.0.0).xml"); + + var dsdRef = new MaintainableRefBeanImpl("AGENCY_ID", "SIMPLE_DSD", "3.0.0"); + var dsdSuperBean = superBeanRetrievalManager.getDataStructureSuperBean(dsdRef); + var dsd = dsdSuperBean.getBuiltFrom(); + + var dataflowRef = new MaintainableRefBeanImpl("AGENCY_ID", "SIMPLE_DF", "2.0.0"); + var dataflowSuperBean = superBeanRetrievalManager.getDataflowSuperBean(dataflowRef); + var dataflow = dataflowSuperBean.getBuiltFrom(); + + var is = ReadWriteEngineTest.class.getClassLoader().getResourceAsStream("data/json/timeseries-init-data.json"); + byte[] initDataBytes = is.readAllBytes(); + var dataLocation = dataLocationFactory.getReadableDataLocation(initDataBytes); + var reader = new JsonDataReaderEngine(dataLocation, sdmxBeanRetrievalManager, dsd, dataflow, null); + + assertTrue(reader.moveNextDataset()); + var series = readSeries(reader); + var datasetAttributes = reader.getDatasetAttributes(); // TODO works only if attributes go before series + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataWriterEngine writer = new JsonDataWriterEngine(output, superBeanRetrievalManager, false); + + writer.startDataset(null, dataflow, dsd, reader.getCurrentDatasetHeaderBean()); + datasetAttributes.forEach(attribute -> writer.writeAttributeValue(attribute.getConcept(), attribute.getCode())); // TODO always writes attributes after series + series.forEach(it -> writeSeries(writer, it, TIME_DIMENSION_FIXED_ID)); + + /* writer.startGroup("A1"); // TODO unable to write group attributes + writer.writeGroupKeyValue("DATA_DOMAIN", "cpi"); + writer.writeGroupKeyValue("COUNTRY", "c_1"); + writer.writeGroupKeyValue("COUNTERPART_AREA", "ca_1"); + writer.writeAttributeValue("A1", "group test"); +*/ + writer.close(); + assertThatJson(output.toString()).whenIgnoringPaths("header").isEqualTo(new String(initDataBytes)); + } + + @Test + public void shouldReadWriteFlatDataset() throws IOException { + String dimAtObs = DatasetStructureReferenceBean.ALL_DIMENSIONS; + var superBeanRetrievalManager = getDataStructureSuperBean("structure/AGENCY_SIMPLE_GENERAL_DF(1.0.0).xml"); + + var dsdRef = new MaintainableRefBeanImpl("AGENCY", "GENERAL_SIMPLE_DSD", "1.0.0"); + var dsdSuperBean = superBeanRetrievalManager.getDataStructureSuperBean(dsdRef); + var dsd = dsdSuperBean.getBuiltFrom(); + + var dataflowRef = new MaintainableRefBeanImpl("AGENCY", "SIMPLE_GENERAL_DF", "1.0.0"); + var dataflowSuperBean = superBeanRetrievalManager.getDataflowSuperBean(dataflowRef); + var dataflow = dataflowSuperBean.getBuiltFrom(); + + var is = ReadWriteEngineTest.class.getClassLoader().getResourceAsStream("data/json/flat-init-data.json"); + byte[] initDataBytes = is.readAllBytes(); + var dataLocation = dataLocationFactory.getReadableDataLocation(initDataBytes); + var reader = new JsonDataReaderEngine(dataLocation, sdmxBeanRetrievalManager, dsd, dataflow, null); + + assertTrue(reader.moveNextDataset()); + var series = readSeries(reader); + var datasetAttributes = reader.getDatasetAttributes(); + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DataWriterEngine writer = new JsonDataWriterEngine(output, superBeanRetrievalManager, true); + + DatasetStructureReferenceBean datasetStructureReferenceBean = new DatasetStructureReferenceBeanImpl( + UUID.randomUUID().toString(), dsd.asReference(), null, null, dimAtObs); + DatasetHeaderBean datasetHeaderBean = new DatasetHeaderBeanImpl(null, DATASET_ACTION.INFORMATION, + datasetStructureReferenceBean, dataflowRef, null, null, null, null, + -1, null, null); + writer.startDataset(null, dataflow, dsd, datasetHeaderBean); + datasetAttributes.forEach(attribute -> writer.writeAttributeValue(attribute.getConcept(), attribute.getCode())); + series.forEach(it -> writeSeries(writer, it, TIME_DIMENSION_FIXED_ID)); // TODO works only if pass dim at obs as time dimension + + /* writer.startGroup("A1"); // TODO not working + writer.writeGroupKeyValue("DATA_DOMAIN", "cpi"); + writer.writeGroupKeyValue("COUNTRY", "c_1"); + writer.writeGroupKeyValue("COUNTERPART_AREA", "ca_1"); + writer.writeAttributeValue("A1", "group test");*/ + + writer.close(); + assertThatJson(output.toString()).whenIgnoringPaths("header") + .isEqualTo(new String(initDataBytes)); + } + + private List readSeries(DataReaderEngine reader) { + List series = new ArrayList<>(); + + while (reader.moveNextKeyable()) { + var currentKey = reader.getCurrentKey(); + + var dimensions = currentKey.getKey().stream() + .collect(Collectors.toMap(KeyValue::getConcept, KeyValue::getCode,(s, s2) -> s, LinkedHashMap::new)); + + var attributes = currentKey.getAttributes().stream() + .collect(Collectors.toMap(KeyValue::getConcept, KeyValue::getCode)); + + List observations = new ArrayList<>(); + while (reader.moveNextObservation()) { + observations.add(reader.getCurrentObservation()); + } + + series.add(new Series("", attributes, dimensions, observations)); + } + + return series; + } + + private void writeSeries(DataWriterEngine writer, Series series, String dimAtObs) { + writer.startSeries(); + series.getDimensions().forEach(writer::writeSeriesKeyValue); + series.getAttributes().forEach(writer::writeAttributeValue); + series.getObservations().forEach(obs -> writeObservation(writer, obs, dimAtObs)); + } + + private void writeObservation(DataWriterEngine writer, Observation obs, String dimAtObs) { + writer.writeObservation(dimAtObs, obs.getObsTime(), obs.getObservationValue(), obs.getAnnotations().toArray(AnnotationBean[]::new)); + obs.getAttributes().forEach(keyValue -> writer.writeAttributeValue(keyValue.getConcept(), keyValue.getCode())); + } + + private SdmxSuperBeanRetrievalManager getDataStructureSuperBean(String structurePath) { + try (var is = SeriesDataWriter.class.getClassLoader().getResourceAsStream(structurePath)) { + StructureParsingManager manager = new StructureParsingManagerImpl(dataLocationFactory, new StructureParserFactory[0]); + StructureWorkspace structureWorkspace = manager.parseStructures(dataLocationFactory.getReadableDataLocation(is)); + sdmxBeanRetrievalManager = new InMemoryRetrievalManager(structureWorkspace.getStructureBeans(true)); + return new SdmxSuperBeanRetrievalManagerImpl(new SuperBeansBuilderImpl(), sdmxBeanRetrievalManager); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/SdmxDataParser/src/test/resources/data/json/flat-init-data.json b/SdmxDataParser/src/test/resources/data/json/flat-init-data.json new file mode 100644 index 0000000..a77684a --- /dev/null +++ b/SdmxDataParser/src/test/resources/data/json/flat-init-data.json @@ -0,0 +1,271 @@ +{ + "header": { + "id": "8c37c530-e682-4b42-a115-a239544d9860", + "prepared": "2024-01-18T07:23:38", + "test": false, + "sender": { + "id": "unknown", + "name": "unknown" + } + }, + "dataSets": [ + { + "action": "Information", + "attributes": [ + "dataset attribute" + ], + "observations": { + "CPI:c_1:W1:ind_1:0:0": [ + "10", + "obs comment1", + "obs status1", + "aobs date1", + "unit1", + null, + null, + null, + null, + null, + null + ], + "CPI:c_2:W1:ind_1:0:1": [ + "11", + "obs comment2", + "obs status2", + "aobs date2", + "unit2", + null, + null, + null, + null, + null, + null + ], + "CPI:c_3:W1:ind_1:0:2": [ + "12", + "obs comment3", + "obs status3", + "aobs date3", + "unit3", + null, + null, + null, + null, + null, + null + ], + "CPI:c_4:W1:ind_1:0:3": [ + "13", + "obs comment4", + "obs status4", + "aobs date4", + "unit4", + null, + null, + null, + null, + null, + null + ] + } + } + ], + "structure": { + "name": "meta each lvl general df", + "description": null, + "dimensions": { + "dataset": [], + "series": [], + "observation": [ + { + "id": "DATA_DOMAIN", + "name": "DATA_DOMAIN", + "keyPosition": 0, + "role": null, + "values": [] + }, + { + "id": "COUNTRY", + "name": "COUNTRY", + "keyPosition": 1, + "role": null, + "values": [] + }, + { + "id": "COUNTERPART_AREA", + "name": "COUNTERPART_AREA", + "keyPosition": 2, + "role": null, + "values": [] + }, + { + "id": "INDICATOR", + "name": "INDICATOR", + "keyPosition": 3, + "role": null, + "values": [] + }, + { + "id": "FREQ", + "name": "Frequency", + "keyPosition": 4, + "role": null, + "values": [ + { + "id": "A", + "name": "Annual" + } + ] + }, + { + "id": "TIME_PERIOD", + "name": "Time period", + "keyPosition": 5, + "role": "time", + "values": [ + { + "start": "2001-01-01T00:00:00", + "end": "2001-12-31T23:59:59", + "id": "2001", + "name": "2001" + }, + { + "start": "2001-01-01T00:00:00", + "end": "2001-03-31T23:59:59", + "id": "2001-Q1", + "name": "2001-Q1" + }, + { + "start": "2002-01-01T00:00:00", + "end": "2002-12-31T23:59:59", + "id": "2002", + "name": "2002" + }, + { + "start": "2003-01-01T00:00:00", + "end": "2003-12-31T23:59:59", + "id": "2003", + "name": "2003" + } + ] + } + ] + }, + "attributes": { + "dataSet": [ + { + "id": "DATASET_COMMENT_META", + "name": "DATASET_COMMENT_META", + "role": null, + "values": [] + } + ], + "series": [], + "observation": [ + { + "id": "OBS_COMMENT", + "name": "OBS_COMMENT", + "role": null, + "values": [] + }, + { + "id": "OBS_STATUS", + "name": "OBS_STATUS", + "role": null, + "values": [] + }, + { + "id": "OBS_UPDATE_DATE", + "name": "OBS_UPDATE_DATE", + "role": null, + "values": [] + }, + { + "id": "UNIT", + "name": "UNIT", + "role": null, + "values": [] + }, + { + "id": "COMMENT", + "name": "COMMENT", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + }, + { + "id": "STATUS", + "name": "STATUS", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + }, + { + "id": "UPDATE_DATE", + "name": "UPDATE_DATE", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + }, + { + "id": "GROUP_COMMENT_META", + "name": "GROUP_COMMENT_META", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA" + ] + }, + "values": [] + }, + { + "id": "SERIES_COMMENT_META", + "name": "SERIES_COMMENT_META", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + }, + { + "id": "OBS_COMMENT_META", + "name": "OBS_COMMENT_META", + "role": null, + "values": [] + } + ] + } + } +} \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/data/json/timeseries-init-data.json b/SdmxDataParser/src/test/resources/data/json/timeseries-init-data.json new file mode 100644 index 0000000..a0b2adf --- /dev/null +++ b/SdmxDataParser/src/test/resources/data/json/timeseries-init-data.json @@ -0,0 +1,275 @@ +{ + "header": { + "id": "266fef6f-f30a-44b5-994c-d0c98257d210", + "prepared": "2024-01-12T08:29:48", + "test": false, + "sender": { + "id": "unknown", + "name": "unknown" + } + }, + "dataSets": [ + { + "action": "Information", + "attributes": [ + "dataset attribute" + ], + "series": { + "CPI:c_1:ca_1:i_1:0": { + "attributes": [ + "series1 comment", + "series1 status", + null, + null, + null + ], + "observations": { + "0": [ + "11", + "observation1 comment", + "observation1 status", + null, + null, + null + ] + } + }, + "CPI:c_2:ca_1:i_2:1": { + "attributes": [ + "series2 comment", + "series2 status", + null, + null, + null + ], + "observations": { + "1": [ + "21" + ] + } + }, + "CPI:c_3:ca_1:i_2:0": { + "attributes": [ + "series3 comment", + "series3 status", + null, + null, + null + ], + "observations": { + "2": [ + "31" + ], + "3": [ + "32" + ] + } + } + } + } + ], + "structure": { + "name": "simple df", + "description": null, + "dimensions": { + "dataset": [], + "series": [ + { + "id": "DATA_DOMAIN", + "name": "DATA_DOMAIN", + "keyPosition": 0, + "role": null, + "values": [] + }, + { + "id": "COUNTRY", + "name": "COUNTRY", + "keyPosition": 1, + "role": null, + "values": [] + }, + { + "id": "COUNTERPART_AREA", + "name": "COUNTERPART_AREA", + "keyPosition": 2, + "role": null, + "values": [] + }, + { + "id": "INDICATOR", + "name": "INDICATOR", + "keyPosition": 3, + "role": null, + "values": [] + }, + { + "id": "FREQ", + "name": "Frequency", + "keyPosition": 4, + "role": null, + "values": [ + { + "id": "A", + "name": "Annual" + }, + { + "id": "Q", + "name": "Quarterly" + } + ] + } + ], + "observation": [ + { + "id": "TIME_PERIOD", + "name": "Time period", + "keyPosition": 5, + "role": "time", + "values": [ + { + "start": "2001-01-01T00:00:00", + "end": "2001-12-31T23:59:59", + "id": "2001", + "name": "2001" + }, + { + "start": "2001-01-01T00:00:00", + "end": "2001-03-31T23:59:59", + "id": "2001-Q1", + "name": "2001-Q1" + }, + { + "start": "2002-01-01T00:00:00", + "end": "2002-12-31T23:59:59", + "id": "2002", + "name": "2002" + }, + { + "start": "2003-01-01T00:00:00", + "end": "2003-12-31T23:59:59", + "id": "2003", + "name": "2003" + } + ] + } + ] + }, + "attributes": { + "dataSet": [ + { + "id": "A0", + "name": "DATASET_COMMENT_META", + "role": null, + "values": [] + } + ], + "series": [ + { + "id": "COMMENT", + "name": "COMMENT", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + }, + { + "id": "STATUS", + "name": "STATUS", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + }, + { + "id": "UPDATE_DATE", + "name": "UPDATE_DATE", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + }, + { + "id": "A1", + "name": "GROUP_COMMENT_META", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA" + ] + }, + "values": [] + }, + { + "id": "A2", + "name": "SERIES_COMMENT_META", + "role": null, + "relationship": { + "dimensions": [ + "DATA_DOMAIN", + "COUNTRY", + "COUNTERPART_AREA", + "INDICATOR", + "FREQ" + ] + }, + "values": [] + } + ], + "observation": [ + { + "id": "OBS_COMMENT", + "name": "OBS_COMMENT", + "role": null, + "values": [] + }, + { + "id": "OBS_STATUS", + "name": "OBS_STATUS", + "role": null, + "values": [] + }, + { + "id": "OBS_UPDATE_DATE", + "name": "OBS_UPDATE_DATE", + "role": null, + "values": [] + }, + { + "id": "UNIT", + "name": "UNIT", + "role": null, + "values": [] + }, + { + "id": "A3", + "name": "OBS_COMMENT_META", + "role": null, + "values": [] + } + ] + } + } +} \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/structure/AGENCY_ID_SIMPLE_DF(2.0.0).xml b/SdmxDataParser/src/test/resources/structure/AGENCY_ID_SIMPLE_DF(2.0.0).xml new file mode 100644 index 0000000..8b73ba9 --- /dev/null +++ b/SdmxDataParser/src/test/resources/structure/AGENCY_ID_SIMPLE_DF(2.0.0).xml @@ -0,0 +1,587 @@ + + + + IDREF2563 + false + 2024-01-09T15:13:33.319346014Z + + + + + + + + + Frequency + This code list provides a set of values indicating the "frequency" of the data (e.g. weekly, monthly, quarterly). The concept “frequency” may refer to various stages in the production process, e.g. data collection or data dissemination. For example, a time series could be disseminated at annual frequency but the underlying data are compiled monthly. The code list is applicable for all different uses of "frequency". This code list was formally adopted on 4 December 2013. More information about and supporting material for this code list and SDMX code lists in general (e.g. list of generic codes for expressing general concepts like "Total", "Unknown", etc.; syntaxes for the creation of further codes; general guidelines for the creation of SDMX code lists) can be found at this address: https://sdmx.org/?page_id=4345. + + Annual + To be used for data collected or disseminated every year. + + + Quarterly + To be used for data collected or disseminated every quarter. + + + + + + + + + + SIMPLE CONCEPTS + + Frequency + The time interval at which observations occur over a given time period. + + + + + + + + String + + + + + + Observation + The value of a particular variable at a particular period. + + + + + + Time period + The period of time or point in time to which the measured observation refers. + + + + + + DATA_DOMAIN + + + + + + COUNTRY + + + + + + COUNTERPART_AREA + + + + + + OBS_COMMENT + + + + + + OBS_STATUS + + + + + + OBS_UPDATE_DATE + + + + + + UNIT + + + + + + COMMENT + + + + + + STATUS + + + + + + UPDATE_DATE + + + + + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=AGENCY_ID:SIMPLE_CONCEPTS(1.0.0) + + + + SIMPLE CONCEPTS + + Frequency + The time interval at which observations occur over a given time period. + + + + + + + + String + + + + + + Observation + The value of a particular variable at a particular period. + + + + + + Time period + The period of time or point in time to which the measured observation refers. + + + + + + DATA_DOMAIN + + + + + + COUNTRY + + + + + + COUNTERPART_AREA + + + + + + OBS_COMMENT + + + + + + OBS_STATUS + + + + + + OBS_UPDATE_DATE + + + + + + UNIT + + + + + + COMMENT + + + + + + STATUS + + + + + + UPDATE_DATE + + + + + + INDICATOR + + + + + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=AGENCY_ID:SIMPLE_CONCEPTS(1.2.0) + + + + SIMPLE CONCEPTS + + Frequency + The time interval at which observations occur over a given time period. + + + + + + + + String + + + + + + Observation + The value of a particular variable at a particular period. + + + + + + Time period + The period of time or point in time to which the measured observation refers. + + + + + + DATA_DOMAIN + + + + + + COUNTRY + + + + + + COUNTERPART_AREA + + + + + + OBS_COMMENT + + + + + + OBS_STATUS + + + + + + OBS_UPDATE_DATE + + + + + + UNIT + + + + + + COMMENT + + + + + + STATUS + + + + + + UPDATE_DATE + + + + + + INDICATOR + + + + + + DATASET_COMMENT_META + + + + + + GROUP_COMMENT_META + + + + + + SERIES_COMMENT_META + + + + + + OBS_COMMENT_META + + + + + + + + + + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=AGENCY_ID:SIMPLE_DSD(2.0.0) + + + + simple dsd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple df + + + + + + + \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/structure/AGENCY_SIMPLE_GENERAL_DF(1.0.0).xml b/SdmxDataParser/src/test/resources/structure/AGENCY_SIMPLE_GENERAL_DF(1.0.0).xml new file mode 100644 index 0000000..b9cd160 --- /dev/null +++ b/SdmxDataParser/src/test/resources/structure/AGENCY_SIMPLE_GENERAL_DF(1.0.0).xml @@ -0,0 +1,672 @@ + + + + IDREF4695 + false + 2024-01-17T13:58:42.414461093Z + + + + + + + + Frequency + This code list provides a set of values indicating the "frequency" of the data (e.g. weekly, monthly, quarterly). The concept “frequency” may refer to various stages in the production process, e.g. data collection or data dissemination. For example, a time series could be disseminated at annual frequency but the underlying data are compiled monthly. The code list is applicable for all different uses of "frequency". This code list was formally adopted on 4 December 2013. More information about and supporting material for this code list and SDMX code lists in general (e.g. list of generic codes for expressing general concepts like "Total", "Unknown", etc.; syntaxes for the creation of further codes; general guidelines for the creation of SDMX code lists) can be found at this address: https://sdmx.org/?page_id=4345. + chq + + Annual CHAPLIUK 2 + To be used for data collected or disseminated every year. + + + Daily – businessweek + Similar to "daily", however there are no observations for Saturdays and Sundays (so, neither "missing values" nor "numeric values" should be provided for Saturday and Sunday). This treatment ("business") is one way to deal with such cases, but it is not the only option. Such a time series could alternatively be considered daily ("D"), thus, with missing values in the weekend. + + + Daily + To be used for data collected or disseminated every day. + + + Hourly + To be used for data collected or disseminated every hour. + + + Monthly + To be used for data collected or disseminated every month. + + + Minutely + While N denotes "minutely", usually, there may be no observations every minute (for several series the frequency is usually "irregular" within a day/days). And though observations may be sparse (not collected or disseminated every minute), missing values do not need to be given for the minutes when no observations exist: in any case the time stamp determines when an observation is observed. + + + Quarterly + To be used for data collected or disseminated every quarter. + + + Half-yearly, semester + To be used for data collected or disseminated every semester. + + + Weekly CHAPLIUK 2 + To be used for data collected or disseminated every week. + + + + + + Frequency + This code list provides a set of values indicating the "frequency" of the data (e.g. weekly, monthly, quarterly). The concept “frequency” may refer to various stages in the production process, e.g. data collection or data dissemination. For example, a time series could be disseminated at annual frequency but the underlying data are compiled monthly. The code list is applicable for all different uses of "frequency". This code list was formally adopted on 4 December 2013. More information about and supporting material for this code list and SDMX code lists in general (e.g. list of generic codes for expressing general concepts like "Total", "Unknown", etc.; syntaxes for the creation of further codes; general guidelines for the creation of SDMX code lists) can be found at this address: https://sdmx.org/?page_id=4345. + + Annual + To be used for data collected or disseminated every year. + + + Daily – businessweek + Similar to "daily", however there are no observations for Saturdays and Sundays (so, neither "missing values" nor "numeric values" should be provided for Saturday and Sunday). This treatment ("business") is one way to deal with such cases, but it is not the only option. Such a time series could alternatively be considered daily ("D"), thus, with missing values in the weekend. + + + Daily + To be used for data collected or disseminated every day. + + + Hourly + To be used for data collected or disseminated every hour. + + + Monthly + To be used for data collected or disseminated every month. + + + Minutely + While N denotes "minutely", usually, there may be no observations every minute (for several series the frequency is usually "irregular" within a day/days). And though observations may be sparse (not collected or disseminated every minute), missing values do not need to be given for the minutes when no observations exist: in any case the time stamp determines when an observation is observed. + + + Quarterly + To be used for data collected or disseminated every quarter. + + + Half-yearly, semester + To be used for data collected or disseminated every semester. + + + Weekly + To be used for data collected or disseminated every week. + + + + + + + + SIMPLE CONCEPTS + + Frequency + The time interval at which observations occur over a given time period. + + + + + + + + String + + + + + + Observation + The value of a particular variable at a particular period. + + + + + + Time period + The period of time or point in time to which the measured observation refers. + + + + + + DATA_DOMAIN + + + + + + COUNTRY + + + + + + COUNTERPART_AREA + + + + + + OBS_COMMENT + + + + + + OBS_STATUS + + + + + + OBS_UPDATE_DATE + + + + + + UNIT + + + + + + COMMENT + + + + + + STATUS + + + + + + UPDATE_DATE + + + + + + INDICATOR + + + + + + + + + + + simple concepts + + Observation + The value of a particular variable at a particular period. + + + + + + Time period + The period of time or point in time to which the measured observation refers. + + + + + + String + + + + + + Frequency + The time interval at which observations occur over a given time period. + + + + + + + + DATA_DOMAIN + + + + + + COUNTRY + + + + + + COUNTERPART_AREA + + + + + + INDICATOR + + + + + + OBS_COMMENT_ATTR + + + + + + OBS_STATUS + + + + + + OBS_UPDATE_DATE + + + + + + UNIT + + + + + + COMMENT + + + + + + STATUS + + + + + + UPDATE_DATE + + + + + + DATASET_COMMENT_META + + + + + + GROUP_COMMENT_META + + + + + + SERIES_COMMENT_META + + + + + + OBS_COMMENT_META + + + + + + + + + SIMPLE CONCEPTS + + Frequency + The time interval at which observations occur over a given time period. + + + + + + + + String + + + + + + Observation + The value of a particular variable at a particular period. + + + + + + Time period + The period of time or point in time to which the measured observation refers. + + + + + + DATA_DOMAIN + + + + + + COUNTRY + + + + + + COUNTERPART_AREA + + + + + + OBS_COMMENT + + + + + + OBS_STATUS + + + + + + OBS_UPDATE_DATE + + + + + + UNIT + + + + + + COMMENT + + + + + + STATUS + + + + + + UPDATE_DATE + + + + + + INDICATOR + + + + + + DATASET_COMMENT_META + + + + + + GROUP_COMMENT_META + + + + + + SERIES_COMMENT_META + + + + + + OBS_COMMENT_META + + + + + + + + + + + general simple dsd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + meta each lvl general df + + + + + + + \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/writer/Json_ts_0.json b/SdmxDataParser/src/test/resources/writer/Json_ts_0.json index f4547c5..936f3aa 100644 --- a/SdmxDataParser/src/test/resources/writer/Json_ts_0.json +++ b/SdmxDataParser/src/test/resources/writer/Json_ts_0.json @@ -1 +1 @@ -{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":[0],"observations":{"0":["10"],"1":["11"],"2":["12"],"3":["25"]}},"1:0:0":{"attributes":[null],"observations":{"4":["0"],"5":["1"],"6":["2"],"7":["3"],"8":["4"],"9":["5"]}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"Q","name":"Quarterly"},{"id":"M","name":"Monthly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[{"start":"2021-01-01T00:00:00","end":"2021-03-31T23:59:59","id":"2021-Q1","name":"2021-Q1"},{"start":"2021-04-01T00:00:00","end":"2021-06-30T23:59:59","id":"2021-Q2","name":"2021-Q2"},{"start":"2021-07-01T00:00:00","end":"2021-09-30T23:59:59","id":"2021-Q3","name":"2021-Q3"},{"start":"2021-10-01T00:00:00","end":"2021-12-31T23:59:59","id":"2021-Q4","name":"2021-Q4"},{"start":"2022-01-01T00:00:00","end":"2022-01-31T23:59:59","id":"2022-M01","name":"2022-M01"},{"start":"2022-02-01T00:00:00","end":"2022-02-28T23:59:59","id":"2022-M02","name":"2022-M02"},{"start":"2022-03-01T00:00:00","end":"2022-03-31T23:59:59","id":"2022-M03","name":"2022-M03"},{"start":"2022-04-01T00:00:00","end":"2022-04-30T23:59:59","id":"2022-M04","name":"2022-M04"},{"start":"2022-05-01T00:00:00","end":"2022-05-31T23:59:59","id":"2022-M05","name":"2022-M05"},{"start":"2022-06-01T00:00:00","end":"2022-06-30T23:59:59","id":"2022-M06","name":"2022-M06"}]}]},"attributes":{"dataset":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"1","name":"1"}]}],"observation":[]}}} \ No newline at end of file +{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":["0"],"observations":{"0":["10"],"1":["11"],"2":["12"],"3":["25"]}},"1:0:0":{"attributes":[null],"observations":{"4":["0"],"5":["1"],"6":["2"],"7":["3"],"8":["4"],"9":["5"]}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"Q","name":"Quarterly"},{"id":"M","name":"Monthly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[{"start":"2021-01-01T00:00:00","end":"2021-03-31T23:59:59","id":"2021-Q1","name":"2021-Q1"},{"start":"2021-04-01T00:00:00","end":"2021-06-30T23:59:59","id":"2021-Q2","name":"2021-Q2"},{"start":"2021-07-01T00:00:00","end":"2021-09-30T23:59:59","id":"2021-Q3","name":"2021-Q3"},{"start":"2021-10-01T00:00:00","end":"2021-12-31T23:59:59","id":"2021-Q4","name":"2021-Q4"},{"start":"2022-01-01T00:00:00","end":"2022-01-31T23:59:59","id":"2022-M01","name":"2022-M01"},{"start":"2022-02-01T00:00:00","end":"2022-02-28T23:59:59","id":"2022-M02","name":"2022-M02"},{"start":"2022-03-01T00:00:00","end":"2022-03-31T23:59:59","id":"2022-M03","name":"2022-M03"},{"start":"2022-04-01T00:00:00","end":"2022-04-30T23:59:59","id":"2022-M04","name":"2022-M04"},{"start":"2022-05-01T00:00:00","end":"2022-05-31T23:59:59","id":"2022-M05","name":"2022-M05"},{"start":"2022-06-01T00:00:00","end":"2022-06-30T23:59:59","id":"2022-M06","name":"2022-M06"}]}]},"attributes":{"dataSet":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"1","name":"1"}]}],"observation":[]}}} \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/writer/Json_ts_3.json b/SdmxDataParser/src/test/resources/writer/Json_ts_3.json index da5c3ed..ca8057a 100644 --- a/SdmxDataParser/src/test/resources/writer/Json_ts_3.json +++ b/SdmxDataParser/src/test/resources/writer/Json_ts_3.json @@ -1 +1 @@ -{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":[0],"observations":{}},"1:0:0":{"attributes":[1],"observations":{"0":["10"],"1":["11"],"2":["12"],"3":["25"]}},"2:0:0":{"attributes":[null],"observations":{"4":["0"],"5":["1"],"6":["2"],"7":["3"],"8":["4"],"9":["5"]}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"A","name":"Annually"},{"id":"Q","name":"Quarterly"},{"id":"M","name":"Monthly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[{"start":"2021-01-01T00:00:00","end":"2021-03-31T23:59:59","id":"2021-Q1","name":"2021-Q1"},{"start":"2021-04-01T00:00:00","end":"2021-06-30T23:59:59","id":"2021-Q2","name":"2021-Q2"},{"start":"2021-07-01T00:00:00","end":"2021-09-30T23:59:59","id":"2021-Q3","name":"2021-Q3"},{"start":"2021-10-01T00:00:00","end":"2021-12-31T23:59:59","id":"2021-Q4","name":"2021-Q4"},{"start":"2022-01-01T00:00:00","end":"2022-01-31T23:59:59","id":"2022-M01","name":"2022-M01"},{"start":"2022-02-01T00:00:00","end":"2022-02-28T23:59:59","id":"2022-M02","name":"2022-M02"},{"start":"2022-03-01T00:00:00","end":"2022-03-31T23:59:59","id":"2022-M03","name":"2022-M03"},{"start":"2022-04-01T00:00:00","end":"2022-04-30T23:59:59","id":"2022-M04","name":"2022-M04"},{"start":"2022-05-01T00:00:00","end":"2022-05-31T23:59:59","id":"2022-M05","name":"2022-M05"},{"start":"2022-06-01T00:00:00","end":"2022-06-30T23:59:59","id":"2022-M06","name":"2022-M06"}]}]},"attributes":{"dataset":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"2","name":"2"},{"id":"1","name":"1"}]}],"observation":[]}}} \ No newline at end of file +{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":["0"],"observations":{}},"1:0:0":{"attributes":["1"],"observations":{"0":["10"],"1":["11"],"2":["12"],"3":["25"]}},"2:0:0":{"attributes":[null],"observations":{"4":["0"],"5":["1"],"6":["2"],"7":["3"],"8":["4"],"9":["5"]}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"A","name":"Annually"},{"id":"Q","name":"Quarterly"},{"id":"M","name":"Monthly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[{"start":"2021-01-01T00:00:00","end":"2021-03-31T23:59:59","id":"2021-Q1","name":"2021-Q1"},{"start":"2021-04-01T00:00:00","end":"2021-06-30T23:59:59","id":"2021-Q2","name":"2021-Q2"},{"start":"2021-07-01T00:00:00","end":"2021-09-30T23:59:59","id":"2021-Q3","name":"2021-Q3"},{"start":"2021-10-01T00:00:00","end":"2021-12-31T23:59:59","id":"2021-Q4","name":"2021-Q4"},{"start":"2022-01-01T00:00:00","end":"2022-01-31T23:59:59","id":"2022-M01","name":"2022-M01"},{"start":"2022-02-01T00:00:00","end":"2022-02-28T23:59:59","id":"2022-M02","name":"2022-M02"},{"start":"2022-03-01T00:00:00","end":"2022-03-31T23:59:59","id":"2022-M03","name":"2022-M03"},{"start":"2022-04-01T00:00:00","end":"2022-04-30T23:59:59","id":"2022-M04","name":"2022-M04"},{"start":"2022-05-01T00:00:00","end":"2022-05-31T23:59:59","id":"2022-M05","name":"2022-M05"},{"start":"2022-06-01T00:00:00","end":"2022-06-30T23:59:59","id":"2022-M06","name":"2022-M06"}]}]},"attributes":{"dataSet":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"2","name":"2"},{"id":"1","name":"1"}]}],"observation":[]}}} \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/writer/Json_ts_empty.json b/SdmxDataParser/src/test/resources/writer/Json_ts_empty.json index 0ea7a2f..6b55c33 100644 --- a/SdmxDataParser/src/test/resources/writer/Json_ts_empty.json +++ b/SdmxDataParser/src/test/resources/writer/Json_ts_empty.json @@ -1 +1 @@ -{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":[null],"observations":{}},"1:0:0":{"attributes":[0],"observations":{}},"2:0:0":{"attributes":[1],"observations":{}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"A","name":"Annually"},{"id":"Q","name":"Quarterly"},{"id":"M","name":"Monthly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[]}]},"attributes":{"dataset":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"1","name":"1"},{"id":"2","name":"2"}]}],"observation":[]}}} \ No newline at end of file +{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":[null],"observations":{}},"1:0:0":{"attributes":["0"],"observations":{}},"2:0:0":{"attributes":["1"],"observations":{}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"A","name":"Annually"},{"id":"Q","name":"Quarterly"},{"id":"M","name":"Monthly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[]}]},"attributes":{"dataSet":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"1","name":"1"},{"id":"2","name":"2"}]}],"observation":[]}}} \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/writer/Json_ts_empty_2.json b/SdmxDataParser/src/test/resources/writer/Json_ts_empty_2.json index 477a968..70a9773 100644 --- a/SdmxDataParser/src/test/resources/writer/Json_ts_empty_2.json +++ b/SdmxDataParser/src/test/resources/writer/Json_ts_empty_2.json @@ -1 +1 @@ -{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":[0],"observations":{}},"1:0:0":{"attributes":[1],"observations":{}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"A","name":"Annually"},{"id":"Q","name":"Quarterly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[]}]},"attributes":{"dataset":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"2","name":"2"},{"id":"1","name":"1"}]}],"observation":[]}}} \ No newline at end of file +{"header":{"id":"MESSAGE_ID","prepared":"2021-07-07T00:00:00","test":true,"sender":{"id":"SENDER_ID","name":"unknown"}},"dataSets":[{"action":"Information","series":{"0:0:0":{"attributes":["0"],"observations":{}},"1:0:0":{"attributes":["1"],"observations":{}}}}],"structure":{"name":"FLOW_NAME","description":null,"dimensions":{"dataset":[],"series":[{"id":"FREQ","name":"FREQ","keyPosition":0,"role":null,"values":[{"id":"A","name":"Annually"},{"id":"Q","name":"Quarterly"}]},{"id":"ADJUSTMENT","name":"ADJUSTMENT","keyPosition":1,"role":null,"values":[{"id":"N","name":"No"}]},{"id":"STS_ACTIVITY","name":"STS_ACTIVITY","keyPosition":2,"role":null,"values":[{"id":"A","name":"Act"}]}],"observation":[{"id":"TIME_PERIOD","name":"TIME_PERIOD","keyPosition":3,"role":"time","values":[]}]},"attributes":{"dataSet":[],"series":[{"id":"DECIMALS","name":"DECIMALS","role":null,"relationship":{"dimensions":["FREQ","ADJUSTMENT","STS_ACTIVITY"]},"values":[{"id":"2","name":"2"},{"id":"1","name":"1"}]}],"observation":[]}}} \ No newline at end of file diff --git a/SdmxDataParser/src/test/resources/writer/shouldWriteTimeSeriesWithUncodedComponents/expected.json b/SdmxDataParser/src/test/resources/writer/shouldWriteTimeSeriesWithUncodedComponents/expected.json new file mode 100644 index 0000000..42b76c0 --- /dev/null +++ b/SdmxDataParser/src/test/resources/writer/shouldWriteTimeSeriesWithUncodedComponents/expected.json @@ -0,0 +1,180 @@ +{ + "header": { + "id": "MESSAGE_ID", + "prepared": "2021-07-07T00:00:00", + "test": true, + "sender": { + "id": "SENDER_ID", + "name": "unknown" + } + }, + "dataSets": [ + { + "action": "Information", + "series": { + "A:N:A": { + "attributes": [ + "2" + ], + "observations": {} + }, + "Q:N:A": { + "attributes": [ + "1" + ], + "observations": { + "0": [ + "10" + ], + "1": [ + "11" + ], + "2": [ + "12" + ], + "3": [ + "25" + ] + } + }, + "M:N:A": { + "attributes": [ + null + ], + "observations": { + "4": [ + "0" + ], + "5": [ + "1" + ], + "6": [ + "2" + ], + "7": [ + "3" + ], + "8": [ + "4" + ], + "9": [ + "5" + ] + } + } + } + } + ], + "structure": { + "name": "FLOW_NAME", + "description": null, + "dimensions": { + "dataset": [], + "series": [ + { + "id": "FREQ", + "name": "FREQ", + "keyPosition": 0, + "role": null, + "values": [] + }, + { + "id": "ADJUSTMENT", + "name": "ADJUSTMENT", + "keyPosition": 1, + "role": null, + "values": [] + }, + { + "id": "STS_ACTIVITY", + "name": "STS_ACTIVITY", + "keyPosition": 2, + "role": null, + "values": [] + } + ], + "observation": [ + { + "id": "TIME_PERIOD", + "name": "TIME_PERIOD", + "keyPosition": 3, + "role": "time", + "values": [ + { + "start": "2021-01-01T00:00:00", + "end": "2021-03-31T23:59:59", + "id": "2021-Q1", + "name": "2021-Q1" + }, + { + "start": "2021-04-01T00:00:00", + "end": "2021-06-30T23:59:59", + "id": "2021-Q2", + "name": "2021-Q2" + }, + { + "start": "2021-07-01T00:00:00", + "end": "2021-09-30T23:59:59", + "id": "2021-Q3", + "name": "2021-Q3" + }, + { + "start": "2021-10-01T00:00:00", + "end": "2021-12-31T23:59:59", + "id": "2021-Q4", + "name": "2021-Q4" + }, + { + "start": "2022-01-01T00:00:00", + "end": "2022-01-31T23:59:59", + "id": "2022-M01", + "name": "2022-M01" + }, + { + "start": "2022-02-01T00:00:00", + "end": "2022-02-28T23:59:59", + "id": "2022-M02", + "name": "2022-M02" + }, + { + "start": "2022-03-01T00:00:00", + "end": "2022-03-31T23:59:59", + "id": "2022-M03", + "name": "2022-M03" + }, + { + "start": "2022-04-01T00:00:00", + "end": "2022-04-30T23:59:59", + "id": "2022-M04", + "name": "2022-M04" + }, + { + "start": "2022-05-01T00:00:00", + "end": "2022-05-31T23:59:59", + "id": "2022-M05", + "name": "2022-M05" + }, + { + "start": "2022-06-01T00:00:00", + "end": "2022-06-30T23:59:59", + "id": "2022-M06", + "name": "2022-M06" + } + ] + } + ] + }, + "attributes": { + "dataset": [], + "series": [ + { + "id": "DECIMALS", + "name": "DECIMALS", + "role": null, + "values": [] + } + ], + "observation": [] + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 01b8166..08e2d07 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,7 @@ version=1.7.0-SNAPSHOT fasterxml_version=2.16.0 spring_version=5.3.31 -slf4j_version=2.0.9 \ No newline at end of file +slf4j_version=2.0.9 + +assertj_version=3.24.2 +json_unit_version=2.37.0