Skip to main content

lance_encoding/
version.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4use std::str::FromStr;
5
6use lance_arrow::DataTypeExt;
7use lance_core::datatypes::Field;
8use lance_core::deepsize::{Context, DeepSizeOf};
9use lance_core::{Error, Result};
10
11pub const LEGACY_FORMAT_VERSION: &str = "0.1";
12pub const V2_FORMAT_2_0: &str = "2.0";
13pub const V2_FORMAT_2_1: &str = "2.1";
14pub const V2_FORMAT_2_2: &str = "2.2";
15pub const V2_FORMAT_2_3: &str = "2.3";
16
17/// Lance file version
18#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, strum::EnumIter)]
19pub enum LanceFileVersion {
20    // This is a little confusing but we rely on the following facts:
21    //
22    // Any version <= Next is stable
23    // The latest version before Stable is the default version for new datasets
24    // Any version >= Next is unstable
25    //
26    // As a result, 'Stable' is not the divider between stable and unstable (Next does this)
27    // but only serves to mark the default version for new datasets.
28    //
29    /// The legacy (0.1) format
30    Legacy,
31    V2_0,
32    #[default]
33    V2_1,
34    /// The latest stable release (also the default version for new datasets)
35    Stable,
36    V2_2,
37    /// The latest unstable release
38    Next,
39    V2_3,
40}
41
42impl DeepSizeOf for LanceFileVersion {
43    fn deep_size_of_children(&self, _context: &mut Context) -> usize {
44        0
45    }
46}
47
48impl LanceFileVersion {
49    /// Convert Stable or Next to the actual version
50    pub fn resolve(&self) -> Self {
51        match self {
52            Self::Stable => Self::default(),
53            Self::Next => Self::V2_3,
54            _ => *self,
55        }
56    }
57
58    pub fn is_unstable(&self) -> bool {
59        self >= &Self::Next
60    }
61
62    pub fn iter_non_legacy() -> impl Iterator<Item = Self> {
63        use strum::IntoEnumIterator;
64
65        Self::iter().filter(|&v| v != Self::Stable && v != Self::Next && v != Self::Legacy)
66    }
67
68    pub fn support_add_sub_column(&self) -> bool {
69        self > &Self::V2_1
70    }
71
72    pub fn support_remove_sub_column(&self, field: &Field) -> bool {
73        if self <= &Self::V2_1 {
74            field.data_type().is_struct()
75        } else {
76            field.data_type().is_nested()
77        }
78    }
79}
80
81impl std::fmt::Display for LanceFileVersion {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(
84            f,
85            "{}",
86            match self {
87                Self::Legacy => LEGACY_FORMAT_VERSION,
88                Self::V2_0 => V2_FORMAT_2_0,
89                Self::V2_1 => V2_FORMAT_2_1,
90                Self::V2_2 => V2_FORMAT_2_2,
91                Self::V2_3 => V2_FORMAT_2_3,
92                Self::Stable => "stable",
93                Self::Next => "next",
94            }
95        )
96    }
97}
98
99impl FromStr for LanceFileVersion {
100    type Err = Error;
101
102    fn from_str(value: &str) -> Result<Self> {
103        match value.to_lowercase().as_str() {
104            LEGACY_FORMAT_VERSION => Ok(Self::Legacy),
105            V2_FORMAT_2_0 => Ok(Self::V2_0),
106            V2_FORMAT_2_1 => Ok(Self::V2_1),
107            V2_FORMAT_2_2 => Ok(Self::V2_2),
108            V2_FORMAT_2_3 => Ok(Self::V2_3),
109            "stable" => Ok(Self::Stable),
110            "legacy" => Ok(Self::Legacy),
111            "next" => Ok(Self::Next),
112            // Version 0.3 is an alias of 2.0
113            "0.3" => Ok(Self::V2_0),
114            _ => Err(Error::invalid_input_source(
115                format!("Unknown Lance storage version: {}", value).into(),
116            )),
117        }
118    }
119}