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