LCOV - code coverage report
Current view: top level - dashql-core/src/formatter - create.rs Coverage Total Hit
Test: DashQL 915828b Lines: 95.6 % 180 172
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : //! CREATE, DROP, ATTACH and SET statements.
       2              : 
       3              : use dashql_parser::attrs;
       4              : use super::{FmtReg, Formatter, FormattingJoinPolicy, K};
       5              : use dashql_buffers::parser::{Node, NodeType, OnCommitOption, TempType};
       6              : 
       7              : impl<'a> Formatter<'a> {
       8          105 :     pub(super) fn format_temp_type(&self, node: &'a Node) -> FmtReg {
       9          105 :         let f = &self.fmt;
      10          105 :         match TempType(super::value_u8(node)) {
      11           51 :             TempType::DEFAULT | TempType::LOCAL => f.text("temporary"),
      12            3 :             TempType::GLOBAL => f.text("global temporary"),
      13            3 :             TempType::UNLOGGED => f.text("unlogged"),
      14           48 :             TempType::NONE => f.empty(),
      15            0 :             _ => self.format_unimplemented(node),
      16              :         }
      17          105 :     }
      18              : 
      19           33 :     pub(super) fn format_on_commit_option(&self, node: &'a Node) -> FmtReg {
      20           33 :         let f = &self.fmt;
      21           33 :         match OnCommitOption(super::value_u8(node)) {
      22           15 :             OnCommitOption::DROP => f.text("on commit drop"),
      23            9 :             OnCommitOption::DELETE_ROWS => f.text("on commit delete rows"),
      24            9 :             OnCommitOption::PRESERVE_ROWS => f.text("on commit preserve rows"),
      25            0 :             OnCommitOption::NOOP => f.empty(),
      26            0 :             _ => self.format_unimplemented(node),
      27              :         }
      28           33 :     }
      29              : 
      30          335 :     pub(super) fn format_create(&self, node_id: usize) -> FmtReg {
      31          335 :         let f = &self.fmt;
      32          335 :         let node: &'a Node = &self.ast[node_id];
      33          335 :         if !self.node_states[node_id].is_statement_root {
      34            1 :             return self.format_unimplemented(node);
      35          334 :         }
      36          334 :         let [name, elements, if_not_exists, temp, on_commit] = attrs!(self.children(node), [
      37              :                 K::SQL_CREATE_TABLE_NAME,
      38              :                 K::SQL_CREATE_TABLE_ELEMENTS,
      39              :                 K::SQL_CREATE_TABLE_IF_NOT_EXISTS,
      40              :                 K::SQL_CREATE_TABLE_TEMP,
      41              :                 K::SQL_CREATE_TABLE_ON_COMMIT,
      42              :             ],
      43              :         );
      44          334 :         let (Some(name), Some(elements)) = (name, elements) else { return self.format_unimplemented(node) };
      45              : 
      46          334 :         let mut header_parts = vec![f.text("create ")];
      47          334 :         if let Some(temp) = temp {
      48           33 :             header_parts.push(self.reg(temp));
      49           33 :             header_parts.push(f.text(" "));
      50          301 :         }
      51          334 :         header_parts.push(f.text("table "));
      52          334 :         if if_not_exists.is_some() {
      53           15 :             header_parts.push(f.text("if not exists "));
      54          319 :         }
      55          334 :         header_parts.push(self.reg(name));
      56          334 :         let header = f.concat(&header_parts);
      57              : 
      58          334 :         let mut table_elements = f.empty();
      59          334 :         if elements.children_count() > 0 {
      60          334 :             let mut parts = Vec::with_capacity(elements.children_count() as usize);
      61         1387 :             for element in self.children(elements) {
      62         1387 :                 let reg = self.reg(element);
      63         1387 :                 if reg == 0 {
      64            0 :                     return self.format_unimplemented(node);
      65         1387 :                 }
      66         1387 :                 parts.push(reg);
      67              :             }
      68          334 :             let (inline_separator, break_separator) = self.comma_separators();
      69          334 :             table_elements = f.join(&parts, inline_separator, break_separator, None, false);
      70            0 :         }
      71              : 
      72          334 :         let element_block = if elements.children_count() > 0 { f.parenthesized(table_elements) } else { f.text("()") };
      73          334 :         let mut statement = f.concat(&[header, f.text(" "), element_block]);
      74          334 :         if let Some(on_commit) = on_commit {
      75           24 :             statement = f.concat(&[statement, f.text(" "), self.reg(on_commit)]);
      76          310 :         }
      77          334 :         statement
      78          335 :     }
      79              : 
      80           39 :     pub(super) fn format_create_as(&self, node: &'a Node) -> FmtReg {
      81           39 :         let f = &self.fmt;
      82           39 :         let [name, columns, if_not_exists, temp, statement, with_data, on_commit] = attrs!(self.children(node), [
      83              :                 K::SQL_CREATE_AS_NAME,
      84              :                 K::SQL_CREATE_AS_COLUMNS,
      85              :                 K::SQL_CREATE_AS_IF_NOT_EXISTS,
      86              :                 K::SQL_CREATE_AS_TEMP,
      87              :                 K::SQL_CREATE_AS_STATEMENT,
      88              :                 K::SQL_CREATE_AS_WITH_DATA,
      89              :                 K::SQL_CREATE_AS_ON_COMMIT,
      90              :             ],
      91              :         );
      92           39 :         let (Some(name), Some(statement)) = (name, statement) else { return self.format_unimplemented(node) };
      93              : 
      94           39 :         let mut parts = vec![f.text("create ")];
      95           39 :         if let Some(temp) = temp {
      96           15 :             parts.push(self.reg(temp));
      97           15 :             parts.push(f.text(" "));
      98           24 :         }
      99           39 :         parts.push(f.text("table "));
     100           39 :         if if_not_exists.is_some() {
     101           15 :             parts.push(f.text("if not exists "));
     102           33 :         }
     103           39 :         parts.push(self.reg(name));
     104           39 :         if let Some(columns) = columns.filter(|c| c.children_count() > 0) {
     105            6 :             parts.push(f.parenthesized(self.reg(columns)));
     106           33 :         }
     107           39 :         if let Some(on_commit) = on_commit {
     108            9 :             parts.push(f.text(" "));
     109            9 :             parts.push(self.reg(on_commit));
     110           30 :         }
     111           39 :         parts.push(f.text(" as"));
     112              :         // The query follows on the same line only if the whole statement fits, like the query of a view
     113           39 :         let header = f.concat(&parts);
     114           39 :         let body = self.space_join(&[header, self.reg(statement)], FormattingJoinPolicy::BreakAllOrNone, false);
     115           39 :         match with_data {
     116            9 :             Some(with_data) => {
     117            9 :                 let include_data = with_data.node_type() == NodeType::BOOL && with_data.children_begin_or_value() != 0;
     118            9 :                 f.concat(&[body, f.text(if include_data { " with data" } else { " with no data" })])
     119              :             }
     120           30 :             None => body,
     121              :         }
     122           39 :     }
     123              : 
     124           24 :     pub(super) fn format_view(&self, node: &'a Node) -> FmtReg {
     125           24 :         let f = &self.fmt;
     126           24 :         let [name, columns, or_replace, temp, statement] = attrs!(self.children(node), [K::SQL_VIEW_NAME, K::SQL_VIEW_COLUMNS, K::SQL_VIEW_OR_REPLACE, K::SQL_VIEW_TEMP, K::SQL_VIEW_STATEMENT],
     127              :         );
     128           24 :         let (Some(name), Some(statement)) = (name, statement) else { return self.format_unimplemented(node) };
     129              : 
     130           24 :         let mut parts = vec![f.text("create ")];
     131           24 :         if or_replace.is_some() {
     132            6 :             parts.push(f.text("or replace "));
     133           18 :         }
     134           24 :         if let Some(temp) = temp {
     135            6 :             parts.push(self.reg(temp));
     136            6 :             parts.push(f.text(" "));
     137           18 :         }
     138           24 :         parts.push(f.text("view "));
     139           24 :         parts.push(self.reg(name));
     140           24 :         if let Some(columns) = columns.filter(|c| c.children_count() > 0) {
     141            3 :             parts.push(f.parenthesized(self.reg(columns)));
     142           21 :         }
     143           24 :         parts.push(f.text(" as"));
     144           24 :         let header = f.concat(&parts);
     145           24 :         self.space_join(&[header, self.reg(statement)], FormattingJoinPolicy::BreakAllOrNone, false)
     146           24 :     }
     147              : 
     148           57 :     pub(super) fn format_function_param(&self, node: &'a Node) -> FmtReg {
     149           57 :         let f = &self.fmt;
     150           57 :         let [name, type_node] = attrs!(self.children(node), [K::SQL_FUNCTION_PARAM_NAME, K::SQL_FUNCTION_PARAM_TYPE]);
     151           57 :         let (Some(name), Some(type_node)) = (name, type_node) else { return self.format_unimplemented(node) };
     152           57 :         f.concat(&[self.reg(name), f.text(" "), self.reg(type_node)])
     153           57 :     }
     154              : 
     155           45 :     pub(super) fn format_create_function(&self, node: &'a Node) -> FmtReg {
     156           45 :         let f = &self.fmt;
     157           45 :         let [name, params, returns, aggregate] = attrs!(self.children(node), [
     158              :                 K::SQL_CREATE_FUNCTION_NAME,
     159              :                 K::SQL_CREATE_FUNCTION_PARAMS,
     160              :                 K::SQL_CREATE_FUNCTION_RETURNS,
     161              :                 K::SQL_CREATE_FUNCTION_IS_AGGREGATE,
     162              :             ],
     163              :         );
     164           45 :         let (Some(name), Some(returns)) = (name, returns) else { return self.format_unimplemented(node) };
     165           45 :         let kind = if aggregate.is_some() { "create aggregate " } else { "create function " };
     166           45 :         let params_reg = params.map(|p| self.reg(p)).unwrap_or(0);
     167           45 :         let params_reg = if params_reg == 0 { f.text("()") } else { f.parenthesized(params_reg) };
     168           45 :         f.concat(&[f.text(kind), self.reg(name), params_reg, f.text(" returns "), self.reg(returns)])
     169           45 :     }
     170              : 
     171           42 :     pub(super) fn format_drop(&self, node: &'a Node, table: bool) -> FmtReg {
     172           42 :         let f = &self.fmt;
     173           42 :         let [name, if_exists] = attrs!(self.children(node), [K::SQL_DROP_NAME, K::SQL_DROP_IF_EXISTS]);
     174           42 :         let Some(name) = name else { return self.format_unimplemented(node) };
     175           42 :         let object = if table { "table " } else { "view " };
     176           42 :         let if_exists_reg = if if_exists.is_some() { f.text("if exists ") } else { f.empty() };
     177           42 :         f.concat(&[f.text("drop "), f.text(object), if_exists_reg, self.reg(name)])
     178           42 :     }
     179              : 
     180           18 :     pub(super) fn format_attach_database_option(&self, node: &'a Node) -> FmtReg {
     181           18 :         let f = &self.fmt;
     182           18 :         let [key, value] = attrs!(self.children(node), [K::SQL_GENERIC_OPTION_KEY, K::SQL_GENERIC_OPTION_VALUE]);
     183           18 :         let (Some(key), Some(value)) = (key, value) else { return self.format_unimplemented(node) };
     184           18 :         f.concat(&[self.reg(key), f.text(" = "), self.reg(value)])
     185           18 :     }
     186              : 
     187           18 :     pub(super) fn format_attach_database(&self, node: &'a Node) -> FmtReg {
     188           18 :         let f = &self.fmt;
     189           18 :         let [path, alias, local, options] = attrs!(self.children(node), [
     190              :                 K::SQL_ATTACH_DATABASE_PATH,
     191              :                 K::SQL_ATTACH_DATABASE_ALIAS,
     192              :                 K::SQL_ATTACH_DATABASE_LOCAL,
     193              :                 K::SQL_ATTACH_DATABASE_OPTIONS,
     194              :             ],
     195              :         );
     196           18 :         let (Some(path), Some(alias)) = (path, alias) else { return self.format_unimplemented(node) };
     197           18 :         let mut parts = vec![
     198           18 :             f.text(if local.is_some() { "attach local database " } else { "attach database " }),
     199           18 :             self.reg(path),
     200           18 :             f.text(" as "),
     201           18 :             self.reg(alias),
     202              :         ];
     203           18 :         if let Some(options) = options {
     204            9 :             parts.push(f.text(" with "));
     205            9 :             parts.push(f.parenthesized(self.reg(options)));
     206            9 :         }
     207           18 :         f.concat(&parts)
     208           18 :     }
     209              : 
     210           78 :     pub(super) fn format_vararg_field(&self, node: &'a Node) -> FmtReg {
     211           78 :         let f = &self.fmt;
     212           78 :         let [key, value] = attrs!(self.children(node), [K::EXT_VARARG_FIELD_KEY, K::EXT_VARARG_FIELD_VALUE]);
     213           78 :         let (Some(key), Some(value)) = (key, value) else { return self.format_unimplemented(node) };
     214           78 :         f.concat(&[self.reg(key), f.text(" = "), self.reg(value)])
     215           78 :     }
     216              : 
     217            9 :     pub(super) fn format_vararg_array(&self, node: &'a Node) -> FmtReg {
     218            9 :         let f = &self.fmt;
     219            9 :         let [values] = attrs!(self.children(node), [K::EXT_VARARG_ARRAY_VALUES]);
     220            9 :         let Some(values) = values.filter(|v| v.node_type() == NodeType::ARRAY) else {
     221            0 :             return self.format_unimplemented(node);
     222              :         };
     223            9 :         if values.children_count() == 0 {
     224            0 :             return f.text("[]");
     225            9 :         }
     226           18 :         let items: Vec<FmtReg> = self.children(values).iter().map(|v| self.reg(v)).filter(|&r| r != 0).collect();
     227            9 :         if items.is_empty() {
     228            0 :             return f.text("[]");
     229            9 :         }
     230            9 :         let (inline_separator, break_separator) = self.comma_separators();
     231            9 :         let list =
     232            9 :             f.join(&items, inline_separator, break_separator, Some(FormattingJoinPolicy::BreakOnOverflow), false);
     233            9 :         f.concat(&[f.text("["), list, f.text("]")])
     234            9 :     }
     235              : 
     236           24 :     pub(super) fn format_set(&self, node: &'a Node) -> FmtReg {
     237           24 :         let f = &self.fmt;
     238           24 :         let [varargs] = attrs!(self.children(node), [K::EXT_SET_VARARGS]);
     239           24 :         let Some(varargs) = varargs else { return self.format_unimplemented(node) };
     240           24 :         f.concat(&[f.text("set "), self.reg(varargs)])
     241           24 :     }
     242              : }
        

Generated by: LCOV version 2.0-1