use std::{error::Error, sync::Arc};
use reqwest::Client;
use super::store::{is_graphql_name, Store};
use crate::embedding::Embedder;
pub struct StoreBuilder {
client: Option<Client>,
url: String,
api_key: Option<String>,
class_name: Option<String>,
embedder: Option<Arc<dyn Embedder>>,
text_key: String,
namespace_key: String,
namespace: Option<String>,
metadata_fields: Option<Vec<String>>,
}
impl Default for StoreBuilder {
fn default() -> Self {
Self::new()
}
}
impl StoreBuilder {
pub fn new() -> Self {
StoreBuilder {
client: None,
url: "http://localhost:8080".to_string(),
api_key: None,
class_name: None,
embedder: None,
text_key: "text".to_string(),
namespace_key: "nameSpace".to_string(),
namespace: None,
metadata_fields: None,
}
}
pub fn url(mut self, url: &str) -> Self {
self.url = url.trim_end_matches('/').to_string();
self
}
pub fn api_key(mut self, api_key: &str) -> Self {
self.api_key = Some(api_key.to_string());
self
}
pub fn client(mut self, client: Client) -> Self {
self.client = Some(client);
self
}
pub fn class_name(mut self, name: &str) -> Self {
self.class_name = Some(name.to_string());
self
}
pub fn embedder<E: Embedder + 'static>(mut self, embedder: E) -> Self {
self.embedder = Some(Arc::new(embedder));
self
}
pub fn text_key(mut self, key: &str) -> Self {
self.text_key = key.to_string();
self
}
pub fn namespace_key(mut self, key: &str) -> Self {
self.namespace_key = key.to_string();
self
}
pub fn namespace(mut self, namespace: &str) -> Self {
self.namespace = Some(namespace.to_string());
self
}
pub fn metadata_fields<S: Into<String>>(mut self, fields: impl IntoIterator<Item = S>) -> Self {
self.metadata_fields = Some(fields.into_iter().map(Into::into).collect());
self
}
pub fn build(self) -> Result<Store, Box<dyn Error>> {
let class_name = self.class_name.ok_or("'class_name' is required")?;
let embedder = self.embedder.ok_or("'embedder' is required")?;
let mut chars = class_name.chars();
let class_name = match chars.next() {
Some(first) => first.to_ascii_uppercase().to_string() + chars.as_str(),
None => String::new(),
};
for (what, name) in [
("class name", &class_name),
("text_key", &self.text_key),
("namespace_key", &self.namespace_key),
] {
if !is_graphql_name(name) {
return Err(format!("invalid Weaviate {what} {name:?}").into());
}
}
Ok(Store {
client: self.client.unwrap_or_default(),
url: self.url,
api_key: self.api_key,
class_name,
embedder,
text_key: self.text_key,
namespace_key: self.namespace_key,
namespace: self.namespace,
metadata_fields: self.metadata_fields,
schema_ready: Default::default(),
})
}
}