Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version

== [Unreleased]

=== Fixed

- Update query at Oracle NoSQL to support parameter with enum type

== [1.1.8] - 2025-05-21

=== Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ protected void predicateBetween(StringBuilder query,List<FieldValue> params, Ele
((Iterable<?>) document.get()).forEach(values::add);

query.append(name).append(" BETWEEN ? AND ? ");
FieldValue fieldValue = FieldValueConverter.INSTANCE.of(values.get(ORIGIN));
FieldValue fieldValue2 = FieldValueConverter.INSTANCE.of(values.get(1));
FieldValue fieldValue = FieldValueConverter.of(values.get(ORIGIN));
FieldValue fieldValue2 = FieldValueConverter.of(values.get(1));
params.add(fieldValue);
params.add(fieldValue2);
}
Expand Down Expand Up @@ -125,7 +125,7 @@ protected void predicate(StringBuilder query,
List<FieldValue> params) {
String name = identifierOf(document.name());
Object value = document.get();
FieldValue fieldValue = FieldValueConverter.INSTANCE.of(value);
FieldValue fieldValue = FieldValueConverter.of(value);
if(fieldValue.isArray()){
query.append(name).append(condition).append(" ?[] ");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public Stream<CommunicationEntity> sql(String query) {
public Stream<CommunicationEntity> sql(String query, Object... params) {
Objects.requireNonNull(query, "query is required");
Objects.requireNonNull(params, "params is required");
List<FieldValue> fields = Arrays.stream(params).map(FieldValueConverter.INSTANCE::of).toList();
List<FieldValue> fields = Arrays.stream(params).map(FieldValueConverter::of).toList();
return executeSQL(query, fields).stream();
}

Expand All @@ -274,7 +274,7 @@ private List<CommunicationEntity> executeSQL(String sql, List<FieldValue> params
}
for (Map.Entry<String, FieldValue> entry : result) {
if (isNotOracleField(entry)) {
entity.add(Element.of(entry.getKey(), FieldValueConverter.INSTANCE.of(entry.getValue())));
entity.add(Element.of(entry.getKey(), FieldValueConverter.of(entry.getValue())));
}
}
var id = result.get(ORACLE_ID).asString().getValue().split(":")[1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,47 +27,48 @@
import oracle.nosql.driver.values.StringValue;

import java.lang.reflect.Array;
import java.util.List;
import java.util.Map;

enum FieldValueConverter {
class FieldValueConverter {
private static final List<FieldValueMapper> MAPPERS = List.of(
new FieldValuePassthroughMapper(),
new StringValueMapper(),
new IntegerValueMapper(),
new LongValueMapper(),
new DoubleValueMapper(),
new BooleanValueMapper(),
new NumberValueMapper(),
new ByteArrayValueMapper(),
new EnumValueMapper(),
new IterableValueMapper(),
new ArrayValueMapper(),
new MapValueMapper()
);

INSTANCE;
private FieldValueConverter() {
throw new AssertionError("Utility class");
}

FieldValue of(Object value){
if(value == null){
static FieldValue of(Object value) {
if (value == null) {
return NullValue.getInstance();
}
if (value instanceof String string) {
return new StringValue(string);
} else if (value instanceof Integer integer) {
return new IntegerValue(integer);
} else if (value instanceof Long longValue) {
return new LongValue(longValue);
} else if (value instanceof Double doubleValue) {
return new DoubleValue(doubleValue);
} else if (value instanceof Boolean booleanValue) {
return Boolean.TRUE.equals(booleanValue) ? BooleanValue.trueInstance() : BooleanValue.falseInstance();
} else if (value instanceof Number) {
return new NumberValue(value.toString());
} else if (value instanceof byte[]) {
return new BinaryValue((byte[]) value);
} else if (value instanceof Iterable<?> values) {
return createList(values);
} else if (value.getClass().isArray()) {
return createArray(value);
} else if (value instanceof Map<?,?>) {
return entries((Map<String, ?>) value);
}else if (value instanceof FieldValue) {
return (FieldValue) value;
} else {
throw new UnsupportedOperationException("There is not support to: " + value.getClass());

for (FieldValueMapper mapper : MAPPERS) {
if (mapper.supports(value)) {
return mapper.toFieldValue(value);
}
}

throw new UnsupportedOperationException("Unsupported value type: " + value.getClass());
}

Object toObject(FieldValue value) {
if (value.isNull()) {
public static Object toJavaObject(FieldValue value) {
if (value == null || value.isNull()) {
return null;
}

return switch (value.getType()) {
case STRING -> value.asString();
case INTEGER -> value.asInteger();
Expand All @@ -78,31 +79,153 @@ Object toObject(FieldValue value) {
case BINARY -> value.asBinary();
case ARRAY -> value.asArray();
case MAP -> value.asMap();
default -> throw new UnsupportedOperationException("There is not support to: " + value.getType());
default -> throw new UnsupportedOperationException("Unsupported FieldValue type: " + value.getType());
};
}
private MapValue entries(Map<String, ?> value) {
MapValue mapValue = new MapValue();
for (Map.Entry<String, ?> entry : value.entrySet()) {
mapValue.put(entry.getKey(), of(entry.getValue()));

private interface FieldValueMapper {
boolean supports(Object value);
FieldValue toFieldValue(Object value);
}

private static final class FieldValuePassthroughMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof FieldValue;
}

public FieldValue toFieldValue(Object value) {
return (FieldValue) value;
}
}

private static final class StringValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof String;
}

public FieldValue toFieldValue(Object value) {
return new StringValue((String) value);
}
}

private static final class IntegerValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Integer;
}

public FieldValue toFieldValue(Object value) {
return new IntegerValue((Integer) value);
}
}

private static final class LongValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Long;
}

public FieldValue toFieldValue(Object value) {
return new LongValue((Long) value);
}
}

private static final class DoubleValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Double;
}

public FieldValue toFieldValue(Object value) {
return new DoubleValue((Double) value);
}
}

private static final class BooleanValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Boolean;
}

public FieldValue toFieldValue(Object value) {
return Boolean.TRUE.equals(value)
? BooleanValue.trueInstance()
: BooleanValue.falseInstance();
}
}

private static final class NumberValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Number &&
!(value instanceof Integer || value instanceof Long || value instanceof Double);
}

public FieldValue toFieldValue(Object value) {
return new NumberValue(value.toString());
}
}

private static final class ByteArrayValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof byte[];
}

public FieldValue toFieldValue(Object value) {
return new BinaryValue((byte[]) value);
}
}

private static final class EnumValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Enum<?>;
}

public FieldValue toFieldValue(Object value) {
return new StringValue(((Enum<?>) value).name());
}
}

private static final class IterableValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Iterable<?>;
}

public FieldValue toFieldValue(Object value) {
ArrayValue array = new ArrayValue();
for (Object item : (Iterable<?>) value) {
array.add(FieldValueConverter.of(item));
}
return array;
}
return mapValue;
}

private ArrayValue createArray(Object value) {
var arrayValue = new ArrayValue();
int length = Array.getLength(value);
for (int i = 0; i < length; i ++) {
arrayValue.add(of(Array.get(value, i)));
private static final class ArrayValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value != null && value.getClass().isArray();
}

public FieldValue toFieldValue(Object value) {
int length = Array.getLength(value);
ArrayValue array = new ArrayValue();
for (int i = 0; i < length; i++) {
array.add(FieldValueConverter.of(Array.get(value, i)));
}
return array;
}
return arrayValue;
}

private ArrayValue createList(Iterable<?> values) {
var arrayValue = new ArrayValue();
for (Object value : values) {
arrayValue.add(of(value));
private static final class MapValueMapper implements FieldValueMapper {
public boolean supports(Object value) {
return value instanceof Map<?, ?>;
}

public FieldValue toFieldValue(Object value) {
Map<?, ?> map = (Map<?, ?>) value;
MapValue mapValue = new MapValue();
for (Map.Entry<?, ?> entry : map.entrySet()) {
Object key = entry.getKey();
if (!(key instanceof String keyStr)) {
throw new IllegalArgumentException("Map keys must be strings. Found: " + key);
}
mapValue.put(keyStr, FieldValueConverter.of(entry.getValue()));
}
return mapValue;
}
return arrayValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,48 @@ void shouldQueryParams(){
assertThat(names).contains("Poliana");
}

@Test
void shouldInsertAndRetrieveWithEnum() {
var entity = CommunicationEntity.of(COLLECTION_NAME);
String id = UUID.randomUUID().toString();
entity.add("_id", id);
entity.add("name", "Test Name");
entity.add("contact_type", ContactType.EMAIL);
entityManager.insert(entity);

var query = select().from(COLLECTION_NAME)
.where("_id").eq(id).build();
Optional<CommunicationEntity> optional = entityManager.select(query).findFirst();
SoftAssertions.assertSoftly(soft -> {
soft.assertThat(optional).isPresent();
CommunicationEntity documentEntity = optional.get();
soft.assertThat(documentEntity.find("name").orElseThrow().get(String.class)).isEqualTo("Test Name");
soft.assertThat(documentEntity.find("contact_type").orElseThrow().get(ContactType.class))
.isEqualTo(ContactType.EMAIL);
});
}

@Test
void shouldDoQueryUsingEnumAsParameter() {
var entity = CommunicationEntity.of(COLLECTION_NAME);
String id = UUID.randomUUID().toString();
entity.add("_id", id);
entity.add("name", "Test Name");
entity.add("contact_type", ContactType.EMAIL);
entityManager.insert(entity);

var query = select().from(COLLECTION_NAME)
.where("contact_type").eq(ContactType.EMAIL).build();
Optional<CommunicationEntity> optional = entityManager.select(query).findFirst();
SoftAssertions.assertSoftly(soft -> {
soft.assertThat(optional).isPresent();
CommunicationEntity documentEntity = optional.get();
soft.assertThat(documentEntity.find("name").orElseThrow().get(String.class)).isEqualTo("Test Name");
soft.assertThat(documentEntity.find("contact_type").orElseThrow().get(ContactType.class))
.isEqualTo(ContactType.EMAIL);
});
}

private CommunicationEntity createDocumentList() {
var entity = CommunicationEntity.of("AppointmentBook");
entity.add(Element.of("_id", new Random().nextInt()));
Expand Down