Skip to content

Commit 85940bb

Browse files
authored
Merge pull request #21 from Altinity/replace_stringbuilder_describe
ice: Use classes to create describe metadata instead of stringBuilder.
2 parents fdb7006 + 3743ed8 commit 85940bb

File tree

3 files changed

+102
-102
lines changed

3 files changed

+102
-102
lines changed

ice/src/main/java/com/altinity/ice/Main.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,10 @@ void describe(
6969
@CommandLine.Option(
7070
names = {"--json"},
7171
description = "Output JSON instead of YAML")
72-
boolean json,
73-
@CommandLine.Option(
74-
names = {"--include-metrics"},
75-
description = "Include table metrics in the output")
76-
boolean includeMetrics)
72+
boolean json)
7773
throws IOException {
7874
try (RESTCatalog catalog = loadCatalog(this.configFile)) {
79-
Describe.run(catalog, target, json, includeMetrics);
75+
Describe.run(catalog, target, json);
8076
}
8177
}
8278

Lines changed: 59 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package com.altinity.ice.internal.cmd;
22

3-
import com.fasterxml.jackson.core.JsonParser;
4-
import com.fasterxml.jackson.databind.JsonNode;
3+
import com.altinity.ice.internal.model.TableMetadata;
4+
import com.altinity.ice.internal.model.TableMetadata.*;
55
import com.fasterxml.jackson.databind.ObjectMapper;
66
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
77
import java.io.IOException;
88
import java.nio.ByteBuffer;
99
import java.time.Instant;
1010
import java.time.ZoneId;
1111
import java.time.format.DateTimeFormatter;
12+
import java.util.ArrayList;
1213
import java.util.List;
1314
import java.util.Map;
14-
import java.util.stream.Collectors;
1515
import org.apache.iceberg.*;
1616
import org.apache.iceberg.catalog.Namespace;
1717
import org.apache.iceberg.catalog.TableIdentifier;
@@ -24,13 +24,10 @@ public final class Describe {
2424

2525
private Describe() {}
2626

27-
// TODO: refactor: the use of StringBuilder below is absolutely criminal
28-
public static void run(RESTCatalog catalog, String target, boolean json, boolean includeMetrics)
29-
throws IOException {
27+
public static void run(RESTCatalog catalog, String target, boolean json) throws IOException {
3028
String targetNamespace = null;
3129
String targetTable = null;
3230
if (target != null && !target.isEmpty()) {
33-
// TODO: support catalog.ns.table
3431
var s = target.split("[.]", 2);
3532
switch (s.length) {
3633
case 2:
@@ -42,8 +39,8 @@ public static void run(RESTCatalog catalog, String target, boolean json, boolean
4239
break;
4340
}
4441
}
45-
// FIXME: there is no need to list nss/tables when target is given
46-
var sb = new StringBuilder();
42+
43+
List<TableMetadata> tablesMetadata = new ArrayList<>();
4744
List<Namespace> namespaces = catalog.listNamespaces();
4845
for (Namespace namespace : namespaces) {
4946
if (targetNamespace != null && !targetNamespace.equals(namespace.toString())) {
@@ -54,73 +51,55 @@ public static void run(RESTCatalog catalog, String target, boolean json, boolean
5451
if (targetTable != null && !targetTable.equals(tableId.name())) {
5552
continue;
5653
}
57-
sb.append("---\n");
58-
sb.append("kind: Table\n");
59-
sb.append("metadata:\n");
60-
sb.append("\tid: " + tableId + "\n");
6154
Table table = catalog.loadTable(tableId);
62-
sb.append("data:\n");
63-
sb.append("\tschema_raw: |-\n" + prefixEachLine(table.schema().toString(), "\t\t") + "\n");
64-
sb.append(
65-
"\tpartition_spec_raw: |-\n" + prefixEachLine(table.spec().toString(), "\t\t") + "\n");
66-
sb.append(
67-
"\tsort_order_raw: |-\n" + prefixEachLine(table.sortOrder().toString(), "\t\t") + "\n");
68-
sb.append("\tproperties: \n");
69-
for (var property : table.properties().entrySet()) {
70-
var v = property.getValue();
71-
if (v.contains("\n")) {
72-
sb.append("\t\t" + property.getKey() + ": |-\n" + prefixEachLine(v, "\t\t\t") + "\n");
73-
} else {
74-
sb.append("\t\t" + property.getKey() + ": \"" + v + "\"\n");
75-
}
76-
}
77-
sb.append("\tlocation: " + table.location() + "\n");
78-
sb.append("\tcurrent_snapshot: \n");
7955
Snapshot snapshot = table.currentSnapshot();
56+
57+
SnapshotInfo snapshotInfo = null;
8058
if (snapshot != null) {
81-
sb.append("\t\tsequence_number: " + snapshot.sequenceNumber() + "\n");
82-
sb.append("\t\tid: " + snapshot.snapshotId() + "\n");
83-
sb.append("\t\tparent_id: " + snapshot.parentId() + "\n");
84-
sb.append("\t\ttimestamp: " + snapshot.timestampMillis() + "\n");
85-
sb.append(
86-
"\t\ttimestamp_iso: \""
87-
+ Instant.ofEpochMilli(snapshot.timestampMillis()).toString()
88-
+ "\"\n");
89-
sb.append(
90-
"\t\ttimestamp_iso_local: \""
91-
+ Instant.ofEpochMilli(snapshot.timestampMillis())
59+
snapshotInfo =
60+
new SnapshotInfo(
61+
snapshot.sequenceNumber(),
62+
snapshot.snapshotId(),
63+
snapshot.parentId(),
64+
snapshot.timestampMillis(),
65+
Instant.ofEpochMilli(snapshot.timestampMillis()).toString(),
66+
Instant.ofEpochMilli(snapshot.timestampMillis())
9267
.atZone(ZoneId.systemDefault())
93-
.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
94-
+ "\"\n");
95-
sb.append("\t\toperation: " + snapshot.operation() + "\n");
96-
sb.append("\t\tsummary:\n");
97-
for (var property : snapshot.summary().entrySet()) {
98-
sb.append("\t\t\t" + property.getKey() + ": \"" + property.getValue() + "\"\n");
99-
}
100-
sb.append("\t\tlocation: " + snapshot.manifestListLocation() + "\n");
68+
.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
69+
snapshot.operation(),
70+
snapshot.summary(),
71+
snapshot.manifestListLocation());
10172
}
10273

103-
if (includeMetrics) {
104-
printTableMetrics(table, sb);
105-
}
74+
List<MetricsInfo> metrics = getTableMetrics(table);
75+
76+
TableData tableData =
77+
new TableData(
78+
table.schema().toString(),
79+
table.spec().toString(),
80+
table.sortOrder().toString(),
81+
table.properties(),
82+
table.location(),
83+
snapshotInfo,
84+
metrics);
85+
86+
tablesMetadata.add(new TableMetadata("Table", new Metadata(tableId.toString()), tableData));
10687
}
10788
}
108-
String r = sb.toString().replace("\t", " ");
109-
if (json) {
110-
r = convertYamlToJson(r);
111-
}
112-
System.out.println(r);
89+
90+
ObjectMapper mapper = json ? new ObjectMapper() : new ObjectMapper(new YAMLFactory());
91+
String output = mapper.writeValueAsString(tablesMetadata);
92+
System.out.println(output);
11393
}
11494

115-
private static void printTableMetrics(Table table, StringBuilder buffer) throws IOException {
95+
private static List<MetricsInfo> getTableMetrics(Table table) throws IOException {
96+
List<MetricsInfo> metricsList = new ArrayList<>();
11697
TableScan scan = table.newScan().includeColumnStats();
11798
CloseableIterable<FileScanTask> tasks = scan.planFiles();
11899

119100
for (FileScanTask task : tasks) {
120101
DataFile dataFile = task.file();
121-
buffer.append("\tmetrics:\n");
122-
buffer.append("\t\tfile: " + dataFile.path() + "\n");
123-
buffer.append("\t\trecord_count: " + dataFile.recordCount() + "\n");
102+
List<ColumnMetrics> columnMetrics = new ArrayList<>();
124103

125104
Map<Integer, Long> valueCounts = dataFile.valueCounts();
126105
Map<Integer, Long> nullCounts = dataFile.nullValueCounts();
@@ -131,52 +110,36 @@ private static void printTableMetrics(Table table, StringBuilder buffer) throws
131110
continue;
132111
}
133112

134-
buffer.append("\t\tcolumns:\n");
135113
for (Types.NestedField field : table.schema().columns()) {
136114
int id = field.fieldId();
137-
buffer.append("\t\t\t" + field.name() + ":\n");
138-
if (valueCounts != null) {
139-
buffer.append("\t\t\t\tvalue_count: " + valueCounts.get(id) + "\n");
140-
}
141-
if (nullCounts != null) {
142-
buffer.append("\t\t\t\tnull_count: " + nullCounts.get(id) + "\n");
143-
}
115+
String lowerBound = null;
116+
String upperBound = null;
117+
144118
if (lowerBounds != null) {
145119
ByteBuffer lower = lowerBounds.get(id);
146-
String lowerStr =
147-
lower != null ? Conversions.fromByteBuffer(field.type(), lower).toString() : "null";
148-
buffer.append("\t\t\t\tlower_bound: " + lowerStr + "\n");
120+
lowerBound =
121+
lower != null ? Conversions.fromByteBuffer(field.type(), lower).toString() : null;
149122
}
150123
if (upperBounds != null) {
151124
ByteBuffer upper = upperBounds.get(id);
152-
String upperStr =
153-
upper != null ? Conversions.fromByteBuffer(field.type(), upper).toString() : "null";
154-
buffer.append("\t\t\t\tupper_bound: " + upperStr + "\n");
125+
upperBound =
126+
upper != null ? Conversions.fromByteBuffer(field.type(), upper).toString() : null;
155127
}
156-
}
157-
}
158-
159-
tasks.close();
160-
}
161128

162-
private static String convertYamlToJson(String yaml) throws IOException {
163-
YAMLFactory yamlFactory = new YAMLFactory();
164-
ObjectMapper yamlReader = new ObjectMapper(yamlFactory);
165-
ObjectMapper jsonWriter = new ObjectMapper();
166-
StringBuilder result = new StringBuilder();
167-
try (JsonParser parser = yamlFactory.createParser(yaml)) {
168-
while (!parser.isClosed()) {
169-
JsonNode node = yamlReader.readTree(parser);
170-
if (node != null) {
171-
String json = jsonWriter.writeValueAsString(node);
172-
result.append(json).append("\n");
173-
}
129+
columnMetrics.add(
130+
new ColumnMetrics(
131+
field.name(),
132+
valueCounts != null ? valueCounts.get(id) : null,
133+
nullCounts != null ? nullCounts.get(id) : null,
134+
lowerBound,
135+
upperBound));
174136
}
137+
138+
metricsList.add(
139+
new MetricsInfo(dataFile.path().toString(), dataFile.recordCount(), columnMetrics));
175140
}
176-
return result.toString().trim();
177-
}
178141

179-
private static String prefixEachLine(String v, String prefix) {
180-
return v.lines().map(line -> prefix + line).collect(Collectors.joining("\n"));
142+
tasks.close();
143+
return metricsList;
181144
}
182145
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.altinity.ice.internal.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
@JsonInclude(JsonInclude.Include.NON_NULL)
8+
public record TableMetadata(String kind, Metadata metadata, TableData data) {
9+
public TableMetadata {
10+
if (kind == null) {
11+
kind = "Table";
12+
}
13+
}
14+
15+
public record Metadata(String id) {}
16+
17+
public record TableData(
18+
String schema_raw,
19+
String partition_spec_raw,
20+
String sort_order_raw,
21+
Map<String, String> properties,
22+
String location,
23+
SnapshotInfo current_snapshot,
24+
List<MetricsInfo> metrics) {}
25+
26+
public record SnapshotInfo(
27+
long sequence_number,
28+
long id,
29+
Long parent_id,
30+
long timestamp,
31+
String timestamp_iso,
32+
String timestamp_iso_local,
33+
String operation,
34+
Map<String, String> summary,
35+
String location) {}
36+
37+
public record MetricsInfo(String file, long record_count, List<ColumnMetrics> columns) {}
38+
39+
public record ColumnMetrics(
40+
String name, Long value_count, Long null_count, String lower_bound, String upper_bound) {}
41+
}

0 commit comments

Comments
 (0)