Repository: diesel-rs/diesel
File: diesel/src/collation/mod.rs (Rust)

Code before:
impl fmt::Display for C {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "\"C\"")
    }
}

/// The `NOCASE` collation.
///
/// This collation is ASCII-only case-insensitive.
/// It is supported by SQLite.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg(feature = "sqlite")]
pub struct NoCase;

#[cfg(feature = "sqlite")]
impl fmt::Display for NoCase {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "NOCASE")
    }
}

/// The `POSIX` collation.
///
/// This collation is byte-wise, with only ASCII A-Z treated as letters.
/// It is supported by PostgreSQL.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg(feature = "postgres")]
pub struct Posix;

#[cfg(feature = "postgres")]
impl fmt::Display for Posix {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "\"POSIX\"")
    }
}

/// The `RTRIM` collation.
///
/// This collation ignores trailing spaces.
/// It is supported by SQLite.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg(feature = "sqlite")]
pub struct RTrim;

#[cfg(feature = "sqlite")]
impl fmt::Display for RTrim {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "RTRIM")
    }
}


Review comment (bug):
I'm sorry to bring up yet another request, but I had something different in mind here. The current implementation would allow to pass a `collation::Binary` to a postgres query if you enable both the `sqlite` and `postgres` feature at the same time. This is something I would like to avoid. 

Instead of the current implementation I would prefer using more of diesels query builder to exactly prevent this situation

Something like that would be closer to what I have in mind:


```suggestion
pub trait Collation {}

/// The `BINARY` collation.
///
/// This collation is binary, case-sensitive, and locale-free.
/// It is supported by SQLite.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, QueryId)]
#[cfg(feature = "sqlite")]
pub struct Binary;

impl Collation for Binary {}

#[cfg(feature = "sqlite")]
impl QueryFragment<Sqlite> for Binary {
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        pass.push_sql("BINARY");
        Ok(())
    }
}
// same impl for Mysql


/// The `C` collation.
///
/// This collation is byte-wise, with only ASCII A-Z treated as letters.
/// It is supported by PostgreSQL.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, QueryId)]
#[cfg(feature = "postgres")]
pub struct C;

impl Collation for C {}

#[cfg(feature = "postgres")]
impl QueryFragment<Sqlite> for C {
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        pass.push_sql("BINARY");
        Ok(())
    }
}
```

then the `TextExpressionMethod` crate should have a single `collate` method that's defined like this:

```
fn collate<C>(self, collation: C) -> dsl::Collate<Self, C> where C: Collation {
    Grouped(Collate::new(self, collation))
}
```

This allows us to use static query ids (and therefore prepared statement caching) for all collations but `Custom`. Also it makes everything more strictly typed and harder to mix up collations between backends in multi-backend code-bases.

Code after:
#[cfg(feature = "sqlite")]
impl QueryFragment<crate::sqlite::Sqlite> for Binary {
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, crate::sqlite::Sqlite>) -> QueryResult<()> {
        out.push_sql("BINARY");
        Ok(())
    }
}

/// The `C` collation.
///
/// This collation is byte-wise, with only ASCII A-Z treated as letters.
/// It is supported by PostgreSQL.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, QueryId)]
#[cfg(feature = "postgres_backend")]
pub struct C;

#[cfg(feature = "postgres_backend")]
impl Collation for C {}

#[cfg(feature = "postgres_backend")]
impl QueryFragment<crate::pg::Pg> for C {
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, crate::pg::Pg>) -> QueryResult<()> {
        out.push_sql("\"C\"");
        Ok(())
    }
}

/// The `NOCASE` collation.
///
/// This collation is ASCII-only case-insensitive.
/// It is supported by SQLite.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, QueryId)]
#[cfg(feature = "sqlite")]
pub struct NoCase;

#[cfg(feature = "sqlite")]
impl Collation for NoCase {}

#[cfg(feature = "sqlite")]
impl QueryFragment<crate::sqlite::Sqlite> for NoCase {
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, crate::sqlite::Sqlite>) -> QueryResult<()> {
        out.push_sql("NOCASE");
        Ok(())
    }
}

/// The `POSIX` collation.
///
/// This collation is byte-wise, with only ASCII A-Z treated as letters.
/// It is supported by PostgreSQL.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, QueryId)]