Skip to content

Commit 47b63e0

Browse files
authored
Merge pull request #259 from com-pas/return-labels-by-list
Return Labels when Listing SCL Files for a SCL Type
2 parents 269b067 + 85aff73 commit 47b63e0

File tree

29 files changed

+402
-157
lines changed

29 files changed

+402
-157
lines changed

app/src/test/java/org/lfenergy/compas/scl/data/rest/v1/CompasSclDataResourceAsEditorTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import java.io.IOException;
2424
import java.util.Collections;
25+
import java.util.List;
2526
import java.util.UUID;
2627

2728
import static io.restassured.RestAssured.given;
@@ -50,9 +51,10 @@ void list_WhenCalled_ThenItemResponseRetrieved() {
5051
var uuid = UUID.randomUUID();
5152
var name = "name";
5253
var version = "1.0.0";
54+
var labels = List.of("Label1");
5355

5456
when(compasSclDataService.list(type))
55-
.thenReturn(Collections.singletonList(new Item(uuid.toString(), name, version)));
57+
.thenReturn(Collections.singletonList(new Item(uuid.toString(), name, version, labels)));
5658

5759
var response = given()
5860
.pathParam(TYPE_PATH_PARAM, type)
@@ -66,6 +68,7 @@ void list_WhenCalled_ThenItemResponseRetrieved() {
6668
assertEquals(uuid.toString(), xmlPath.get("ListResponse.Item[0].Id"));
6769
assertEquals(name, xmlPath.get("ListResponse.Item[0].Name"));
6870
assertEquals(version, xmlPath.get("ListResponse.Item[0].Version"));
71+
assertEquals(labels.get(0), xmlPath.get("ListResponse.Item[0].Label"));
6972
verify(compasSclDataService, times(1)).list(type);
7073
}
7174

app/src/test/java/org/lfenergy/compas/scl/data/rest/v1/CompasSclDataResourceAsReaderTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.io.IOException;
2222
import java.util.Collections;
23+
import java.util.List;
2324
import java.util.UUID;
2425

2526
import static io.restassured.RestAssured.given;
@@ -42,9 +43,10 @@ void list_WhenCalled_ThenItemResponseRetrieved() {
4243
var uuid = UUID.randomUUID();
4344
var name = "name";
4445
var version = "1.0.0";
46+
var labels = List.of("Label1");
4547

4648
when(compasSclDataService.list(type))
47-
.thenReturn(Collections.singletonList(new Item(uuid.toString(), name, version)));
49+
.thenReturn(Collections.singletonList(new Item(uuid.toString(), name, version, labels)));
4850

4951
var response = given()
5052
.pathParam(TYPE_PATH_PARAM, type)
@@ -58,6 +60,7 @@ void list_WhenCalled_ThenItemResponseRetrieved() {
5860
assertEquals(uuid.toString(), xmlPath.get("ListResponse.Item[0].Id"));
5961
assertEquals(name, xmlPath.get("ListResponse.Item[0].Name"));
6062
assertEquals(version, xmlPath.get("ListResponse.Item[0].Version"));
63+
assertEquals(labels.get(0), xmlPath.get("ListResponse.Item[0].Label"));
6164
verify(compasSclDataService, times(1)).list(type);
6265
}
6366

repository-basex/src/main/java/org/lfenergy/compas/scl/data/basex/repository/CompasSclDataBaseXRepository.java

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,19 @@
2626
import java.util.List;
2727
import java.util.UUID;
2828

29-
import static org.lfenergy.compas.scl.data.SclDataServiceConstants.*;
29+
import static org.lfenergy.compas.scl.data.SclDataServiceConstants.SCL_DATA_SERVICE_V1_NS_URI;
30+
import static org.lfenergy.compas.scl.data.SclDataServiceConstants.SCL_NS_URI;
3031
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.BASEX_COMMAND_ERROR_CODE;
3132
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.BASEX_QUERY_ERROR_CODE;
33+
import static org.lfenergy.compas.scl.extensions.commons.CompasExtensionsConstants.COMPAS_EXTENSION_NS_URI;
34+
import static org.lfenergy.compas.scl.extensions.commons.CompasExtensionsConstants.COMPAS_SCL_EXTENSION_TYPE;
3235

3336
/**
3437
* This implementation of the repository will store the SCL XML Files in BaseX, this is a XML Database.
3538
* For more information see https://basex.org/.
3639
* <p>
3740
* For every type of SCL a separate database is created in which the SCL XML Files are stored.
38-
* every entries is stored under &lt;ID&gt;/&lt;Major version&gt;/&lt;Minor version&gt;/&lt;Patch version&gt;/scl.xml.
41+
* Every entry is stored under &lt;ID&gt;/&lt;Major version&gt;/&lt;Minor version&gt;/&lt;Patch version&gt;/scl.xml.
3942
* This combination is always unique and easy to use.
4043
*/
4144
public class CompasSclDataBaseXRepository implements CompasSclDataRepository {
@@ -48,8 +51,8 @@ public class CompasSclDataBaseXRepository implements CompasSclDataRepository {
4851
declare variable $compasSclExtensionType := '%s';
4952
declare variable $compasDataServiceNamespace := '%s';
5053
""".formatted(SCL_NS_URI, COMPAS_EXTENSION_NS_URI, COMPAS_SCL_EXTENSION_TYPE, SCL_DATA_SERVICE_V1_NS_URI);
51-
// This find method always searches for the latest version.
52-
// Retrieve all versions using db:list-details function.
54+
55+
// This find method always searches for the latest version. Retrieve all versions using db:list-details function.
5356
// Sort the result descending, this way the last version is the first.
5457
private static final String DECLARE_LATEST_VERSION_FUNC = """
5558
declare function local:latest-version($db as xs:string, $id as xs:string) as document-node()? {
@@ -66,6 +69,15 @@ public class CompasSclDataBaseXRepository implements CompasSclDataRepository {
6669
};
6770
""";
6871

72+
// Retrieve the Labels as XML Label elements from the XML. The result can be returned by the List functions.
73+
private static final String DECLARE_LABELS_FUNC = """
74+
declare function local:createLabelsResponse($latestScl as document-node()) as xs:string* {
75+
let $labels := $latestScl/scl:SCL/scl:Private[@type=$compasSclExtensionType]/compas:Labels/compas:Label
76+
for $label in $labels
77+
return ' <Label>' || $label || '</Label>'
78+
};
79+
""";
80+
6981
private final BaseXClientFactory baseXClientFactory;
7082
private final SclDataModelMarshaller sclDataMarshaller;
7183

@@ -91,6 +103,7 @@ public CompasSclDataBaseXRepository(BaseXClientFactory baseXClientFactory,
91103
@Override
92104
public List<Item> list(SclFileType type) {
93105
return executeQuery(type, """
106+
%s
94107
%s
95108
%s
96109
declare variable $db := '%s';
@@ -99,14 +112,16 @@ public List<Item> list(SclFileType type) {
99112
group by $id
100113
let $latestScl := local:latest-version($db, $id)
101114
let $version := $latestScl/scl:SCL/scl:Header/@version
102-
let $name := $latestScl/scl:SCL/scl:Private[@type=$compasSclExtensionType]/compas:SclName
115+
let $name := ($latestScl/scl:SCL/scl:Private[@type=$compasSclExtensionType]/compas:SclName)[1]
116+
let $labels := fn:string-join(local:createLabelsResponse($latestScl))
103117
order by fn:lower-case($name)
104118
return '<Item xmlns="' || $compasDataServiceNamespace || '">'
105-
|| ' <Id>' || $id || '</Id>'
106-
|| ' <Name>' || $name || '</Name>'
107-
|| ' <Version>' || $version || '</Version>'
119+
|| ' <Id>' || $id || '</Id>'
120+
|| ' <Name>' || $name || '</Name>'
121+
|| ' <Version>' || $version || '</Version>'
122+
|| $labels
108123
|| '</Item>'
109-
""".formatted(DECLARE_NS_AND_VARS, DECLARE_LATEST_VERSION_FUNC, type)
124+
""".formatted(DECLARE_NS_AND_VARS, DECLARE_LATEST_VERSION_FUNC, DECLARE_LABELS_FUNC, type)
110125
,
111126
sclDataMarshaller::unmarshalItem);
112127
}
@@ -127,12 +142,12 @@ public List<HistoryItem> listVersionsByUUID(SclFileType type, UUID id) {
127142
let $patchVersion := xs:int($parts[3])
128143
order by $majorVersion, $minorVersion, $patchVersion
129144
return '<HistoryItem xmlns="' || $compasDataServiceNamespace || '">'
130-
|| ' <Id>' || $id || '</Id>'
131-
|| ' <Name>' || $name || '</Name>'
132-
|| ' <Version>' || $version || '</Version>'
133-
|| ' <Who>' || $header/@who || '</Who>'
134-
|| ' <When>' || $header/@when || '</When>'
135-
|| ' <What>' || $header/@what || '</What>'
145+
|| ' <Id>' || $id || '</Id>'
146+
|| ' <Name>' || $name || '</Name>'
147+
|| ' <Version>' || $version || '</Version>'
148+
|| ' <Who>' || $header/@who || '</Who>'
149+
|| ' <When>' || $header/@when || '</When>'
150+
|| ' <What>' || $header/@what || '</What>'
136151
|| '</HistoryItem>'
137152
""".formatted(DECLARE_NS_AND_VARS, type, id),
138153
sclDataMarshaller::unmarshalHistoryItem);
@@ -194,9 +209,9 @@ public SclMetaInfo findMetaInfoByUUID(SclFileType type, UUID id) {
194209
let $version := $resource/scl:SCL/scl:Header/@version
195210
let $name := $resource/scl:SCL/scl:Private[@type=$compasSclExtensionType]/compas:SclName
196211
return '<SclMetaInfo xmlns="' || $compasDataServiceNamespace || '">'
197-
|| ' <Id>' || $id || '</Id>'
198-
|| ' <Name>' || $name || '</Name>'
199-
|| ' <Version>' || $version || '</Version>'
212+
|| ' <Id>' || $id || '</Id>'
213+
|| ' <Name>' || $name || '</Name>'
214+
|| ' <Version>' || $version || '</Version>'
200215
|| '</SclMetaInfo>'
201216
)
202217
""".formatted(DECLARE_NS_AND_VARS, DECLARE_LATEST_VERSION_FUNC, type, id),

repository-postgresql/src/main/java/org/lfenergy/compas/scl/data/repository/postgresql/CompasSclDataPostgreSQLRepository.java

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,16 @@
1414
import org.lfenergy.compas.scl.extensions.model.SclFileType;
1515

1616
import javax.sql.DataSource;
17+
import java.sql.Array;
1718
import java.sql.ResultSet;
1819
import java.sql.SQLException;
1920
import java.util.ArrayList;
21+
import java.util.Arrays;
2022
import java.util.List;
2123
import java.util.UUID;
2224

2325
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.*;
26+
import static org.lfenergy.compas.scl.extensions.commons.CompasExtensionsConstants.COMPAS_SCL_EXTENSION_TYPE;
2427

2528
public class CompasSclDataPostgreSQLRepository implements CompasSclDataRepository {
2629
private static final String ID_FIELD = "id";
@@ -42,43 +45,45 @@ public CompasSclDataPostgreSQLRepository(DataSource dataSource) {
4245
@Override
4346
public List<Item> list(SclFileType type) {
4447
var sql = """
45-
select scl_file.id, scl_file.name, scl_file.major_version, scl_file.minor_version, scl_file.patch_version
46-
from scl_file
47-
where scl_file.type = ?
48-
and (scl_file.id, scl_file.major_version, scl_file.minor_version, scl_file.patch_version) in (
49-
-- Last select the maximum patch version with the major/minor version per id.
50-
select id, major_version, minor_version, max(patch_version)
51-
from scl_file patch_scl
52-
where patch_scl.type = scl_file.type
53-
and (id, major_version, minor_version) in (
54-
-- Next select the maximum minor version with the major version per id.
55-
select id, major_version, max(minor_version)
56-
from scl_file minor_scl
57-
where minor_scl.type = scl_file.type
58-
and (id, major_version) in (
59-
-- First select the maximum major version per id.
60-
select id, max(major_version)
61-
from scl_file major_scl
62-
where major_scl.type = scl_file.type
63-
group by id
64-
)
65-
group by id, major_version
66-
)
67-
group by id, major_version, minor_version
68-
)
69-
order by scl_file.name, scl_file.major_version, scl_file.minor_version, scl_file.patch_version
48+
select scl_file.id, scl_file.name,
49+
scl_file.major_version, scl_file.minor_version, scl_file.patch_version,
50+
(xpath('//compas:Labels/compas:Label/text()'
51+
, scl_data.compas_private
52+
, ARRAY[ARRAY['compas', 'https://www.lfenergy.org/compas/extension/v1']])) as labels
53+
from (select distinct on (scl_file.id) *
54+
from scl_file
55+
where scl_file.type = ?
56+
order by scl_file.id
57+
, scl_file.major_version desc
58+
, scl_file.minor_version desc
59+
, scl_file.patch_version desc
60+
) scl_file
61+
left outer join (
62+
select id, major_version, minor_version, patch_version,
63+
unnest(
64+
xpath( '(/scl:SCL/scl:Private[@type="' || ? || '"])[1]'
65+
, scl_data::xml
66+
, ARRAY[ARRAY['scl', 'http://www.iec.ch/61850/2003/SCL']])) as compas_private
67+
from scl_file) scl_data
68+
on scl_data.id = scl_file.id
69+
and scl_data.major_version = scl_file.major_version
70+
and scl_data.minor_version = scl_file.minor_version
71+
and scl_data.patch_version = scl_file.patch_version
72+
order by scl_file.name, scl_file.major_version, scl_file.minor_version, scl_file.patch_version
7073
""";
7174

7275
var items = new ArrayList<Item>();
7376
try (var connection = dataSource.getConnection();
7477
var stmt = connection.prepareStatement(sql)) {
7578
stmt.setString(1, type.name());
79+
stmt.setString(2, COMPAS_SCL_EXTENSION_TYPE);
7680

7781
try (var resultSet = stmt.executeQuery()) {
7882
while (resultSet.next()) {
7983
items.add(new Item(resultSet.getString(ID_FIELD),
8084
resultSet.getString(NAME_FIELD),
81-
createVersion(resultSet)));
85+
createVersion(resultSet),
86+
createLabelList(resultSet.getArray("labels"))));
8287
}
8388
}
8489
} catch (SQLException exp) {
@@ -305,4 +310,17 @@ private String createVersion(ResultSet resultSet) throws SQLException {
305310
resultSet.getInt(PATCH_VERSION_FIELD));
306311
return version.toString();
307312
}
313+
314+
private List<String> createLabelList(Array sqlArray) throws SQLException {
315+
var labelsList = new ArrayList<String>();
316+
// Sadly no generics in JDBC so we need to check what the Array() method returns.
317+
if (sqlArray.getArray() instanceof Object[] objectArray) {
318+
Arrays.stream(objectArray)
319+
.forEach(arrayObject ->
320+
// Just use toString() to return the value of the PostgreSQL Object.
321+
labelsList.add(arrayObject.toString())
322+
);
323+
}
324+
return labelsList;
325+
}
308326
}

repository-postgresql/src/test/java/org/lfenergy/compas/scl/data/repository/postgresql/CompasSclDataPostgreSQLRepositoryTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ void beforeEach() {
3636
void hasDuplicateSclName_WhenUsingSclNameThatHasBeenUsedYet_ThenDuplicateIsFound() {
3737
var expectedVersion = new Version(1, 0, 0);
3838
var uuid = UUID.randomUUID();
39-
var scl = readSCL(uuid, expectedVersion, NAME_1);
39+
var scl = readStandardSCL(uuid, expectedVersion, NAME_1);
4040
getRepository().create(TYPE, uuid, NAME_1, scl, expectedVersion, WHO);
4141

4242
assertTrue(getRepository().hasDuplicateSclName(TYPE, NAME_1));

repository/src/main/java/org/lfenergy/compas/scl/data/SclDataServiceConstants.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,4 @@ public class SclDataServiceConstants {
2525
public static final String SCL_WHO_ATTR = "who";
2626
public static final String SCL_WHEN_ATTR = "when";
2727
public static final String SCL_WHAT_ATTR = "what";
28-
29-
public static final String COMPAS_EXTENSION_NS_URI = "https://www.lfenergy.org/compas/extension/v1";
30-
public static final String COMPAS_EXTENSION_NS_PREFIX = "compas";
31-
public static final String COMPAS_SCL_EXTENSION_TYPE = "compas_scl";
32-
public static final String COMPAS_SCL_NAME_EXTENSION = "SclName";
33-
public static final String COMPAS_SCL_FILE_TYPE_EXTENSION = "SclFileType";
3428
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-FileCopyrightText: 2021 Alliander N.V.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
package org.lfenergy.compas.scl.data.model;
5+
6+
import org.eclipse.microprofile.openapi.annotations.media.Schema;
7+
8+
import javax.xml.bind.annotation.XmlAccessType;
9+
import javax.xml.bind.annotation.XmlAccessorType;
10+
import javax.xml.bind.annotation.XmlElement;
11+
12+
import static org.lfenergy.compas.scl.data.SclDataServiceConstants.SCL_DATA_SERVICE_V1_NS_URI;
13+
14+
@XmlAccessorType(XmlAccessType.FIELD)
15+
public abstract class AbstractItem {
16+
@Schema(description = "The ID of the SCL as stored in the database. Often a UUID.",
17+
example = "123e4567-e89b-12d3-a456-426614174000")
18+
@XmlElement(name = "Id",
19+
namespace = SCL_DATA_SERVICE_V1_NS_URI,
20+
required = true)
21+
private String id;
22+
23+
@Schema(description = "The name of the SCL. This can also be used as part of the filename.",
24+
example = "STATION-0012312")
25+
@XmlElement(name = "Name",
26+
namespace = SCL_DATA_SERVICE_V1_NS_URI,
27+
required = true)
28+
private String name;
29+
30+
@Schema(description = "The version of the SCL.",
31+
example = "1.2.4")
32+
@XmlElement(name = "Version",
33+
namespace = SCL_DATA_SERVICE_V1_NS_URI,
34+
required = true)
35+
private String version;
36+
37+
protected AbstractItem() {
38+
}
39+
40+
protected AbstractItem(String id, String name, String version) {
41+
this.id = id;
42+
this.name = name;
43+
this.version = version;
44+
}
45+
46+
public String getId() {
47+
return id;
48+
}
49+
50+
public void setId(String id) {
51+
this.id = id;
52+
}
53+
54+
public String getName() {
55+
return name;
56+
}
57+
58+
public void setName(String name) {
59+
this.name = name;
60+
}
61+
62+
public String getVersion() {
63+
return version;
64+
}
65+
66+
public void setVersion(String version) {
67+
this.version = version;
68+
}
69+
}

repository/src/main/java/org/lfenergy/compas/scl/data/model/HistoryItem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
@Schema(description = "Item found in the database with all basic information including version info about a SCL.")
1515
@XmlAccessorType(XmlAccessType.FIELD)
16-
public class HistoryItem extends Item {
16+
public class HistoryItem extends AbstractItem {
1717
@Schema(description = "Who created this version of the SCL.",
1818
example = "John Doe")
1919
@XmlElement(name = "Who",

0 commit comments

Comments
 (0)