Skip to main content

qraft_core/select/
project.rs

1//! Projection lowering for `select` and `returning` clauses.
2
3use crate::{
4    alias::Aliased,
5    count_idents,
6    expression::Expression,
7    impl_for_all_tuples,
8    lower::{Instructions, LowerCtx},
9    span::TextSpan,
10};
11
12/// Lowers projection values into a separated list of selected expressions.
13pub trait LowerProject {
14    /// Appends the projection to the lowering context.
15    fn lower_project(self, ctx: &mut LowerCtx);
16}
17
18/// Marker for `*`.
19#[derive(Debug, Clone, Copy)]
20pub struct Star {
21    _priv: (),
22}
23
24/// Returns a projection value for `*`.
25pub fn star() -> Star {
26    Star { _priv: () }
27}
28
29impl LowerProject for Star {
30    fn lower_project(self, ctx: &mut LowerCtx) {
31        let _ = ctx.lower_star();
32    }
33}
34
35impl<E> LowerProject for E
36where
37    E: Expression,
38{
39    fn lower_project(self, ctx: &mut LowerCtx) {
40        let _ = self.lower(ctx);
41    }
42}
43
44impl<E> LowerProject for Aliased<E>
45where
46    E: Expression,
47{
48    fn lower_project(self, ctx: &mut LowerCtx) {
49        let inner = self.inner.lower(ctx);
50        let _ = ctx.lower_alias(self.alias, inner);
51    }
52}
53
54impl LowerProject for &'static str {
55    fn lower_project(self, ctx: &mut LowerCtx) {
56        let span = TextSpan::new_static(self);
57        ctx.instrs.push_column(None, span);
58    }
59}
60
61impl LowerProject for Aliased<&'static str> {
62    fn lower_project(self, ctx: &mut LowerCtx) {
63        self.inner.lower_project(ctx);
64        let _ = ctx.lower_alias(self.alias, 1);
65    }
66}
67
68/// A table-qualified column used by generated pivot metadata.
69#[derive(Debug, PartialEq, Eq, Hash)]
70pub struct ColumnOf {
71    /// Table name to qualify the column with.
72    pub table: &'static str,
73    /// Column name to emit.
74    pub name: &'static str,
75}
76
77impl ColumnOf {
78    /// Creates a table-qualified column description.
79    pub const fn new(table: &'static str, name: &'static str) -> Self {
80        Self { table, name }
81    }
82}
83
84impl LowerProject for ColumnOf {
85    fn lower_project(self, ctx: &mut LowerCtx) {
86        let _ = ctx.lower_column(Some(self.table), self.name);
87    }
88}
89
90impl LowerProject for Aliased<ColumnOf> {
91    fn lower_project(self, ctx: &mut LowerCtx) {
92        self.inner.lower_project(ctx);
93        let _ = ctx.lower_alias(self.alias, 1);
94    }
95}
96
97impl<T: LowerProject, const N: usize> LowerProject for [T; N] {
98    fn lower_project(self, ctx: &mut LowerCtx) {
99        let len = self.len();
100        for item in self {
101            item.lower_project(ctx);
102        }
103        ctx.instrs.push_seperated(len);
104    }
105}
106
107impl<T: LowerProject> LowerProject for Vec<T> {
108    fn lower_project(self, ctx: &mut LowerCtx) {
109        let len = self.len();
110        for item in self {
111            item.lower_project(ctx);
112        }
113        ctx.instrs.push_seperated(len);
114    }
115}
116
117// impl for tuples
118// todo: change here when stable https://github.com/rust-lang/rust/issues/83527
119macro_rules! impl_project_macro {
120    ($($T:ident),+) => {
121        impl<$($T,)+> LowerProject for ($($T,)+)
122        where
123            $($T: LowerProject,)+
124        {
125            fn lower_project(self, ctx: &mut LowerCtx) {
126                #[allow(non_snake_case)]
127                let ($($T,)+) = self;
128                $(
129                    $T.lower_project(ctx);
130                )+
131                let count = count_idents!($($T,)+);
132                ctx.instrs.push_seperated(count);
133            }
134        }
135    };
136}
137
138impl_for_all_tuples!(impl_project_macro);