Skip to main content

uqa_sql/ast/
relation_lifecycle.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Relation persistence, view options, and sequence lifecycle nodes.
8
9use serde::{Deserialize, Serialize};
10
11/// `PostgreSQL`'s `pg_class.relpersistence` contract.
12#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
13pub enum RelationPersistence {
14    #[default]
15    Permanent,
16    Unlogged,
17    Temporary,
18}
19
20impl RelationPersistence {
21    #[must_use]
22    pub const fn catalog_code(self) -> &'static str {
23        match self {
24            Self::Permanent => "p",
25            Self::Unlogged => "u",
26            Self::Temporary => "t",
27        }
28    }
29}
30
31/// `ON COMMIT` behavior retained with a temporary table definition.
32#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
33pub enum OnCommitAction {
34    #[default]
35    PreserveRows,
36    DeleteRows,
37    Drop,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
41pub enum AlterViewKind {
42    View,
43    MaterializedView,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47pub enum AlterViewOptionsAction {
48    Set(Vec<(String, String)>),
49    Reset(Vec<String>),
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
53pub struct AlterViewOptionsStmt {
54    pub name: String,
55    pub kind: AlterViewKind,
56    pub if_exists: bool,
57    pub action: AlterViewOptionsAction,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct CreateSequence {
62    pub name: String,
63    pub if_not_exists: bool,
64    pub start: i64,
65    pub increment: i64,
66    #[serde(default)]
67    pub persistence: RelationPersistence,
68}
69
70/// Physical restart action carried by `ALTER SEQUENCE`.
71#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
72pub enum SequenceRestart {
73    /// No `RESTART` clause was specified.
74    #[default]
75    Unchanged,
76    /// Bare `RESTART`; allocate the configured start value next.
77    FromStart,
78    /// `RESTART WITH value`; allocate the supplied value next.
79    With(i64),
80}
81
82fn deserialize_sequence_restart<'de, D>(deserializer: D) -> Result<SequenceRestart, D::Error>
83where
84    D: serde::Deserializer<'de>,
85{
86    #[derive(Deserialize)]
87    enum Current {
88        Unchanged,
89        FromStart,
90        With(i64),
91    }
92
93    #[derive(Deserialize)]
94    #[serde(untagged)]
95    enum Representation {
96        Current(Current),
97        // Before SequenceRestart existed this field was
98        // Option<Option<i64>>, serialized as null or an integer.
99        Legacy(Option<i64>),
100    }
101
102    Ok(match Representation::deserialize(deserializer)? {
103        Representation::Current(Current::Unchanged) | Representation::Legacy(None) => {
104            SequenceRestart::Unchanged
105        }
106        Representation::Current(Current::FromStart) => SequenceRestart::FromStart,
107        Representation::Current(Current::With(value)) | Representation::Legacy(Some(value)) => {
108            SequenceRestart::With(value)
109        }
110    })
111}
112
113#[derive(Debug, Clone, Default, Serialize, Deserialize)]
114pub struct AlterSequence {
115    pub name: String,
116    /// `ALTER SEQUENCE IF EXISTS` suppresses only a missing sequence.
117    #[serde(default)]
118    pub if_exists: bool,
119    /// `RESTART [WITH n]`, preserving omitted, bare, and explicit forms.
120    #[serde(default, deserialize_with = "deserialize_sequence_restart")]
121    pub restart: SequenceRestart,
122    pub increment: Option<i64>,
123    pub start: Option<i64>,
124}