From bf959a2534d23c5c667ea3914bc57d6ef2aeb2b2 Mon Sep 17 00:00:00 2001 From: Tobias Wiese Date: Wed, 3 Dec 2025 21:49:13 +0100 Subject: Initial commit Signed-off-by: Tobias Wiese --- src/db.rs | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/db.rs (limited to 'src/db.rs') diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..b088f0a --- /dev/null +++ b/src/db.rs @@ -0,0 +1,149 @@ +#![allow(non_camel_case_types)] + +use diesel::backend::Backend; +use diesel::expression::{ + IsContainedInGroupBy, ValidGrouping, is_aggregate, is_contained_in_group_by, +}; +use diesel::internal::table_macro::{FromClause, SelectStatement}; +use diesel::prelude::*; +use diesel::query_builder::{AsQuery, AstPass, QueryFragment, QueryId}; +use diesel::query_source::{AppearsInFromClause, Once, Table as TableTrait}; +use diesel::sql_types::{Text, Uuid}; + +pub use self::columns::*; + +pub mod columns { + use super::*; + + macro_rules! col { + ($col:ident, $sql_type:ty) => { + pub struct $col; + + impl Expression for $col { + type SqlType = $sql_type; + } + + impl<'a, QS> AppearsOnTable for $col where + QS: AppearsInFromClause, Count = Once> + { + } + + impl<'a> SelectableExpression> for $col {} + + impl ValidGrouping<()> for $col { + type IsAggregate = is_aggregate::No; + } + + impl ValidGrouping for $col + where + GB: IsContainedInGroupBy<$col, Output = is_contained_in_group_by::Yes>, + { + type IsAggregate = is_aggregate::Yes; + } + + impl<'a> Column for $col { + type Table = Table<'static>; + + const NAME: &'static str = stringify!($col); + } + + impl QueryFragment for $col + where + DB: Backend, + { + fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> { + pass.push_identifier(<$col as Column>::NAME)?; + Ok(()) + } + } + + impl QueryId for $col { + type QueryId = $col; + + const HAS_STATIC_QUERY_ID: bool = true; + } + }; + } + + col!(id, Uuid); + col!(username, Text); + col!(token, Text); +} + +//pub const all_columns: as TableTrait>::AllColumns = (id, username, token); + +pub type SqlType = (Uuid, Text, Text); + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct Table<'a> { + name: &'a str, + schema: Option<&'a str>, +} + +impl<'a> Table<'a> { + pub fn new(name: &'a str, schema: Option<&'a str>) -> Self { + Self { name, schema } + } +} + +impl QuerySource for Table<'_> { + type FromClause = Self; + type DefaultSelection = ::AllColumns; + + fn from_clause(&self) -> Self::FromClause { + self.clone() + } + + fn default_selection(&self) -> Self::DefaultSelection { + ::all_columns() + } +} + +impl AsQuery for Table<'_> { + type SqlType = SqlType; + type Query = SelectStatement>; + + fn as_query(self) -> Self::Query { + SelectStatement::simple(self) + } +} + +impl TableTrait for Table<'_> +where + Self: QuerySource + AsQuery, +{ + type PrimaryKey = id; + type AllColumns = (id, username, token); + + fn primary_key(&self) -> Self::PrimaryKey { + id + } + + fn all_columns() -> Self::AllColumns { + (id, username, token) + } +} + +impl QueryFragment for Table<'_> +where + DB: Backend, +{ + fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> { + if let Some(ref schema) = self.schema { + pass.push_identifier(schema)?; + pass.push_sql("."); + } + pass.push_identifier(self.name)?; + Ok(()) + } +} + +impl QueryId for Table<'_> { + type QueryId = (); + + const HAS_STATIC_QUERY_ID: bool = false; +} + +impl AppearsInFromClause> for Table<'_> { + type Count = Once; +} -- cgit v1.2.3