I’ve tried every way I can think of to refresh the data in my grid. In the logs I can see that the method is getting called, but on the rendered page, the grid remains empty.
There are 2 clues:
- The second refresh call does work. It comes at the end of the long async process that is running.
- The first call has a strange limit setting.
Here’s the method:
public void refreshGrid() {
backendDataProvider.refreshAll();
}
Here are the relevant logs:
KeywordGrid * starting refresh
- KeywordDtoDataProvider starting refreshAll
- Loaded 121 keywords for collection KeywordCollectionId[value=877dd040-1326-47de-b1c3-6a1b148d80b8]
- KeywordDtoDataProvider calling super.refreshAll()
- KeywordDtoDataProvider completed refreshAll
- KeywordGrid completed refresh call
- Fetching data from backend with offset: 0, limit: 2147483647
Later, when the second refresh is called, the limit is much different:
- Fetching data from backend with offset: 0, limit: 49
I think that limit is handled by this method:
@Override
protected int sizeInBackEnd(Query<KeywordDto, KeywordFilter> query) {
KeywordFilter filter = query.getFilter().orElse(null);
return (int) applyFiltersAndSorting(fullDataset.stream(), filter, null).count();
}
Here’s the full class:
public class KeywordDtoDataProvider extends AbstractBackEndDataProvider<KeywordDto, KeywordFilter> {
private final ResearchRepository repository;
private final KeywordCollectionId keywordCollectionId;
private Set fullDataset;
private static final Logger log = LoggerFactory.getLogger(KeywordDtoDataProvider.class);
public KeywordDtoDataProvider(ResearchRepository repository, KeywordCollectionId keywordCollectionId) {
this.repository = Objects.requireNonNull(repository, "Repository must not be null");
this.keywordCollectionId = Objects.requireNonNull(keywordCollectionId, "KeywordCollectionId must not be null");
reloadData();
}
private void reloadData() {
Optional<KeywordCollection> keywordCollection = repository.findById(keywordCollectionId);
if (keywordCollection.isEmpty()) {
log.debug("No keyword collection found for id: {}", keywordCollectionId);
this.fullDataset = Collections.emptySet();
} else {
log.debug("Loaded {} keywords for collection {}",
keywordCollection.get().keywordResults().size(),
keywordCollectionId);
this.fullDataset = keywordCollection.get().keywordResults();
}
}
@Override
public void refreshAll() {
log.debug("KeywordDtoDataProvider starting refreshAll");
reloadData();
log.debug("KeywordDtoDataProvider calling super.refreshAll()");
super.refreshAll();
log.debug("KeywordDtoDataProvider completed refreshAll");
}
@Override
protected Stream<KeywordDto> fetchFromBackEnd(Query<KeywordDto, KeywordFilter> query) {
log.debug("Fetching data from backend with offset: {}, limit: {}", query.getOffset(), query.getLimit());
int offset = query.getOffset();
int limit = query.getLimit();
KeywordFilter filter = query.getFilter().orElse(null);
List<QuerySortOrder> sortOrders = getQuerySortOrders(query);
Comparator<KeywordResult> comparator = createComparator(sortOrders);
return assignRowNumber(applyFiltersAndSorting(fullDataset.stream(), filter, comparator)
.skip(offset)
.limit(limit))
.map(pair -> KeywordDto.from(pair.element()))
.toList()
.stream();
}
@NotNull
private Comparator<KeywordResult> createComparator(List<QuerySortOrder> sortOrders) {
return sortOrders.stream()
.map(this::getComparatorForSortOrder)
.reduce(Comparator::thenComparing)
.orElse((_, _) -> 0);
}
private Stream<KeywordResult> applyFiltersAndSorting(Stream<KeywordResult> keywordStream,
KeywordFilter filter,
Comparator<KeywordResult> comparator) {
if (filter != null) {
keywordStream = keywordStream.filter(filter::test);
}
if (comparator != null) {
keywordStream = keywordStream.sorted(comparator);
}
return keywordStream;
}
private List<QuerySortOrder> getQuerySortOrders(Query<KeywordDto, KeywordFilter> query) {
List<QuerySortOrder> sortOrders = query.getSortOrders();
if (sortOrders == null || sortOrders.isEmpty()) {
sortOrders = QuerySortOrder.desc("createdAt").build();
}
return sortOrders;
}
@Override
protected int sizeInBackEnd(Query<KeywordDto, KeywordFilter> query) {
KeywordFilter filter = query.getFilter().orElse(null);
return (int) applyFiltersAndSorting(fullDataset.stream(), filter, null).count();
}
private <T> Stream<Pair<T>> assignRowNumber(Stream<T> stream) {
AtomicInteger index = new AtomicInteger();
return stream.map(element -> new Pair<>(element, index.getAndIncrement()));
}
private record Pair<T>(T element, int index) {
}
private Comparator<KeywordResult> getComparatorForSortOrder(QuerySortOrder order) {
Objects.requireNonNull(order, "QuerySortOrder must not be null");
Objects.requireNonNull(order.getSorted(), "Sort field must not be null");
Objects.requireNonNull(order.getDirection(), "Sort direction must not be null");
Comparator<KeywordResult> comparator;
switch (order.getSorted()) {
case "keyword" -> comparator = Comparator.comparing(
kr -> kr.keyword().replaceAll("(\\D*)(\\d+)(.*)", "$1$2"),
String.CASE_INSENSITIVE_ORDER
);
case "avgMonthlySearches" -> comparator = Comparator.comparing(
KeywordResult::searchVolume, Comparator.nullsLast(Comparator.naturalOrder())
);
case "compositeTrend" -> comparator = Comparator.comparing(
KeywordResult::compositeTrendScore, Comparator.nullsLast(Comparator.naturalOrder())
);
case "competition" -> comparator = Comparator.comparing(
KeywordResult::competitionIndex, Comparator.nullsLast(Comparator.naturalOrder())
);
case "createdAt" -> comparator = Comparator.comparing(
KeywordResult::createdAt, Comparator.nullsLast(Comparator.naturalOrder())
);
case "industryAlignmentConfidence" -> comparator = Comparator.comparing(
KeywordResult::minIndustryAlignmentConfidence, Comparator.nullsLast(Comparator.naturalOrder())
);
case "avgDomainAuth" -> comparator = Comparator.comparing(
KeywordResult::avgDomainAuthority, Comparator.nullsLast(Comparator.naturalOrder())
);
case "serpUri" -> comparator = Comparator.comparing(
KeywordResult::serpUri, Comparator.nullsLast(Comparator.naturalOrder())
);
case "difficulty" -> comparator = Comparator.comparing(
KeywordResult::difficulty, Comparator.nullsLast(Comparator.naturalOrder())
);
case "commercialValue" -> comparator = Comparator.comparing(
KeywordResult::commercialValue, Comparator.nullsLast(Comparator.naturalOrder())
);
case "searchIntent" -> comparator = Comparator.comparing(
KeywordResult::searchIntent, Comparator.nullsLast(Comparator.naturalOrder())
);
default -> throw new IllegalArgumentException("Unsupported sorting field: " + order.getSorted());
}
return order.getDirection() == SortDirection.DESCENDING ? comparator.reversed() : comparator;
}
}