Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upTimestamp/Timestamptz coercion for "now - '30 days'" #1514
Comments
This comment has been minimized.
jeremybmerrill
commented
Feb 27, 2018
|
@searing : Were you able to find a solution to this? I have the same problem (minus the nullable stuff), so "type mismatch resolving |
This comment has been minimized.
searing
commented
Feb 28, 2018
|
No, my temporary solution is to use |
This comment has been minimized.
jeremybmerrill
commented
Feb 28, 2018
|
@searing Ah okay. Thanks! |
This comment has been minimized.
|
I'm not a maintainer, but I was looking at how this might be solved just out of curiosity. I think that the root of the problem is that the /// Represents the SQL `CURRENT_TIMESTAMP` constant. This is equivalent to the
/// `NOW()` function on backends that support it.
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, QueryId)]
pub struct now;
impl Expression for now {
type SqlType = Timestamp;
}When you subtract an impl Sub for super::Timestamp {
type Rhs = super::Interval;
type Output = super::Timestamp;
}(And an off-handed comment: I found it helpful to read the obtuse error produced by the compiler backwards. When it says
#[cfg(feature = "postgres")]
impl AsExpression<Timestamptz> for now {
type Expression = Coerce<now, Timestamptz>;
fn as_expression(self) -> Self::Expression {
Coerce::new(self)
}
}
#[cfg(feature = "postgres")]
impl AsExpression<Nullable<Timestamptz>> for now {
type Expression = Coerce<now, Nullable<Timestamptz>>;
fn as_expression(self) -> Self::Expression {
Coerce::new(self)
}
}But it doesn't seem to happen soon enough. I would think that even after the interval subtraction, it should be able to coerce the resulting I was able to fix the problem by introducing a new struct diff --git a/diesel/src/expression/functions/date_and_time.rs b/diesel/src/expression/functions/date_and_time.rs
index 1461b8e7..d931bce9 100644
--- a/diesel/src/expression/functions/date_and_time.rs
+++ b/diesel/src/expression/functions/date_and_time.rs
@@ -46,6 +46,35 @@ let today: chrono::NaiveDate = diesel::select(date(now)).first(&connection).unwr
",
"The return type of [`date(expr)`](../dsl/fn.date.html)");
+#[allow(non_camel_case_types)]
+#[cfg(feature = "postgres")]
+#[derive(Debug, Copy, Clone, QueryId)]
+pub struct nowtz;
+
+#[cfg(feature = "postgres")]
+impl Expression for nowtz {
+ type SqlType = Timestamptz;
+}
+
+#[cfg(feature = "postgres")]
+impl NonAggregate for nowtz {}
+
+#[cfg(feature = "postgres")]
+impl<DB: Backend> QueryFragment<DB> for nowtz {
+ fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
+ out.push_sql("CURRENT_TIMESTAMP");
+ Ok(())
+ }
+}
+
+#[cfg(feature = "postgres")]
+impl_selectable_expression!(nowtz);
+
+#[cfg(feature = "postgres")]
+operator_allowed!(nowtz, Add, add);
+#[cfg(feature = "postgres")]
+operator_allowed!(nowtz, Sub, sub);
+
#[cfg(feature = "postgres")]
use expression::AsExpression;
#[cfg(feature = "postgres")]
diff --git a/diesel/src/sql_types/ops.rs b/diesel/src/sql_types/ops.rs
index afb35d67..46f53678 100644
--- a/diesel/src/sql_types/ops.rs
+++ b/diesel/src/sql_types/ops.rs
@@ -170,3 +170,27 @@ impl Sub for super::Nullable<super::Timestamp> {
type Rhs = super::Nullable<super::Interval>;
type Output = super::Nullable<super::Timestamp>;
}
+
+#[cfg(feature = "postgres")]
+impl Add for super::Timestamptz {
+ type Rhs = super::Interval;
+ type Output = super::Timestamptz;
+}
+
+#[cfg(feature = "postgres")]
+impl Add for super::Nullable<super::Timestamptz> {
+ type Rhs = super::Nullable<super::Interval>;
+ type Output = super::Nullable<super::Timestamptz>;
+}
+
+#[cfg(feature = "postgres")]
+impl Sub for super::Timestamptz {
+ type Rhs = super::Interval;
+ type Output = super::Timestamptz;
+}
+
+#[cfg(feature = "postgres")]
+impl Sub for super::Nullable<super::Timestamptz> {
+ type Rhs = super::Nullable<super::Interval>;
+ type Output = super::Nullable<super::Timestamptz>;
+}
And then changing your line above to use let foo2 = test_table::table
.filter(test_table::foo.lt((nowtz - 30.days()).nullable()))... but I assume that there's a much more elegant way to go about this which is a little beyond my grasp. If anyone more familiar with the type system could give me a high level explanation for how this might be generally solved, I could try my hand at sending over a patch. |
This comment has been minimized.
searing
commented
Feb 28, 2018
|
I suppose you could introduce a new SQL type (perhaps |
This comment has been minimized.
So the idea there would be that
I took a quick look at the datetime docs in Postgres and interestingly,
Yeah, I tried my current solution to verify that I had at least a partial understanding of the problem, but it's not very good. |
searing commentedJan 26, 2018
I'm having trouble expressing "now - '30 days'" in a filter expression. This short code sample illustrates what I want:
This fails to compile at "foo2" with the following error:
Being able to get rid of the "nullable()" call would also be nice, but might be a separate issue (or difficult/impossible).