Skip to content

Commit

Permalink
Fix method mapping convention issues with transformed fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Koboo committed Dec 24, 2024
1 parent 858de5e commit 45d79be
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 40 deletions.
20 changes: 10 additions & 10 deletions src/main/java/eu/koboo/en2do/MongoManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ public MongoManager(Credentials credentials, ExecutorService executorService, Se
.register(internalPropertyCodecProvider)
.automatic(true)
.conventions(List.of(
new MethodMappingConvention(this, parser),
new AnnotationConvention(),
new MethodMappingConvention(this, parser),
Conventions.ANNOTATION_CONVENTION,
Conventions.SET_PRIVATE_FIELDS_CONVENTION
// Conventions.USE_GETTERS_FOR_SETTERS
Expand Down Expand Up @@ -407,34 +407,34 @@ public <E, ID, R extends Repository<E, ID>> R create(Class<R> repositoryClass) {
// Add safe break to avoid infinite loops
safeBreakAmount--;

String bsonName = null;
String bsonFilterKey = null;
// Check if we can find any nested fields
for (NestedField nestedField : nestedFieldSet) {
String loweredKey = nestedField.key().toLowerCase(Locale.ROOT);
if (!loweredStrip.startsWith(loweredKey)) {
continue;
}
loweredStrip = loweredStrip.replaceFirst(loweredKey, "");
bsonName = nestedField.query();
bsonFilterKey = nestedField.query();
break;
}

// Check if we can find any direct entity fields
Field entityField = null;
for (Field field : sortedFieldMap.values()) {
String bsonFieldName = FieldUtils.parseBsonName(field);
String loweredBsonName = bsonFieldName.toLowerCase(Locale.ROOT);
if (!loweredStrip.startsWith(loweredBsonName)) {
String fieldName = field.getName();
String loweredFieldName = fieldName.toLowerCase(Locale.ROOT);
if (!loweredStrip.startsWith(loweredFieldName)) {
continue;
}
loweredStrip = loweredStrip.replaceFirst(loweredBsonName, "");
loweredStrip = loweredStrip.replaceFirst(loweredFieldName, "");
entityField = field;
bsonName = bsonFieldName;
bsonFilterKey = FieldUtils.parseBsonName(field);
break;
}

// Check if we found any field.
if (bsonName == null) {
if (bsonFilterKey == null) {
throw new MethodFieldNotFoundException(strippedMethodName, method, entityClass, repositoryClass);
}

Expand Down Expand Up @@ -480,7 +480,7 @@ public <E, ID, R extends Repository<E, ID>> R create(Class<R> repositoryClass) {
Validator.validateTypes(repositoryClass, method, entityField, filterOperator, nextParameterIndex);
}

IndexedFilter indexedFilter = new IndexedFilter(bsonName, notFilter, filterOperator, nextParameterIndex);
IndexedFilter indexedFilter = new IndexedFilter(bsonFilterKey, notFilter, filterOperator, nextParameterIndex);
indexedFilterList.add(indexedFilter);
int operatorParameterCount = filterOperator.getExpectedParameterCount();
expectedParameterCount += operatorParameterCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
@Getter
public class IndexedFilter {

String bsonName;
String bsonFilterFieldKey;
boolean notFilter;
FilterOperator operator;
int nextParameterIndex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,53 +68,53 @@ public <F> F createFilter(Object[] arguments) throws Exception {
@SuppressWarnings("unchecked")
private Bson processBson(IndexedFilter filter, int paramsIndexAt,
Object[] args) throws Exception {
String queryFieldName = filter.getBsonName();
String bsonFilterFieldKey = filter.getBsonFilterFieldKey();

// Check if the id field of the entity is used.
// We need to convert the actual field name to mongodb's "_id" of documents
// to be able to filter the id field.
if (queryFieldName.equalsIgnoreCase(repositoryData.getEntityUniqueIdField().getName())) {
queryFieldName = "_id";
if (bsonFilterFieldKey.equalsIgnoreCase(repositoryData.getEntityUniqueIdField().getName())) {
bsonFilterFieldKey = "_id";
}

Bson retFilter = null;
switch (filter.getOperator()) {
case EQUALS:
retFilter = Filters.eq(queryFieldName, repositoryData.getFilterableValue(args[paramsIndexAt]));
retFilter = Filters.eq(bsonFilterFieldKey, repositoryData.getFilterableValue(args[paramsIndexAt]));
break;
case EQUALS_IGNORE_CASE:
String ignCasePatternString = "(?i)^" + repositoryData.getFilterableValue(args[paramsIndexAt]) + "$";
Pattern ignCasePattern = Pattern.compile(ignCasePatternString, Pattern.CASE_INSENSITIVE);
retFilter = Filters.regex(queryFieldName, ignCasePattern);
retFilter = Filters.regex(bsonFilterFieldKey, ignCasePattern);
break;
case CONTAINS:
String containsPatternString = ".*" + repositoryData.getFilterableValue(args[paramsIndexAt]) + ".*";
Pattern containsPattern = Pattern.compile(containsPatternString, Pattern.CASE_INSENSITIVE);
retFilter = Filters.regex(queryFieldName, containsPattern);
retFilter = Filters.regex(bsonFilterFieldKey, containsPattern);
break;
case GREATER_THAN:
retFilter = Filters.gt(queryFieldName, repositoryData.getFilterableValue(args[paramsIndexAt]));
retFilter = Filters.gt(bsonFilterFieldKey, repositoryData.getFilterableValue(args[paramsIndexAt]));
break;
case LESS_THAN:
retFilter = Filters.lt(queryFieldName, repositoryData.getFilterableValue(args[paramsIndexAt]));
retFilter = Filters.lt(bsonFilterFieldKey, repositoryData.getFilterableValue(args[paramsIndexAt]));
break;
case GREATER_EQUALS:
retFilter = Filters.gte(queryFieldName, repositoryData.getFilterableValue(args[paramsIndexAt]));
retFilter = Filters.gte(bsonFilterFieldKey, repositoryData.getFilterableValue(args[paramsIndexAt]));
break;
case LESS_EQUALS:
retFilter = Filters.lte(queryFieldName, repositoryData.getFilterableValue(args[paramsIndexAt]));
retFilter = Filters.lte(bsonFilterFieldKey, repositoryData.getFilterableValue(args[paramsIndexAt]));
break;
case REGEX:
// MongoDB supports multiple types of regex filtering, so check which type is provided.
// We support plain Strings and Pattern types.
Object value = repositoryData.getFilterableValue(args[paramsIndexAt]);
if (value instanceof String) {
String regexPatternString = (String) value;
retFilter = Filters.regex(queryFieldName, regexPatternString);
retFilter = Filters.regex(bsonFilterFieldKey, regexPatternString);
}
if (value instanceof Pattern) {
Pattern regexPattern = (Pattern) value;
retFilter = Filters.regex(queryFieldName, regexPattern);
retFilter = Filters.regex(bsonFilterFieldKey, regexPattern);
}
// No supported type provided, we can't do anything other than throwing exceptions.
if (retFilter == null) {
Expand All @@ -126,20 +126,20 @@ private Bson processBson(IndexedFilter filter, int paramsIndexAt,
}
break;
case EXISTS:
retFilter = Filters.exists(queryFieldName);
retFilter = Filters.exists(bsonFilterFieldKey);
break;
case BETWEEN:
Object betweenStart = repositoryData.getFilterableValue(args[paramsIndexAt]);
Object betweenEnd = args[paramsIndexAt + 1];
retFilter = Filters.and(
Filters.gt(queryFieldName, betweenStart), Filters.lt(queryFieldName, betweenEnd)
Filters.gt(bsonFilterFieldKey, betweenStart), Filters.lt(bsonFilterFieldKey, betweenEnd)
);
break;
case BETWEEN_EQUALS:
Object betweenEqStart = repositoryData.getFilterableValue(args[paramsIndexAt]);
Object betweenEqEnd = args[paramsIndexAt + 1];
retFilter = Filters.and(
Filters.gte(queryFieldName, betweenEqStart), Filters.lte(queryFieldName, betweenEqEnd)
Filters.gte(bsonFilterFieldKey, betweenEqStart), Filters.lte(bsonFilterFieldKey, betweenEqEnd)
);
break;
case IN:
Expand All @@ -163,17 +163,17 @@ private Bson processBson(IndexedFilter filter, int paramsIndexAt,
"https://github.com/Koboo/en2do\n" +
"to ensure others don't get this bug and we can't look further into this issue.");
}
retFilter = Filters.in(queryFieldName, objectArray);
retFilter = Filters.in(bsonFilterFieldKey, objectArray);
break;
case HAS_KEY:
// We need a separate getFilterableValue here, because we "faked" UUIDs map keys as strings
// in the codec. That's why we need the explicit "true" parameter here.
Object keyObject = repositoryData.getFilterableValue(args[paramsIndexAt], true);
retFilter = Filters.exists(queryFieldName + "." + keyObject);
retFilter = Filters.exists(bsonFilterFieldKey + "." + keyObject);
break;
case HAS:
Object hasObject = repositoryData.getFilterableValue(args[paramsIndexAt]);
retFilter = Filters.in(queryFieldName, hasObject);
retFilter = Filters.in(bsonFilterFieldKey, hasObject);
break;
case GEO:
// Do not ask about the geo filters.
Expand All @@ -183,26 +183,26 @@ private Bson processBson(IndexedFilter filter, int paramsIndexAt,
case NEAR_SPHERE:
Point point = new Point(new Position(geo.getLongitude(), geo.getLatitude()));
if (geo.getType() == GeoType.NEAR) {
retFilter = Filters.near(queryFieldName, point, geo.getMaxDistance(), geo.getMinDistance());
retFilter = Filters.near(bsonFilterFieldKey, point, geo.getMaxDistance(), geo.getMinDistance());
} else {
retFilter = Filters.nearSphere(queryFieldName, point, geo.getMaxDistance(), geo.getMinDistance());
retFilter = Filters.nearSphere(bsonFilterFieldKey, point, geo.getMaxDistance(), geo.getMinDistance());
}
break;
default:
throw new RuntimeException("Only near and near sphere are currently supported!");
}
break;
case IS_NULL:
retFilter = Filters.eq(queryFieldName, null);
retFilter = Filters.eq(bsonFilterFieldKey, null);
break;
case NON_NULL:
retFilter = Filters.not(Filters.eq(queryFieldName, null));
retFilter = Filters.not(Filters.eq(bsonFilterFieldKey, null));
break;
case IS_TRUE:
retFilter = Filters.eq(queryFieldName, true);
retFilter = Filters.eq(bsonFilterFieldKey, true);
break;
case IS_FALSE:
retFilter = Filters.eq(queryFieldName, false);
retFilter = Filters.eq(bsonFilterFieldKey, false);
break;
case LIST_EMPTY:
// The thing with "IsListEmpty" check is the following:
Expand All @@ -214,9 +214,9 @@ private Bson processBson(IndexedFilter filter, int paramsIndexAt,
// but some tests are not working with that,
// so lets just create and use the empty list here.
retFilter = Filters.and(
Filters.exists(queryFieldName, true),
Filters.type(queryFieldName, "array"),
Filters.ne(queryFieldName, new ArrayList<Document>())
Filters.exists(bsonFilterFieldKey, true),
Filters.type(bsonFilterFieldKey, "array"),
Filters.ne(bsonFilterFieldKey, new ArrayList<Document>())
);
break;
default: // This filter is not supported. Throw exception.
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/eu/koboo/en2do/utility/FieldUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public <E> Set<Field> collectFields(Class<E> typeClass) {
*/
public Field findFieldByName(String fieldName, Set<Field> fieldSet) {
for (Field field : fieldSet) {
String bsonName = parseBsonName(field);
if (!bsonName.equalsIgnoreCase(fieldName)) {
String entityFieldName = field.getName();
if (!entityFieldName.equals(fieldName)) {
continue;
}
return field;
Expand Down

0 comments on commit 45d79be

Please sign in to comment.