Skip to main content

uqa_sql/ast/
sequence.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Durable provenance for implicit SERIAL and identity sequences.
8
9use serde::{Deserialize, Deserializer, Serialize};
10
11/// `PostgreSQL` syntax that supplies an omitted column value from an implicit sequence. `SERIAL` is a sequence-backed default, while identity columns retain a separate generation attribute and do not have a column default.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum AutoIncrementKind {
15    Serial,
16    IdentityAlways,
17    IdentityByDefault,
18    /// Catalogs written before sequence provenance was persisted cannot distinguish `SERIAL` from identity syntax. Preserve their historical table-counter behavior instead of guessing and changing stored data.
19    Legacy,
20}
21
22/// Durable owner of an implicit sequence. Inherited `SERIAL` defaults and declarative partitions copy this owner unchanged, so truncating a child cannot reset a sequence owned by its parent.
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24pub struct AutoIncrementOwner {
25    pub table: String,
26    pub column: String,
27}
28
29/// Durable sequence provenance for a `SERIAL` or identity column.
30#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31pub struct AutoIncrement {
32    pub kind: AutoIncrementKind,
33    /// Canonical sequence relation name. Compiler-produced column definitions leave this empty until `CREATE TABLE` resolves the destination schema.
34    #[serde(default, skip_serializing_if = "Option::is_none")]
35    pub sequence: Option<String>,
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub owner: Option<AutoIncrementOwner>,
38    /// The sequence options an identity declaration writes, which create its sequence. Creating the sequence consumes them, so a stored column holds none: the sequence keeps them.
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub declaration: Option<Box<super::IdentitySequenceDeclaration>>,
41}
42
43impl AutoIncrement {
44    #[must_use]
45    pub const fn serial() -> Self {
46        Self {
47            kind: AutoIncrementKind::Serial,
48            sequence: None,
49            owner: None,
50            declaration: None,
51        }
52    }
53
54    #[must_use]
55    pub const fn identity_always() -> Self {
56        Self {
57            kind: AutoIncrementKind::IdentityAlways,
58            sequence: None,
59            owner: None,
60            declaration: None,
61        }
62    }
63
64    #[must_use]
65    pub const fn identity_by_default() -> Self {
66        Self {
67            kind: AutoIncrementKind::IdentityByDefault,
68            sequence: None,
69            owner: None,
70            declaration: None,
71        }
72    }
73
74    #[must_use]
75    pub const fn legacy() -> Self {
76        Self {
77            kind: AutoIncrementKind::Legacy,
78            sequence: None,
79            owner: None,
80            declaration: None,
81        }
82    }
83
84    #[must_use]
85    pub const fn is_identity(&self) -> bool {
86        matches!(
87            self.kind,
88            AutoIncrementKind::IdentityAlways | AutoIncrementKind::IdentityByDefault
89        )
90    }
91
92    #[must_use]
93    pub const fn is_legacy(&self) -> bool {
94        matches!(self.kind, AutoIncrementKind::Legacy)
95    }
96}
97
98pub(super) fn deserialize_auto_increment<'de, D>(
99    deserializer: D,
100) -> Result<Option<AutoIncrement>, D::Error>
101where
102    D: Deserializer<'de>,
103{
104    #[derive(Deserialize)]
105    #[serde(untagged)]
106    enum Representation {
107        Legacy(bool),
108        Provenance(AutoIncrement),
109    }
110
111    Ok(match Option::<Representation>::deserialize(deserializer)? {
112        Some(Representation::Legacy(true)) => Some(AutoIncrement::legacy()),
113        Some(Representation::Legacy(false)) | None => None,
114        Some(Representation::Provenance(provenance)) => Some(provenance),
115    })
116}