-
Notifications
You must be signed in to change notification settings - Fork 21
SER-13233 Add support for sorting on multiple columns using CollectinOptions sortby. #680
base: master
Are you sure you want to change the base?
Changes from all commits
d7a52ab
6e8b328
188ec2e
7abd4f9
7493e75
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,10 @@ | |
|
||
import java.lang.reflect.Method; | ||
import java.sql.SQLException; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import static com.google.common.collect.Iterables.indexOf; | ||
import static java.util.Arrays.asList; | ||
|
@@ -17,6 +21,7 @@ public class CollectionOptionsQueryPart implements QueryPart { | |
private final int collectionOptionsArgIndex; | ||
private final Query queryAnnotation; | ||
private final boolean isMono; | ||
private static final Pattern SORT_BY_PART = Pattern.compile("(?<sortby>[a-zåäö0-9_]+)(\\s+(?<order>asc|desc))?"); | ||
|
||
public CollectionOptionsQueryPart(Method method) { | ||
collectionOptionsArgIndex = indexOf(asList(method.getParameterTypes()), CollectionOptions.class::isAssignableFrom); | ||
|
@@ -36,11 +41,33 @@ public void visit(StringBuilder sql, Object[] args) { | |
if (collectionOptions != null) { | ||
if (collectionOptions.getSortBy() != null) { | ||
String sortBy = CamelSnakeConverter.camelToSnake(collectionOptions.getSortBy()); | ||
for (String allowed : queryAnnotation.allowedSortColumns()) { | ||
if (allowed.equals(sortBy)) { | ||
collectionOptionsHasOrderBy = true; | ||
addOrderBy(sql, buildOrderBy(collectionOptions.getOrder(), allowed)); | ||
break; | ||
var sortByParts = sortBy.split(","); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be good to have a check for max length for the sortBy unless Netty's query decoder already checks that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not know. sortBy is however not a new parameter and that change request is not addressing this change. How long should it be? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, but we are now splitting it and running a regex for each column when sorting by multiple columns compared to only sorting by a single column with an equals comparison? I'd say 256 bytes is a reasonable limit, but we can put it at 1024 to be on the safe side, doesn't make that much of a difference performance wise. |
||
if (sortByParts.length == 1) { | ||
for (String allowed : queryAnnotation.allowedSortColumns()) { | ||
if (allowed.equals(sortBy)) { | ||
collectionOptionsHasOrderBy = true; | ||
addOrderBy(sql, buildOrderBy(collectionOptions.getOrder(), allowed)); | ||
break; | ||
} | ||
} | ||
} else { | ||
Collections.reverse(Arrays.asList(sortByParts)); | ||
for (var sortByPart: sortByParts) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be nice to filter out the columns that have already been appended to the ordering. For instance, sortBy="name asc, id desc, name asc, id desc, ..." should not become "ORDER BY name ASC, id DESC, name ASC, id DESC, ..." but rather "ORDER BY name ASC, id DESC". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would make the code more complicated and would not change the result. It is also a fault made by the user of RW and should not occur. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that it would make the code more complicated and would not change the output. I am not sure I understand what you mean that it is a fault made by the user of RW and should not occur. Do you mean that the responsibility of dealing with "sortby=id asc, name desc, id asc, name desc, ..." falls on the application developer? Even though it would make the code more complicated and doesn't change the output (as well as probably a slight performance impact), I prefer to see the filtering because I find it unreasonable that we would allow an end user to craft a query that looks like that. Furthermore, while it may not be a security concern related to postgres, I have other security concerns that we can discuss in private. |
||
Matcher matcher = SORT_BY_PART.matcher(sortByPart); | ||
if (matcher.find()) { | ||
var sortByColumn = matcher.group("sortby"); | ||
if (sortByColumn != null) { | ||
var order = matcher.group("order"); | ||
for (String allowed : queryAnnotation.allowedSortColumns()) { | ||
if (allowed.equals(sortByColumn)) { | ||
collectionOptionsHasOrderBy = true; | ||
var sortOrder = order != null ? CollectionOptions.SortOrder.valueOf(order.toUpperCase()) : collectionOptions.getOrder(); | ||
addOrderBy(sql, buildOrderBy(sortOrder, allowed)); | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need åäö?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. We are a swedish company...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to think that åäö is not being used even though Fortnox is a swedish company :). Regardless, it is probably ok to leave it as is.