Merge 'refactor parser fmt' from Lâm Hoàng Phúc

@penberg this PR try to clean up `turso_parser`'s`fmt` code.
- `get_table_name` and `get_column_name` should return None when
table/column does not exist.
```rust
/// Context to be used in ToSqlString
pub trait ToSqlContext {
    /// Given an id, get the table name
    /// First Option indicates whether the table exists
    ///
    /// Currently not considering aliases
    fn get_table_name(&self, _id: TableInternalId) -> Option<&str> {
        None
    }

    /// Given a table id and a column index, get the column name
    /// First Option indicates whether the column exists
    /// Second Option indicates whether the column has a name
    fn get_column_name(&self, _table_id: TableInternalId, _col_idx: usize) -> Option<Option<&str>> {
        None
    }

    // help function to handle missing table/column names
    fn get_table_and_column_names(
        &self,
        table_id: TableInternalId,
        col_idx: usize,
    ) -> (String, String) {
        let table_name = self
            .get_table_name(table_id)
            .map(|s| s.to_owned())
            .unwrap_or_else(|| format!("t{}", table_id.0));

        let column_name = self
            .get_column_name(table_id, col_idx)
            .map(|opt| {
                opt.map(|s| s.to_owned())
                    .unwrap_or_else(|| format!("c{col_idx}"))
            })
            .unwrap_or_else(|| format!("c{col_idx}"));

        (table_name, column_name)
    }
}
```
- remove `FmtTokenStream` because it is same as `WriteTokenStream `
- remove useless functions and simplify `ToTokens`
```rust
/// Generate token(s) from AST node
/// Also implements Display to make sure devs won't forget Display
pub trait ToTokens: Display {
    /// Send token(s) to the specified stream with context
    fn to_tokens<S: TokenStream + ?Sized, C: ToSqlContext>(
        &self,
        s: &mut S,
        context: &C,
    ) -> Result<(), S::Error>;

    // Return displayer representation with context
    fn displayer<'a, 'b, C: ToSqlContext>(&'b self, ctx: &'a C) -> SqlDisplayer<'a, 'b, C, Self>
    where
        Self: Sized,
    {
        SqlDisplayer::new(ctx, self)
    }
}
```

Closes #2748
This commit is contained in:
Pekka Enberg
2025-09-02 18:35:43 +03:00
committed by GitHub
16 changed files with 576 additions and 576 deletions

View File

@@ -3,8 +3,6 @@ pub mod fmt;
use strum_macros::{EnumIter, EnumString};
use crate::ast::fmt::ToTokens;
/// `?` or `$` Prepared statement arg placeholder(s)
#[derive(Default)]
pub struct ParameterInfo {
@@ -931,13 +929,6 @@ pub struct QualifiedName {
pub alias: Option<Name>, // FIXME restrict alias usage (fullname vs xfullname)
}
impl std::fmt::Display for QualifiedName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use fmt::ToTokens as _;
self.to_fmt(f)
}
}
impl QualifiedName {
/// Constructor
pub fn single(name: Name) -> Self {
@@ -1155,12 +1146,6 @@ pub enum SortOrder {
Desc,
}
impl core::fmt::Display for SortOrder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
/// `NULLS FIRST` or `NULLS LAST`
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]

File diff suppressed because it is too large Load Diff

View File

@@ -11483,14 +11483,23 @@ mod tests {
];
for (input, expected) in test_cases {
println!("Testing input: {:?}", from_bytes(input));
let input_str = from_bytes(input);
let parser = Parser::new(input);
let mut results = Vec::new();
for cmd in parser {
results.push(cmd.unwrap());
}
assert_eq!(results, expected, "Input: {input:?}");
assert_eq!(results, expected, "Input: {input_str:?}");
// to_string tests
for (i, r) in results.iter().enumerate() {
let rstring = r.to_string();
// put new string into parser again
let result = Parser::new(rstring.as_bytes()).next().unwrap().unwrap();
let expected = &expected[i];
assert_eq!(result, expected.clone(), "Input: {rstring:?}");
}
}
}
}