Skip to main content

pgevolve_core/render/
sequence.rs

1//! Sequence renderer.
2
3use crate::ir::sequence::Sequence;
4use crate::plan::rewrite::sql as rewrite_sql;
5
6/// Render a `Sequence` as SQL.
7///
8/// Emits `CREATE SEQUENCE <qname> AS <type> ... ;` followed by an optional
9/// `COMMENT ON SEQUENCE ...` statement.
10#[must_use]
11pub fn render_sequence(s: &Sequence) -> String {
12    let mut out = rewrite_sql::create_sequence(s);
13    out.push('\n');
14    if let Some(comment) = &s.comment {
15        out.push_str(&rewrite_sql::comment_on_sequence(
16            &s.qname,
17            Some(comment.as_str()),
18        ));
19        out.push('\n');
20    }
21    out
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27    use crate::identifier::Identifier;
28    use crate::identifier::QualifiedName;
29    use crate::ir::column_type::ColumnType;
30    use crate::ir::sequence::{Sequence, SequenceOwner};
31
32    fn id(s: &str) -> Identifier {
33        Identifier::from_unquoted(s).unwrap()
34    }
35
36    fn qn(schema: &str, name: &str) -> QualifiedName {
37        QualifiedName::new(id(schema), id(name))
38    }
39
40    fn assert_pg_parseable(sql: &str) {
41        let r = pg_query::parse(sql);
42        assert!(r.is_ok(), "pg_query rejected SQL:\n{sql}\nerr: {r:?}");
43    }
44
45    fn base_seq() -> Sequence {
46        Sequence {
47            qname: qn("app", "users_id_seq"),
48            data_type: ColumnType::BigInt,
49            start: 1,
50            increment: 1,
51            min_value: None,
52            max_value: None,
53            cache: 1,
54            cycle: false,
55            owned_by: None,
56            comment: None,
57            owner: None,
58            grants: vec![],
59        }
60    }
61
62    #[test]
63    fn plain_sequence_renders() {
64        let sql = render_sequence(&base_seq());
65        assert!(sql.contains("CREATE SEQUENCE app.users_id_seq"));
66        assert!(sql.contains("AS bigint"));
67        assert!(!sql.contains("COMMENT"));
68        assert_pg_parseable(&sql);
69    }
70
71    #[test]
72    fn sequence_with_min_max_renders() {
73        let seq = Sequence {
74            min_value: Some(1),
75            max_value: Some(9_999_999),
76            ..base_seq()
77        };
78        let sql = render_sequence(&seq);
79        assert!(sql.contains("MINVALUE 1"));
80        assert!(sql.contains("MAXVALUE 9999999"));
81        assert_pg_parseable(&sql);
82    }
83
84    #[test]
85    fn sequence_with_no_minmax_renders() {
86        let sql = render_sequence(&base_seq());
87        assert!(sql.contains("NO MINVALUE"));
88        assert!(sql.contains("NO MAXVALUE"));
89        assert_pg_parseable(&sql);
90    }
91
92    #[test]
93    fn cycling_sequence_renders() {
94        let seq = Sequence {
95            cycle: true,
96            ..base_seq()
97        };
98        let sql = render_sequence(&seq);
99        assert!(sql.contains(" CYCLE"));
100        assert!(!sql.contains("NO CYCLE"));
101        assert_pg_parseable(&sql);
102    }
103
104    #[test]
105    fn sequence_with_owned_by_renders() {
106        let seq = Sequence {
107            owned_by: Some(SequenceOwner {
108                table: qn("app", "users"),
109                column: id("id"),
110            }),
111            ..base_seq()
112        };
113        let sql = render_sequence(&seq);
114        assert!(sql.contains("OWNED BY app.users.id"));
115        assert_pg_parseable(&sql);
116    }
117
118    #[test]
119    fn sequence_with_comment_renders() {
120        let seq = Sequence {
121            comment: Some("primary key sequence".into()),
122            ..base_seq()
123        };
124        let sql = render_sequence(&seq);
125        assert!(sql.contains("COMMENT ON SEQUENCE app.users_id_seq IS 'primary key sequence';"));
126        assert_pg_parseable(&sql);
127    }
128
129    #[test]
130    fn smallint_sequence_renders() {
131        let seq = Sequence {
132            data_type: ColumnType::SmallInt,
133            ..base_seq()
134        };
135        let sql = render_sequence(&seq);
136        assert!(sql.contains("AS smallint"));
137        assert_pg_parseable(&sql);
138    }
139
140    #[test]
141    fn integer_sequence_renders() {
142        let seq = Sequence {
143            data_type: ColumnType::Integer,
144            start: 100,
145            increment: 10,
146            cache: 5,
147            ..base_seq()
148        };
149        let sql = render_sequence(&seq);
150        assert!(sql.contains("AS integer"));
151        assert!(sql.contains("INCREMENT BY 10"));
152        assert!(sql.contains("START WITH 100"));
153        assert!(sql.contains("CACHE 5"));
154        assert_pg_parseable(&sql);
155    }
156}