Skip to content

Commit

Permalink
Nessie CLI: Add initial Iceberg REST functionality (#8511)
Browse files Browse the repository at this point in the history
`CONNECT TO` and `USE` working, `SHOW TABLE/VIEW` displays the table/view metadata.

Also adds the `ON initialReference` clause to `CONNECT TO`.
  • Loading branch information
snazy committed May 27, 2024
1 parent 9987f17 commit 49cf7f7
Show file tree
Hide file tree
Showing 18 changed files with 872 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@

import java.util.Iterator;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntSupplier;
import java.util.stream.Stream;
import org.projectnessie.catalog.formats.iceberg.meta.IcebergBlobMetadata;
import org.projectnessie.catalog.formats.iceberg.meta.IcebergNestedField;
Expand All @@ -59,6 +61,11 @@

public class IcebergFixtures {
public static Stream<IcebergType> icebergTypes() {
AtomicInteger idGen = new AtomicInteger();
return icebergTypes(idGen::incrementAndGet);
}

public static Stream<IcebergType> icebergTypes(IntSupplier idSupplier) {
return Stream.of(
booleanType(),
uuidType(),
Expand All @@ -70,16 +77,20 @@ public static Stream<IcebergType> icebergTypes() {
doubleType(),
dateType(),
timeType(),
structType(singletonList(nestedField(11, "field11", true, stringType(), null)), null),
structType(singletonList(nestedField(11, "field11", false, stringType(), null)), null),
listType(1, stringType(), true),
listType(1, stringType(), false),
listType(1, uuidType(), true),
listType(1, uuidType(), false),
mapType(3, stringType(), 4, dateType(), true),
mapType(3, stringType(), 4, dateType(), false),
mapType(3, uuidType(), 4, timeType(), true),
mapType(3, uuidType(), 4, timeType(), false),
structType(
singletonList(nestedField(idSupplier.getAsInt(), "field11", true, stringType(), null)),
null),
structType(
singletonList(nestedField(idSupplier.getAsInt(), "field11", false, stringType(), null)),
null),
listType(idSupplier.getAsInt(), stringType(), true),
listType(idSupplier.getAsInt(), stringType(), false),
listType(idSupplier.getAsInt(), uuidType(), true),
listType(idSupplier.getAsInt(), uuidType(), false),
mapType(idSupplier.getAsInt(), stringType(), idSupplier.getAsInt(), dateType(), true),
mapType(idSupplier.getAsInt(), stringType(), idSupplier.getAsInt(), dateType(), false),
mapType(idSupplier.getAsInt(), uuidType(), idSupplier.getAsInt(), timeType(), true),
mapType(idSupplier.getAsInt(), uuidType(), idSupplier.getAsInt(), timeType(), false),
decimalType(10, 3),
fixedType(42),
timestampType(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.zip.GZIPOutputStream;
import org.projectnessie.catalog.formats.iceberg.meta.IcebergJson;
import org.projectnessie.catalog.formats.iceberg.meta.IcebergSnapshot;
import org.projectnessie.catalog.formats.iceberg.meta.IcebergSortOrder;
import org.projectnessie.catalog.formats.iceberg.meta.IcebergTableMetadata;

public class IcebergGenerateFixtures {
Expand Down Expand Up @@ -94,6 +96,12 @@ public static String generateSimpleMetadata(ObjectWriter writer, int icebergSpec

public static String generateMetadataWithManifestList(String basePath, ObjectWriter writer)
throws Exception {
return generateMetadataWithManifestList(basePath, writer, m -> {});
}

public static String generateMetadataWithManifestList(
String basePath, ObjectWriter writer, Consumer<IcebergTableMetadata> metadataConsumer)
throws Exception {
IcebergSchemaGenerator schemaGenerator =
IcebergSchemaGenerator.spec().numColumns(10).numPartitionColumns(2).generate();

Expand All @@ -109,6 +117,7 @@ public void close() throws IOException {
UUID commitId = randomUUID();
long snapshotId = 1;
long sequenceNumber = 1;
long timestamp = 1715175169320L;
IcebergManifestFileGenerator manifestFileGenerator =
IcebergManifestFileGenerator.builder()
.addDataFiles(3)
Expand All @@ -133,7 +142,7 @@ public void close() throws IOException {
IcebergSnapshot snapshotWithManifestList =
IcebergSnapshot.builder()
.snapshotId(snapshotId)
.timestampMs(System.currentTimeMillis())
.timestampMs(timestamp)
.schemaId(schemaGenerator.getIcebergSchema().schemaId())
.sequenceNumber(sequenceNumber)
.manifestList(manifestList)
Expand All @@ -142,12 +151,17 @@ public void close() throws IOException {
IcebergTableMetadata icebergMetadataWithManifestList =
IcebergTableMetadata.builder()
.from(tableMetadataSimple().formatVersion(2).build())
.lastUpdatedMs(timestamp)
.schemas(singletonList(schemaGenerator.getIcebergSchema()))
.partitionSpecs(singletonList(schemaGenerator.getIcebergPartitionSpec()))
.sortOrders(singletonList(IcebergSortOrder.UNSORTED_ORDER))
.currentSnapshotId(snapshotId)
.defaultSpecId(schemaGenerator.getIcebergPartitionSpec().specId())
.defaultSortOrderId(IcebergSortOrder.UNSORTED_ORDER.orderId())
.lastSequenceNumber(1L)
.snapshots(singletonList(snapshotWithManifestList))
.build();
metadataConsumer.accept(icebergMetadataWithManifestList);
return writer.write(
URI.create("table-metadata-with-manifest-list/table-metadata-with-manifest-list.json"),
IcebergJson.objectMapper()
Expand Down
38 changes: 38 additions & 0 deletions cli/cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ extra["maven.name"] = "Nessie - CLI"

configurations.all { exclude(group = "org.projectnessie.nessie", module = "nessie-model") }

val versionIceberg = libs.versions.iceberg.get()

val nessieQuarkusServer by configurations.creating

dependencies {
implementation(project(":nessie-model-quarkus"))
implementation(project(":nessie-client"))
Expand All @@ -37,6 +41,10 @@ dependencies {
implementation(libs.jline)
implementation(libs.picocli)

implementation(platform("org.apache.iceberg:iceberg-bom:$versionIceberg"))
implementation("org.apache.iceberg:iceberg-core")
runtimeOnly(libs.hadoop.common) { isTransitive = false }

compileOnly(libs.immutables.value.annotations)
annotationProcessor(libs.immutables.value.processor)

Expand All @@ -56,12 +64,29 @@ dependencies {

testFixturesApi(platform(libs.junit.bom))
testFixturesApi(libs.bundles.junit.testing)
testFixturesImplementation(project(":nessie-client"))
testFixturesImplementation(project(":nessie-cli-grammar"))
testFixturesImplementation(libs.jline)

testImplementation(project(":nessie-jaxrs-testextension"))

testImplementation(project(":nessie-versioned-storage-inmemory-tests"))

testCompileOnly(libs.immutables.value.annotations)

intTestImplementation(project(":nessie-object-storage-mock"))
intTestImplementation(project(":nessie-catalog-format-iceberg"))
intTestImplementation(project(":nessie-catalog-format-iceberg-fixturegen"))
intTestImplementation(project(":nessie-catalog-files-api"))
intTestImplementation(project(":nessie-catalog-files-impl"))
intTestImplementation(libs.nessie.runner.common)
intTestImplementation(platform(libs.awssdk.bom))
intTestImplementation("software.amazon.awssdk:s3")
intTestImplementation("software.amazon.awssdk:apache-client") {
exclude("commons-logging", "commons-logging")
}

nessieQuarkusServer(project(":nessie-quarkus", "quarkusRunner"))
}

tasks.withType<ProcessResources>().configureEach {
Expand All @@ -81,3 +106,16 @@ if (Os.isFamily(Os.FAMILY_WINDOWS)) {
if (Os.isFamily(Os.FAMILY_MAC) && System.getenv("CI") != null) {
tasks.named<Test>("intTest").configure { this.enabled = false }
}

tasks.named<Test>("intTest").configure {
// Spark keeps a lot of stuff around in the JVM, breaking tests against different Iceberg
// catalogs, so give every test class its own JVM
forkEvery = 1
inputs.files(nessieQuarkusServer)
val execJarProvider =
configurations.named("nessieQuarkusServer").map { c ->
val file = c.fileCollection(*c.dependencies.toTypedArray()).files.first()
listOf("-Dnessie.exec-jar=${file.absolutePath}")
}
jvmArgumentProviders.add(CommandLineArgumentProvider { execJarProvider.get() })
}
Loading

0 comments on commit 49cf7f7

Please sign in to comment.