Skip to main content

drizzle_core/expr/
seq.rs

1//! PostgreSQL sequence functions: `NEXTVAL`, `CURRVAL` and `SETVAL`.
2//!
3//! Sequences back `serial` and identity columns. The functions take the
4//! sequence name as text and do not compile for SQLite or MySQL.
5
6use crate::dialect::DialectTypes;
7use crate::dialect::{DialectSupports, feature};
8use crate::sql::SQL;
9use crate::traits::SQLParam;
10use crate::types::Textual;
11
12use super::{AggregateKind, Expr, NonNull, Nullability, SQLExpr, Scalar};
13use crate::scope::ScopeOnly;
14
15use crate::PostgresDialect;
16
17impl DialectSupports<feature::Sequence> for PostgresDialect {}
18
19/// Advances a sequence and returns the new value (`NEXTVAL`), on PostgreSQL.
20///
21/// The argument is the sequence name as text. The result is `int8` and never
22/// NULL.
23///
24/// # Examples
25///
26/// ```rust
27/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
28/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
29/// # #[derive(Clone, Debug)] struct Value(String);
30/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
31/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
32/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
33/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
34/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
35/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
36/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
37/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
38/// let next_id = nextval::<Value, _>("users_id_seq");
39/// assert_eq!(next_id.sql(), "NEXTVAL ($1)");
40/// ```
41pub fn nextval<'a, V, E>(
42    sequence: E,
43) -> SQLExpr<
44    'a,
45    V,
46    <V::DialectMarker as DialectTypes>::BigInt,
47    NonNull,
48    Scalar,
49    ScopeOnly<E::Sources>,
50>
51where
52    V: SQLParam + 'a,
53    V::DialectMarker: DialectSupports<feature::Sequence>,
54    E: Expr<'a, V>,
55    E::SQLType: Textual,
56{
57    SQLExpr::new(SQL::func("NEXTVAL", sequence.into_sql()))
58}
59
60/// The value most recently returned by `NEXTVAL` for a sequence in this
61/// session (`CURRVAL`), on PostgreSQL.
62///
63/// PostgreSQL raises an error if `NEXTVAL` has not been called for the
64/// sequence in the current session. The argument is the sequence name as
65/// text. The result is `int8` and never NULL.
66///
67/// # Examples
68///
69/// ```rust
70/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
71/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
72/// # #[derive(Clone, Debug)] struct Value(String);
73/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
74/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
75/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
76/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
77/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
78/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
79/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
80/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
81/// let current_id = currval::<Value, _>("users_id_seq");
82/// assert_eq!(current_id.sql(), "CURRVAL ($1)");
83/// ```
84pub fn currval<'a, V, E>(
85    sequence: E,
86) -> SQLExpr<
87    'a,
88    V,
89    <V::DialectMarker as DialectTypes>::BigInt,
90    NonNull,
91    Scalar,
92    ScopeOnly<E::Sources>,
93>
94where
95    V: SQLParam + 'a,
96    V::DialectMarker: DialectSupports<feature::Sequence>,
97    E: Expr<'a, V>,
98    E::SQLType: Textual,
99{
100    SQLExpr::new(SQL::func("CURRVAL", sequence.into_sql()))
101}
102
103/// Sets a sequence's current value (`SETVAL`), on PostgreSQL.
104///
105/// The next `NEXTVAL` returns `value + 1`. `sequence` must be text and `value`
106/// an integer. The result is the value set, as `int8`, nullable if either
107/// argument is.
108///
109/// # Examples
110///
111/// ```rust
112/// # use drizzle_core::dialect::{Dialect, DialectTypes, PostgresDialect as D};
113/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
114/// # #[derive(Clone, Debug)] struct Value(String);
115/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::PostgreSQL; type DialectMarker = D; }
116/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
117/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
118/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
119/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
120/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
121/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
122/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
123/// let reset = setval::<Value, _, _>("users_id_seq", 100);
124/// assert_eq!(reset.sql(), "SETVAL ($1, $2)");
125/// ```
126#[allow(clippy::type_complexity)]
127pub fn setval<'a, V, E, N>(
128    sequence: E,
129    value: N,
130) -> SQLExpr<
131    'a,
132    V,
133    <V::DialectMarker as DialectTypes>::BigInt,
134    <E::Nullable as Nullability>::Or<N::Nullable>,
135    <E::Aggregate as AggregateKind>::Or<N::Aggregate>,
136    (E::Sources, N::Sources),
137>
138where
139    V: SQLParam + 'a,
140    V::DialectMarker: DialectSupports<feature::Sequence>,
141    E: Expr<'a, V>,
142    E::SQLType: Textual,
143    N: Expr<'a, V>,
144    N::SQLType: crate::types::Integral,
145    N::Nullable: Nullability,
146    N::Aggregate: AggregateKind,
147{
148    SQLExpr::new(SQL::func(
149        "SETVAL",
150        sequence
151            .into_sql()
152            .push(crate::Token::COMMA)
153            .append(value.into_sql()),
154    ))
155}