Skip to content

Commit 04b232c

Browse files
committed
Use DTOs for JSON
1 parent 94fbb69 commit 04b232c

File tree

3 files changed

+64
-141
lines changed

3 files changed

+64
-141
lines changed

plugin/trino-hive/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@
6666
<artifactId>configuration</artifactId>
6767
</dependency>
6868

69+
<dependency>
70+
<groupId>io.airlift</groupId>
71+
<artifactId>http-client</artifactId>
72+
</dependency>
73+
6974
<dependency>
7075
<groupId>io.airlift</groupId>
7176
<artifactId>json</artifactId>

plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/polaris/PolarisHiveMetastore.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,10 @@
4444
import io.trino.spi.type.Type;
4545
import org.apache.iceberg.Schema;
4646
import org.apache.iceberg.Transaction;
47-
import org.apache.iceberg.catalog.Namespace;
47+
import org.apache.iceberg.catalog.SessionCatalog;
4848
import org.apache.iceberg.catalog.TableIdentifier;
4949
import org.apache.iceberg.exceptions.NoSuchTableException;
5050
import org.apache.iceberg.rest.RESTSessionCatalog;
51-
import org.apache.iceberg.catalog.SessionCatalog;
5251
import org.apache.iceberg.types.Types;
5352

5453
import java.util.Collection;
@@ -59,8 +58,6 @@
5958
import java.util.Set;
6059
import java.util.UUID;
6160
import java.util.concurrent.atomic.AtomicInteger;
62-
import java.util.function.Function;
63-
import java.util.stream.Collectors;
6461

6562
import static com.google.common.collect.ImmutableList.toImmutableList;
6663
import static io.trino.plugin.hive.HiveErrorCode.HIVE_METASTORE_ERROR;
@@ -752,7 +749,7 @@ private Table convertGenericToHiveTable(String databaseName, PolarisGenericTable
752749

753750
// Set storage information
754751
genericTable.getBaseLocation().ifPresent(location ->
755-
tableBuilder.withStorage(storage -> storage
752+
tableBuilder.withStorage(storage -> storage
756753
.setLocation(location)
757754
.setStorageFormat(storageFormat)
758755
.setSerdeParameters(ImmutableMap.of("path", location))));

plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/polaris/PolarisRestClient.java

Lines changed: 57 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
*/
1414
package io.trino.plugin.hive.metastore.polaris;
1515

16-
import com.fasterxml.jackson.databind.JsonNode;
16+
import com.fasterxml.jackson.annotation.JsonCreator;
17+
import com.fasterxml.jackson.annotation.JsonProperty;
1718
import com.fasterxml.jackson.databind.ObjectMapper;
1819
import com.google.common.collect.ImmutableList;
1920
import com.google.common.collect.ImmutableMap;
2021
import com.google.common.collect.ImmutableMultimap;
22+
import com.google.common.collect.ImmutableMultimap;
2123
import com.google.common.collect.Multimap;
2224
import com.google.inject.Inject;
2325
import io.airlift.http.client.BodyGenerator;
@@ -26,39 +28,31 @@
2628
import io.airlift.http.client.Response;
2729
import io.airlift.http.client.ResponseHandler;
2830
import io.airlift.http.client.StaticBodyGenerator;
29-
import io.airlift.json.JsonCodec;
30-
import io.airlift.log.Logger;
31-
import io.trino.hive.thrift.metastore.Table;
32-
import io.trino.metastore.TableAlreadyExistsException;
33-
import io.trino.spi.connector.SchemaNotFoundException;
3431
import io.trino.spi.connector.SchemaTableName;
3532
import io.trino.spi.connector.TableNotFoundException;
33+
import org.apache.iceberg.HasTableOperations;
34+
import org.apache.iceberg.PartitionSpec;
35+
import org.apache.iceberg.Schema;
36+
import org.apache.iceberg.TableOperations;
3637
import org.apache.iceberg.catalog.Namespace;
3738
import org.apache.iceberg.catalog.SessionCatalog;
3839
import org.apache.iceberg.catalog.TableIdentifier;
3940
import org.apache.iceberg.exceptions.NoSuchTableException;
4041
import org.apache.iceberg.exceptions.RESTException;
4142
import org.apache.iceberg.rest.RESTSessionCatalog;
4243
import org.apache.iceberg.rest.auth.OAuth2Properties;
43-
import org.apache.iceberg.HasTableOperations;
44-
import org.apache.iceberg.TableOperations;
45-
import org.apache.iceberg.Schema;
46-
import org.apache.iceberg.PartitionSpec;
4744

45+
import java.io.IOException;
4846
import java.net.URI;
47+
import java.util.ArrayList;
48+
import java.util.HashMap;
4949
import java.util.List;
5050
import java.util.Map;
5151
import java.util.Optional;
5252
import java.util.UUID;
53-
import java.util.ArrayList;
54-
import java.util.HashMap;
55-
import java.io.IOException;
5653

5754
import static com.google.common.collect.ImmutableList.toImmutableList;
58-
import static io.airlift.http.client.Request.Builder.prepareDelete;
5955
import static io.airlift.http.client.Request.Builder.prepareGet;
60-
import static io.airlift.http.client.Request.Builder.prepareHead;
61-
import static io.airlift.http.client.Request.Builder.preparePost;
6256
import static java.nio.charset.StandardCharsets.UTF_8;
6357
import static java.util.Objects.requireNonNull;
6458

@@ -189,30 +183,9 @@ public List<PolarisTableIdentifier> handle(Request request, Response response)
189183
if (response.getStatusCode() != 200) {
190184
throw new PolarisException("Failed to list generic tables: " + response.getStatusCode());
191185
}
192-
193186
try {
194-
JsonNode root = objectMapper.readTree(response.getInputStream());
195-
JsonNode identifiers = root.get("identifiers");
196-
197-
if (identifiers == null || !identifiers.isArray()) {
198-
return ImmutableList.of();
199-
}
200-
201-
ImmutableList.Builder<PolarisTableIdentifier> tables = ImmutableList.builder();
202-
for (JsonNode identifier : identifiers) {
203-
JsonNode namespaceNode = identifier.get("namespace");
204-
JsonNode nameNode = identifier.get("name");
205-
206-
if (namespaceNode != null && nameNode != null && namespaceNode.isArray()) {
207-
List<String> namespaceParts = new ArrayList<>();
208-
for (JsonNode part : namespaceNode) {
209-
namespaceParts.add(part.asText());
210-
}
211-
String namespace = String.join(".", namespaceParts);
212-
tables.add(new PolarisTableIdentifier(namespace, nameNode.asText()));
213-
}
214-
}
215-
return tables.build();
187+
ListGenericTablesResponse listResponse = objectMapper.readValue(response.getInputStream(), ListGenericTablesResponse.class);
188+
return listResponse.toPolarisTableIdentifiers();
216189
}
217190
catch (IOException e) {
218191
throw new PolarisException("Failed to parse generic tables response", e);
@@ -250,19 +223,12 @@ public PolarisGenericTable handle(Request request, Response response)
250223
if (response.getStatusCode() != 200) {
251224
throw new PolarisException("Failed to load generic table: " + response.getStatusCode());
252225
}
253-
254226
try {
255-
JsonNode root = objectMapper.readTree(response.getInputStream());
256-
JsonNode tableNode = root.get("table");
257-
258-
if (tableNode == null) {
259-
throw new PolarisException("Missing 'table' field in response");
260-
}
261-
262-
return parseGenericTable(tableNode);
227+
LoadGenericTableResponse loadResponse = objectMapper.readValue(response.getInputStream(), LoadGenericTableResponse.class);
228+
return loadResponse.getTable();
263229
}
264230
catch (IOException e) {
265-
throw new PolarisException("Failed to parse generic table response", e);
231+
throw new PolarisException("Failed to parse load generic table response", e);
266232
}
267233
}
268234
});
@@ -284,26 +250,6 @@ public void dropGenericTable(String databaseName, String tableName)
284250
// TODO: Implement REST API call
285251
}
286252

287-
/**
288-
* Parses a Generic table from JSON response
289-
*/
290-
private PolarisGenericTable parseGenericTable(JsonNode tableNode)
291-
{
292-
String name = getRequiredString(tableNode, "name");
293-
String format = getRequiredString(tableNode, "format");
294-
String baseLocation = getOptionalString(tableNode, "base-location");
295-
String doc = getOptionalString(tableNode, "doc");
296-
297-
Map<String, String> properties = new HashMap<>();
298-
JsonNode propertiesNode = tableNode.get("properties");
299-
if (propertiesNode != null && propertiesNode.isObject()) {
300-
propertiesNode.fields().forEachRemaining(entry ->
301-
properties.put(entry.getKey(), entry.getValue().asText()));
302-
}
303-
304-
return new PolarisGenericTable(name, format, baseLocation, doc, properties);
305-
}
306-
307253
// HELPER METHODS
308254

309255
/**
@@ -329,7 +275,7 @@ private PolarisTableMetadata convertIcebergTableToPolaris(org.apache.iceberg.Tab
329275
TableOperations ops = ((HasTableOperations) table).operations();
330276
String location = ops.current().location();
331277
Map<String, String> properties = ops.current().properties();
332-
278+
333279
// Convert Iceberg schema to map representation
334280
Schema icebergSchema = ops.current().schema();
335281
Map<String, Object> schemaMap = ImmutableMap.of(
@@ -342,11 +288,11 @@ private PolarisTableMetadata convertIcebergTableToPolaris(org.apache.iceberg.Tab
342288
"required", field.isRequired(),
343289
"type", field.type().toString()))
344290
.collect(toImmutableList()));
345-
291+
346292
return new PolarisTableMetadata(
347-
location,
348-
schemaMap,
349-
properties);
293+
location,
294+
schemaMap,
295+
properties);
350296
}
351297

352298
// AUTHENTICATION & HTTP UTILITIES
@@ -423,86 +369,61 @@ private URI buildUri(String path)
423369
*/
424370
private String encodeNamespace(String namespace)
425371
{
426-
return namespace.replace(".", "%1F");
372+
// TODO: Add proper URL encoding
373+
return namespace;
427374
}
428375

429-
// TODO: CONVERSION METHODS
430-
431-
private org.apache.iceberg.Schema extractSchemaFromRequest(Map<String, Object> tableRequest)
376+
private static class ListGenericTablesResponse
432377
{
433-
// Extract schema from table creation request
434-
Object schemaObj = tableRequest.get("schema");
435-
if (schemaObj == null) {
436-
throw new PolarisException("Schema not found in table request");
437-
}
438-
439-
try {
440-
// For now, return a dummy schema - actual implementation would parse the schema
441-
// from the JSON representation in the table request
442-
return new Schema();
443-
}
444-
catch (Exception e) {
445-
throw new PolarisException("Failed to parse schema from table request", e);
446-
}
447-
}
378+
private final List<TableIdentifierDto> identifiers;
448379

449-
private org.apache.iceberg.PartitionSpec extractPartitionSpecFromRequest(Map<String, Object> tableRequest)
450-
{
451-
// Extract partition spec from table creation request
452-
Object partitionSpecObj = tableRequest.get("partition-spec");
453-
if (partitionSpecObj == null) {
454-
// No partitioning specified
455-
return PartitionSpec.unpartitioned();
380+
@JsonCreator
381+
public ListGenericTablesResponse(@JsonProperty("identifiers") List<TableIdentifierDto> identifiers)
382+
{
383+
this.identifiers = identifiers != null ? ImmutableList.copyOf(identifiers) : ImmutableList.of();
456384
}
457385

458-
try {
459-
// For now, return unpartitioned - actual implementation would parse the spec
460-
return PartitionSpec.unpartitioned();
461-
}
462-
catch (Exception e) {
463-
throw new PolarisException("Failed to parse partition spec from table request", e);
386+
public List<PolarisTableIdentifier> toPolarisTableIdentifiers()
387+
{
388+
return identifiers.stream()
389+
.map(TableIdentifierDto::toPolarisTableIdentifier)
390+
.collect(toImmutableList());
464391
}
465392
}
466393

467-
private Map<String, String> extractPropertiesFromRequest(Map<String, Object> tableRequest)
394+
private static class TableIdentifierDto
468395
{
469-
// Extract properties from table creation request
470-
Object propertiesObj = tableRequest.get("properties");
471-
if (propertiesObj == null) {
472-
return ImmutableMap.of();
473-
}
396+
private final List<String> namespace;
397+
private final String name;
474398

475-
if (propertiesObj instanceof Map) {
476-
ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
477-
((Map<?, ?>) propertiesObj).forEach((key, value) -> {
478-
if (key != null && value != null) {
479-
properties.put(key.toString(), value.toString());
480-
}
481-
});
482-
return properties.build();
399+
@JsonCreator
400+
public TableIdentifierDto(
401+
@JsonProperty("namespace") List<String> namespace,
402+
@JsonProperty("name") String name)
403+
{
404+
this.namespace = requireNonNull(namespace, "namespace is null");
405+
this.name = requireNonNull(name, "name is null");
483406
}
484407

485-
throw new PolarisException("Properties must be a map");
486-
}
487-
488-
private String getRequiredString(JsonNode node, String fieldName)
489-
{
490-
JsonNode fieldNode = node.get(fieldName);
491-
if (fieldNode == null || !fieldNode.isTextual()) {
492-
throw new PolarisException("Missing or invalid " + fieldName + " field");
408+
public PolarisTableIdentifier toPolarisTableIdentifier()
409+
{
410+
return new PolarisTableIdentifier(String.join(".", namespace), name);
493411
}
494-
return fieldNode.asText();
495412
}
496413

497-
private String getOptionalString(JsonNode node, String fieldName)
414+
private static class LoadGenericTableResponse
498415
{
499-
JsonNode fieldNode = node.get(fieldName);
500-
if (fieldNode == null || fieldNode.isNull()) {
501-
return null;
416+
private final PolarisGenericTable table;
417+
418+
@JsonCreator
419+
public LoadGenericTableResponse(@JsonProperty("table") PolarisGenericTable table)
420+
{
421+
this.table = requireNonNull(table, "table is null");
502422
}
503-
if (!fieldNode.isTextual()) {
504-
throw new PolarisException("Invalid " + fieldName + " field format");
423+
424+
public PolarisGenericTable getTable()
425+
{
426+
return table;
505427
}
506-
return fieldNode.asText();
507428
}
508429
}

0 commit comments

Comments
 (0)