Skip to content

Centralize table property default values in TableProperties #1821

@DrakeLin

Description

@DrakeLin

Summary

Table property defaults should be centralized by adding accessor methods on TableProperties that return resolved values with their protocol-defined defaults.

Motivation

Currently, some table property defaults are applied at access sites rather than being centralized in TableProperties. For example:

// in column_filter.rs — consumer must know to call unwrap_or_default()
let n_cols = props.data_skipping_num_indexed_cols.unwrap_or_default();

// in table_configuration.rs — consumer applies default directly
self.table_properties().row_tracking_suspended.unwrap_or(false)

As the codebase grows and more consumers access these properties, centralizing defaults in accessor methods prevents inconsistencies and makes the protocol-defined defaults discoverable in one place.

Recommended Pattern

Add accessor methods on TableProperties as the unified public API for getting resolved values. Consumers always call an accessor and don't need to know the default themselves.

There are two possible approaches for how the accessor resolves the default. We should investigate and pick one to use consistently:

Approach 1: Inline unwrap_or in the accessor

The default value is specified directly in the accessor method:

impl TableProperties {
    pub fn should_write_stats_as_json(&self) -> bool {
        self.checkpoint_write_stats_as_json.unwrap_or(true)
    }
    pub fn data_skipping_num_indexed_cols(&self) -> DataSkippingNumIndexedCols {
        self.data_skipping_num_indexed_cols
            .unwrap_or(DataSkippingNumIndexedCols::NumColumns(DEFAULT_NUM_INDEXED_COLS))
    }
}

Pros: Simple, explicit, all defaults are visible in one place (impl TableProperties). Works uniformly for all types.
Cons: Default value is not accessible independently from the accessor.

Approach 2: impl Default on custom types + unwrap_or_default

Custom types implement Default and the accessor calls unwrap_or_default():

impl Default for DataSkippingNumIndexedCols {
    fn default() -> Self { Self::NumColumns(32) }
}

impl TableProperties {
    pub fn data_skipping_num_indexed_cols(&self) -> DataSkippingNumIndexedCols {
        self.data_skipping_num_indexed_cols.unwrap_or_default()
    }
}

Pros: Default is colocated with the type definition. unwrap_or_default() is idiomatic Rust.
Cons: Only works for custom types (not bool, since bool::default() is false and some properties default to true), so you end up with two styles anyway.

Prior Art

Scope

  1. Decide which approach to use consistently.
  2. Audit all remaining unwrap_or / unwrap_or_default calls on TableProperties fields across the codebase.
  3. Migrate them to centralized accessor methods on TableProperties.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions