Skip to content

[pull] main from supabase-community:main #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,21 @@ jobs:
uses: biomejs/setup-biome@v2
with:
version: latest

- name: Run Lints
run: |
cargo sqlx prepare --check --workspace
cargo clippy
cargo clippy --fix
cargo run -p rules_check
biome lint
biome lint --write
- name: Check for changes
run: |
if [[ $(git status --porcelain) ]]; then
git status
git diff
exit 1
fi
test:
name: Test
Expand Down
6 changes: 3 additions & 3 deletions crates/pgt_completions/benches/sanitization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn sql_and_pos(sql: &str) -> (String, usize) {
fn get_tree(sql: &str) -> tree_sitter::Tree {
let mut parser = tree_sitter::Parser::new();
parser.set_language(tree_sitter_sql::language()).unwrap();
parser.parse(sql.to_string(), None).unwrap()
parser.parse(sql, None).unwrap()
}

fn to_params<'a>(
Expand All @@ -25,9 +25,9 @@ fn to_params<'a>(
let pos: u32 = pos.try_into().unwrap();
CompletionParams {
position: TextSize::new(pos),
schema: &cache,
schema: cache,
text,
tree: tree,
tree,
}
}

Expand Down
3 changes: 1 addition & 2 deletions crates/pgt_completions/src/providers/columns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,7 @@ mod tests {
let has_column_in_first_four = |col: &'static str| {
first_four
.iter()
.find(|compl_item| compl_item.label.as_str() == col)
.is_some()
.any(|compl_item| compl_item.label.as_str() == col)
};

assert!(
Expand Down
2 changes: 1 addition & 1 deletion crates/pgt_completions/src/providers/schemas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub fn complete_schemas(ctx: &CompletionContext, builder: &mut CompletionBuilder
let available_schemas = &ctx.schema_cache.schemas;

for schema in available_schemas {
let relevance = CompletionRelevanceData::Schema(&schema);
let relevance = CompletionRelevanceData::Schema(schema);

let item = CompletionItem {
label: schema.name.clone(),
Expand Down
8 changes: 4 additions & 4 deletions crates/pgt_completions/src/sanitization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub(crate) struct SanitizedCompletionParams<'a> {
}

pub fn benchmark_sanitization(params: CompletionParams) -> String {
let params: SanitizedCompletionParams = params.try_into().unwrap();
let params: SanitizedCompletionParams = params.into();
params.text
}

Expand Down Expand Up @@ -212,7 +212,7 @@ mod tests {
.set_language(tree_sitter_sql::language())
.expect("Error loading sql language");

let mut tree = parser.parse(input.to_string(), None).unwrap();
let mut tree = parser.parse(input, None).unwrap();

// select | from users; <-- just right, one space after select token, one space before from
assert!(cursor_inbetween_nodes(&mut tree, TextSize::new(7)));
Expand All @@ -236,7 +236,7 @@ mod tests {
.set_language(tree_sitter_sql::language())
.expect("Error loading sql language");

let mut tree = parser.parse(input.to_string(), None).unwrap();
let mut tree = parser.parse(input, None).unwrap();

// select * from| <-- still on previous token
assert!(!cursor_prepared_to_write_token_after_last_node(
Expand Down Expand Up @@ -274,7 +274,7 @@ mod tests {
.set_language(tree_sitter_sql::language())
.expect("Error loading sql language");

let mut tree = parser.parse(input.to_string(), None).unwrap();
let mut tree = parser.parse(input, None).unwrap();

// select * from ;| <-- it's after the statement
assert!(!cursor_before_semicolon(&mut tree, TextSize::new(19)));
Expand Down
8 changes: 8 additions & 0 deletions crates/pgt_statement_splitter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ mod tests {
.expect_statements(vec!["select 1 from contact", "select 1"]);
}

#[test]
fn grant() {
Tester::from("GRANT SELECT ON TABLE \"public\".\"my_table\" TO \"my_role\";")
.expect_statements(vec![
"GRANT SELECT ON TABLE \"public\".\"my_table\" TO \"my_role\";",
]);
}

#[test]
fn double_newlines() {
Tester::from("select 1 from contact\n\nselect 1\n\nselect 3").expect_statements(vec![
Expand Down
4 changes: 4 additions & 0 deletions crates/pgt_statement_splitter/src/parser/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ pub(crate) fn unknown(p: &mut Parser, exclude: &[SyntaxKind]) {
SyntaxKind::All,
// for UNION ... EXCEPT
SyntaxKind::Except,
// for grant
SyntaxKind::Grant,
]
.iter()
.all(|x| Some(x) != prev.as_ref())
Expand All @@ -230,6 +232,8 @@ pub(crate) fn unknown(p: &mut Parser, exclude: &[SyntaxKind]) {
SyntaxKind::Also,
// for create rule
SyntaxKind::Instead,
// for grant
SyntaxKind::Grant,
]
.iter()
.all(|x| Some(x) != prev.as_ref())
Expand Down
20 changes: 9 additions & 11 deletions crates/pgt_typecheck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ mod diagnostics;
pub use diagnostics::TypecheckDiagnostic;
use diagnostics::create_type_error;
use pgt_text_size::TextRange;
use sqlx::Executor;
use sqlx::PgPool;
use sqlx::postgres::PgDatabaseError;
pub use sqlx::postgres::PgSeverity;
use sqlx::{Executor, PgPool};

#[derive(Debug)]
pub struct TypecheckParams<'a> {
Expand All @@ -29,7 +28,9 @@ pub struct TypeError {
pub constraint: Option<String>,
}

pub async fn check_sql(params: TypecheckParams<'_>) -> Option<TypecheckDiagnostic> {
pub async fn check_sql(
params: TypecheckParams<'_>,
) -> Result<Option<TypecheckDiagnostic>, sqlx::Error> {
// Check if the AST is not a supported statement type
if !matches!(
params.ast,
Expand All @@ -39,13 +40,10 @@ pub async fn check_sql(params: TypecheckParams<'_>) -> Option<TypecheckDiagnosti
| pgt_query_ext::NodeEnum::DeleteStmt(_)
| pgt_query_ext::NodeEnum::CommonTableExpr(_)
) {
return None;
return Ok(None);
}

let mut conn = match params.conn.acquire().await {
Ok(c) => c,
Err(_) => return None,
};
let mut conn = params.conn.acquire().await?;

// Postgres caches prepared statements within the current DB session (connection).
// This can cause issues if the underlying table schema changes while statements
Expand All @@ -56,11 +54,11 @@ pub async fn check_sql(params: TypecheckParams<'_>) -> Option<TypecheckDiagnosti
let res = conn.prepare(params.sql).await;

match res {
Ok(_) => None,
Ok(_) => Ok(None),
Err(sqlx::Error::Database(err)) => {
let pg_err = err.downcast_ref::<PgDatabaseError>();
Some(create_type_error(pg_err, params.tree))
Ok(Some(create_type_error(pg_err, params.tree)))
}
Err(_) => None,
Err(err) => Err(err),
}
}
2 changes: 1 addition & 1 deletion crates/pgt_typecheck/tests/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async fn test(name: &str, query: &str, setup: &str) {

Formatter::new(&mut writer)
.write_markup(markup! {
{PrintDiagnostic::simple(&result.unwrap())}
{PrintDiagnostic::simple(&result.unwrap().unwrap())}
})
.unwrap();

Expand Down
28 changes: 8 additions & 20 deletions crates/pgt_workspace/src/features/completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ impl IntoIterator for CompletionsResult {
}
}

pub(crate) fn get_statement_for_completions<'a>(
doc: &'a ParsedDocument,
pub(crate) fn get_statement_for_completions(
doc: &ParsedDocument,
position: TextSize,
) -> Option<(StatementId, TextRange, String, Arc<tree_sitter::Tree>)> {
let count = doc.count();
Expand Down Expand Up @@ -89,7 +89,7 @@ mod tests {
(
ParsedDocument::new(
PgTPath::new("test.sql"),
sql.replace(CURSOR_POSITION, "").into(),
sql.replace(CURSOR_POSITION, ""),
5,
),
TextSize::new(pos),
Expand Down Expand Up @@ -119,14 +119,11 @@ mod tests {

#[test]
fn does_not_break_when_no_statements_exist() {
let sql = format!("{}", CURSOR_POSITION);
let sql = CURSOR_POSITION.to_string();

let (doc, position) = get_doc_and_pos(sql.as_str());

assert!(matches!(
get_statement_for_completions(&doc, position),
None
));
assert!(get_statement_for_completions(&doc, position).is_none());
}

#[test]
Expand All @@ -138,10 +135,7 @@ mod tests {
// make sure these are parsed as two
assert_eq!(doc.count(), 2);

assert!(matches!(
get_statement_for_completions(&doc, position),
None
));
assert!(get_statement_for_completions(&doc, position).is_none());
}

#[test]
Expand Down Expand Up @@ -174,10 +168,7 @@ mod tests {

let (doc, position) = get_doc_and_pos(sql.as_str());

assert!(matches!(
get_statement_for_completions(&doc, position),
None
));
assert!(get_statement_for_completions(&doc, position).is_none());
}

#[test]
Expand All @@ -186,9 +177,6 @@ mod tests {

let (doc, position) = get_doc_and_pos(sql.as_str());

assert!(matches!(
get_statement_for_completions(&doc, position),
None
));
assert!(get_statement_for_completions(&doc, position).is_none());
}
}
19 changes: 11 additions & 8 deletions crates/pgt_workspace/src/workspace/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,6 @@ impl Workspace for WorkspaceServer {

let mut diagnostics: Vec<SDiagnostic> = parser.document_diagnostics().to_vec();

// TODO: run this in parallel with rayon based on rayon.count()

if let Some(pool) = self
.connection
.read()
Expand All @@ -385,13 +383,15 @@ impl Workspace for WorkspaceServer {
})
.await
.map(|d| {
let r = d.location().span.map(|span| span + range.start());
d.map(|d| {
let r = d.location().span.map(|span| span + range.start());

d.with_file_path(path.as_path().display().to_string())
.with_file_span(r.unwrap_or(range))
d.with_file_path(path.as_path().display().to_string())
.with_file_span(r.unwrap_or(range))
})
})
} else {
None
Ok(None)
}
}
})
Expand All @@ -400,8 +400,11 @@ impl Workspace for WorkspaceServer {
.await
})?;

for result in async_results.into_iter().flatten() {
diagnostics.push(SDiagnostic::new(result));
for result in async_results.into_iter() {
let result = result?;
if let Some(diag) = result {
diagnostics.push(SDiagnostic::new(diag));
}
}
}

Expand Down
66 changes: 66 additions & 0 deletions crates/pgt_workspace/src/workspace/server/change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,72 @@ mod tests {
assert!(d.has_fatal_error());
}

#[test]
fn typing_comments() {
let path = PgTPath::new("test.sql");
let input = "select id from users;\n";

let mut d = Document::new(input.to_string(), 0);

let change1 = ChangeFileParams {
path: path.clone(),
version: 1,
changes: vec![ChangeParams {
text: "-".to_string(),
range: Some(TextRange::new(22.into(), 23.into())),
}],
};

let _changed1 = d.apply_file_change(&change1);

assert_eq!(d.content, "select id from users;\n-");
assert_eq!(d.positions.len(), 2);

let change2 = ChangeFileParams {
path: path.clone(),
version: 2,
changes: vec![ChangeParams {
text: "-".to_string(),
range: Some(TextRange::new(23.into(), 24.into())),
}],
};

let _changed2 = d.apply_file_change(&change2);

assert_eq!(d.content, "select id from users;\n--");
assert_eq!(d.positions.len(), 1);

let change3 = ChangeFileParams {
path: path.clone(),
version: 3,
changes: vec![ChangeParams {
text: " ".to_string(),
range: Some(TextRange::new(24.into(), 25.into())),
}],
};

let _changed3 = d.apply_file_change(&change3);

assert_eq!(d.content, "select id from users;\n-- ");
assert_eq!(d.positions.len(), 1);

let change4 = ChangeFileParams {
path: path.clone(),
version: 3,
changes: vec![ChangeParams {
text: "t".to_string(),
range: Some(TextRange::new(25.into(), 26.into())),
}],
};

let _changed4 = d.apply_file_change(&change4);

assert_eq!(d.content, "select id from users;\n-- t");
assert_eq!(d.positions.len(), 1);

assert_document_integrity(&d);
}

#[test]
fn change_into_scan_error_within_statement() {
let path = PgTPath::new("test.sql");
Expand Down
Loading