Skip to content

Commit ff5ea5a

Browse files
authored
build(deps): pin SQLQuack 353861ea, after its layout refactor (#48)
SQLQuack now builds each dialect only with its feature, so SQLClean enables the ones it reads: lint for BigQuery, Databricks, DuckDB, PostgreSQL, Snowflake and SQLite; format for BigQuery, DuckDB, PostgreSQL, Snowflake and SQL Server; fingerprints for every dialect they name. The shared lossless tokenizer is now reached through sqlquack-parse. A test checks that every dialect the configuration page names is checked, formatted and fingerprinted as it says. Behaviour is unchanged: across the 1,066-query format corpus, formatting at no width and at 80, fingerprints, and lint on every dialect are byte-identical to 0.6.2.
1 parent 470e7f4 commit ff5ea5a

7 files changed

Lines changed: 167 additions & 32 deletions

File tree

‎Cargo.lock‎

Lines changed: 42 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ sha2 = "0.10"
3030
similar = "2"
3131
sqlclean = { path = "crates/sqlclean" }
3232
# SQLQuack's formatter and lint engine, and the tokens and trees they read, which replace Polyglot.
33-
sqlquack-fingerprint = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "804864d2073ef869cbfe4a9334f7e48b20072326" }
34-
sqlquack-format = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "804864d2073ef869cbfe4a9334f7e48b20072326" }
35-
sqlquack-lint = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "804864d2073ef869cbfe4a9334f7e48b20072326" }
36-
sqlquack-syntax = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "804864d2073ef869cbfe4a9334f7e48b20072326" }
37-
sqlquack-syntax-sqlserver = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "804864d2073ef869cbfe4a9334f7e48b20072326" }
33+
sqlquack-fingerprint = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "353861ea9c44307f076e06281cb1ac91110969de", features = ["bigquery", "duckdb", "postgres", "snowflake", "sqlite", "sqlserver"] }
34+
sqlquack-format = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "353861ea9c44307f076e06281cb1ac91110969de", features = ["bigquery", "duckdb", "postgres", "snowflake", "sqlserver"] }
35+
sqlquack-lint = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "353861ea9c44307f076e06281cb1ac91110969de", features = ["bigquery", "databricks", "duckdb", "postgres", "snowflake", "sqlite"] }
36+
sqlquack-parse = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "353861ea9c44307f076e06281cb1ac91110969de" }
37+
sqlquack-syntax = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "353861ea9c44307f076e06281cb1ac91110969de" }
38+
sqlquack-syntax-sqlserver = { git = "https://github.com/sqlstack-io/sqlquack.git", rev = "353861ea9c44307f076e06281cb1ac91110969de" }
3839

3940
[workspace.lints.rust]
4041
unsafe_code = "forbid"

‎crates/sqlclean/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ test-support = []
1717
sqlquack-fingerprint.workspace = true
1818
sqlquack-format.workspace = true
1919
sqlquack-lint.workspace = true
20+
sqlquack-parse.workspace = true
2021
sqlquack-syntax.workspace = true
2122
sqlquack-syntax-sqlserver.workspace = true
2223
rayon.workspace = true

‎crates/sqlclean/src/sql_lint/_helpers/cte_macros.rs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub(super) fn take_out_cte_macros(
3838
if !sql.contains(INTERPOLATION_PLACEHOLDER_PREFIX) {
3939
return Ok(None);
4040
}
41-
let Ok(tokens) = sqlquack_syntax::tokenize(sql, dialect) else {
41+
let Ok(tokens) = sqlquack_parse::tokenize(sql, dialect) else {
4242
return Ok(None);
4343
};
4444
let significant: Vec<usize> = (0..tokens.len())
@@ -109,7 +109,7 @@ pub(super) fn take_out_cte_macros(
109109
impl WithoutCteMacros {
110110
/// Put the placeholders back into `formatted`, the laid-out stripped SQL, each on its own line.
111111
pub(super) fn put_back(&self, formatted: &str, dialect: Dialect) -> Result<String, String> {
112-
let tokens = sqlquack_syntax::tokenize(formatted, dialect)
112+
let tokens = sqlquack_parse::tokenize(formatted, dialect)
113113
.map_err(|_| RESTORE_FAILURE.to_string())?;
114114
let significant: Vec<usize> = (0..tokens.len())
115115
.filter(|&index| matches!(tokens[index].kind, TokenKind::Significant(_)))
@@ -177,7 +177,7 @@ pub(super) fn wrap_query_placeholders(
177177
if !sql.contains(INTERPOLATION_PLACEHOLDER_PREFIX) {
178178
return None;
179179
}
180-
let Ok(tokens) = sqlquack_syntax::tokenize(sql, dialect) else {
180+
let Ok(tokens) = sqlquack_parse::tokenize(sql, dialect) else {
181181
return None;
182182
};
183183
let significant: Vec<&LosslessToken> = tokens
@@ -219,7 +219,7 @@ pub(super) fn wrap_query_placeholders(
219219
impl WrappedQueryPlaceholders {
220220
/// Take the `SELECT` written before each wrapped placeholder back out of `formatted`.
221221
pub(super) fn restore(&self, formatted: &str, dialect: Dialect) -> Result<String, String> {
222-
let tokens = sqlquack_syntax::tokenize(formatted, dialect)
222+
let tokens = sqlquack_parse::tokenize(formatted, dialect)
223223
.map_err(|_| RESTORE_FAILURE.to_string())?;
224224
let significant: Vec<&LosslessToken> = tokens
225225
.iter()
@@ -253,7 +253,7 @@ fn restored_with_tokens(
253253
dialect: Dialect,
254254
) -> Result<String, String> {
255255
let restored_tokens =
256-
sqlquack_syntax::tokenize(&restored, dialect).map_err(|_| RESTORE_FAILURE.to_string())?;
256+
sqlquack_parse::tokenize(&restored, dialect).map_err(|_| RESTORE_FAILURE.to_string())?;
257257
let restored_texts = token_texts(&restored, &restored_tokens);
258258
let same_tokens = restored_texts.len() == original.len()
259259
&& restored_texts.iter().zip(original).all(

‎crates/sqlclean/src/sql_lint/tests/test_sql_lint.rs‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use serde_json::{Value, json};
33
use crate::sql_lint::main::engine::lint_json;
44
use crate::sql_lint::tests::helpers::{fixture_harness, format_batch_json};
55
use crate::sql_lint::tests::{helpers, test_types};
6+
use crate::sql_tokens::main::query_fingerprint::query_fingerprint;
67

78
#[test]
89
fn given_production_function_depth_when_linting_then_bounded_parser_accepts_it() {
@@ -1879,3 +1880,107 @@ fn given_unknown_rule_when_linting_then_request_is_rejected() -> Result<(), Stri
18791880
}
18801881
Ok(())
18811882
}
1883+
1884+
/// SQLQuack builds each dialect only with its feature, so every dialect the configuration page names is checked, formatted and fingerprinted as it says, and never refused as not built.
1885+
#[test]
1886+
fn given_each_documented_dialect_when_reading_sql_then_sqlquack_was_built_for_it()
1887+
-> Result<(), String> {
1888+
let sql = "select a from t where a = 1";
1889+
let test_cases = [
1890+
test_types::DialectReadersTestCase {
1891+
description: "bigquery is checked and formatted",
1892+
dialect: "bigquery",
1893+
expected_linted: true,
1894+
expected_formatted: true,
1895+
},
1896+
test_types::DialectReadersTestCase {
1897+
description: "databricks is checked, and reported unavailable to be formatted",
1898+
dialect: "databricks",
1899+
expected_linted: true,
1900+
expected_formatted: false,
1901+
},
1902+
test_types::DialectReadersTestCase {
1903+
description: "duckdb is checked and formatted",
1904+
dialect: "duckdb",
1905+
expected_linted: true,
1906+
expected_formatted: true,
1907+
},
1908+
test_types::DialectReadersTestCase {
1909+
description: "generic is checked, and reported unavailable to be formatted",
1910+
dialect: "generic",
1911+
expected_linted: true,
1912+
expected_formatted: false,
1913+
},
1914+
test_types::DialectReadersTestCase {
1915+
description: "postgres is checked and formatted",
1916+
dialect: "postgres",
1917+
expected_linted: true,
1918+
expected_formatted: true,
1919+
},
1920+
test_types::DialectReadersTestCase {
1921+
description: "postgresql is checked and formatted",
1922+
dialect: "postgresql",
1923+
expected_linted: true,
1924+
expected_formatted: true,
1925+
},
1926+
test_types::DialectReadersTestCase {
1927+
description: "snowflake is checked and formatted",
1928+
dialect: "snowflake",
1929+
expected_linted: true,
1930+
expected_formatted: true,
1931+
},
1932+
test_types::DialectReadersTestCase {
1933+
description: "sqlite is checked, and reported unavailable to be formatted",
1934+
dialect: "sqlite",
1935+
expected_linted: true,
1936+
expected_formatted: false,
1937+
},
1938+
test_types::DialectReadersTestCase {
1939+
description: "tsql is formatted, and reported unavailable to be checked",
1940+
dialect: "tsql",
1941+
expected_linted: false,
1942+
expected_formatted: true,
1943+
},
1944+
test_types::DialectReadersTestCase {
1945+
description: "mssql is formatted, and reported unavailable to be checked",
1946+
dialect: "mssql",
1947+
expected_linted: false,
1948+
expected_formatted: true,
1949+
},
1950+
test_types::DialectReadersTestCase {
1951+
description: "sqlserver is formatted, and reported unavailable to be checked",
1952+
dialect: "sqlserver",
1953+
expected_linted: false,
1954+
expected_formatted: true,
1955+
},
1956+
];
1957+
for test_case in &test_cases {
1958+
let linted: Value = serde_json::from_str(&lint_json(
1959+
&json!({"version": 1, "sql": sql, "dialect": test_case.dialect}).to_string(),
1960+
)?)
1961+
.map_err(|error| error.to_string())?;
1962+
let formatted = helpers::format_at_width(sql, test_case.dialect, 100)?;
1963+
let fingerprint = query_fingerprint(sql, test_case.dialect);
1964+
assert_eq!(
1965+
linted["unavailable"].is_null() && linted["diagnostics"] == json!([]),
1966+
test_case.expected_linted,
1967+
"{}: {linted}",
1968+
test_case.description
1969+
);
1970+
assert_eq!(
1971+
(
1972+
formatted["formatted"] == true,
1973+
formatted["unavailable"].is_null()
1974+
),
1975+
(test_case.expected_formatted, test_case.expected_formatted),
1976+
"{}: {formatted}",
1977+
test_case.description
1978+
);
1979+
assert!(
1980+
fingerprint.is_ok(),
1981+
"{}: {fingerprint:?}",
1982+
test_case.description
1983+
);
1984+
}
1985+
Ok(())
1986+
}

‎crates/sqlclean/src/sql_lint/tests/test_types.rs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,10 @@ pub(crate) struct UnavailableCorpusTestCase {
164164
pub dialect: &'static str,
165165
pub expected_unavailable: usize,
166166
}
167+
168+
pub(crate) struct DialectReadersTestCase {
169+
pub description: &'static str,
170+
pub dialect: &'static str,
171+
pub expected_linted: bool,
172+
pub expected_formatted: bool,
173+
}

‎crates/sqlclean/src/sql_tokens/tests/helpers.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use sqlquack_syntax::tokens::models::Dialect;
33

44
/// Significant token texts of `sql` under one of SQLQuack's tokenizers.
55
pub(crate) fn significant_texts(sql: &str, tokenizer: Dialect) -> Result<Vec<String>, String> {
6-
Ok(sqlquack_syntax::tokenize(sql, tokenizer)
6+
Ok(sqlquack_parse::tokenize(sql, tokenizer)
77
.map_err(|error| error.to_string())?
88
.iter()
99
.filter(|token| matches!(token.kind, TokenKind::Significant(_)))

0 commit comments

Comments
 (0)