11package 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 .* ;
55import com .fasterxml .jackson .databind .ObjectMapper ;
66import com .fasterxml .jackson .dataformat .yaml .YAMLFactory ;
77import java .io .IOException ;
88import java .nio .ByteBuffer ;
99import java .time .Instant ;
1010import java .time .ZoneId ;
1111import java .time .format .DateTimeFormatter ;
12+ import java .util .ArrayList ;
1213import java .util .List ;
1314import java .util .Map ;
14- import java .util .stream .Collectors ;
1515import org .apache .iceberg .*;
1616import org .apache .iceberg .catalog .Namespace ;
1717import org .apache .iceberg .catalog .TableIdentifier ;
@@ -24,12 +24,10 @@ public final class Describe {
2424
2525 private Describe () {}
2626
27- // TODO: refactor: the use of StringBuilder below is absolutely criminal
2827 public static void run (RESTCatalog catalog , String target , boolean json ) throws IOException {
2928 String targetNamespace = null ;
3029 String targetTable = null ;
3130 if (target != null && !target .isEmpty ()) {
32- // TODO: support catalog.ns.table
3331 var s = target .split ("[.]" , 2 );
3432 switch (s .length ) {
3533 case 2 :
@@ -41,8 +39,8 @@ public static void run(RESTCatalog catalog, String target, boolean json) throws
4139 break ;
4240 }
4341 }
44- // FIXME: there is no need to list nss/tables when target is given
45- var sb = new StringBuilder ();
42+
43+ List < TableMetadata > tablesMetadata = new ArrayList <> ();
4644 List <Namespace > namespaces = catalog .listNamespaces ();
4745 for (Namespace namespace : namespaces ) {
4846 if (targetNamespace != null && !targetNamespace .equals (namespace .toString ())) {
@@ -53,71 +51,55 @@ public static void run(RESTCatalog catalog, String target, boolean json) throws
5351 if (targetTable != null && !targetTable .equals (tableId .name ())) {
5452 continue ;
5553 }
56- sb .append ("---\n " );
57- sb .append ("kind: Table\n " );
58- sb .append ("metadata:\n " );
59- sb .append ("\t id: " + tableId + "\n " );
6054 Table table = catalog .loadTable (tableId );
61- sb .append ("data:\n " );
62- sb .append ("\t schema_raw: |-\n " + prefixEachLine (table .schema ().toString (), "\t \t " ) + "\n " );
63- sb .append (
64- "\t partition_spec_raw: |-\n " + prefixEachLine (table .spec ().toString (), "\t \t " ) + "\n " );
65- sb .append (
66- "\t sort_order_raw: |-\n " + prefixEachLine (table .sortOrder ().toString (), "\t \t " ) + "\n " );
67- sb .append ("\t properties: \n " );
68- for (var property : table .properties ().entrySet ()) {
69- var v = property .getValue ();
70- if (v .contains ("\n " )) {
71- sb .append ("\t \t " + property .getKey () + ": |-\n " + prefixEachLine (v , "\t \t \t " ) + "\n " );
72- } else {
73- sb .append ("\t \t " + property .getKey () + ": \" " + v + "\" \n " );
74- }
75- }
76- sb .append ("\t location: " + table .location () + "\n " );
77- sb .append ("\t current_snapshot: \n " );
7855 Snapshot snapshot = table .currentSnapshot ();
56+
57+ SnapshotInfo snapshotInfo = null ;
7958 if (snapshot != null ) {
80- sb .append ("\t \t sequence_number: " + snapshot .sequenceNumber () + "\n " );
81- sb .append ("\t \t id: " + snapshot .snapshotId () + "\n " );
82- sb .append ("\t \t parent_id: " + snapshot .parentId () + "\n " );
83- sb .append ("\t \t timestamp: " + snapshot .timestampMillis () + "\n " );
84- sb .append (
85- "\t \t timestamp_iso: \" "
86- + Instant .ofEpochMilli (snapshot .timestampMillis ()).toString ()
87- + "\" \n " );
88- sb .append (
89- "\t \t timestamp_iso_local: \" "
90- + 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 ())
9167 .atZone (ZoneId .systemDefault ())
92- .format (DateTimeFormatter .ISO_OFFSET_DATE_TIME )
93- + "\" \n " );
94- sb .append ("\t \t operation: " + snapshot .operation () + "\n " );
95- sb .append ("\t \t summary:\n " );
96- for (var property : snapshot .summary ().entrySet ()) {
97- sb .append ("\t \t \t " + property .getKey () + ": \" " + property .getValue () + "\" \n " );
98- }
99- sb .append ("\t \t location: " + snapshot .manifestListLocation () + "\n " );
68+ .format (DateTimeFormatter .ISO_OFFSET_DATE_TIME ),
69+ snapshot .operation (),
70+ snapshot .summary (),
71+ snapshot .manifestListLocation ());
10072 }
10173
102- printTableMetrics (table , sb );
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 ));
10387 }
10488 }
105- String r = sb .toString ().replace ("\t " , " " );
106- if (json ) {
107- r = convertYamlToJson (r );
108- }
109- 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 );
11093 }
11194
112- 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 <>();
11397 TableScan scan = table .newScan ().includeColumnStats ();
11498 CloseableIterable <FileScanTask > tasks = scan .planFiles ();
11599
116100 for (FileScanTask task : tasks ) {
117101 DataFile dataFile = task .file ();
118- buffer .append ("\t metrics:\n " );
119- buffer .append ("\t \t file: " + dataFile .path () + "\n " );
120- buffer .append ("\t \t record_count: " + dataFile .recordCount () + "\n " );
102+ List <ColumnMetrics > columnMetrics = new ArrayList <>();
121103
122104 Map <Integer , Long > valueCounts = dataFile .valueCounts ();
123105 Map <Integer , Long > nullCounts = dataFile .nullValueCounts ();
@@ -128,52 +110,36 @@ private static void printTableMetrics(Table table, StringBuilder buffer) throws
128110 continue ;
129111 }
130112
131- buffer .append ("\t \t columns:\n " );
132113 for (Types .NestedField field : table .schema ().columns ()) {
133114 int id = field .fieldId ();
134- buffer .append ("\t \t \t " + field .name () + ":\n " );
135- if (valueCounts != null ) {
136- buffer .append ("\t \t \t \t value_count: " + valueCounts .get (id ) + "\n " );
137- }
138- if (nullCounts != null ) {
139- buffer .append ("\t \t \t \t null_count: " + nullCounts .get (id ) + "\n " );
140- }
115+ String lowerBound = null ;
116+ String upperBound = null ;
117+
141118 if (lowerBounds != null ) {
142119 ByteBuffer lower = lowerBounds .get (id );
143- String lowerStr =
144- lower != null ? Conversions .fromByteBuffer (field .type (), lower ).toString () : "null" ;
145- buffer .append ("\t \t \t \t lower_bound: " + lowerStr + "\n " );
120+ lowerBound =
121+ lower != null ? Conversions .fromByteBuffer (field .type (), lower ).toString () : null ;
146122 }
147123 if (upperBounds != null ) {
148124 ByteBuffer upper = upperBounds .get (id );
149- String upperStr =
150- upper != null ? Conversions .fromByteBuffer (field .type (), upper ).toString () : "null" ;
151- buffer .append ("\t \t \t \t upper_bound: " + upperStr + "\n " );
125+ upperBound =
126+ upper != null ? Conversions .fromByteBuffer (field .type (), upper ).toString () : null ;
152127 }
153- }
154- }
155-
156- tasks .close ();
157- }
158128
159- private static String convertYamlToJson (String yaml ) throws IOException {
160- YAMLFactory yamlFactory = new YAMLFactory ();
161- ObjectMapper yamlReader = new ObjectMapper (yamlFactory );
162- ObjectMapper jsonWriter = new ObjectMapper ();
163- StringBuilder result = new StringBuilder ();
164- try (JsonParser parser = yamlFactory .createParser (yaml )) {
165- while (!parser .isClosed ()) {
166- JsonNode node = yamlReader .readTree (parser );
167- if (node != null ) {
168- String json = jsonWriter .writeValueAsString (node );
169- result .append (json ).append ("\n " );
170- }
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 ));
171136 }
137+
138+ metricsList .add (
139+ new MetricsInfo (dataFile .path ().toString (), dataFile .recordCount (), columnMetrics ));
172140 }
173- return result .toString ().trim ();
174- }
175141
176- private static String prefixEachLine ( String v , String prefix ) {
177- return v . lines (). map ( line -> prefix + line ). collect ( Collectors . joining ( " \n " )) ;
142+ tasks . close ();
143+ return metricsList ;
178144 }
179145}
0 commit comments