use anyhow::{Context, Result};
use std::collections::HashSet;
use crate::catalog::id::DbObjectId;
use oid_index::OidIndex;
pub fn dedup_preserving_order(dependencies: &mut Vec<DbObjectId>) {
let mut seen = HashSet::new();
dependencies.retain(|dependency| seen.insert(dependency.clone()));
}
pub fn merge_indexes(indexes: Vec<(&'static str, OidIndex)>) -> Result<OidIndex> {
let mut merged = OidIndex::new();
for (kind, index) in indexes {
for (class, oid, id) in index.iter() {
merged
.insert(class, oid, id.clone())
.with_context(|| format!("merging the OID index of every {kind}"))?;
}
}
Ok(merged)
}
pub mod aggregate;
pub mod cast;
pub mod collation;
pub mod constraint;
pub mod custom_type;
pub mod domain;
pub mod exclusion;
pub mod extension;
pub mod function;
pub mod grant;
pub mod index;
pub mod oid_index;
pub mod operator;
pub mod policy;
pub mod reference;
pub mod schema;
pub mod sequence;
pub mod shared;
pub mod snapshot;
pub mod table;
pub mod trigger;
pub mod view;
#[cfg(test)]
mod tests {
use super::*;
use shared::class;
use sqlx::postgres::types::Oid;
fn table(name: &str) -> DbObjectId {
DbObjectId::Table {
schema: "public".to_string(),
name: name.to_string(),
}
}
#[test]
fn test_merge_keeps_every_kind_addressable() {
let tables = OidIndex::from_pairs(class::PG_CLASS, [(Oid(16400), table("users"))]).unwrap();
let types = OidIndex::from_pairs(
class::PG_TYPE,
[(
Oid(16500),
DbObjectId::Type {
schema: "public".to_string(),
name: "status".to_string(),
},
)],
)
.unwrap();
let merged = merge_indexes(vec![("table", tables), ("type", types)]).unwrap();
assert_eq!(merged.len(), 2);
assert_eq!(
merged.get(class::PG_CLASS, Oid(16400)),
Some(&table("users"))
);
assert!(merged.contains(class::PG_TYPE, Oid(16500)));
}
#[test]
fn test_merge_reports_the_kind_a_conflicting_address_came_from() {
let tables = OidIndex::from_pairs(class::PG_CLASS, [(Oid(16400), table("users"))]).unwrap();
let views = OidIndex::from_pairs(
class::PG_CLASS,
[(
Oid(16400),
DbObjectId::View {
schema: "public".to_string(),
name: "user_emails".to_string(),
},
)],
)
.unwrap();
let error = merge_indexes(vec![("table", tables), ("view", views)]).unwrap_err();
let message = format!("{error:#}");
assert!(message.contains("view"), "message was: {message}");
assert!(message.contains("16400"), "message was: {message}");
}
#[test]
fn test_merge_accepts_one_identity_under_several_addresses() {
let composite = DbObjectId::Type {
schema: "public".to_string(),
name: "point2d".to_string(),
};
let mut types = OidIndex::new();
types
.insert(class::PG_TYPE, Oid(16500), composite.clone())
.unwrap();
types
.insert(class::PG_CLASS, Oid(16501), composite.clone())
.unwrap();
let merged = merge_indexes(vec![("type", types)]).unwrap();
assert_eq!(merged.len(), 2);
assert_eq!(merged.get(class::PG_CLASS, Oid(16501)), Some(&composite));
}
}