Repository: diesel-rs/diesel
File: diesel/src/expression_methods/global_expression_methods.rs (Rust)

Code before:
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = &mut establish_connection();
    /// #
    /// use diesel::sql_types;
    ///
    /// let data = diesel::select(
    ///     12_i32
    ///         .into_sql::<sql_types::Int4>()
    ///         .cast::<sql_types::Text>(),
    /// )
    /// .first::<String>(connection)?;
    /// assert_eq!("12", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn cast<ST>(self) -> dsl::Cast<Self, ST>
    where
        ST: SingleValue,
        Self::SqlType: cast::CastsTo<ST>,
    {
        cast::Cast::new(self)
    }

    /// Generates a `CAST(expr AS sql_type)` expression, this version does not check the castability, like [`cast()`](Self::cast).
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = &mut establish_connection();
    /// #
    /// use diesel::sql_types;
    ///
    /// let data = diesel::select(
    ///     "12"
    ///         .into_sql::<sql_types::Text>()
    ///         .faillible_cast::<sql_types::Int4>(),
    /// )
    /// .first::<i32>(connection)?;
    /// assert_eq!(12i32, data);
    /// #     Ok(())
    /// # }

Review comment (bug):
Ooh I thought you were suggesting that we still check "castability" in the sense that it "may work depending on the value", but not "castability" in the sense that it "will always work from this type to that type".

And then we'd move the Int8 -> Int4 to fallible cast for example.

It seems that we could do that just by having a separate `FaillibleCast` trait that would replace `Cast` for the faillible cast.

(We could also do that by having an `IsFaillible` associated type on `Cast` but it doesn't look like we would have a use for guaranteed disjointness here so I would tend to favor the simpler interface that gives us easy access to custom `on_unimplemented` error message.)

While that removes the ability to use casts that are un-registered by Diesel, I would tend to believe that we can get most of them in Diesel fairly quickly...

WDYT?

Code after:
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = &mut establish_connection();
    /// #
    /// use diesel::sql_types;
    ///
    /// let data = diesel::select(
    ///     12_i32
    ///         .into_sql::<sql_types::Int4>()
    ///         .cast::<sql_types::Text>(),
    /// )
    /// .first::<String>(connection)?;
    /// assert_eq!("12", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn cast<ST>(self) -> dsl::Cast<Self, ST>
    where
        ST: SingleValue,
        Self::SqlType: cast::CastsTo<ST>,
    {
        cast::Cast::new(self)
    }

    /// Generates a `CAST(expr AS sql_type)` expression, this version does not check the castability, like [`cast()`](Self::cast).
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = &mut establish_connection();
    /// #
    /// use diesel::sql_types;
    ///
    /// let data = diesel::select(
    ///     "12"
    ///         .into_sql::<sql_types::Text>()
    ///         .fallible_cast::<sql_types::Int8>(),
    /// )
    /// .first::<i64>(connection)?;
    /// assert_eq!(12i64, data);
    /// #     Ok(())
    /// # }