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};
9use snafu::location;
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";
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    /// The latest unstable release
36    Next,
37    V2_2,
38}
39
40impl LanceFileVersion {
41    /// Convert Stable or Next to the actual version
42    pub fn resolve(&self) -> Self {
43        match self {
44            Self::Stable => Self::V2_0,
45            Self::Next => Self::V2_1,
46            _ => *self,
47        }
48    }
49
50    pub fn is_unstable(&self) -> bool {
51        self >= &Self::Next
52    }
53
54    pub fn try_from_major_minor(major: u32, minor: u32) -> Result<Self> {
55        match (major, minor) {
56            (0, 0) => Ok(Self::Legacy),
57            (0, 1) => Ok(Self::Legacy),
58            (0, 2) => Ok(Self::Legacy),
59            (0, 3) => Ok(Self::V2_0),
60            (2, 0) => Ok(Self::V2_0),
61            (2, 1) => Ok(Self::V2_1),
62            (2, 2) => Ok(Self::V2_2),
63            _ => Err(Error::InvalidInput {
64                source: format!("Unknown Lance storage version: {}.{}", major, minor).into(),
65                location: location!(),
66            }),
67        }
68    }
69
70    pub fn to_numbers(&self) -> (u32, u32) {
71        match self {
72            Self::Legacy => (0, 2),
73            Self::V2_0 => (2, 0),
74            Self::V2_1 => (2, 1),
75            Self::V2_2 => (2, 2),
76            Self::Stable => self.resolve().to_numbers(),
77            Self::Next => self.resolve().to_numbers(),
78        }
79    }
80
81    pub fn iter_non_legacy() -> impl Iterator<Item = Self> {
82        use strum::IntoEnumIterator;
83
84        Self::iter().filter(|&v| v != Self::Stable && v != Self::Next && v != Self::Legacy)
85    }
86
87    pub fn support_add_sub_column(&self) -> bool {
88        self > &Self::V2_1
89    }
90
91    pub fn support_remove_sub_column(&self, field: &Field) -> bool {
92        if self <= &Self::V2_1 {
93            field.data_type().is_struct()
94        } else {
95            field.data_type().is_nested()
96        }
97    }
98}
99
100impl std::fmt::Display for LanceFileVersion {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        write!(
103            f,
104            "{}",
105            match self {
106                Self::Legacy => LEGACY_FORMAT_VERSION,
107                Self::V2_0 => V2_FORMAT_2_0,
108                Self::V2_1 => V2_FORMAT_2_1,
109                Self::V2_2 => V2_FORMAT_2_2,
110                Self::Stable => "stable",
111                Self::Next => "next",
112            }
113        )
114    }
115}
116
117impl FromStr for LanceFileVersion {
118    type Err = Error;
119
120    fn from_str(value: &str) -> Result<Self> {
121        match value.to_lowercase().as_str() {
122            LEGACY_FORMAT_VERSION => Ok(Self::Legacy),
123            V2_FORMAT_2_0 => Ok(Self::V2_0),
124            V2_FORMAT_2_1 => Ok(Self::V2_1),
125            V2_FORMAT_2_2 => Ok(Self::V2_2),
126            "stable" => Ok(Self::Stable),
127            "legacy" => Ok(Self::Legacy),
128            "next" => Ok(Self::Next),
129            // Version 0.3 is an alias of 2.0
130            "0.3" => Ok(Self::V2_0),
131            _ => Err(Error::InvalidInput {
132                source: format!("Unknown Lance storage version: {}", value).into(),
133                location: location!(),
134            }),
135        }
136    }
137}