diff --git a/.github/workflows/compile.yaml b/.github/workflows/compile.yaml index d31b328c9..e2509748e 100644 --- a/.github/workflows/compile.yaml +++ b/.github/workflows/compile.yaml @@ -35,6 +35,16 @@ jobs: ./gradlew build testNative --no-daemon ./gradlew server:app:printVersion --no-daemon -q shell: bash + - name: Run integration test + shell: bash + env: + WHITEFOX_TEST_AWS_REGION: ${{ vars.WHITEFOX_AWS_REGION }} + WHITEFOX_TEST_AWS_ACCESS_KEY_ID: ${{ secrets.WHITEFOX_AWS_ACCESS_KEY_ID }} + WHITEFOX_TEST_AWS_SECRET_ACCESS_KEY: ${{ secrets.WHITEFOX_AWS_SECRET_ACCESS_KEY }} + run: | + java -jar server/app/build/quarkus-app/quarkus-run.jar & + ./gradlew :client-spark:clientSparkTest --no-daemon + kill -9 %1 - name: Build container image if: runner.os == 'Linux' run: | diff --git a/client-spark/build.gradle.kts b/client-spark/build.gradle.kts new file mode 100644 index 000000000..7c5391c1a --- /dev/null +++ b/client-spark/build.gradle.kts @@ -0,0 +1,86 @@ +import org.openapitools.generator.gradle.plugin.tasks.GenerateTask + +plugins { + java + id("com.diffplug.spotless") + id("whitefox.java-conventions") +} + +repositories { + mavenCentral() +} + +dependencies { + // OPENAPI + implementation("org.eclipse.microprofile.openapi:microprofile-openapi-api:3.1.1") + implementation("org.openapitools:jackson-databind-nullable:0.2.6") + testImplementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") + testImplementation("jakarta.annotation:jakarta.annotation-api:2.1.1") + + // DELTA + testImplementation("org.apache.hadoop:hadoop-common:3.3.6") + testImplementation("io.delta:delta-sharing-spark_2.12:1.0.2") + + //SPARK + testImplementation("org.apache.spark:spark-core_2.12:3.3.2") + testImplementation("org.apache.spark:spark-sql_2.12:3.3.2") + testImplementation("com.github.mrpowers:spark-fast-tests_2.12:1.3.0") + + //JUNIT + testImplementation("org.junit.jupiter:junit-jupiter:5.8.1") +} + + +tasks.getByName("test") { + useJUnitPlatform { + excludeTags.add("clientSparkTest") + } +} + +tasks.withType { + environment = env.allVariables + systemProperty ("java.util.logging.manager", "java.util.logging.LogManager") //TODO modularize the whitefox-conventions plugin +} + +tasks.register("clientSparkTest") { + useJUnitPlatform { + includeTags.add("clientSparkTest") + } +} + +val openApiCodeGenDir = "generated/openapi" +val generatedCodeDirectory = generatedCodeDirectory(layout, openApiCodeGenDir) + +val whiteFoxGenerate = tasks.register("openapiGenerateClientApi") { + dependsOn(tasks.spotlessApply) + generatorName.set("java") + inputSpec.set("$rootDir/protocol/whitefox-protocol-api.yml") + library.set("native") + outputDir.set(generatedCodeDirectory) + additionalProperties.set(mapOf( + "apiPackage" to "io.whitefox.api.client", + "invokerPackage" to "io.whitefox.api.utils", + "modelPackage" to "io.whitefox.api.client.model", + "dateLibrary" to "java8", + "sourceFolder" to "src/gen/java", + "openApiNullable" to "true", + "annotationLibrary" to "none", + "serializationLibrary" to "jackson", + "useJakartaEe" to "true", + "useRuntimeException" to "true" + )) +} + +sourceSets { + getByName("test") { + java { + srcDir("${generatedCodeDirectory(layout, openApiCodeGenDir)}/src/gen/java") + } + } +} + +tasks.withType { + options.encoding = "UTF-8" + options.compilerArgs.add("-parameters") + dependsOn(whiteFoxGenerate) +} \ No newline at end of file diff --git a/client-spark/src/test/java/io/whitefox/api/client/ITDeltaSharingClient.java b/client-spark/src/test/java/io/whitefox/api/client/ITDeltaSharingClient.java new file mode 100644 index 000000000..4124c87c0 --- /dev/null +++ b/client-spark/src/test/java/io/whitefox/api/client/ITDeltaSharingClient.java @@ -0,0 +1,61 @@ +package io.whitefox.api.client; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.github.mrpowers.spark.fast.tests.DatasetComparer; +import io.whitefox.api.models.MrFoxDeltaTableSchema; +import io.whitefox.api.utils.StorageManagerInitializer; +import java.util.List; +import org.apache.spark.sql.SparkSession; +import org.apache.spark.sql.types.DataType; +import org.apache.spark.sql.types.Metadata; +import org.apache.spark.sql.types.StructField; +import org.apache.spark.sql.types.StructType; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import scala.collection.GenMap; + +@Tag("clientSparkTest") +public class ITDeltaSharingClient implements DatasetComparer { + + private final String tablePath = String.format( + "%s#%s.%s.%s", + getClass().getClassLoader().getResource("MrFoxProfile.json"), + "s3share", + "s3schema", + "s3Table1"); + + private final SparkSession spark = SparkSession.builder() + .appName("delta sharing client test") + .config("spark.driver.host", "localhost") + .master("local[1, 4]") + .getOrCreate(); + + @BeforeAll + static void initStorageManager() { + new StorageManagerInitializer().initStorageManager(); + } + + @Test + void showS3Table1withQueryTableApi() { + var ds = spark.read().format("deltaSharing").load(tablePath); + var expectedSchema = new StructType(new StructField[] { + new StructField("id", DataType.fromDDL("long"), true, new Metadata(GenMap.empty())) + }); + var expectedData = spark + .createDataFrame( + List.of( + new MrFoxDeltaTableSchema(0), + new MrFoxDeltaTableSchema(3), + new MrFoxDeltaTableSchema(2), + new MrFoxDeltaTableSchema(1), + new MrFoxDeltaTableSchema(4)), + MrFoxDeltaTableSchema.class) + .toDF(); + + assertEquals(expectedSchema.json(), ds.schema().json()); + assertEquals(5, ds.count()); + assertSmallDatasetEquality(ds, expectedData, true, false, false, 500); + } +} diff --git a/client-spark/src/test/java/io/whitefox/api/models/MrFoxDeltaTableSchema.java b/client-spark/src/test/java/io/whitefox/api/models/MrFoxDeltaTableSchema.java new file mode 100644 index 000000000..0f01846a3 --- /dev/null +++ b/client-spark/src/test/java/io/whitefox/api/models/MrFoxDeltaTableSchema.java @@ -0,0 +1,13 @@ +package io.whitefox.api.models; + +public class MrFoxDeltaTableSchema { + private final long id; + + public MrFoxDeltaTableSchema(long id) { + this.id = id; + } + + public long getId() { + return id; + } +} diff --git a/client-spark/src/test/java/io/whitefox/api/utils/S3TestConfig.java b/client-spark/src/test/java/io/whitefox/api/utils/S3TestConfig.java new file mode 100644 index 000000000..3f1a15f85 --- /dev/null +++ b/client-spark/src/test/java/io/whitefox/api/utils/S3TestConfig.java @@ -0,0 +1,32 @@ +package io.whitefox.api.utils; + +public class S3TestConfig { + private final String region; + private final String accessKey; + private final String secretKey; + + public String getRegion() { + return region; + } + + public String getAccessKey() { + return accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public S3TestConfig(String region, String accessKey, String secretKey) { + this.region = region; + this.accessKey = accessKey; + this.secretKey = secretKey; + } + + public static S3TestConfig loadFromEnv() { + return new S3TestConfig( + System.getenv().get("WHITEFOX_TEST_AWS_REGION"), + System.getenv().get("WHITEFOX_TEST_AWS_ACCESS_KEY_ID"), + System.getenv().get("WHITEFOX_TEST_AWS_SECRET_ACCESS_KEY")); + } +} diff --git a/client-spark/src/test/java/io/whitefox/api/utils/StorageManagerInitializer.java b/client-spark/src/test/java/io/whitefox/api/utils/StorageManagerInitializer.java new file mode 100644 index 000000000..fd6639943 --- /dev/null +++ b/client-spark/src/test/java/io/whitefox/api/utils/StorageManagerInitializer.java @@ -0,0 +1,77 @@ +package io.whitefox.api.utils; + +import io.whitefox.api.client.*; +import io.whitefox.api.client.model.*; +import java.util.List; +import java.util.Map; + +public class StorageManagerInitializer { + private final S3TestConfig s3TestConfig; + private final StorageV1Api storageV1Api; + private final ProviderV1Api providerV1Api; + private final TableV1Api tableV1Api; + private final ShareV1Api shareV1Api; + private final SchemaV1Api schemaV1Api; + + public StorageManagerInitializer() { + var apiClient = new ApiClient(); + this.s3TestConfig = S3TestConfig.loadFromEnv(); + this.storageV1Api = new StorageV1Api(apiClient); + this.providerV1Api = new ProviderV1Api(apiClient); + this.tableV1Api = new TableV1Api(apiClient); + this.shareV1Api = new ShareV1Api(apiClient); + this.schemaV1Api = new SchemaV1Api(apiClient); + } + + public void initStorageManager() { + storageV1Api.createStorage(createStorageRequest(s3TestConfig)); + providerV1Api.addProvider(addProviderRequest()); + tableV1Api.createTableInProvider(addProviderRequest().getName(), createTableRequest()); + shareV1Api.createShare(createShareRequest()); + schemaV1Api.createSchema(createShareRequest().getName(), createSchemaRequest()); + schemaV1Api.addTableToSchema( + createShareRequest().getName(), createSchemaRequest(), addTableToSchemaRequest()); + } + + private String createSchemaRequest() { + return "s3schema"; + } + + private AddTableToSchemaRequest addTableToSchemaRequest() { + return new AddTableToSchemaRequest() + .name("s3Table1") + .reference(new TableReference().providerName("MrFoxProvider").name("s3Table1")); + } + + private CreateShareInput createShareRequest() { + return new CreateShareInput().name("s3share").recipients(List.of("Mr.Fox")).schemas(List.of()); + } + + private CreateTableInput createTableRequest() { + return new CreateTableInput() + .name("s3Table1") + .skipValidation(true) + .properties(Map.of( + "type", "delta", + "location", "s3a://whitefox-s3-test-bucket/delta/samples/delta-table")); + } + + private ProviderInput addProviderRequest() { + return new ProviderInput() + .name("MrFoxProvider") + .storageName("MrFoxStorage") + .metastoreName(null); + } + + private CreateStorage createStorageRequest(S3TestConfig s3TestConfig) { + return new CreateStorage() + .name("MrFoxStorage") + .type(CreateStorage.TypeEnum.S3) + .properties(new StorageProperties(new S3Properties() + .credentials(new SimpleAwsCredentials() + .region(s3TestConfig.getRegion()) + .awsAccessKeyId(s3TestConfig.getAccessKey()) + .awsSecretAccessKey(s3TestConfig.getSecretKey())))) + .skipValidation(true); + } +} diff --git a/client-spark/src/test/resources/MrFoxProfile.json b/client-spark/src/test/resources/MrFoxProfile.json new file mode 100644 index 000000000..05c48f70a --- /dev/null +++ b/client-spark/src/test/resources/MrFoxProfile.json @@ -0,0 +1,6 @@ +{ + "shareCredentialsVersion": 1, + "endpoint": "http://localhost:8080/delta-api/v1/", + "bearerToken": "fakeToken", + "expirationTime": null +} \ No newline at end of file diff --git a/protocol/delta-sharing-protocol-api.yml b/protocol/delta-sharing-protocol-api.yml index 32c822709..fbc435827 100644 --- a/protocol/delta-sharing-protocol-api.yml +++ b/protocol/delta-sharing-protocol-api.yml @@ -419,6 +419,12 @@ paths: description: 'Starting Timestamp ISO8601 format, in the UTC timezone' schema: type: string + - in: header + name: delta-sharing-capabilities + required: false + description: 'Delta Sharing Capabilities' + schema: + type: string requestBody: required: true content: @@ -670,7 +676,7 @@ components: items: type: string jsonPredicateHints: - type: object + type: string description: | query predicates on partition columns specified using a structured JSON format. When it’s present, the server will try to use the predicates to filter table's @@ -680,19 +686,20 @@ components: If the server encounters any errors during predicate processing (for example, invalid syntax or non existing columns), it will skip filtering and return all the files. When it’s absent, the server will return all the files in the table. - properties: - op: - $ref: '#/components/schemas/Ops' - children: - type: string - name: - type: string - value: - type: string - valueType: - type: string +# properties: +# op: +# $ref: '#/components/schemas/Ops' +# children: +# type: string +# name: +# type: string +# value: +# type: string +# valueType: +# type: string limitHint: type: integer + format: int64 example: 1000 description: | It’s a hint from the client to tell the server how many rows the @@ -717,6 +724,7 @@ components: timestamp. This is only supported on tables with history sharing enabled. startingVersion: type: integer + format: int64 example: 1000 description: | an optional version number. If set, will return all data change files @@ -724,6 +732,7 @@ components: in the delta log. endingVersion: type: integer + format: int64 example: 1000 description: | an optional version number, only used if startingVersion is set. If set, @@ -836,7 +845,7 @@ components: MetadataObject: type: object properties: - metadata: + metaData: type: object properties: id: diff --git a/server/app/build.gradle.kts b/server/app/build.gradle.kts index c00d3bcf3..c85b7577c 100644 --- a/server/app/build.gradle.kts +++ b/server/app/build.gradle.kts @@ -11,12 +11,12 @@ val quarkusPlatformArtifactId: String by project val quarkusPlatformVersion: String by project // region dependencies - +val hadoopVersion = "3.3.6" dependencies { // INTERNAL implementation(project(":server:core")) implementation(project(":server:persistence:memory")) - + // QUARKUS implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")) implementation("io.quarkus:quarkus-arc") diff --git a/server/app/src/main/java/io/whitefox/api/configuration/JsonConfiguration.java b/server/app/src/main/java/io/whitefox/api/configuration/JsonConfiguration.java index 4ae92e567..079903d63 100644 --- a/server/app/src/main/java/io/whitefox/api/configuration/JsonConfiguration.java +++ b/server/app/src/main/java/io/whitefox/api/configuration/JsonConfiguration.java @@ -1,6 +1,7 @@ package io.whitefox.api.configuration; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.quarkus.arc.All; import io.quarkus.jackson.ObjectMapperCustomizer; @@ -16,6 +17,7 @@ public class JsonConfiguration { ObjectMapper objectMapper(@All List customizers) { ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // Apply all ObjectMapperCustomizer beans (incl. Quarkus) for (ObjectMapperCustomizer customizer : customizers) { customizer.customize(mapper); diff --git a/server/app/src/main/java/io/whitefox/api/deltasharing/DeltaMappers.java b/server/app/src/main/java/io/whitefox/api/deltasharing/DeltaMappers.java index 1ba496428..6948065c7 100644 --- a/server/app/src/main/java/io/whitefox/api/deltasharing/DeltaMappers.java +++ b/server/app/src/main/java/io/whitefox/api/deltasharing/DeltaMappers.java @@ -5,11 +5,8 @@ import io.whitefox.core.*; import io.whitefox.core.Schema; import io.whitefox.core.Share; -import java.util.Arrays; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; -import org.jboss.resteasy.reactive.common.NotImplementedYet; public class DeltaMappers { @@ -26,9 +23,15 @@ public static io.whitefox.api.deltasharing.model.v1.generated.Schema schema2api( } public static ReadTableRequest api2ReadTableRequest(QueryRequest request) { - if (request.getEndingVersion() != null || request.getStartingVersion() != null) - throw new NotImplementedYet(); - if (request.getVersion() != null && request.getTimestamp() == null) { + if (request.getStartingVersion() != null && request.getEndingVersion() != null) { + throw new IllegalArgumentException("The startingVersion and endingVersion are not supported"); + } else if (request.getStartingVersion() != null) { + throw new IllegalArgumentException("The startingVersion is not supported"); + } else if (request.getEndingVersion() != null) { + throw new IllegalArgumentException("The endingVersion is not supported"); + } else if (request.getVersion() != null && request.getVersion() < 0) { + throw new IllegalArgumentException("version cannot be negative."); + } else if (request.getVersion() != null && request.getTimestamp() == null) { return new ReadTableRequest.ReadTableVersion( request.getPredicateHints(), Optional.ofNullable(request.getLimitHint()), @@ -57,7 +60,7 @@ public static TableQueryResponseObject readTableResult2api(ReadTableResult readT private static MetadataObject metadata2Api(Metadata metadata) { return new MetadataObject() - .metadata(new MetadataObjectMetadata() + .metaData(new MetadataObjectMetaData() .id(metadata.id()) .name(metadata.name().orElse(null)) .description(metadata.description().orElse(null)) diff --git a/server/app/src/main/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImpl.java b/server/app/src/main/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImpl.java index b1450be75..8bb0b18ca 100644 --- a/server/app/src/main/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImpl.java +++ b/server/app/src/main/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImpl.java @@ -188,15 +188,25 @@ public Response queryTable( String schema, String table, QueryRequest queryRequest, - String startingTimestamp) { - + String startingTimestamp, + String deltaSharingCapabilities) { return wrapExceptions( - () -> Response.ok( - tableQueryResponseSerializer.serialize( - DeltaMappers.readTableResult2api(deltaSharesService.queryTable( - share, schema, table, DeltaMappers.api2ReadTableRequest(queryRequest)))), - ndjsonMediaType) - .build(), + () -> optionalToNotFound( + deltaSharesService.getTableVersion(share, schema, table, startingTimestamp), + version -> Response.ok( + tableQueryResponseSerializer.serialize( + DeltaMappers.readTableResult2api(deltaSharesService.queryTable( + share, + schema, + table, + DeltaMappers.api2ReadTableRequest(queryRequest)))), + ndjsonMediaType) + .header(DELTA_TABLE_VERSION_HEADER, version) + .header( + DELTA_SHARE_CAPABILITIES_HEADER, + getResponseFormatHeader( + DeltaMappers.toHeaderCapabilitiesMap(deltaSharingCapabilities))) + .build()), exceptionToResponse); } diff --git a/server/app/src/main/java/io/whitefox/api/server/WhitefoxMappers.java b/server/app/src/main/java/io/whitefox/api/server/WhitefoxMappers.java index c08516e83..ac5dd4d36 100644 --- a/server/app/src/main/java/io/whitefox/api/server/WhitefoxMappers.java +++ b/server/app/src/main/java/io/whitefox/api/server/WhitefoxMappers.java @@ -175,7 +175,7 @@ public static MetastoreType api2MetastoreType( private static MetadataObject metadata2Api(Metadata metadata) { return new MetadataObject() - .metadata(new MetadataObjectMetadata() + .metaData(new MetadataObjectMetaData() .id(metadata.id()) .name(metadata.name().orElse(null)) .description(metadata.description().orElse(null)) diff --git a/server/app/src/test/java/io/whitefox/api/deltasharing/SampleTables.java b/server/app/src/test/java/io/whitefox/api/deltasharing/SampleTables.java index d490d9a53..777cc5523 100644 --- a/server/app/src/test/java/io/whitefox/api/deltasharing/SampleTables.java +++ b/server/app/src/test/java/io/whitefox/api/deltasharing/SampleTables.java @@ -53,7 +53,7 @@ public static StorageManager createStorageManager() { } public static final MetadataObject deltaTable1Metadata = new MetadataObject() - .metadata(new MetadataObjectMetadata() + .metaData(new MetadataObjectMetaData() .id("56d48189-cdbc-44f2-9b0e-2bded4c79ed7") .name("table1") .format(new FormatObject().provider("parquet")) @@ -64,7 +64,7 @@ public static StorageManager createStorageManager() { ._configuration(Map.of())); public static final MetadataObject s3DeltaTable1Metadata = new MetadataObject() - .metadata(new MetadataObjectMetadata() + .metaData(new MetadataObjectMetaData() .id("ed2297c4-8bb8-4c74-963d-8fed6bebfd8b") .name("s3Table1") .format(new FormatObject().provider("parquet")) @@ -74,7 +74,7 @@ public static StorageManager createStorageManager() { .version(0L) ._configuration(Map.of())); public static final MetadataObject deltaTableWithHistory1Metadata = new MetadataObject() - .metadata(new MetadataObjectMetadata() + .metaData(new MetadataObjectMetaData() .id("56d48189-cdbc-44f2-9b0e-2bded4c79ed7") .name("table-with-history") .format(new FormatObject().provider("parquet")) diff --git a/server/app/src/test/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImplTest.java b/server/app/src/test/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImplTest.java index ae520482d..6a89f0f32 100644 --- a/server/app/src/test/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImplTest.java +++ b/server/app/src/test/java/io/whitefox/api/deltasharing/server/DeltaSharesApiImplTest.java @@ -192,7 +192,7 @@ public void tableMetadata() throws IOException { objectMapper.reader().readValue(responseBodyLines[0], ProtocolObject.class)); assertEquals( new MetadataObject() - .metadata(new MetadataObjectMetadata() + .metaData(new MetadataObjectMetaData() .id("56d48189-cdbc-44f2-9b0e-2bded4c79ed7") .name("table1") .format(new FormatObject().provider("parquet")) diff --git a/server/core/build.gradle.kts b/server/core/build.gradle.kts index b529ee65a..0fd2f8dc2 100644 --- a/server/core/build.gradle.kts +++ b/server/core/build.gradle.kts @@ -1,6 +1,3 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat -import org.openapitools.generator.gradle.plugin.tasks.GenerateTask - plugins { `java-library` `java-test-fixtures` diff --git a/server/core/src/main/java/io/whitefox/core/ReadTableRequest.java b/server/core/src/main/java/io/whitefox/core/ReadTableRequest.java index b2232f48c..aa6df33ab 100644 --- a/server/core/src/main/java/io/whitefox/core/ReadTableRequest.java +++ b/server/core/src/main/java/io/whitefox/core/ReadTableRequest.java @@ -9,12 +9,11 @@ public interface ReadTableRequest { public static class ReadTableVersion implements ReadTableRequest { private final List predicateHints; - private final Optional limitHint; + private final Optional limitHint; private final Long version; - public ReadTableVersion( - List predicateHints, Optional limitHint, Long version) { + public ReadTableVersion(List predicateHints, Optional limitHint, Long version) { this.predicateHints = predicateHints; this.limitHint = limitHint; this.version = version; @@ -24,7 +23,7 @@ public List predicateHints() { return predicateHints; } - public Optional limitHint() { + public Optional limitHint() { return limitHint; } @@ -61,11 +60,11 @@ public String toString() { public static class ReadTableAsOfTimestamp implements ReadTableRequest { private final List predicateHints; - private final Optional limitHint; + private final Optional limitHint; private final Long timestamp; public ReadTableAsOfTimestamp( - List predicateHints, Optional limitHint, Long timestamp) { + List predicateHints, Optional limitHint, Long timestamp) { this.predicateHints = predicateHints; this.limitHint = limitHint; this.timestamp = timestamp; @@ -101,7 +100,7 @@ public List predicateHints() { return predicateHints; } - public Optional limitHint() { + public Optional limitHint() { return limitHint; } @@ -112,9 +111,9 @@ public Long timestamp() { public static class ReadTableCurrentVersion implements ReadTableRequest { private final List predicateHints; - private final Optional limitHint; + private final Optional limitHint; - public ReadTableCurrentVersion(List predicateHints, Optional limitHint) { + public ReadTableCurrentVersion(List predicateHints, Optional limitHint) { this.predicateHints = predicateHints; this.limitHint = limitHint; } @@ -123,7 +122,7 @@ public List predicateHints() { return predicateHints; } - public Optional limitHint() { + public Optional limitHint() { return limitHint; } diff --git a/settings.gradle.kts b/settings.gradle.kts index 8aa5e835f..7c9fd8e30 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,6 +4,7 @@ include("server:core") include("server:persistence:memory") include("server:app") include("docsite") +include("client-spark") pluginManagement { val quarkusPluginVersion: String by settings