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}