Skip to content

Commit fb78309

Browse files
committed
SYSMOAS_-8: PrimitiveConstraint#operator and PrimitiveConstraint#value
1 parent 1bdf8e8 commit fb78309

10 files changed

Lines changed: 335 additions & 121 deletions

File tree

app/dao/impl/jpa/JpaDataDao.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SysML v2 REST/HTTP Pilot Implementation
3-
* Copyright (C) 2021-2023 Twingineer LLC
3+
* Copyright (C) 2021-2025 Twingineer LLC
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -59,6 +59,7 @@
5959
import java.util.stream.Stream;
6060

6161
import static dao.impl.jpa.JpaDao.paginateQuery;
62+
import static org.omg.sysml.query.impl.PrimitiveConstraintImpl.extractId;
6263

6364
public class JpaDataDao implements DataDao {
6465

@@ -239,7 +240,7 @@ else if (constraint instanceof PrimitiveConstraint) {
239240
JsonNode constrainedValueJson;
240241
try {
241242
constrainedValueJson = primitiveConstraint.getValue() != null ?
242-
Json.mapper().readTree(primitiveConstraint.getValue()) :
243+
Json.mapper().readTree(primitiveConstraint.getValue().get(0)) :
243244
null;
244245
} catch (IOException e) {
245246
throw new IllegalArgumentException(e);
@@ -279,13 +280,7 @@ else if (constraint instanceof PrimitiveConstraint) {
279280
} else if (Data.class.isAssignableFrom(property.getPropertyType())) {
280281
Object _actualValue = JavaBeanHelper.getBeanPropertyValue(data, property);
281282
actualValue = _actualValue != null ? ((Data) _actualValue).getId() : null;
282-
constrainedValue = constrainedValueJson != null ?
283-
JavaBeanHelper.convert(
284-
// intentionally `textValue` instead of `asText` to get a null value for
285-
// improved error reporting
286-
constrainedValueJson.path("@id").textValue(),
287-
UUID.class
288-
) : null;
283+
constrainedValue = constrainedValueJson != null ? extractId(constrainedValueJson) : null;
289284
if (constrainedValue == null) {
290285
throw new IllegalArgumentException();
291286
}
@@ -303,12 +298,18 @@ else if (constraint instanceof PrimitiveConstraint) {
303298
case LESS_THAN:
304299
comparisonResult = comparison < 0;
305300
break;
301+
case LESS_THAN_OR_EQUALS:
302+
comparisonResult = comparison <= 0;
303+
break;
306304
case EQUALS:
307305
comparisonResult = comparison == 0;
308306
break;
309307
case GREATER_THAN:
310308
comparisonResult = comparison > 0;
311309
break;
310+
case GREATER_THAN_OR_EQUALS:
311+
comparisonResult = comparison >= 0;
312+
break;
312313
default:
313314
throw new UnsupportedOperationException("Unsupported primitive constraint operator: " + primitiveConstraint.getOperator().name());
314315
}

app/org/omg/sysml/query/PrimitiveConstraint.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5-
* Copyright (C) 2023 Twingineer LLC
5+
* Copyright (C) 2023-2025 Twingineer LLC
66
*
77
* This program is free software: you can redistribute it and/or modify
88
* it under the terms of the GNU Lesser General Public License as published by
@@ -22,6 +22,9 @@
2222

2323
package org.omg.sysml.query;
2424

25+
import javax.annotation.Nullable;
26+
import java.util.List;
27+
2528
public interface PrimitiveConstraint extends Constraint {
2629
Boolean getInverse();
2730

@@ -31,7 +34,7 @@ public interface PrimitiveConstraint extends Constraint {
3134

3235
void setProperty(String property);
3336

34-
String getValue();
37+
@Nullable List<String> getValue();
3538

3639
// void setValue(String value);
3740

app/org/omg/sysml/query/PrimitiveOperator.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5+
* Copyright (C) 2025 Twingineer LLC
56
*
67
* This program is free software: you can redistribute it and/or modify
78
* it under the terms of the GNU Lesser General Public License as published by
@@ -24,10 +25,18 @@
2425
import com.fasterxml.jackson.annotation.JsonProperty;
2526

2627
public enum PrimitiveOperator {
28+
@JsonProperty("<")
29+
LESS_THAN,
30+
@JsonProperty("<=")
31+
LESS_THAN_OR_EQUALS,
2732
@JsonProperty("=")
2833
EQUALS,
2934
@JsonProperty(">")
3035
GREATER_THAN,
31-
@JsonProperty("<")
32-
LESS_THAN;
36+
@JsonProperty(">=")
37+
GREATER_THAN_OR_EQUALS,
38+
@JsonProperty("in")
39+
IN,
40+
@JsonProperty("instanceOf")
41+
INSTANCE_OF,
3342
}

app/org/omg/sysml/query/impl/PrimitiveConstraintImpl.java

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5-
* Copyright (C) 2023 Twingineer LLC
5+
* Copyright (C) 2023-2025 Twingineer LLC
66
*
77
* This program is free software: you can redistribute it and/or modify
88
* it under the terms of the GNU Lesser General Public License as published by
@@ -22,17 +22,30 @@
2222

2323
package org.omg.sysml.query.impl;
2424

25-
import com.fasterxml.jackson.annotation.JsonRawValue;
25+
import com.fasterxml.jackson.annotation.JsonGetter;
26+
import com.fasterxml.jackson.annotation.JsonProperty;
27+
import com.fasterxml.jackson.annotation.JsonSetter;
2628
import com.fasterxml.jackson.annotation.JsonTypeName;
29+
import com.fasterxml.jackson.core.JsonGenerator;
2730
import com.fasterxml.jackson.core.JsonProcessingException;
2831
import com.fasterxml.jackson.databind.JsonNode;
32+
import com.fasterxml.jackson.databind.SerializerProvider;
2933
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
34+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
3035
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
36+
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
37+
import javabean.JavaBeanHelper;
3138
import org.omg.sysml.query.PrimitiveConstraint;
3239
import org.omg.sysml.query.PrimitiveOperator;
3340
import play.libs.Json;
3441

42+
import javax.annotation.Nullable;
3543
import javax.persistence.*;
44+
import java.io.IOException;
45+
import java.util.ArrayList;
46+
import java.util.Collections;
47+
import java.util.List;
48+
import java.util.UUID;
3649

3750
// @Embeddable // Can't embed and have polymorphism between Constraints, which is necessary for CompositeConstraint.constraint
3851
@Entity(name = "PrimitiveConstraint")
@@ -41,7 +54,7 @@
4154
public class PrimitiveConstraintImpl extends ConstraintImpl implements PrimitiveConstraint {
4255
private Boolean inverse;
4356
private String property;
44-
private String value;
57+
private List<String> value;
4558
private PrimitiveOperator operator;
4659

4760
@Override
@@ -60,6 +73,7 @@ public void setInverse(Boolean inverse) {
6073

6174
@Override
6275
@Column
76+
@JsonProperty(required = true)
6377
public String getProperty() {
6478
return property;
6579
}
@@ -70,23 +84,54 @@ public void setProperty(String property) {
7084
}
7185

7286
@Override
73-
@Column
74-
@JsonRawValue
75-
public String getValue() {
76-
return value != null ? value : "null";
87+
@JsonProperty(required = true)
88+
@JsonSerialize(contentUsing = RawValueSerializer.class)
89+
@Lob
90+
@org.hibernate.annotations.Type(type = "org.hibernate.type.TextType")
91+
@ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
92+
@CollectionTable
93+
public @Nullable List<String> getValue() {
94+
return value.isEmpty() ? null : value;
7795
}
7896

79-
@JsonDeserialize(using = OpenJsonNodeDeserializer.class)
80-
public void setValue(JsonNode value) throws JsonProcessingException {
81-
this.value = value != null ? Json.mapper().writeValueAsString(value) : "null";
97+
public void setValue(@Nullable List<String> value) {
98+
this.value = value == null ? Collections.emptyList() : value;
99+
}
100+
101+
@JsonSetter("value")
102+
@JsonDeserialize(contentUsing = OpenJsonNodeDeserializer.class)
103+
public void setValueJson(@Nullable List<JsonNode> value) throws JsonProcessingException {
104+
if (value == null) {
105+
this.value = Collections.emptyList();
106+
return;
107+
}
108+
if (value.isEmpty()) {
109+
throw new IllegalArgumentException("value must not be empty");
110+
}
111+
112+
List<String> result = new ArrayList<>(value.size());
113+
for (JsonNode node : value) {
114+
if (node.isBoolean() || node.isNumber() || node.isTextual()) {
115+
result.add(Json.mapper().writeValueAsString(node));
116+
} else if (node.isObject()) {
117+
if (node.size() != 1) {
118+
throwBadValue();
119+
}
120+
if (extractId(node) == null) {
121+
throwBadValue();
122+
}
123+
result.add(Json.mapper().writeValueAsString(node));
124+
} else {
125+
throwBadValue();
126+
}
127+
}
128+
this.value = result;
82129
}
83130

84131
@Override
85132
@Enumerated(EnumType.STRING)
133+
@JsonProperty(required = true)
86134
public PrimitiveOperator getOperator() {
87-
if (operator == null) {
88-
operator = PrimitiveOperator.EQUALS;
89-
}
90135
return operator;
91136
}
92137

@@ -95,6 +140,29 @@ public void setOperator(PrimitiveOperator operator) {
95140
this.operator = operator;
96141
}
97142

143+
public static @Nullable UUID extractId(JsonNode node) {
144+
return JavaBeanHelper.convert(
145+
// intentionally `textValue` instead of `asText` to get a null value for improved error reporting
146+
node.path("@id").textValue(),
147+
UUID.class
148+
);
149+
}
150+
151+
private static void throwBadValue() {
152+
throw new IllegalArgumentException("value must be typed boolean, number, string, or Identified");
153+
}
154+
155+
public static final class RawValueSerializer extends StdSerializer<String> {
156+
public RawValueSerializer() {
157+
super(String.class);
158+
}
159+
160+
@Override
161+
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
162+
gen.writeRawValue(value);
163+
}
164+
}
165+
98166
public static final class OpenJsonNodeDeserializer extends JsonNodeDeserializer {
99167
public OpenJsonNodeDeserializer() {
100168
super();

conf/json/schema/api/schemas-sans-metamodel-requests.json

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,9 +1021,13 @@
10211021
"operator": {
10221022
"type": "string",
10231023
"enum": [
1024+
"<",
1025+
"<=",
10241026
"=",
10251027
">",
1026-
"<"
1028+
">=",
1029+
"in",
1030+
"instanceOf"
10271031
]
10281032
},
10291033
"property": {
@@ -1032,16 +1036,27 @@
10321036
"value": {
10331037
"oneOf": [
10341038
{
1035-
"type": "boolean"
1036-
},
1037-
{
1038-
"type": "number"
1039-
},
1040-
{
1041-
"type": "string"
1042-
},
1043-
{
1044-
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
1039+
"type": "array",
1040+
"items": {
1041+
"oneOf": [
1042+
{
1043+
"type": "boolean"
1044+
},
1045+
{
1046+
"type": "number"
1047+
},
1048+
{
1049+
"type": "string"
1050+
},
1051+
{
1052+
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
1053+
},
1054+
{
1055+
"type": "null"
1056+
}
1057+
]
1058+
},
1059+
"minItems": 1
10451060
},
10461061
{
10471062
"type": "null"
@@ -1073,9 +1088,13 @@
10731088
"operator": {
10741089
"type": "string",
10751090
"enum": [
1091+
"<",
1092+
"<=",
10761093
"=",
10771094
">",
1078-
"<"
1095+
">=",
1096+
"in",
1097+
"instanceOf"
10791098
]
10801099
},
10811100
"property": {
@@ -1084,16 +1103,27 @@
10841103
"value": {
10851104
"oneOf": [
10861105
{
1087-
"type": "boolean"
1088-
},
1089-
{
1090-
"type": "number"
1091-
},
1092-
{
1093-
"type": "string"
1094-
},
1095-
{
1096-
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
1106+
"type": "array",
1107+
"items": {
1108+
"oneOf": [
1109+
{
1110+
"type": "boolean"
1111+
},
1112+
{
1113+
"type": "number"
1114+
},
1115+
{
1116+
"type": "string"
1117+
},
1118+
{
1119+
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
1120+
},
1121+
{
1122+
"type": "null"
1123+
}
1124+
]
1125+
},
1126+
"minItems": 1
10971127
},
10981128
{
10991129
"type": "null"

0 commit comments

Comments
 (0)