@@ -35,9 +35,46 @@ use crate::Result;
3535/// - <https://github.com/apache/iceberg/blob/ac865e334e143dfd9e33011d8cf710b46d91f1e5/core/src/main/java/org/apache/iceberg/MetadataTableType.java#L23-L39>
3636/// - <https://iceberg.apache.org/docs/latest/spark-queries/#querying-with-sql>
3737/// - <https://py.iceberg.apache.org/api/#inspecting-tables>
38- #[ derive( Debug ) ]
38+ #[ derive( Debug , Clone ) ]
3939pub struct MetadataTable ( Table ) ;
4040
41+ /// Metadata table type.
42+ #[ derive( Debug , Clone , strum:: EnumIter ) ]
43+ pub enum MetadataTableType {
44+ /// [`SnapshotsTable`]
45+ Snapshots ,
46+ /// [`ManifestsTable`]
47+ Manifests ,
48+ }
49+
50+ impl MetadataTableType {
51+ /// Returns the string representation of the metadata table type.
52+ pub fn as_str ( & self ) -> & str {
53+ match self {
54+ MetadataTableType :: Snapshots => "snapshots" ,
55+ MetadataTableType :: Manifests => "manifests" ,
56+ }
57+ }
58+
59+ /// Returns all the metadata table types.
60+ pub fn all_types ( ) -> impl Iterator < Item = Self > {
61+ use strum:: IntoEnumIterator ;
62+ Self :: iter ( )
63+ }
64+ }
65+
66+ impl TryFrom < & str > for MetadataTableType {
67+ type Error = String ;
68+
69+ fn try_from ( value : & str ) -> std:: result:: Result < Self , String > {
70+ match value {
71+ "snapshots" => Ok ( Self :: Snapshots ) ,
72+ "manifests" => Ok ( Self :: Manifests ) ,
73+ _ => Err ( format ! ( "invalid metadata table type: {value}" ) ) ,
74+ }
75+ }
76+ }
77+
4178impl MetadataTable {
4279 /// Creates a new metadata scan.
4380 pub ( super ) fn new ( table : Table ) -> Self {
@@ -257,58 +294,10 @@ impl<'a> ManifestsTable<'a> {
257294
258295#[ cfg( test) ]
259296mod tests {
260- use expect_test:: { expect, Expect } ;
261- use itertools:: Itertools ;
297+ use expect_test:: expect;
262298
263- use super :: * ;
264299 use crate :: scan:: tests:: TableTestFixture ;
265-
266- /// Snapshot testing to check the resulting record batch.
267- ///
268- /// - `expected_schema/data`: put `expect![[""]]` as a placeholder,
269- /// and then run test with `UPDATE_EXPECT=1 cargo test` to automatically update the result,
270- /// or use rust-analyzer (see [video](https://github.com/rust-analyzer/expect-test)).
271- /// Check the doc of [`expect_test`] for more details.
272- /// - `ignore_check_columns`: Some columns are not stable, so we can skip them.
273- /// - `sort_column`: The order of the data might be non-deterministic, so we can sort it by a column.
274- fn check_record_batch (
275- record_batch : RecordBatch ,
276- expected_schema : Expect ,
277- expected_data : Expect ,
278- ignore_check_columns : & [ & str ] ,
279- sort_column : Option < & str > ,
280- ) {
281- let mut columns = record_batch. columns ( ) . to_vec ( ) ;
282- if let Some ( sort_column) = sort_column {
283- let column = record_batch. column_by_name ( sort_column) . unwrap ( ) ;
284- let indices = arrow_ord:: sort:: sort_to_indices ( column, None , None ) . unwrap ( ) ;
285- columns = columns
286- . iter ( )
287- . map ( |column| arrow_select:: take:: take ( column. as_ref ( ) , & indices, None ) . unwrap ( ) )
288- . collect_vec ( ) ;
289- }
290-
291- expected_schema. assert_eq ( & format ! (
292- "{}" ,
293- record_batch. schema( ) . fields( ) . iter( ) . format( ",\n " )
294- ) ) ;
295- expected_data. assert_eq ( & format ! (
296- "{}" ,
297- record_batch
298- . schema( )
299- . fields( )
300- . iter( )
301- . zip_eq( columns)
302- . map( |( field, column) | {
303- if ignore_check_columns. contains( & field. name( ) . as_str( ) ) {
304- format!( "{}: (skipped)" , field. name( ) )
305- } else {
306- format!( "{}: {:?}" , field. name( ) , column)
307- }
308- } )
309- . format( ",\n " )
310- ) ) ;
311- }
300+ use crate :: test_utils:: check_record_batch;
312301
313302 #[ test]
314303 fn test_snapshots_table ( ) {
0 commit comments