use hamelin_lib::tree::ast::identifier::SimpleIdentifier;
pub trait HasName {
fn has_name(&self, id: &SimpleIdentifier) -> bool;
}
#[derive(Debug)]
pub struct UniqueNameGenerator {
prefix: &'static str,
counter: usize,
}
impl UniqueNameGenerator {
pub fn new(prefix: &'static str) -> Self {
Self { prefix, counter: 0 }
}
pub fn next(&mut self, namespace: &impl HasName) -> SimpleIdentifier {
loop {
let name = format!("{}_{}", self.prefix, self.counter);
self.counter += 1;
let id = SimpleIdentifier::new(name);
if !namespace.has_name(&id) {
return id;
}
}
}
}
use std::sync::Arc;
use hamelin_lib::tree::{
ast::identifier::Identifier,
typed_ast::{environment::TypeEnvironment, query::TypedStatement},
};
impl HasName for TypeEnvironment {
fn has_name(&self, id: &SimpleIdentifier) -> bool {
self.lookup(&id.clone().into()).is_some()
}
}
impl HasName for Arc<TypeEnvironment> {
fn has_name(&self, id: &SimpleIdentifier) -> bool {
self.as_ref().has_name(id)
}
}
impl HasName for TypedStatement {
fn has_name(&self, id: &SimpleIdentifier) -> bool {
self.with_clauses.iter().any(|wc| {
wc.name
.valid_ref()
.map(|name| matches!(name, Identifier::Simple(s) if s == id))
.unwrap_or(false)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use hamelin_lib::types::INT;
#[test]
fn test_generates_sequential_names() {
let mut gen = UniqueNameGenerator::new("__test");
let schema = TypeEnvironment::default();
assert_eq!(gen.next(&schema).as_str(), "__test_0");
assert_eq!(gen.next(&schema).as_str(), "__test_1");
assert_eq!(gen.next(&schema).as_str(), "__test_2");
}
#[test]
fn test_different_prefixes_are_independent() {
let mut alias_gen = UniqueNameGenerator::new("__alias");
let mut from_gen = UniqueNameGenerator::new("__from");
let schema = TypeEnvironment::default();
assert_eq!(alias_gen.next(&schema).as_str(), "__alias_0");
assert_eq!(from_gen.next(&schema).as_str(), "__from_0");
assert_eq!(alias_gen.next(&schema).as_str(), "__alias_1");
assert_eq!(from_gen.next(&schema).as_str(), "__from_1");
}
#[test]
fn test_skips_existing_names_in_schema() {
let mut gen = UniqueNameGenerator::new("__test");
let schema = TypeEnvironment::default()
.with_base(SimpleIdentifier::new("__test_0").into(), INT.clone())
.unwrap()
.with_base(SimpleIdentifier::new("__test_2").into(), INT.clone())
.unwrap();
assert_eq!(gen.next(&schema).as_str(), "__test_1");
assert_eq!(gen.next(&schema).as_str(), "__test_3");
assert_eq!(gen.next(&schema).as_str(), "__test_4");
}
}