lance_namespace_impls/
connect.rs1use std::collections::HashMap;
7use std::sync::Arc;
8
9use lance::session::Session;
10use lance_core::{Error, Result};
11use lance_namespace::LanceNamespace;
12
13#[derive(Debug, Clone)]
50pub struct ConnectBuilder {
51 impl_name: String,
52 properties: HashMap<String, String>,
53 session: Option<Arc<Session>>,
54}
55
56impl ConnectBuilder {
57 pub fn new(impl_name: impl Into<String>) -> Self {
63 Self {
64 impl_name: impl_name.into(),
65 properties: HashMap::new(),
66 session: None,
67 }
68 }
69
70 pub fn property(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
77 self.properties.insert(key.into(), value.into());
78 self
79 }
80
81 pub fn properties(mut self, properties: HashMap<String, String>) -> Self {
87 self.properties.extend(properties);
88 self
89 }
90
91 pub fn session(mut self, session: Arc<Session>) -> Self {
101 self.session = Some(session);
102 self
103 }
104
105 pub async fn connect(self) -> Result<Arc<dyn LanceNamespace>> {
118 match self.impl_name.as_str() {
119 #[cfg(feature = "rest")]
120 "rest" => {
121 crate::rest::RestNamespaceBuilder::from_properties(self.properties)
123 .map(|builder| Arc::new(builder.build()) as Arc<dyn LanceNamespace>)
124 }
125 #[cfg(not(feature = "rest"))]
126 "rest" => Err(Error::Namespace {
127 source: "REST namespace implementation requires 'rest' feature to be enabled"
128 .into(),
129 location: snafu::location!(),
130 }),
131 "dir" => {
132 crate::dir::DirectoryNamespaceBuilder::from_properties(
134 self.properties,
135 self.session,
136 )?
137 .build()
138 .await
139 .map(|ns| Arc::new(ns) as Arc<dyn LanceNamespace>)
140 }
141 _ => Err(Error::Namespace {
142 source: format!(
143 "Implementation '{}' is not available. Supported: dir{}",
144 self.impl_name,
145 if cfg!(feature = "rest") { ", rest" } else { "" }
146 )
147 .into(),
148 location: snafu::location!(),
149 }),
150 }
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use lance_core::utils::tempfile::TempStdDir;
158 use lance_namespace::models::ListTablesRequest;
159 use std::collections::HashMap;
160
161 #[tokio::test]
162 async fn test_connect_builder_basic() {
163 let temp_dir = TempStdDir::default();
164
165 let namespace = ConnectBuilder::new("dir")
166 .property("root", temp_dir.to_str().unwrap())
167 .connect()
168 .await
169 .unwrap();
170
171 let request = ListTablesRequest::new();
173 let response = namespace.list_tables(request).await.unwrap();
174 assert_eq!(response.tables.len(), 0);
175 }
176
177 #[tokio::test]
178 async fn test_connect_builder_with_properties() {
179 let temp_dir = TempStdDir::default();
180 let mut props = HashMap::new();
181 props.insert("storage.option1".to_string(), "value1".to_string());
182
183 let namespace = ConnectBuilder::new("dir")
184 .property("root", temp_dir.to_str().unwrap())
185 .properties(props)
186 .connect()
187 .await
188 .unwrap();
189
190 let request = ListTablesRequest::new();
192 let response = namespace.list_tables(request).await.unwrap();
193 assert_eq!(response.tables.len(), 0);
194 }
195
196 #[tokio::test]
197 async fn test_connect_builder_with_session() {
198 let temp_dir = TempStdDir::default();
199 let session = Arc::new(Session::default());
200
201 let namespace = ConnectBuilder::new("dir")
202 .property("root", temp_dir.to_str().unwrap())
203 .session(session.clone())
204 .connect()
205 .await
206 .unwrap();
207
208 let request = ListTablesRequest::new();
210 let response = namespace.list_tables(request).await.unwrap();
211 assert_eq!(response.tables.len(), 0);
212 }
213
214 #[tokio::test]
215 async fn test_connect_builder_invalid_impl() {
216 let result = ConnectBuilder::new("invalid")
217 .property("root", "/tmp")
218 .connect()
219 .await;
220
221 assert!(result.is_err());
222 let err = result.err().unwrap();
223 assert!(err.to_string().contains("not available"));
224 }
225}