use of io.cdap.cdap.spi.metadata.Sorting in project cdap by caskdata.
the class DatasetMetadataStorage method search.
@Override
public SearchResponse search(SearchRequest request) {
Cursor cursor = request.getCursor() != null && !request.getCursor().isEmpty() ? Cursor.fromString(request.getCursor()) : null;
Set<String> namespaces = cursor == null ? request.getNamespaces() : cursor.getNamespaces();
ImmutablePair<NamespaceId, Set<EntityScope>> namespaceAndScopes = determineNamespaceAndScopes(namespaces);
CursorAndOffsetInfo cursorOffsetAndLimits = determineCursorOffsetAndLimits(request, cursor);
String query = cursor != null ? cursor.getQuery() : request.getQuery() == null || request.getQuery().isEmpty() ? "*" : request.getQuery();
Set<String> types = cursor != null ? cursor.getTypes() : request.getTypes();
types = types == null ? Collections.emptySet() : types;
Sorting sorting = cursor == null ? request.getSorting() : cursor.getSorting() == null ? null : Sorting.of(cursor.getSorting());
SortInfo sortInfo = sorting == null ? SortInfo.DEFAULT : new SortInfo(sorting.getKey(), SortInfo.SortOrder.valueOf(sorting.getOrder().name()));
boolean showHidden = cursor != null ? cursor.isShowHidden() : request.isShowHidden();
MetadataScope scope = cursor != null ? cursor.getScope() : request.getScope();
MetadataSearchResponse response = search(new io.cdap.cdap.data2.metadata.dataset.SearchRequest(namespaceAndScopes.getFirst(), query, types, sortInfo, cursorOffsetAndLimits.getOffsetToRequest(), cursorOffsetAndLimits.getLimitToRequest(), request.isCursorRequested() ? 1 : 0, cursorOffsetAndLimits.getCursor(), showHidden, namespaceAndScopes.getSecond()), scope);
// translate results back and limit them to at most what was requested (see above where we add 1)
int limitToRespond = cursorOffsetAndLimits.getLimitToRespond();
int offsetToRespond = cursorOffsetAndLimits.getOffsetToRespond();
List<MetadataRecord> results = response.getResults().stream().limit(limitToRespond).map(record -> {
Metadata metadata = Metadata.EMPTY;
for (Map.Entry<MetadataScope, io.cdap.cdap.api.metadata.Metadata> entry : record.getMetadata().entrySet()) {
Metadata toAdd = new Metadata(entry.getKey(), entry.getValue().getTags(), entry.getValue().getProperties());
metadata = mergeDisjointMetadata(metadata, toAdd);
}
return new MetadataRecord(record.getMetadataEntity(), metadata);
}).collect(Collectors.toList());
Cursor newCursor = null;
if (response.getCursors() != null && !response.getCursors().isEmpty()) {
String actualCursor = response.getCursors().get(0);
if (cursor != null) {
// the new cursor's offset is the previous cursor's offset plus the number of results
newCursor = new Cursor(cursor, cursor.getOffset() + results.size(), actualCursor);
} else {
newCursor = new Cursor(offsetToRespond + results.size(), limitToRespond, showHidden, scope, namespaces, types, sorting == null ? null : sorting.toString(), actualCursor, query);
}
}
// adjust the total results by the difference of requested offset and the true offset that we respond back
int totalResults = offsetToRespond - cursorOffsetAndLimits.getOffsetToRequest() + response.getTotal();
return new SearchResponse(request, newCursor == null ? null : newCursor.toString(), offsetToRespond, limitToRespond, totalResults, results);
}
use of io.cdap.cdap.spi.metadata.Sorting in project cdap by caskdata.
the class MetadataHttpHandler method getValidatedSearchRequest.
// TODO (CDAP-14946): Find a better way to determine allowed combinations of search parameters
private SearchRequest getValidatedSearchRequest(@Nullable String scope, @Nullable List<String> namespaces, @Nullable String searchQuery, @Nullable List<String> targets, @Nullable String sort, int offset, int limit, @Nullable Integer numCursors, boolean cursorRequested, @Nullable String cursor, boolean showHidden, @Nullable String entityScope) throws BadRequestException {
try {
SearchRequest.Builder builder = SearchRequest.of(searchQuery == null ? "*" : searchQuery);
if (scope != null) {
builder.setScope(validateScope(scope));
}
if (EntityScope.SYSTEM == validateEntityScope(entityScope)) {
builder.addNamespace(entityScope.toLowerCase());
} else if (namespaces != null) {
for (String namespace : namespaces) {
builder.addNamespace(namespace);
}
}
if (targets != null) {
targets.forEach(builder::addType);
}
if (sort != null) {
Sorting sorting;
try {
sorting = Sorting.of(URLDecoder.decode(sort, StandardCharsets.UTF_8.name()));
} catch (UnsupportedEncodingException e) {
// this cannot happen because UTF_8 is always supported
throw new IllegalStateException(e);
}
if (!MetadataConstants.ENTITY_NAME_KEY.equalsIgnoreCase(sorting.getKey()) && !MetadataConstants.CREATION_TIME_KEY.equalsIgnoreCase(sorting.getKey())) {
throw new IllegalArgumentException("Sorting is only supported on fields: " + MetadataConstants.ENTITY_NAME_KEY + ", " + MetadataConstants.CREATION_TIME_KEY);
}
builder.setSorting(sorting);
}
builder.setOffset(offset);
builder.setLimit(limit);
if (cursorRequested || (numCursors != null && numCursors > 0)) {
if (sort == null) {
throw new IllegalArgumentException("Specify a sort order when requesting a cursor");
}
builder.setCursorRequested(true);
}
if (cursor != null) {
if (sort == null) {
throw new IllegalArgumentException("Specify a sort order when passing in a cursor");
}
builder.setCursor(cursor);
}
builder.setShowHidden(showHidden);
SearchRequest request = builder.build();
LOG.trace("Received search request {}", request);
return request;
} catch (IllegalArgumentException e) {
throw new BadRequestException(e.getMessage(), e);
}
}
Aggregations