Skip to main content

nodedb_sql/resolver/
column_naming.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! How a column reference names its field in the rows a clause reads.
4//!
5//! A join's merged rows key every field `qualifier.column`, so a clause read
6//! over them rewrites each column reference to its owning relation's
7//! qualifier. A join aggregate's group rows key fields by bare column name,
8//! so a clause read over them drops the qualifier.
9
10use crate::error::Result;
11use crate::resolver::columns::{ResolvedTable, TableScope};
12
13/// How a column reference to a relation of the scope names its field in the
14/// rows the clause reads.
15#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
16pub enum ColumnNaming {
17    /// The reference keeps the qualifier it is written with.
18    #[default]
19    AsWritten,
20    /// The rows are a join's merged rows, keyed `qualifier.column`. Every
21    /// reference carries its owning relation's row qualifier.
22    JoinRow,
23    /// The rows are a join aggregate's output rows, keyed by bare column
24    /// name. Every reference drops its relation qualifier.
25    OutputRow,
26}
27
28/// Where an unqualified column reference resolves.
29#[derive(Debug, Clone, Copy)]
30pub enum BareColumn<'a> {
31    /// A SELECT output name.
32    Output,
33    /// A relation of this scope.
34    Relation(&'a ResolvedTable),
35    /// A relation of an enclosing query.
36    Outer,
37}
38
39impl TableScope {
40    /// The qualifier an unqualified column reference is rewritten to.
41    ///
42    /// `Some` only over a join's merged rows, for a column of one of this
43    /// scope's own relations that the merged row keys by qualifier. The
44    /// reference is checked in every naming.
45    pub fn bare_column_qualifier(&self, column: &str) -> Result<Option<String>> {
46        let resolved = self.resolve_bare(column)?;
47        Ok(match (self.column_naming(), resolved) {
48            (ColumnNaming::JoinRow, BareColumn::Relation(table)) => {
49                table.row_qualifier().map(str::to_owned)
50            }
51            (ColumnNaming::JoinRow, BareColumn::Output | BareColumn::Outer)
52            | (ColumnNaming::AsWritten | ColumnNaming::OutputRow, _) => None,
53        })
54    }
55
56    /// The qualifier a qualified column reference converts with.
57    ///
58    /// A qualifier naming one of this scope's own relations becomes that
59    /// relation's row qualifier over a join's merged rows, and is dropped
60    /// over a join aggregate's output rows. Any other qualifier, and every
61    /// qualifier in `AsWritten` naming, is kept.
62    pub fn qualified_column_qualifier(&self, table_ref: &str) -> Option<String> {
63        match (self.column_naming(), self.table_by_ref(table_ref)) {
64            (ColumnNaming::JoinRow, Some(table)) => table.row_qualifier().map(str::to_owned),
65            (ColumnNaming::OutputRow, Some(_)) => None,
66            (ColumnNaming::AsWritten, _)
67            | (ColumnNaming::JoinRow | ColumnNaming::OutputRow, None) => Some(table_ref.to_owned()),
68        }
69    }
70}