use std::collections::BTreeSet;
use serde::{Deserialize, Serialize};
use crate::identifier::{Identifier, QualifiedName};
use crate::ir::default_expr::NormalizedExpr;
use crate::ir::difference::Difference;
use crate::ir::eq::{Equiv, field_difference};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Publication {
pub name: Identifier,
pub scope: PublicationScope,
pub publish: PublishKinds,
pub publish_via_partition_root: bool,
pub owner: Option<Identifier>,
pub comment: Option<String>,
}
impl Equiv for Publication {
fn differences(&self, other: &Self) -> Vec<Difference> {
let Self {
name: _,
scope: _,
publish: _,
publish_via_partition_root: _,
owner: _,
comment: _,
} = self;
let mut out = Vec::new();
out.extend(field_difference("name", &self.name, &other.name));
out.extend(field_difference(
"scope",
&format!("{:?}", self.scope),
&format!("{:?}", other.scope),
));
out.extend(field_difference(
"publish",
&format!("{:?}", self.publish),
&format!("{:?}", other.publish),
));
out.extend(field_difference(
"publish_via_partition_root",
&format!("{:?}", self.publish_via_partition_root),
&format!("{:?}", other.publish_via_partition_root),
));
out.extend(field_difference(
"owner",
&format!("{:?}", self.owner),
&format!("{:?}", other.owner),
));
out.extend(field_difference(
"comment",
&format!("{:?}", self.comment),
&format!("{:?}", other.comment),
));
out
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PublicationScope {
AllTables,
Selective {
schemas: BTreeSet<Identifier>,
tables: Vec<PublishedTable>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PublishedTable {
pub qname: QualifiedName,
pub row_filter: Option<NormalizedExpr>,
pub columns: Option<Vec<Identifier>>,
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct PublishKinds {
pub insert: bool,
pub update: bool,
pub delete: bool,
pub truncate: bool,
}
impl PublishKinds {
#[must_use]
pub const fn pg_default() -> Self {
Self {
insert: true,
update: true,
delete: true,
truncate: true,
}
}
#[must_use]
pub const fn is_empty(&self) -> bool {
!self.insert && !self.update && !self.delete && !self.truncate
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::identifier::Identifier;
fn id(s: &str) -> Identifier {
Identifier::from_unquoted(s).unwrap()
}
#[test]
fn publish_kinds_default_all_true() {
let k = PublishKinds::pg_default();
assert!(k.insert && k.update && k.delete && k.truncate);
assert!(!k.is_empty());
}
#[test]
fn publish_kinds_is_empty_when_all_false() {
let k = PublishKinds {
insert: false,
update: false,
delete: false,
truncate: false,
};
assert!(k.is_empty());
}
#[test]
fn scope_all_tables_does_not_equal_empty_selective() {
let a = PublicationScope::AllTables;
let b = PublicationScope::Selective {
schemas: BTreeSet::new(),
tables: Vec::new(),
};
assert_ne!(a, b);
}
#[test]
fn selective_with_a_schema_equals_itself() {
let s = PublicationScope::Selective {
schemas: BTreeSet::from([id("app")]),
tables: Vec::new(),
};
assert_eq!(s.clone(), s);
}
}