Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1677 - page state returned #1689

Merged
merged 5 commits into from
Nov 12, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public Iterable<Row> currentPage() {

@Override
public int remaining() {
throw new NotImplementedException();
return -1;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ public Optional<String> getPagingStateString() {
return isEmpty ? Optional.empty() : Optional.of(pagingStateString);
}

@Override
public String toString() {
return new StringBuilder("CqlPagingState{")
.append("isEmpty=")
.append(isEmpty)
.append(", pagingStateString='")
.append(pagingStateString)
.append('\'')
.append('}')
.toString();
}

private static ByteBuffer decode(String pagingState) {
return ByteBuffer.wrap(Base64.getDecoder().decode(pagingState));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ static class ReadResult {
this.resultSet = Objects.requireNonNull(resultSet, "resultSet must not be null");
this.currentPage = resultSet.currentPage();
this.pagingState = rowSorter.buildPagingState(resultSet);

if (LOGGER.isDebugEnabled()) {
LOGGER.debug(
"ReadResult() created resultSet.remaining: {}, resultSet.hasMorePages={}, (api) pagingState:{}",
resultSet.remaining(),
resultSet.hasMorePages(),
pagingState);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,21 @@ protected GenericOperation<TableSchemaObject, ReadAttempt<TableSchemaObject>> bu
var orderByWithWarnings = tableCqlSortClauseResolver.resolve(commandContext, command);
attemptBuilder.addOrderBy(orderByWithWarnings);

// if the user did not provide a limit, we will use the default page size as read limit
int commandLimit = command.limit().orElseGet(operationsConfig::defaultPageSize);
// if the user did not provide a limit,we read all the possible rows. Paging is then handled
// by the driver pagination
int commandLimit = command.limit().orElseGet(() -> Integer.MAX_VALUE);

int commandSkip = command.skip().orElse(0);

// and then if we need to do in memory sorting
var inMemorySort =
new TableMemorySortClauseResolver<>(
operationsConfig, orderByWithWarnings.target(), commandSkip, commandLimit)
operationsConfig,
orderByWithWarnings.target(),
commandSkip,
// Math.min is used because the max documents the api return is
// `operationsConfig.defaultPageSize()`
Math.min(commandLimit, operationsConfig.defaultPageSize()))
.resolve(commandContext, command);
attemptBuilder.addSorter(inMemorySort);

Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ datastax-java-driver {
}
}
basic.request.timeout = 20 seconds
// setting this at the global and the profile level
basic.request.page-size = 20
profiles {

create {
Expand All @@ -69,6 +71,9 @@ datastax-java-driver {

table-read {
basic.request.timeout = 10 seconds
// this will be the number of rows we return in a single page of results to the user.
// It may be overridded for in memory sorting, but this is the default.
basic.request.page-size = 20
consistency = LOCAL_QUORUM
}
table-write {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.stargate.sgv2.jsonapi.api.v1.tables;

import static io.stargate.sgv2.jsonapi.api.v1.util.DataApiCommandSenders.assertTableCommand;

import io.quarkus.test.common.WithTestResource;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import io.stargate.sgv2.jsonapi.api.v1.util.scenarios.KeyValueTable10Scenario;
import io.stargate.sgv2.jsonapi.testresource.DseTestResource;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.*;

@QuarkusIntegrationTest
@WithTestResource(value = DseTestResource.class, restrictToAnnotatedClass = false)
@TestClassOrder(ClassOrderer.OrderAnnotation.class)
public class FindNoPaginationTableIntegrationTest extends AbstractTableIntegrationTestBase {

private static final String TABLE_NAME = "findPaginationTableIntegrationTest";
private static final KeyValueTable10Scenario SCENARIO =
new KeyValueTable10Scenario(keyspaceName, TABLE_NAME);

@BeforeAll
public final void createScenario() {
SCENARIO.create();
}

@AfterAll
public final void dropScenario() {
SCENARIO.drop();
}

@Test
public void findWithPageState() {

assertTableCommand(keyspaceName, TABLE_NAME)
.templated()
.find(Map.of(), List.of())
.wasSuccessful()
.doesNotHaveNextPageState();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.stargate.sgv2.jsonapi.api.v1.tables;

import static io.stargate.sgv2.jsonapi.api.v1.util.DataApiCommandSenders.assertTableCommand;

import io.quarkus.test.common.WithTestResource;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import io.stargate.sgv2.jsonapi.api.v1.util.scenarios.KeyValueTable100Scenario;
import io.stargate.sgv2.jsonapi.testresource.DseTestResource;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.*;

@QuarkusIntegrationTest
@WithTestResource(value = DseTestResource.class, restrictToAnnotatedClass = false)
@TestClassOrder(ClassOrderer.OrderAnnotation.class)
public class FindPaginationTableIntegrationTest extends AbstractTableIntegrationTestBase {

private static final String TABLE_NAME = "findPaginationTableIntegrationTest";
private static final KeyValueTable100Scenario SCENARIO =
new KeyValueTable100Scenario(keyspaceName, TABLE_NAME);

@BeforeAll
public final void createScenario() {
SCENARIO.create();
}

@AfterAll
public final void dropScenario() {
SCENARIO.drop();
}

@Test
public void findWithPageState() {

assertTableCommand(keyspaceName, TABLE_NAME)
.templated()
.find(Map.of(), List.of())
.wasSuccessful()
.hasNextPageState();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,12 @@ public DataApiResponseValidator doesNotHaveIndexes(String... indexes) {
}
return toReturn;
}

public DataApiResponseValidator hasNextPageState() {
return body("data.nextPageState", is(notNullValue()));
}

public DataApiResponseValidator doesNotHaveNextPageState() {
return body("$", not(hasKey("data.nextPageState")));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.stargate.sgv2.jsonapi.api.v1.util.scenarios;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import io.stargate.sgv2.jsonapi.fixtures.data.DefaultData;
import io.stargate.sgv2.jsonapi.service.schema.tables.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** basic key-value table with 100 rows */
public class KeyValueTable100Scenario extends TestDataScenario {

public static final ApiColumnDef VALUE_COL =
new ApiColumnDef(CqlIdentifier.fromCql("value_col"), ApiDataTypeDefs.TEXT);

public KeyValueTable100Scenario(String keyspaceName, String tableName) {
super(
keyspaceName,
tableName,
ID_COL,
createClusteringDefs(),
createColumns(),
new DefaultData());
}

private static ApiColumnDefContainer createColumns() {

var columns = new ApiColumnDefContainer();
columns.put(ID_COL);
columns.put(VALUE_COL);
return columns;
}

private static List<ApiClusteringDef> createClusteringDefs() {

return List.of();
}

@Override
protected void insertRows() {

var rows = new ArrayList<Map<String, Object>>();
for (int i = 0; i < 100; i++) {
var row = new HashMap<String, Object>();
row.put(fieldName(ID_COL), "row" + i);
row.put(fieldName(VALUE_COL), "value-" + i);
rows.add(row);
}
insertManyRows(rows);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.stargate.sgv2.jsonapi.api.v1.util.scenarios;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import io.stargate.sgv2.jsonapi.fixtures.data.DefaultData;
import io.stargate.sgv2.jsonapi.service.schema.tables.ApiClusteringDef;
import io.stargate.sgv2.jsonapi.service.schema.tables.ApiColumnDef;
import io.stargate.sgv2.jsonapi.service.schema.tables.ApiColumnDefContainer;
import io.stargate.sgv2.jsonapi.service.schema.tables.ApiDataTypeDefs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** basic key-value table with 10 rows */
public class KeyValueTable10Scenario extends TestDataScenario {

public static final ApiColumnDef VALUE_COL =
new ApiColumnDef(CqlIdentifier.fromCql("value_col"), ApiDataTypeDefs.TEXT);

public KeyValueTable10Scenario(String keyspaceName, String tableName) {
super(
keyspaceName,
tableName,
ID_COL,
createClusteringDefs(),
createColumns(),
new DefaultData());
}

private static ApiColumnDefContainer createColumns() {

var columns = new ApiColumnDefContainer();
columns.put(ID_COL);
columns.put(VALUE_COL);
return columns;
}

private static List<ApiClusteringDef> createClusteringDefs() {

return List.of();
}

@Override
protected void insertRows() {

var rows = new ArrayList<Map<String, Object>>();
for (int i = 0; i < 10; i++) {
var row = new HashMap<String, Object>();
row.put(fieldName(ID_COL), "row" + i);
row.put(fieldName(VALUE_COL), "value-" + i);
rows.add(row);
}
insertManyRows(rows);
}
}