Skip to content

Commit 16e11bc

Browse files
authored
Merge pull request #329 from eclipse-jnosql/oracle-enum-support
Fix: makes Oracle NoSQL with enum as parameter
2 parents e2d6724 + 652141c commit 16e11bc

File tree

5 files changed

+221
-52
lines changed

5 files changed

+221
-52
lines changed

CHANGELOG.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version
88

99
== [Unreleased]
1010

11+
=== Fixed
12+
13+
- Update query at Oracle NoSQL to support parameter with enum type
14+
1115
== [1.1.8] - 2025-05-21
1216

1317
=== Changed

jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ protected void predicateBetween(StringBuilder query,List<FieldValue> params, Ele
9494
((Iterable<?>) document.get()).forEach(values::add);
9595

9696
query.append(name).append(" BETWEEN ? AND ? ");
97-
FieldValue fieldValue = FieldValueConverter.INSTANCE.of(values.get(ORIGIN));
98-
FieldValue fieldValue2 = FieldValueConverter.INSTANCE.of(values.get(1));
97+
FieldValue fieldValue = FieldValueConverter.of(values.get(ORIGIN));
98+
FieldValue fieldValue2 = FieldValueConverter.of(values.get(1));
9999
params.add(fieldValue);
100100
params.add(fieldValue2);
101101
}
@@ -125,7 +125,7 @@ protected void predicate(StringBuilder query,
125125
List<FieldValue> params) {
126126
String name = identifierOf(document.name());
127127
Object value = document.get();
128-
FieldValue fieldValue = FieldValueConverter.INSTANCE.of(value);
128+
FieldValue fieldValue = FieldValueConverter.of(value);
129129
if(fieldValue.isArray()){
130130
query.append(name).append(condition).append(" ?[] ");
131131
} else {

jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/DefaultOracleNoSQLDocumentManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ public Stream<CommunicationEntity> sql(String query) {
247247
public Stream<CommunicationEntity> sql(String query, Object... params) {
248248
Objects.requireNonNull(query, "query is required");
249249
Objects.requireNonNull(params, "params is required");
250-
List<FieldValue> fields = Arrays.stream(params).map(FieldValueConverter.INSTANCE::of).toList();
250+
List<FieldValue> fields = Arrays.stream(params).map(FieldValueConverter::of).toList();
251251
return executeSQL(query, fields).stream();
252252
}
253253

@@ -274,7 +274,7 @@ private List<CommunicationEntity> executeSQL(String sql, List<FieldValue> params
274274
}
275275
for (Map.Entry<String, FieldValue> entry : result) {
276276
if (isNotOracleField(entry)) {
277-
entity.add(Element.of(entry.getKey(), FieldValueConverter.INSTANCE.of(entry.getValue())));
277+
entity.add(Element.of(entry.getKey(), FieldValueConverter.of(entry.getValue())));
278278
}
279279
}
280280
var id = result.get(ORACLE_ID).asString().getValue().split(":")[1];

jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/FieldValueConverter.java

Lines changed: 170 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -27,47 +27,48 @@
2727
import oracle.nosql.driver.values.StringValue;
2828

2929
import java.lang.reflect.Array;
30+
import java.util.List;
3031
import java.util.Map;
3132

32-
enum FieldValueConverter {
33+
class FieldValueConverter {
34+
private static final List<FieldValueMapper> MAPPERS = List.of(
35+
new FieldValuePassthroughMapper(),
36+
new StringValueMapper(),
37+
new IntegerValueMapper(),
38+
new LongValueMapper(),
39+
new DoubleValueMapper(),
40+
new BooleanValueMapper(),
41+
new NumberValueMapper(),
42+
new ByteArrayValueMapper(),
43+
new EnumValueMapper(),
44+
new IterableValueMapper(),
45+
new ArrayValueMapper(),
46+
new MapValueMapper()
47+
);
3348

34-
INSTANCE;
49+
private FieldValueConverter() {
50+
throw new AssertionError("Utility class");
51+
}
3552

36-
FieldValue of(Object value){
37-
if(value == null){
53+
static FieldValue of(Object value) {
54+
if (value == null) {
3855
return NullValue.getInstance();
3956
}
40-
if (value instanceof String string) {
41-
return new StringValue(string);
42-
} else if (value instanceof Integer integer) {
43-
return new IntegerValue(integer);
44-
} else if (value instanceof Long longValue) {
45-
return new LongValue(longValue);
46-
} else if (value instanceof Double doubleValue) {
47-
return new DoubleValue(doubleValue);
48-
} else if (value instanceof Boolean booleanValue) {
49-
return Boolean.TRUE.equals(booleanValue) ? BooleanValue.trueInstance() : BooleanValue.falseInstance();
50-
} else if (value instanceof Number) {
51-
return new NumberValue(value.toString());
52-
} else if (value instanceof byte[]) {
53-
return new BinaryValue((byte[]) value);
54-
} else if (value instanceof Iterable<?> values) {
55-
return createList(values);
56-
} else if (value.getClass().isArray()) {
57-
return createArray(value);
58-
} else if (value instanceof Map<?,?>) {
59-
return entries((Map<String, ?>) value);
60-
}else if (value instanceof FieldValue) {
61-
return (FieldValue) value;
62-
} else {
63-
throw new UnsupportedOperationException("There is not support to: " + value.getClass());
57+
58+
for (FieldValueMapper mapper : MAPPERS) {
59+
if (mapper.supports(value)) {
60+
return mapper.toFieldValue(value);
61+
}
6462
}
63+
64+
throw new UnsupportedOperationException("Unsupported value type: " + value.getClass());
6565
}
6666

67-
Object toObject(FieldValue value) {
68-
if (value.isNull()) {
67+
public static Object toJavaObject(FieldValue value) {
68+
if (value == null || value.isNull()) {
6969
return null;
7070
}
71+
7172
return switch (value.getType()) {
7273
case STRING -> value.asString();
7374
case INTEGER -> value.asInteger();
@@ -78,31 +79,153 @@ Object toObject(FieldValue value) {
7879
case BINARY -> value.asBinary();
7980
case ARRAY -> value.asArray();
8081
case MAP -> value.asMap();
81-
default -> throw new UnsupportedOperationException("There is not support to: " + value.getType());
82+
default -> throw new UnsupportedOperationException("Unsupported FieldValue type: " + value.getType());
8283
};
8384
}
84-
private MapValue entries(Map<String, ?> value) {
85-
MapValue mapValue = new MapValue();
86-
for (Map.Entry<String, ?> entry : value.entrySet()) {
87-
mapValue.put(entry.getKey(), of(entry.getValue()));
85+
86+
private interface FieldValueMapper {
87+
boolean supports(Object value);
88+
FieldValue toFieldValue(Object value);
89+
}
90+
91+
private static final class FieldValuePassthroughMapper implements FieldValueMapper {
92+
public boolean supports(Object value) {
93+
return value instanceof FieldValue;
94+
}
95+
96+
public FieldValue toFieldValue(Object value) {
97+
return (FieldValue) value;
98+
}
99+
}
100+
101+
private static final class StringValueMapper implements FieldValueMapper {
102+
public boolean supports(Object value) {
103+
return value instanceof String;
104+
}
105+
106+
public FieldValue toFieldValue(Object value) {
107+
return new StringValue((String) value);
108+
}
109+
}
110+
111+
private static final class IntegerValueMapper implements FieldValueMapper {
112+
public boolean supports(Object value) {
113+
return value instanceof Integer;
114+
}
115+
116+
public FieldValue toFieldValue(Object value) {
117+
return new IntegerValue((Integer) value);
118+
}
119+
}
120+
121+
private static final class LongValueMapper implements FieldValueMapper {
122+
public boolean supports(Object value) {
123+
return value instanceof Long;
124+
}
125+
126+
public FieldValue toFieldValue(Object value) {
127+
return new LongValue((Long) value);
128+
}
129+
}
130+
131+
private static final class DoubleValueMapper implements FieldValueMapper {
132+
public boolean supports(Object value) {
133+
return value instanceof Double;
134+
}
135+
136+
public FieldValue toFieldValue(Object value) {
137+
return new DoubleValue((Double) value);
138+
}
139+
}
140+
141+
private static final class BooleanValueMapper implements FieldValueMapper {
142+
public boolean supports(Object value) {
143+
return value instanceof Boolean;
144+
}
145+
146+
public FieldValue toFieldValue(Object value) {
147+
return Boolean.TRUE.equals(value)
148+
? BooleanValue.trueInstance()
149+
: BooleanValue.falseInstance();
150+
}
151+
}
152+
153+
private static final class NumberValueMapper implements FieldValueMapper {
154+
public boolean supports(Object value) {
155+
return value instanceof Number &&
156+
!(value instanceof Integer || value instanceof Long || value instanceof Double);
157+
}
158+
159+
public FieldValue toFieldValue(Object value) {
160+
return new NumberValue(value.toString());
161+
}
162+
}
163+
164+
private static final class ByteArrayValueMapper implements FieldValueMapper {
165+
public boolean supports(Object value) {
166+
return value instanceof byte[];
167+
}
168+
169+
public FieldValue toFieldValue(Object value) {
170+
return new BinaryValue((byte[]) value);
171+
}
172+
}
173+
174+
private static final class EnumValueMapper implements FieldValueMapper {
175+
public boolean supports(Object value) {
176+
return value instanceof Enum<?>;
177+
}
178+
179+
public FieldValue toFieldValue(Object value) {
180+
return new StringValue(((Enum<?>) value).name());
181+
}
182+
}
183+
184+
private static final class IterableValueMapper implements FieldValueMapper {
185+
public boolean supports(Object value) {
186+
return value instanceof Iterable<?>;
187+
}
188+
189+
public FieldValue toFieldValue(Object value) {
190+
ArrayValue array = new ArrayValue();
191+
for (Object item : (Iterable<?>) value) {
192+
array.add(FieldValueConverter.of(item));
193+
}
194+
return array;
88195
}
89-
return mapValue;
90196
}
91197

92-
private ArrayValue createArray(Object value) {
93-
var arrayValue = new ArrayValue();
94-
int length = Array.getLength(value);
95-
for (int i = 0; i < length; i ++) {
96-
arrayValue.add(of(Array.get(value, i)));
198+
private static final class ArrayValueMapper implements FieldValueMapper {
199+
public boolean supports(Object value) {
200+
return value != null && value.getClass().isArray();
201+
}
202+
203+
public FieldValue toFieldValue(Object value) {
204+
int length = Array.getLength(value);
205+
ArrayValue array = new ArrayValue();
206+
for (int i = 0; i < length; i++) {
207+
array.add(FieldValueConverter.of(Array.get(value, i)));
208+
}
209+
return array;
97210
}
98-
return arrayValue;
99211
}
100212

101-
private ArrayValue createList(Iterable<?> values) {
102-
var arrayValue = new ArrayValue();
103-
for (Object value : values) {
104-
arrayValue.add(of(value));
213+
private static final class MapValueMapper implements FieldValueMapper {
214+
public boolean supports(Object value) {
215+
return value instanceof Map<?, ?>;
216+
}
217+
218+
public FieldValue toFieldValue(Object value) {
219+
Map<?, ?> map = (Map<?, ?>) value;
220+
MapValue mapValue = new MapValue();
221+
for (Map.Entry<?, ?> entry : map.entrySet()) {
222+
Object key = entry.getKey();
223+
if (!(key instanceof String keyStr)) {
224+
throw new IllegalArgumentException("Map keys must be strings. Found: " + key);
225+
}
226+
mapValue.put(keyStr, FieldValueConverter.of(entry.getValue()));
227+
}
228+
return mapValue;
105229
}
106-
return arrayValue;
107230
}
108231
}

jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,48 @@ void shouldQueryParams(){
563563
assertThat(names).contains("Poliana");
564564
}
565565

566+
@Test
567+
void shouldInsertAndRetrieveWithEnum() {
568+
var entity = CommunicationEntity.of(COLLECTION_NAME);
569+
String id = UUID.randomUUID().toString();
570+
entity.add("_id", id);
571+
entity.add("name", "Test Name");
572+
entity.add("contact_type", ContactType.EMAIL);
573+
entityManager.insert(entity);
574+
575+
var query = select().from(COLLECTION_NAME)
576+
.where("_id").eq(id).build();
577+
Optional<CommunicationEntity> optional = entityManager.select(query).findFirst();
578+
SoftAssertions.assertSoftly(soft -> {
579+
soft.assertThat(optional).isPresent();
580+
CommunicationEntity documentEntity = optional.get();
581+
soft.assertThat(documentEntity.find("name").orElseThrow().get(String.class)).isEqualTo("Test Name");
582+
soft.assertThat(documentEntity.find("contact_type").orElseThrow().get(ContactType.class))
583+
.isEqualTo(ContactType.EMAIL);
584+
});
585+
}
586+
587+
@Test
588+
void shouldDoQueryUsingEnumAsParameter() {
589+
var entity = CommunicationEntity.of(COLLECTION_NAME);
590+
String id = UUID.randomUUID().toString();
591+
entity.add("_id", id);
592+
entity.add("name", "Test Name");
593+
entity.add("contact_type", ContactType.EMAIL);
594+
entityManager.insert(entity);
595+
596+
var query = select().from(COLLECTION_NAME)
597+
.where("contact_type").eq(ContactType.EMAIL).build();
598+
Optional<CommunicationEntity> optional = entityManager.select(query).findFirst();
599+
SoftAssertions.assertSoftly(soft -> {
600+
soft.assertThat(optional).isPresent();
601+
CommunicationEntity documentEntity = optional.get();
602+
soft.assertThat(documentEntity.find("name").orElseThrow().get(String.class)).isEqualTo("Test Name");
603+
soft.assertThat(documentEntity.find("contact_type").orElseThrow().get(ContactType.class))
604+
.isEqualTo(ContactType.EMAIL);
605+
});
606+
}
607+
566608
private CommunicationEntity createDocumentList() {
567609
var entity = CommunicationEntity.of("AppointmentBook");
568610
entity.add(Element.of("_id", new Random().nextInt()));

0 commit comments

Comments
 (0)