use crate::catalog::id::DbObjectId;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum NamespaceSlot {
Relation { schema: String, name: String },
Constraint {
schema: String,
table: String,
name: String,
},
Type { schema: String, name: String },
Routine {
schema: String,
name: String,
arguments: String,
},
}
pub fn namespace_slots(id: &DbObjectId) -> Vec<NamespaceSlot> {
match id {
DbObjectId::Table { schema, name }
| DbObjectId::View { schema, name }
| DbObjectId::Sequence { schema, name }
| DbObjectId::Index { schema, name } => vec![NamespaceSlot::Relation {
schema: schema.clone(),
name: name.clone(),
}],
DbObjectId::Constraint {
schema,
table,
name,
} => vec![
NamespaceSlot::Constraint {
schema: schema.clone(),
table: table.clone(),
name: name.clone(),
},
NamespaceSlot::Relation {
schema: schema.clone(),
name: name.clone(),
},
],
DbObjectId::Type { schema, name } | DbObjectId::Domain { schema, name } => {
vec![NamespaceSlot::Type {
schema: schema.clone(),
name: name.clone(),
}]
}
DbObjectId::Function {
schema,
name,
arguments,
}
| DbObjectId::Procedure {
schema,
name,
arguments,
} => vec![NamespaceSlot::Routine {
schema: schema.clone(),
name: name.clone(),
arguments: arguments.clone(),
}],
DbObjectId::Aggregate { .. } => vec![],
DbObjectId::Schema { .. }
| DbObjectId::Trigger { .. }
| DbObjectId::Policy { .. }
| DbObjectId::Grant { .. }
| DbObjectId::Comment { .. }
| DbObjectId::Extension { .. }
| DbObjectId::Operator { .. }
| DbObjectId::Cast { .. }
| DbObjectId::Column { .. } => vec![],
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn table_and_index_share_relation_slot() {
let table = namespace_slots(&DbObjectId::Table {
schema: "public".into(),
name: "foo".into(),
});
let index = namespace_slots(&DbObjectId::Index {
schema: "public".into(),
name: "foo".into(),
});
assert_eq!(
table,
vec![NamespaceSlot::Relation {
schema: "public".into(),
name: "foo".into()
}]
);
assert_eq!(table, index, "table and index of same name must collide");
}
#[test]
fn constraint_occupies_constraint_and_relation_slots() {
let slots = namespace_slots(&DbObjectId::Constraint {
schema: "public".into(),
table: "orders".into(),
name: "foo".into(),
});
assert_eq!(
slots,
vec![
NamespaceSlot::Constraint {
schema: "public".into(),
table: "orders".into(),
name: "foo".into()
},
NamespaceSlot::Relation {
schema: "public".into(),
name: "foo".into()
},
]
);
}
#[test]
fn constraint_and_index_collide_on_relation_slot() {
let constraint = namespace_slots(&DbObjectId::Constraint {
schema: "public".into(),
table: "orders".into(),
name: "foo".into(),
});
let index = namespace_slots(&DbObjectId::Index {
schema: "public".into(),
name: "foo".into(),
});
let shared = NamespaceSlot::Relation {
schema: "public".into(),
name: "foo".into(),
};
assert!(constraint.contains(&shared));
assert!(index.contains(&shared));
}
#[test]
fn type_and_domain_share_type_slot() {
let ty = namespace_slots(&DbObjectId::Type {
schema: "public".into(),
name: "foo".into(),
});
let domain = namespace_slots(&DbObjectId::Domain {
schema: "public".into(),
name: "foo".into(),
});
assert_eq!(ty, domain);
}
#[test]
fn differing_names_do_not_collide() {
let a = namespace_slots(&DbObjectId::Constraint {
schema: "public".into(),
table: "orders".into(),
name: "foo".into(),
});
let b = namespace_slots(&DbObjectId::Index {
schema: "public".into(),
name: "bar".into(),
});
assert!(a.iter().all(|s| !b.contains(s)));
}
#[test]
fn slotless_objects_return_empty() {
assert!(
namespace_slots(&DbObjectId::Schema {
name: "public".into()
})
.is_empty()
);
assert!(
namespace_slots(&DbObjectId::Extension {
name: "citext".into()
})
.is_empty()
);
assert!(
namespace_slots(&DbObjectId::Aggregate {
schema: "public".into(),
name: "a".into(),
arguments: "integer".into()
})
.is_empty()
);
}
#[test]
fn function_and_procedure_share_routine_slot() {
let func = namespace_slots(&DbObjectId::Function {
schema: "public".into(),
name: "foo".into(),
arguments: "integer".into(),
});
let proc = namespace_slots(&DbObjectId::Procedure {
schema: "public".into(),
name: "foo".into(),
arguments: "integer".into(),
});
assert_eq!(
func,
vec![NamespaceSlot::Routine {
schema: "public".into(),
name: "foo".into(),
arguments: "integer".into()
}]
);
assert_eq!(
func, proc,
"a function and procedure with the same signature must collide"
);
}
}