Skip to main content

pgevolve_core/ir/
sequence.rs

1//! `Sequence` — a standalone or column-owned Postgres sequence.
2
3use serde::{Deserialize, Serialize};
4
5use crate::identifier::QualifiedName;
6use crate::ir::column_type::ColumnType;
7use crate::ir::eq::DiffMacro;
8
9/// A Postgres sequence.
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DiffMacro)]
11pub struct Sequence {
12    /// Schema-qualified sequence name.
13    pub qname: QualifiedName,
14    /// Sequence data type (always one of `SmallInt`, `Integer`, `BigInt`).
15    #[diff(via_debug)]
16    pub data_type: ColumnType,
17    /// Start value.
18    pub start: i64,
19    /// Increment.
20    pub increment: i64,
21    /// Min value (`None` = type's minimum).
22    #[diff(via_debug)]
23    pub min_value: Option<i64>,
24    /// Max value (`None` = type's maximum).
25    #[diff(via_debug)]
26    pub max_value: Option<i64>,
27    /// Cache size.
28    pub cache: i64,
29    /// Whether the sequence cycles.
30    pub cycle: bool,
31    /// Owning column, if any (e.g., from `SERIAL` / `IDENTITY`).
32    #[diff(via_debug)]
33    pub owned_by: Option<SequenceOwner>,
34    /// Optional comment.
35    #[diff(via_debug)]
36    pub comment: Option<String>,
37    /// Object owner. `None` = unmanaged (the differ ignores ownership).
38    /// `Some(role)` = managed: diff emits `ALTER SEQUENCE ... OWNER TO role`.
39    #[diff(via_debug)]
40    pub owner: Option<crate::identifier::Identifier>,
41    /// Grants on this object. Empty = no grants. Canonicalized.
42    #[diff(via_debug)]
43    pub grants: Vec<crate::ir::grant::Grant>,
44}
45
46/// Identifies a column that owns this sequence (Postgres `OWNED BY`).
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48pub struct SequenceOwner {
49    /// Owning table.
50    pub table: QualifiedName,
51    /// Owning column name.
52    pub column: crate::identifier::Identifier,
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use crate::identifier::{Identifier, QualifiedName};
59    use crate::ir::eq::Diff;
60
61    fn s(name: &str) -> QualifiedName {
62        QualifiedName::new(
63            Identifier::from_unquoted("app").unwrap(),
64            Identifier::from_unquoted(name).unwrap(),
65        )
66    }
67
68    fn base() -> Sequence {
69        Sequence {
70            qname: s("seq1"),
71            data_type: ColumnType::BigInt,
72            start: 1,
73            increment: 1,
74            min_value: None,
75            max_value: None,
76            cache: 1,
77            cycle: false,
78            owned_by: None,
79            comment: None,
80            owner: None,
81            grants: Vec::new(),
82        }
83    }
84
85    #[test]
86    fn sequences_equal_when_identical() {
87        assert!(base().canonical_eq(&base()));
88    }
89
90    #[test]
91    fn sequence_diff_reports_increment_change() {
92        let mut other = base();
93        other.increment = 2;
94        let d = base().diff(&other);
95        assert!(d.iter().any(|x| x.path == "increment"));
96    }
97
98    #[test]
99    fn sequence_diff_reports_qname_change() {
100        let mut other = base();
101        other.qname = s("seq2");
102        let d = base().diff(&other);
103        assert!(d.iter().any(|x| x.path == "qname"));
104    }
105
106    #[test]
107    fn owner_change_diffs() {
108        let mut b = base();
109        b.owner = Some(Identifier::from_unquoted("new_owner").unwrap());
110        assert!(base().diff(&b).iter().any(|x| x.path == "owner"));
111    }
112
113    #[test]
114    fn grants_change_diffs() {
115        let mut b = base();
116        b.grants.push(crate::ir::grant::Grant {
117            grantee: crate::ir::grant::GrantTarget::Public,
118            privilege: crate::ir::grant::Privilege::Usage,
119            with_grant_option: false,
120            columns: None,
121        });
122        assert!(base().diff(&b).iter().any(|x| x.path == "grants"));
123    }
124}