use lazy_static::lazy_static;
use regex::Regex;
use std::{fmt, str::FromStr};
use crate::common::*;
use crate::drivers::bigquery::BigQueryLocator;
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct TableName {
project: String,
dataset: String,
table: String,
}
impl TableName {
pub(crate) fn project(&self) -> &str {
&self.project
}
pub(crate) fn dotted(&self) -> DottedTableName {
DottedTableName(self)
}
pub(crate) fn temporary_table_name(
&self,
temporary_storage: &TemporaryStorage,
) -> Result<TableName> {
lazy_static! {
static ref DATASET_RE: Regex =
Regex::new("^([^:.]+):([^:.]+)$").expect("invalid regex in source");
}
let temp = temporary_storage.find_scheme(BigQueryLocator::scheme());
let (project, dataset) = if let Some(temp) = temp {
let cap = DATASET_RE
.captures(&temp[BigQueryLocator::scheme().len()..])
.ok_or_else(|| {
format_err!("could not parse BigQuery dataset name: {:?}", temp)
})?;
(cap[1].to_owned(), cap[2].to_owned())
} else {
(self.project.clone(), self.dataset.clone())
};
let tag = TemporaryStorage::random_tag();
let table = format!("temp_{}_{}", self.table, tag);
Ok(TableName {
project,
dataset,
table,
})
}
}
#[test]
fn temporary_table_name() {
let table_name = "project:dataset.table".parse::<TableName>().unwrap();
let default_temp_name = table_name
.temporary_table_name(&TemporaryStorage::new(vec![]))
.unwrap()
.to_string();
assert!(default_temp_name.starts_with("project:dataset.temp_table_"));
let temporary_storage =
TemporaryStorage::new(vec!["bigquery:project2:temp".to_owned()]);
let temp_name = table_name
.temporary_table_name(&temporary_storage)
.unwrap()
.to_string();
assert!(temp_name.starts_with("project2:temp.temp_table_"));
}
impl fmt::Display for TableName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}.{}", self.project, self.dataset, self.table)
}
}
impl FromStr for TableName {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
lazy_static! {
static ref RE: Regex = Regex::new("^([^:.]+):([^:.]+).([^:.]+)$")
.expect("could not parse built-in regex");
}
let cap = RE.captures(s).ok_or_else(|| {
format_err!("could not parse BigQuery table name: {:?}", s)
})?;
let (project, dataset, table) = (&cap[1], &cap[2], &cap[3]);
Ok(TableName {
project: project.to_string(),
dataset: dataset.to_string(),
table: table.to_string(),
})
}
}
pub(crate) struct DottedTableName<'a>(&'a TableName);
impl<'a> fmt::Display for DottedTableName<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.0.project, self.0.dataset, self.0.table)
}
}