use const_format::concatcp;
use std::sync::LazyLock;
use uuid::Uuid;
const GGSQL_PREFIX: &str = "__ggsql_";
const GGSQL_SUFFIX: &str = "__";
static SESSION_ID: LazyLock<String> = LazyLock::new(|| Uuid::new_v4().simple().to_string());
pub fn session_id() -> &'static str {
&SESSION_ID
}
const CONST_PREFIX: &str = concatcp!(GGSQL_PREFIX, "const_");
const STAT_PREFIX: &str = concatcp!(GGSQL_PREFIX, "stat_");
const CTE_PREFIX: &str = concatcp!(GGSQL_PREFIX, "cte_");
const LAYER_PREFIX: &str = concatcp!(GGSQL_PREFIX, "layer_");
const AES_PREFIX: &str = concatcp!(GGSQL_PREFIX, "aes_");
const DATA_PREFIX: &str = concatcp!(GGSQL_PREFIX, "data_");
pub const GLOBAL_DATA_KEY: &str = concatcp!(GGSQL_PREFIX, "global", GGSQL_SUFFIX);
pub const ORDER_COLUMN: &str = concatcp!(GGSQL_PREFIX, "order", GGSQL_SUFFIX);
pub const SOURCE_COLUMN: &str = concatcp!(GGSQL_PREFIX, "source", GGSQL_SUFFIX);
pub const SCHEMA_ALIAS: &str = concatcp!(GGSQL_SUFFIX, "schema", GGSQL_SUFFIX);
pub fn global_table() -> String {
format!("{}global_{}{}", GGSQL_PREFIX, session_id(), GGSQL_SUFFIX)
}
pub fn cte_table(cte_name: &str) -> String {
format!(
"{}{}_{}{}",
CTE_PREFIX,
cte_name,
session_id(),
GGSQL_SUFFIX
)
}
pub fn builtin_data_table(name: &str) -> String {
format!("{}{}{}", DATA_PREFIX, name, GGSQL_SUFFIX)
}
pub fn const_column(aesthetic: &str) -> String {
format!("{}{}{}", CONST_PREFIX, aesthetic, GGSQL_SUFFIX)
}
pub fn const_column_indexed(aesthetic: &str, layer_idx: usize) -> String {
format!(
"{}{}_{}{}",
CONST_PREFIX, aesthetic, layer_idx, GGSQL_SUFFIX
)
}
pub fn stat_column(stat_name: &str) -> String {
format!("{}{}", STAT_PREFIX, stat_name)
}
pub fn layer_key(layer_idx: usize) -> String {
format!("{}{}{}", LAYER_PREFIX, layer_idx, GGSQL_SUFFIX)
}
pub fn aesthetic_column(aesthetic: &str) -> String {
format!("{}{}{}", AES_PREFIX, aesthetic, GGSQL_SUFFIX)
}
pub fn is_const_column(name: &str) -> bool {
name.starts_with(CONST_PREFIX)
}
pub fn is_stat_column(name: &str) -> bool {
name.starts_with(STAT_PREFIX)
}
pub fn is_aesthetic_column(name: &str) -> bool {
name.starts_with(AES_PREFIX) && name.ends_with(GGSQL_SUFFIX)
}
pub fn is_synthetic_column(name: &str) -> bool {
is_const_column(name) || is_stat_column(name) || is_aesthetic_column(name)
}
pub fn bin_end_column(column: &str) -> String {
if let Some(aesthetic) = extract_aesthetic_name(column) {
return aesthetic_column(&format!("{}end", aesthetic));
}
format!("{}bin_end_{}{}", GGSQL_PREFIX, column, GGSQL_SUFFIX)
}
pub fn extract_stat_name(name: &str) -> Option<&str> {
name.strip_prefix(STAT_PREFIX)
}
pub fn extract_aesthetic_name(name: &str) -> Option<&str> {
name.strip_prefix(AES_PREFIX)
.and_then(|s| s.strip_suffix(GGSQL_SUFFIX))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_session_id() {
let id = session_id();
assert_eq!(id.len(), 32);
assert_eq!(session_id(), id);
}
#[test]
fn test_global_table() {
let table = global_table();
assert!(table.starts_with("__ggsql_global_"));
assert!(table.ends_with("__"));
assert_eq!(global_table(), table);
assert!(table.contains(session_id()));
}
#[test]
fn test_cte_table() {
let table = cte_table("sales");
assert!(table.starts_with("__ggsql_cte_sales_"));
assert!(table.ends_with("__"));
assert!(table.contains(session_id()));
let table2 = cte_table("monthly_totals");
assert!(table2.starts_with("__ggsql_cte_monthly_totals_"));
assert!(table2.ends_with("__"));
}
#[test]
fn test_const_column() {
assert_eq!(const_column("color"), "__ggsql_const_color__");
assert_eq!(const_column("fill"), "__ggsql_const_fill__");
}
#[test]
fn test_const_column_indexed() {
assert_eq!(const_column_indexed("color", 0), "__ggsql_const_color_0__");
assert_eq!(const_column_indexed("color", 1), "__ggsql_const_color_1__");
assert_eq!(const_column_indexed("size", 5), "__ggsql_const_size_5__");
}
#[test]
fn test_stat_column() {
assert_eq!(stat_column("count"), "__ggsql_stat_count");
assert_eq!(stat_column("bin"), "__ggsql_stat_bin");
assert_eq!(stat_column("density"), "__ggsql_stat_density");
}
#[test]
fn test_layer_key() {
assert_eq!(layer_key(0), "__ggsql_layer_0__");
assert_eq!(layer_key(1), "__ggsql_layer_1__");
assert_eq!(layer_key(10), "__ggsql_layer_10__");
}
#[test]
fn test_is_const_column() {
assert!(is_const_column("__ggsql_const_color__"));
assert!(is_const_column("__ggsql_const_color_0__"));
assert!(is_const_column("__ggsql_const_fill__"));
assert!(!is_const_column("color"));
assert!(!is_const_column("__ggsql_stat_count"));
}
#[test]
fn test_is_stat_column() {
assert!(is_stat_column("__ggsql_stat_count"));
assert!(is_stat_column("__ggsql_stat_bin"));
assert!(!is_stat_column("count"));
assert!(!is_stat_column("__ggsql_const_color__"));
}
#[test]
fn test_is_synthetic_column() {
assert!(is_synthetic_column("__ggsql_const_color__"));
assert!(is_synthetic_column("__ggsql_stat_count"));
assert!(!is_synthetic_column("revenue"));
assert!(!is_synthetic_column("date"));
}
#[test]
fn test_extract_stat_name() {
assert_eq!(extract_stat_name("__ggsql_stat_count"), Some("count"));
assert_eq!(extract_stat_name("__ggsql_stat_bin"), Some("bin"));
assert_eq!(extract_stat_name("__ggsql_stat_density"), Some("density"));
assert_eq!(extract_stat_name("regular_column"), None);
assert_eq!(extract_stat_name("__ggsql_const_color__"), None);
}
#[test]
fn test_constants() {
assert_eq!(GLOBAL_DATA_KEY, "__ggsql_global__");
assert_eq!(ORDER_COLUMN, "__ggsql_order__");
assert_eq!(SOURCE_COLUMN, "__ggsql_source__");
assert_eq!(SCHEMA_ALIAS, "__schema__");
}
#[test]
fn test_bin_end_column() {
assert_eq!(
bin_end_column("temperature"),
"__ggsql_bin_end_temperature__"
);
assert_eq!(bin_end_column("x"), "__ggsql_bin_end_x__");
assert_eq!(bin_end_column("value"), "__ggsql_bin_end_value__");
assert_eq!(bin_end_column("__ggsql_aes_x__"), "__ggsql_aes_xend__");
assert_eq!(bin_end_column("__ggsql_aes_y__"), "__ggsql_aes_yend__");
}
#[test]
fn test_builtin_data_table() {
assert_eq!(builtin_data_table("penguins"), "__ggsql_data_penguins__");
assert_eq!(
builtin_data_table("airquality"),
"__ggsql_data_airquality__"
);
}
#[test]
fn test_prefixes_built_from_components() {
assert_eq!(CONST_PREFIX, "__ggsql_const_");
assert_eq!(STAT_PREFIX, "__ggsql_stat_");
assert_eq!(CTE_PREFIX, "__ggsql_cte_");
assert_eq!(LAYER_PREFIX, "__ggsql_layer_");
assert_eq!(AES_PREFIX, "__ggsql_aes_");
assert_eq!(DATA_PREFIX, "__ggsql_data_");
}
#[test]
fn test_aesthetic_column() {
assert_eq!(aesthetic_column("x"), "__ggsql_aes_x__");
assert_eq!(aesthetic_column("y"), "__ggsql_aes_y__");
assert_eq!(aesthetic_column("fill"), "__ggsql_aes_fill__");
assert_eq!(aesthetic_column("color"), "__ggsql_aes_color__");
}
#[test]
fn test_is_aesthetic_column() {
assert!(is_aesthetic_column("__ggsql_aes_x__"));
assert!(is_aesthetic_column("__ggsql_aes_fill__"));
assert!(!is_aesthetic_column("x"));
assert!(!is_aesthetic_column("__ggsql_stat_count"));
assert!(!is_aesthetic_column("__ggsql_const_color__"));
assert!(!is_aesthetic_column("__ggsql_aes_x")); }
#[test]
fn test_extract_aesthetic_name() {
assert_eq!(extract_aesthetic_name("__ggsql_aes_x__"), Some("x"));
assert_eq!(extract_aesthetic_name("__ggsql_aes_fill__"), Some("fill"));
assert_eq!(extract_aesthetic_name("__ggsql_aes_color__"), Some("color"));
assert_eq!(extract_aesthetic_name("regular_column"), None);
assert_eq!(extract_aesthetic_name("__ggsql_stat_count"), None);
assert_eq!(extract_aesthetic_name("__ggsql_const_color__"), None);
}
#[test]
fn test_bin_end_column_internal_positional() {
assert_eq!(
bin_end_column("__ggsql_aes_pos1__"),
"__ggsql_aes_pos1end__"
);
assert_eq!(
bin_end_column("__ggsql_aes_pos2__"),
"__ggsql_aes_pos2end__"
);
assert_eq!(
bin_end_column("__ggsql_aes_pos3__"),
"__ggsql_aes_pos3end__"
);
assert_eq!(
bin_end_column("__ggsql_aes_pos10__"),
"__ggsql_aes_pos10end__"
);
}
}