diff --git a/Cargo.toml b/Cargo.toml index 07ef82f3..89a83623 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,17 +30,25 @@ path = "src/lib.rs" [dependencies] inherent = "1.0" sea-query-derive = { version = "0.4.2", path = "sea-query-derive", default-features = false, optional = true } -serde_json = { version = "1", default-features = false, optional = true, features = ["std"] } -chrono = { version = "0.4.27", default-features = false, optional = true, features = ["clock"] } +serde_json = { version = "1", default-features = false, optional = true, features = [ + "std", +] } +chrono = { version = "0.4.27", default-features = false, optional = true, features = [ + "clock", +] } postgres-types = { version = "0", default-features = false, optional = true } pgvector = { version = "~0.4", default-features = false, optional = true } rust_decimal = { version = "1", default-features = false, optional = true } bigdecimal = { version = "0.4", default-features = false, optional = true } uuid = { version = "1", default-features = false, optional = true } -time = { version = "0.3.36", default-features = false, optional = true, features = ["macros", "formatting"] } +time = { version = "0.3.36", default-features = false, optional = true, features = [ + "macros", + "formatting", +] } ipnetwork = { version = "0.20", default-features = false, optional = true } mac_address = { version = "1.1", default-features = false, optional = true } ordered-float = { version = "3.4", default-features = false, optional = true } +strum_macros = { version = "0.26" } [dev-dependencies] sea-query = { path = ".", features = ["tests-cfg"] } diff --git a/src/backend/postgres/query.rs b/src/backend/postgres/query.rs index f0650110..328c196e 100644 --- a/src/backend/postgres/query.rs +++ b/src/backend/postgres/query.rs @@ -124,6 +124,7 @@ impl QueryBuilder for PostgresQueryBuilder { PgFunction::GenRandomUUID => "GEN_RANDOM_UUID", PgFunction::JsonBuildObject => "JSON_BUILD_OBJECT", PgFunction::JsonAgg => "JSON_AGG", + PgFunction::DateTrunc => "DATE_TRUNC", #[cfg(feature = "postgres-array")] PgFunction::Any => "ANY", #[cfg(feature = "postgres-array")] diff --git a/src/extension/postgres/func.rs b/src/extension/postgres/func.rs index 67fc0b2a..0c2181e4 100644 --- a/src/extension/postgres/func.rs +++ b/src/extension/postgres/func.rs @@ -1,6 +1,6 @@ //! For calling built-in Postgres SQL functions. -use crate::{expr::*, func::*}; +use crate::{expr::*, func::*, PgDateTruncUnit}; /// Functions #[derive(Debug, Clone, PartialEq)] @@ -16,6 +16,7 @@ pub enum PgFunction { GenRandomUUID, JsonBuildObject, JsonAgg, + DateTrunc, #[cfg(feature = "postgres-array")] Any, #[cfg(feature = "postgres-array")] @@ -384,6 +385,45 @@ impl PgFunc { FunctionCall::new(Function::PgFunction(PgFunction::JsonBuildObject)).args(args) } + /// Call the `DATE_TRUNC` function. Postgres only. + /// + /// # Examples + /// + /// ``` + /// use sea_query::{tests_cfg::*, *}; + /// + /// let query = Query::select() + /// .expr(PgFunc::date_trunc( + /// PgDateTruncUnit::Day, + /// Expr::val("2020-01-01"), + /// )) + /// .to_owned(); + /// + /// assert_eq!( + /// query.to_string(PostgresQueryBuilder), + /// r#"SELECT DATE_TRUNC('day', '2020-01-01')"# + /// ); + /// + /// let query = Query::select() + /// .expr(PgFunc::date_trunc( + /// PgDateTruncUnit::Microseconds, + /// Expr::val("2020-01-01"), + /// )) + /// .to_owned(); + /// + /// assert_eq!( + /// query.to_string(PostgresQueryBuilder), + /// r#"SELECT DATE_TRUNC('microseconds', '2020-01-01')"# + /// ); + /// ``` + pub fn date_trunc(unit: PgDateTruncUnit, expr: T) -> FunctionCall + where + T: Into, + { + FunctionCall::new(Function::PgFunction(PgFunction::DateTrunc)) + .args([Expr::val(unit.to_string()).into(), expr.into()]) + } + /// Call the `JSON_AGG` function. Postgres only. /// /// # Examples diff --git a/src/table/column.rs b/src/table/column.rs index 4f6d2ba9..953c2cb3 100644 --- a/src/table/column.rs +++ b/src/table/column.rs @@ -1,3 +1,5 @@ +use strum_macros::Display; + use crate::{expr::*, types::*}; /// Specification of a table column @@ -200,6 +202,25 @@ pub enum PgInterval { MinuteToSecond, } +// All possible inputs to DATE_TRUNC (https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC) +#[derive(Debug, Clone, Eq, PartialEq, Display)] +#[strum(serialize_all = "lowercase")] +pub enum PgDateTruncUnit { + Microseconds, + Milliseconds, + Second, + Minute, + Hour, + Day, + Week, + Month, + Quarter, + Year, + Decade, + Century, + Millennium, +} + impl ColumnDef { /// Construct a table column pub fn new(name: T) -> Self