diff --git a/crates/pgls_completions/src/builder.rs b/crates/pgls_completions/src/builder.rs index e7992d7c3..8e7c2b4a6 100644 --- a/crates/pgls_completions/src/builder.rs +++ b/crates/pgls_completions/src/builder.rs @@ -32,10 +32,12 @@ impl<'a> CompletionBuilder<'a> { } pub fn finish(self) -> Vec { + let mut shared_tree = self.ctx.tree.clone(); + let mut items: Vec = self .items .into_iter() - .filter(|i| i.filter.is_relevant(self.ctx).is_some()) + .filter(|i| i.filter.is_relevant(self.ctx, &mut shared_tree).is_some()) .collect(); for item in items.iter_mut() { diff --git a/crates/pgls_completions/src/complete.rs b/crates/pgls_completions/src/complete.rs index 78f5eecdb..617cdc91b 100644 --- a/crates/pgls_completions/src/complete.rs +++ b/crates/pgls_completions/src/complete.rs @@ -6,8 +6,8 @@ use crate::{ builder::CompletionBuilder, item::CompletionItem, providers::{ - complete_columns, complete_functions, complete_policies, complete_roles, complete_schemas, - complete_tables, + complete_columns, complete_functions, complete_keywords, complete_policies, complete_roles, + complete_schemas, complete_tables, }, sanitization::SanitizedCompletionParams, }; @@ -27,6 +27,13 @@ pub struct CompletionParams<'a> { position = params.position.to_string() ))] pub fn complete(params: CompletionParams) -> Vec { + let uses_upper_case = params + .text + .split_ascii_whitespace() + // filter out special chars and numbers + .filter(|word| word.chars().all(|c| c.is_alphabetic())) + .any(|t| t == t.to_ascii_uppercase()); + let sanitized_params = SanitizedCompletionParams::from(params); let ctx = TreesitterContext::new(TreeSitterContextParams { @@ -43,6 +50,7 @@ pub fn complete(params: CompletionParams) -> Vec { complete_schemas(&ctx, sanitized_params.schema, &mut builder); complete_policies(&ctx, sanitized_params.schema, &mut builder); complete_roles(&ctx, sanitized_params.schema, &mut builder); + complete_keywords(&ctx, &mut builder, uses_upper_case); builder.finish() } diff --git a/crates/pgls_completions/src/item.rs b/crates/pgls_completions/src/item.rs index d92454c26..7ba06c0a6 100644 --- a/crates/pgls_completions/src/item.rs +++ b/crates/pgls_completions/src/item.rs @@ -13,6 +13,7 @@ pub enum CompletionItemKind { Schema, Policy, Role, + Keyword, } impl Display for CompletionItemKind { @@ -24,6 +25,7 @@ impl Display for CompletionItemKind { CompletionItemKind::Schema => "Schema", CompletionItemKind::Policy => "Policy", CompletionItemKind::Role => "Role", + CompletionItemKind::Keyword => "Keyword", }; write!(f, "{txt}") diff --git a/crates/pgls_completions/src/providers/columns.rs b/crates/pgls_completions/src/providers/columns.rs index 531bfcbc4..d0908d0e0 100644 --- a/crates/pgls_completions/src/providers/columns.rs +++ b/crates/pgls_completions/src/providers/columns.rs @@ -417,7 +417,6 @@ mod tests { } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] - #[ignore = "will be reintroduced after stacked keyword-completion PRs merge"] async fn suggests_columns_in_where_clause(pool: PgPool) { let setup = r#" create table instruments ( @@ -441,7 +440,7 @@ mod tests { "select name from instruments i join others o on i.z = o.a ", ) .type_sql("where o.<1>a = <2>i.z and <3>i.id > 5;") - .comment("should respect alias speciifcation") + .comment("should respect alias specification") .comment("should not prioritize suggest columns or schemas (right side of binary expression)") .comment("should prioritize columns that aren't already mentioned"), ) diff --git a/crates/pgls_completions/src/providers/keywords.rs b/crates/pgls_completions/src/providers/keywords.rs new file mode 100644 index 000000000..64ee188ee --- /dev/null +++ b/crates/pgls_completions/src/providers/keywords.rs @@ -0,0 +1,836 @@ +use pgls_treesitter::TreesitterContext; + +use crate::{ + CompletionItemKind, CompletionText, + builder::{CompletionBuilder, PossibleCompletionItem}, + providers::helper::get_range_to_replace, + relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore}, +}; + +#[derive(Debug, Clone, Copy)] +pub struct SqlKeyword { + pub name: &'static str, + pub require_prefix: bool, + pub starts_statement: bool, +} + +impl SqlKeyword { + const fn new(name: &'static str) -> Self { + Self { + name, + require_prefix: false, + starts_statement: false, + } + } + + const fn require_prefix(mut self) -> Self { + self.require_prefix = true; + self + } + + const fn starts_statement(mut self) -> Self { + self.starts_statement = true; + self + } +} + +pub static ALL_KEYWORDS: &[SqlKeyword] = &[ + SqlKeyword::new("action"), + SqlKeyword::new("add"), + SqlKeyword::new("admin"), + SqlKeyword::new("after"), + SqlKeyword::new("all"), + SqlKeyword::new("alter").starts_statement(), + SqlKeyword::new("always"), + SqlKeyword::new("analyze").starts_statement(), + SqlKeyword::new("and").require_prefix(), + SqlKeyword::new("any").require_prefix(), + SqlKeyword::new("array").require_prefix(), + SqlKeyword::new("as").require_prefix(), + SqlKeyword::new("asc"), + SqlKeyword::new("atomic"), + SqlKeyword::new("attribute"), + SqlKeyword::new("authorization"), + SqlKeyword::new("before"), + SqlKeyword::new("begin").starts_statement(), + SqlKeyword::new("between").require_prefix(), + SqlKeyword::new("bigint"), + SqlKeyword::new("bigserial"), + SqlKeyword::new("binary"), + SqlKeyword::new("bit"), + SqlKeyword::new("boolean"), + SqlKeyword::new("brin"), + SqlKeyword::new("btree"), + SqlKeyword::new("by"), + SqlKeyword::new("bytea"), + SqlKeyword::new("cache"), + SqlKeyword::new("called"), + SqlKeyword::new("cascade"), + SqlKeyword::new("cascaded"), + SqlKeyword::new("case"), + SqlKeyword::new("cast").require_prefix(), + SqlKeyword::new("char"), + SqlKeyword::new("character"), + SqlKeyword::new("characteristics"), + SqlKeyword::new("check"), + SqlKeyword::new("collate"), + SqlKeyword::new("column"), + SqlKeyword::new("columns"), + SqlKeyword::new("comment").starts_statement(), + SqlKeyword::new("commit").starts_statement(), + SqlKeyword::new("committed"), + SqlKeyword::new("compression"), + SqlKeyword::new("concurrently"), + SqlKeyword::new("conflict"), + SqlKeyword::new("connection"), + SqlKeyword::new("constraint"), + SqlKeyword::new("constraints"), + SqlKeyword::new("copy").starts_statement(), + SqlKeyword::new("cost"), + SqlKeyword::new("create").starts_statement(), + SqlKeyword::new("cross"), + SqlKeyword::new("csv"), + SqlKeyword::new("current"), + SqlKeyword::new("current_role"), + SqlKeyword::new("current_timestamp"), + SqlKeyword::new("current_user"), + SqlKeyword::new("cycle"), + SqlKeyword::new("data"), + SqlKeyword::new("database"), + SqlKeyword::new("date"), + SqlKeyword::new("decimal"), + SqlKeyword::new("declare").starts_statement(), + SqlKeyword::new("default"), + SqlKeyword::new("deferrable"), + SqlKeyword::new("deferred"), + SqlKeyword::new("definer"), + SqlKeyword::new("delete").starts_statement(), + SqlKeyword::new("delimiter"), + SqlKeyword::new("desc"), + SqlKeyword::new("disable_page_skipping"), + SqlKeyword::new("distinct"), + SqlKeyword::new("do").starts_statement(), + SqlKeyword::new("double"), + SqlKeyword::new("drop").starts_statement(), + SqlKeyword::new("each"), + SqlKeyword::new("else"), + SqlKeyword::new("encoding"), + SqlKeyword::new("encrypted"), + SqlKeyword::new("end"), + SqlKeyword::new("enum"), + SqlKeyword::new("escape"), + SqlKeyword::new("except"), + SqlKeyword::new("exclude"), + SqlKeyword::new("execute"), + SqlKeyword::new("exists").require_prefix(), + SqlKeyword::new("explain").starts_statement(), + SqlKeyword::new("extended"), + SqlKeyword::new("extension"), + SqlKeyword::new("external"), + SqlKeyword::new("false").require_prefix(), + SqlKeyword::new("filter"), + SqlKeyword::new("first"), + SqlKeyword::new("float"), + SqlKeyword::new("following"), + SqlKeyword::new("for"), + SqlKeyword::new("force"), + SqlKeyword::new("force_not_null"), + SqlKeyword::new("force_null"), + SqlKeyword::new("force_quote"), + SqlKeyword::new("foreign"), + SqlKeyword::new("format"), + SqlKeyword::new("freeze"), + SqlKeyword::new("from"), + SqlKeyword::new("full"), + SqlKeyword::new("function"), + SqlKeyword::new("functions"), + SqlKeyword::new("generated"), + SqlKeyword::new("gin"), + SqlKeyword::new("gist"), + SqlKeyword::new("grant").starts_statement(), + SqlKeyword::new("granted"), + SqlKeyword::new("group"), + SqlKeyword::new("groups"), + SqlKeyword::new("hash"), + SqlKeyword::new("having"), + SqlKeyword::new("header"), + SqlKeyword::new("if"), + SqlKeyword::new("immediate"), + SqlKeyword::new("immutable"), + SqlKeyword::new("in").require_prefix(), + SqlKeyword::new("increment"), + SqlKeyword::new("index"), + SqlKeyword::new("index_cleanup"), + SqlKeyword::new("inet"), + SqlKeyword::new("inherit"), + SqlKeyword::new("initially"), + SqlKeyword::new("inner"), + SqlKeyword::new("inout"), + SqlKeyword::new("input"), + SqlKeyword::new("insert").starts_statement(), + SqlKeyword::new("instead"), + SqlKeyword::new("int"), + SqlKeyword::new("intersect"), + SqlKeyword::new("interval").require_prefix(), + SqlKeyword::new("into"), + SqlKeyword::new("invoker"), + SqlKeyword::new("is"), + SqlKeyword::new("isolation"), + SqlKeyword::new("join"), + SqlKeyword::new("json"), + SqlKeyword::new("jsonb"), + SqlKeyword::new("key"), + SqlKeyword::new("language"), + SqlKeyword::new("last"), + SqlKeyword::new("lateral"), + SqlKeyword::new("leakproof"), + SqlKeyword::new("left"), + SqlKeyword::new("level"), + SqlKeyword::new("like").require_prefix(), + SqlKeyword::new("limit"), + SqlKeyword::new("list"), + SqlKeyword::new("local"), + SqlKeyword::new("location"), + SqlKeyword::new("logged"), + SqlKeyword::new("main"), + SqlKeyword::new("maintain"), + SqlKeyword::new("match"), + SqlKeyword::new("matched"), + SqlKeyword::new("materialized"), + SqlKeyword::new("maxvalue"), + SqlKeyword::new("merge").starts_statement(), + SqlKeyword::new("minvalue"), + SqlKeyword::new("money"), + SqlKeyword::new("name"), + SqlKeyword::new("names"), + SqlKeyword::new("natural"), + SqlKeyword::new("new"), + SqlKeyword::new("no"), + SqlKeyword::new("none"), + SqlKeyword::new("not").require_prefix(), + SqlKeyword::new("nothing"), + SqlKeyword::new("nowait"), + SqlKeyword::new("null").require_prefix(), + SqlKeyword::new("nulls"), + SqlKeyword::new("numeric"), + SqlKeyword::new("of"), + SqlKeyword::new("off"), + SqlKeyword::new("offset"), + SqlKeyword::new("oid"), + SqlKeyword::new("oids"), + SqlKeyword::new("old"), + SqlKeyword::new("on"), + SqlKeyword::new("only").require_prefix(), + SqlKeyword::new("option"), + SqlKeyword::new("or").require_prefix(), + SqlKeyword::new("order"), + SqlKeyword::new("ordinality"), + SqlKeyword::new("others"), + SqlKeyword::new("out"), + SqlKeyword::new("outer"), + SqlKeyword::new("over"), + SqlKeyword::new("overriding"), + SqlKeyword::new("owned"), + SqlKeyword::new("owner"), + SqlKeyword::new("parallel"), + SqlKeyword::new("partition"), + SqlKeyword::new("partitioned"), + SqlKeyword::new("password"), + SqlKeyword::new("permissive"), + SqlKeyword::new("plain"), + SqlKeyword::new("policy"), + SqlKeyword::new("precedes"), + SqlKeyword::new("preceding"), + SqlKeyword::new("precision"), + SqlKeyword::new("primary"), + SqlKeyword::new("privileges"), + SqlKeyword::new("procedure"), + SqlKeyword::new("procedures"), + SqlKeyword::new("process_toast"), + SqlKeyword::new("program"), + SqlKeyword::new("public"), + SqlKeyword::new("quote"), + SqlKeyword::new("range"), + SqlKeyword::new("read"), + SqlKeyword::new("real"), + SqlKeyword::new("recursive"), + SqlKeyword::new("references"), + SqlKeyword::new("referencing"), + SqlKeyword::new("regclass"), + SqlKeyword::new("regnamespace"), + SqlKeyword::new("regproc"), + SqlKeyword::new("regtype"), + SqlKeyword::new("rename"), + SqlKeyword::new("repeatable"), + SqlKeyword::new("replace"), + SqlKeyword::new("replication"), + SqlKeyword::new("reset").starts_statement(), + SqlKeyword::new("restart"), + SqlKeyword::new("restrict"), + SqlKeyword::new("restricted"), + SqlKeyword::new("restrictive"), + SqlKeyword::new("return"), + SqlKeyword::new("returning"), + SqlKeyword::new("returns"), + SqlKeyword::new("revoke").starts_statement(), + SqlKeyword::new("rewrite"), + SqlKeyword::new("right"), + SqlKeyword::new("role"), + SqlKeyword::new("rollback").starts_statement(), + SqlKeyword::new("routine"), + SqlKeyword::new("routines"), + SqlKeyword::new("row"), + SqlKeyword::new("rows"), + SqlKeyword::new("safe"), + SqlKeyword::new("schema"), + SqlKeyword::new("security"), + SqlKeyword::new("select").starts_statement(), + SqlKeyword::new("sequence"), + SqlKeyword::new("serial"), + SqlKeyword::new("serializable"), + SqlKeyword::new("session"), + SqlKeyword::new("session_user"), + SqlKeyword::new("set").starts_statement(), + SqlKeyword::new("setof"), + SqlKeyword::new("show").starts_statement(), + SqlKeyword::new("similar").require_prefix(), + SqlKeyword::new("skip_locked"), + SqlKeyword::new("smallint"), + SqlKeyword::new("smallserial"), + SqlKeyword::new("snapshot"), + SqlKeyword::new("some"), + SqlKeyword::new("spgist"), + SqlKeyword::new("stable"), + SqlKeyword::new("start"), + SqlKeyword::new("statement"), + SqlKeyword::new("statistics"), + SqlKeyword::new("stdin"), + SqlKeyword::new("storage"), + SqlKeyword::new("stored"), + SqlKeyword::new("strict"), + SqlKeyword::new("support"), + SqlKeyword::new("system"), + SqlKeyword::new("table"), + SqlKeyword::new("tables"), + SqlKeyword::new("tablespace"), + SqlKeyword::new("temp"), + SqlKeyword::new("temporary"), + SqlKeyword::new("text"), + SqlKeyword::new("then").require_prefix(), + SqlKeyword::new("ties"), + SqlKeyword::new("time"), + SqlKeyword::new("timestamp"), + SqlKeyword::new("timestamptz"), + SqlKeyword::new("to"), + SqlKeyword::new("transaction"), + SqlKeyword::new("trigger"), + SqlKeyword::new("true").require_prefix(), + SqlKeyword::new("truncate").starts_statement(), + SqlKeyword::new("type"), + SqlKeyword::new("unbounded"), + SqlKeyword::new("uncommitted"), + SqlKeyword::new("union"), + SqlKeyword::new("unique"), + SqlKeyword::new("unlogged"), + SqlKeyword::new("unsafe"), + SqlKeyword::new("until"), + SqlKeyword::new("update").starts_statement(), + SqlKeyword::new("user"), + SqlKeyword::new("using"), + SqlKeyword::new("uuid"), + SqlKeyword::new("vacuum").starts_statement(), + SqlKeyword::new("valid"), + SqlKeyword::new("value"), + SqlKeyword::new("values"), + SqlKeyword::new("varchar"), + SqlKeyword::new("variadic"), + SqlKeyword::new("varying"), + SqlKeyword::new("verbose"), + SqlKeyword::new("version"), + SqlKeyword::new("view"), + SqlKeyword::new("volatile"), + SqlKeyword::new("when"), + SqlKeyword::new("where"), + SqlKeyword::new("window"), + SqlKeyword::new("with").starts_statement(), + SqlKeyword::new("without"), + SqlKeyword::new("write"), + SqlKeyword::new("xml"), + SqlKeyword::new("zone"), +]; + +pub fn complete_keywords<'a>( + ctx: &TreesitterContext<'a>, + builder: &mut CompletionBuilder<'a>, + use_upper_case: bool, +) { + // no keyword completions if we start with a quote + if ctx + .get_node_under_cursor_content() + .is_some_and(|n| n.starts_with('"')) + { + return; + } + + let keywords_to_try = ALL_KEYWORDS.iter().filter(|kw| { + ctx.tree.root_node().has_error() || ctx.possible_keywords_at_position.contains(&kw.name) + }); + + for kw in keywords_to_try { + let relevance = CompletionRelevanceData::Keyword(kw); + + let label = if use_upper_case { + kw.name.to_ascii_uppercase() + } else { + kw.name.to_string() + }; + + let item = PossibleCompletionItem { + label: label.clone(), + score: CompletionScore::from(relevance.clone()), + filter: CompletionFilter::from(relevance), + description: "".into(), + kind: CompletionItemKind::Keyword, + completion_text: Some(CompletionText { + text: label, + range: get_range_to_replace(ctx), + is_snippet: false, + }), + detail: None, + }; + + builder.add_item(item); + } +} + +#[cfg(test)] +mod tests { + use pgls_test_utils::QueryWithCursorPosition; + use sqlx::PgPool; + + use crate::{ + CompletionItemKind, + test_helper::{ + CompletionAssertion, TestCompletionsCase, TestCompletionsSuite, + assert_complete_results, assert_no_complete_results, + }, + }; + + #[sqlx::test] + async fn completes_stmt_start_keywords(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!("{}", QueryWithCursorPosition::cursor_marker()); + + assert_complete_results( + query.as_str(), + vec![ + CompletionAssertion::LabelAndKind( + "insert".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "reset".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "select".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("set".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "truncate".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "update".into(), + crate::CompletionItemKind::Keyword, + ), + ], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn completes_keywords(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!("s{}", QueryWithCursorPosition::cursor_marker()); + + assert_complete_results( + query.as_str(), + vec![ + CompletionAssertion::LabelAndKind( + "select".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("set".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "insert".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "reset".into(), + crate::CompletionItemKind::Keyword, + ), + ], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn does_not_complete_from_after_select(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!("select f{}", QueryWithCursorPosition::cursor_marker()); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::LabelNotExists("from".into())], // keyword `false` is fine + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn completes_columns_after_select(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!("select {}", QueryWithCursorPosition::cursor_marker()); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::KindNotExists( + CompletionItemKind::Keyword, + )], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn completes_after_from_clause(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + TestCompletionsSuite::new(&pool, Some(setup)) + .with_case( + TestCompletionsCase::new() + .inside_static_statement("select email from users ") + .type_sql("where id = 1;"), + ) + .snapshot("after_from_clause") + .await; + } + + #[sqlx::test] + async fn stays_within_order_clause(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select * from public.users order {}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::LabelAndKind( + "by".into(), + crate::CompletionItemKind::Keyword, + )], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn only_allows_identifier_in_alias_clause(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select * from public.users as {}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_no_complete_results(query.as_str(), Some(setup), &pool).await; + } + + #[sqlx::test] + async fn completes_from_keyword(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!("select * f{}", QueryWithCursorPosition::cursor_marker()); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::LabelAndKind( + "from".into(), + crate::CompletionItemKind::Keyword, + )], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn completes_from_keyword_after_aliases(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select email as em {}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::LabelAndKind( + "from".into(), + crate::CompletionItemKind::Keyword, + )], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn adds_where_after_clause(pool: PgPool) { + let query = format!( + "select * from public.users us left join client_settings as cs on us.id = cs.client_id whe{}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::LabelAndKind( + "where".into(), + crate::CompletionItemKind::Keyword, + )], + None, + &pool, + ) + .await; + } + + #[sqlx::test] + async fn completes_keywords_after_column_aliases(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select email from public.users als (id, email) {}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![ + CompletionAssertion::LabelAndKind( + "cross".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "full".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "group".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "inner".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "join".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "left".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "limit".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "natural".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "order".into(), + crate::CompletionItemKind::Keyword, + ), + ], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn completes_join_kw(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select * from public.users left {}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![ + CompletionAssertion::LabelAndKind( + "join".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "outer".into(), + crate::CompletionItemKind::Keyword, + ), + ], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn stays_in_joins(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select * from public.users u join public.something s {}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::LabelNotExists("join".into())], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn completes_join_after_alias(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select * from public.users u {}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![ + CompletionAssertion::LabelAndKind("cross".into(), CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind("full".into(), CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind("group".into(), CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind("inner".into(), CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind("join".into(), CompletionItemKind::Keyword), + ], + Some(setup), + &pool, + ) + .await; + } + + #[sqlx::test] + async fn allows_starting_new_select_stmt(pool: PgPool) { + let setup = r#" + create table public.users ( + id serial primary key, + email varchar(255) + ); + "#; + + let query = format!( + "select * from public.users u; sel{}", + QueryWithCursorPosition::cursor_marker() + ); + + assert_complete_results( + query.as_str(), + vec![CompletionAssertion::LabelAndKind( + "select".into(), + CompletionItemKind::Keyword, + )], + Some(setup), + &pool, + ) + .await; + } +} diff --git a/crates/pgls_completions/src/providers/mod.rs b/crates/pgls_completions/src/providers/mod.rs index ddbdf252c..3dbb5874f 100644 --- a/crates/pgls_completions/src/providers/mod.rs +++ b/crates/pgls_completions/src/providers/mod.rs @@ -1,6 +1,7 @@ mod columns; mod functions; mod helper; +mod keywords; mod policies; mod roles; mod schemas; @@ -8,6 +9,7 @@ mod tables; pub use columns::*; pub use functions::*; +pub use keywords::*; pub use policies::*; pub use roles::*; pub use schemas::*; diff --git a/crates/pgls_completions/src/providers/roles.rs b/crates/pgls_completions/src/providers/roles.rs index 4e8c7f17a..bbe7f40ef 100644 --- a/crates/pgls_completions/src/providers/roles.rs +++ b/crates/pgls_completions/src/providers/roles.rs @@ -34,7 +34,9 @@ pub fn complete_roles<'a>( mod tests { use sqlx::{Executor, PgPool}; - use crate::test_helper::{CompletionAssertion, assert_complete_results}; + use crate::test_helper::{ + CompletionAssertion, TestCompletionsCase, TestCompletionsSuite, assert_complete_results, + }; use pgls_test_utils::QueryWithCursorPosition; @@ -89,34 +91,44 @@ mod tests { } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] - async fn works_in_set_statement(pool: PgPool) { - pool.execute(SETUP).await.unwrap(); - - assert_complete_results( - format!("set role {}", QueryWithCursorPosition::cursor_marker()).as_str(), - expected_roles(), - None, - &pool, - ) - .await; + async fn works_in_set_role_statement(pool: PgPool) { + TestCompletionsSuite::new(&pool, Some(SETUP)) + .with_case(TestCompletionsCase::new().type_sql("set role anon;")) + .snapshot("works_in_set_role_statement") + .await; + } - assert_complete_results( - format!( - "set session authorization {}", - QueryWithCursorPosition::cursor_marker() + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_session_authorization_statement(pool: PgPool) { + TestCompletionsSuite::new(&pool, Some(SETUP)) + .with_case( + TestCompletionsCase::new().type_sql("set session authorization authenticated;"), ) - .as_str(), - expected_roles(), - None, - &pool, - ) - .await; + .snapshot("works_in_session_authorization_statement") + .await; } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] - async fn works_in_policies(pool: PgPool) { + async fn works_in_policy_restrictive(pool: PgPool) { pool.execute(SETUP).await.unwrap(); + let mut expected = vec![ + CompletionAssertion::LabelAndKind( + "current_role".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "current_user".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("public".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "session_user".into(), + crate::CompletionItemKind::Keyword, + ), + ]; + expected.append(&mut expected_roles()); + assert_complete_results( format!( r#"create policy "my cool policy" on public.users @@ -127,11 +139,33 @@ mod tests { QueryWithCursorPosition::cursor_marker() ) .as_str(), - expected_roles(), + expected, None, &pool, ) .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_policy_select(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); + + let mut expected = vec![ + CompletionAssertion::LabelAndKind( + "current_role".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "current_user".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("public".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "session_user".into(), + crate::CompletionItemKind::Keyword, + ), + ]; + expected.append(&mut expected_roles()); assert_complete_results( format!( @@ -141,7 +175,7 @@ mod tests { QueryWithCursorPosition::cursor_marker() ) .as_str(), - expected_roles(), + expected, None, &pool, ) @@ -149,9 +183,26 @@ mod tests { } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] - async fn works_in_grant_statements(pool: PgPool) { + async fn works_in_grant_on_table_to(pool: PgPool) { pool.execute(SETUP).await.unwrap(); + let mut expected = vec![ + CompletionAssertion::LabelAndKind( + "current_role".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "current_user".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("public".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "session_user".into(), + crate::CompletionItemKind::Keyword, + ), + ]; + expected.append(&mut expected_roles()); + assert_complete_results( format!( r#"grant select @@ -160,11 +211,33 @@ mod tests { QueryWithCursorPosition::cursor_marker() ) .as_str(), - expected_roles(), + expected, None, &pool, ) .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_grant_on_table_to_multiple(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); + + let mut expected = vec![ + CompletionAssertion::LabelAndKind( + "current_role".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "current_user".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("public".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "session_user".into(), + crate::CompletionItemKind::Keyword, + ), + ]; + expected.append(&mut expected_roles()); assert_complete_results( format!( @@ -174,11 +247,16 @@ mod tests { QueryWithCursorPosition::cursor_marker() ) .as_str(), - expected_roles(), + expected, None, &pool, ) .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_grant_role_to(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); assert_complete_results( format!( @@ -194,38 +272,138 @@ mod tests { } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] - async fn works_in_revoke_statements(pool: PgPool) { + async fn works_in_revoke_role(pool: PgPool) { pool.execute(SETUP).await.unwrap(); - let queries = vec![ + assert_complete_results( format!( "revoke {} from owner", QueryWithCursorPosition::cursor_marker() - ), + ) + .as_str(), + expected_roles(), + None, + &pool, + ) + .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_revoke_admin_option_for(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); + + assert_complete_results( format!( "revoke admin option for {} from owner", QueryWithCursorPosition::cursor_marker() + ) + .as_str(), + expected_roles(), + None, + &pool, + ) + .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_revoke_from(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); + + let mut expected = vec![ + CompletionAssertion::LabelAndKind( + "current_role".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind( + "current_user".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("public".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "session_user".into(), + crate::CompletionItemKind::Keyword, ), + ]; + expected.append(&mut expected_roles()); + + assert_complete_results( format!( "revoke owner from {}", QueryWithCursorPosition::cursor_marker() - ), + ) + .as_str(), + expected, + None, + &pool, + ) + .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_revoke_all_on_schema_from_granted_by(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); + + assert_complete_results( format!( "revoke all on schema public from {} granted by", QueryWithCursorPosition::cursor_marker() - ), + ) + .as_str(), + expected_roles(), + None, + &pool, + ) + .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_revoke_all_on_schema_from_multiple(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); + + assert_complete_results( format!( "revoke all on schema public from owner, {}", QueryWithCursorPosition::cursor_marker() + ) + .as_str(), + expected_roles(), + None, + &pool, + ) + .await; + } + + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn works_in_revoke_all_on_table_from_multiple(pool: PgPool) { + pool.execute(SETUP).await.unwrap(); + + let mut expected = vec![ + CompletionAssertion::LabelAndKind( + "current_role".into(), + crate::CompletionItemKind::Keyword, ), - format!( - "revoke all on table users from owner, {}", - QueryWithCursorPosition::cursor_marker() + CompletionAssertion::LabelAndKind( + "current_user".into(), + crate::CompletionItemKind::Keyword, + ), + CompletionAssertion::LabelAndKind("public".into(), crate::CompletionItemKind::Keyword), + CompletionAssertion::LabelAndKind( + "session_user".into(), + crate::CompletionItemKind::Keyword, ), ]; + expected.append(&mut expected_roles()); - for query in queries { - assert_complete_results(query.as_str(), expected_roles(), None, &pool).await; - } + assert_complete_results( + format!( + "revoke all on table users from owner, {}", + QueryWithCursorPosition::cursor_marker() + ) + .as_str(), + expected, + None, + &pool, + ) + .await; } } diff --git a/crates/pgls_completions/src/providers/tables.rs b/crates/pgls_completions/src/providers/tables.rs index 2068577fb..d5003c58d 100644 --- a/crates/pgls_completions/src/providers/tables.rs +++ b/crates/pgls_completions/src/providers/tables.rs @@ -64,8 +64,8 @@ mod tests { use crate::{ CompletionItem, CompletionItemKind, complete, test_helper::{ - CompletionAssertion, assert_complete_results, assert_no_complete_results, - get_test_deps, get_test_params, + CompletionAssertion, TestCompletionsCase, TestCompletionsSuite, + assert_complete_results, assert_no_complete_results, get_test_deps, get_test_params, }, }; @@ -268,70 +268,13 @@ mod tests { ); "#; - pool.execute(setup).await.unwrap(); - - assert_complete_results( - format!("update {}", QueryWithCursorPosition::cursor_marker()).as_str(), - vec![CompletionAssertion::LabelAndKind( - "coos".into(), - CompletionItemKind::Table, - )], - None, - &pool, - ) - .await; - - assert_complete_results( - format!("update public.{}", QueryWithCursorPosition::cursor_marker()).as_str(), - vec![CompletionAssertion::LabelAndKind( - "coos".into(), - CompletionItemKind::Table, - )], - None, - &pool, - ) - .await; - - assert_no_complete_results( - format!( - "update public.coos {}", - QueryWithCursorPosition::cursor_marker() - ) - .as_str(), - None, - &pool, - ) - .await; - - assert_complete_results( - format!( - "update coos set {}", - QueryWithCursorPosition::cursor_marker() + TestCompletionsSuite::new(&pool, Some(setup)) + .with_case( + TestCompletionsCase::new() + .type_sql("update public.coos set name = 'cool' where id = 5;"), ) - .as_str(), - vec![ - CompletionAssertion::Label("id".into()), - CompletionAssertion::Label("name".into()), - ], - None, - &pool, - ) - .await; - - assert_complete_results( - format!( - "update coos set name = 'cool' where {}", - QueryWithCursorPosition::cursor_marker() - ) - .as_str(), - vec![ - CompletionAssertion::Label("id".into()), - CompletionAssertion::Label("name".into()), - ], - None, - &pool, - ) - .await; + .snapshot("suggests_tables_in_update") + .await; } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] @@ -411,31 +354,18 @@ mod tests { ); "#; - assert_complete_results( - format!( - "select * from auth.users u join {}", - QueryWithCursorPosition::cursor_marker() + TestCompletionsSuite::new(&pool, Some(setup)) + .with_case( + TestCompletionsCase::new() + .inside_static_statement("select * from auth.users u ") + .type_sql("join"), ) - .as_str(), - vec![ - CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema), - CompletionAssertion::LabelAndKind( - "information_schema".into(), - CompletionItemKind::Schema, - ), - CompletionAssertion::LabelAndKind("pg_catalog".into(), CompletionItemKind::Schema), - CompletionAssertion::LabelAndKind("pg_toast".into(), CompletionItemKind::Schema), - CompletionAssertion::LabelAndKind("posts".into(), CompletionItemKind::Table), // self-join - CompletionAssertion::LabelAndKind("users".into(), CompletionItemKind::Table), - ], - Some(setup), - &pool, - ) - .await; + .snapshot("suggests_tables_in_join") + .await; } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] - async fn suggests_tables_in_alter_and_drop_statements(pool: PgPool) { + async fn suggests_tables_in_drop_statements(pool: PgPool) { let setup = r#" create schema auth; @@ -454,63 +384,36 @@ mod tests { ); "#; - pool.execute(setup).await.unwrap(); + TestCompletionsSuite::new(&pool, Some(setup)) + .with_case(TestCompletionsCase::new().type_sql("drop table if exists auth.posts")) + .snapshot("suggests_tables_in_drop_statements") + .await; + } - assert_complete_results( - format!("alter table {}", QueryWithCursorPosition::cursor_marker()).as_str(), - vec![ - CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema), - CompletionAssertion::LabelAndKind("posts".into(), CompletionItemKind::Table), - CompletionAssertion::LabelAndKind("users".into(), CompletionItemKind::Table), - ], - None, - &pool, - ) - .await; + #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] + async fn suggests_tables_in_alter_statements(pool: PgPool) { + let setup = r#" + create schema auth; - assert_complete_results( - format!( - "alter table if exists {}", - QueryWithCursorPosition::cursor_marker() - ) - .as_str(), - vec![ - CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema), - CompletionAssertion::LabelAndKind("posts".into(), CompletionItemKind::Table), - CompletionAssertion::LabelAndKind("users".into(), CompletionItemKind::Table), - ], - None, - &pool, - ) - .await; + create table auth.users ( + uid serial primary key, + name text not null, + email text unique not null + ); - assert_complete_results( - format!("drop table {}", QueryWithCursorPosition::cursor_marker()).as_str(), - vec![ - CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema), - CompletionAssertion::LabelAndKind("posts".into(), CompletionItemKind::Table), - CompletionAssertion::LabelAndKind("users".into(), CompletionItemKind::Table), - ], - None, - &pool, - ) - .await; + create table auth.posts ( + pid serial primary key, + user_id int not null references auth.users(uid), + title text not null, + content text, + created_at timestamp default now() + ); + "#; - assert_complete_results( - format!( - "drop table if exists {}", - QueryWithCursorPosition::cursor_marker() - ) - .as_str(), - vec![ - CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema), - CompletionAssertion::LabelAndKind("posts".into(), CompletionItemKind::Table), // self-join - CompletionAssertion::LabelAndKind("users".into(), CompletionItemKind::Table), - ], - None, - &pool, - ) - .await; + TestCompletionsSuite::new(&pool, Some(setup)) + .with_case(TestCompletionsCase::new().type_sql("alter table if exists auth.posts")) + .snapshot("suggests_tables_in_alter_statements") + .await; } #[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")] diff --git a/crates/pgls_completions/src/relevance.rs b/crates/pgls_completions/src/relevance.rs index 9899f1c1d..61a698ffe 100644 --- a/crates/pgls_completions/src/relevance.rs +++ b/crates/pgls_completions/src/relevance.rs @@ -1,6 +1,8 @@ pub(crate) mod filtering; pub(crate) mod scoring; +use crate::providers::SqlKeyword; + #[derive(Debug, Clone)] pub(crate) enum CompletionRelevanceData<'a> { Table(&'a pgls_schema_cache::Table), @@ -9,4 +11,5 @@ pub(crate) enum CompletionRelevanceData<'a> { Schema(&'a pgls_schema_cache::Schema), Policy(&'a pgls_schema_cache::Policy), Role(&'a pgls_schema_cache::Role), + Keyword(&'static SqlKeyword), } diff --git a/crates/pgls_completions/src/relevance/filtering.rs b/crates/pgls_completions/src/relevance/filtering.rs index f273d0591..35adbce44 100644 --- a/crates/pgls_completions/src/relevance/filtering.rs +++ b/crates/pgls_completions/src/relevance/filtering.rs @@ -1,8 +1,69 @@ use pgls_schema_cache::ProcKind; -use pgls_treesitter::context::{TreesitterContext, WrappingClause, WrappingNode}; +use pgls_treesitter::{ + context::{TreesitterContext, WrappingClause, WrappingNode}, + goto_node_at_position, previous_sibling_completed, +}; +use tree_sitter::{InputEdit, Point, Tree}; use super::CompletionRelevanceData; +/// Parses SQL with a keyword injected at the given position, using incremental parsing. +/// +/// Temporarily edits `shared_tree` to hint tree-sitter about the change location, +/// then undoes the edit so the tree can be reused for subsequent keywords. +fn parse_with_replaced_keyword( + shared_tree: &mut Tree, + text: &str, + keyword: &str, + node: tree_sitter::Node, +) -> Tree { + let start_position = node.start_position(); + let start_byte = node.start_byte(); + let old_end_position = node.end_position(); + let old_end_byte = node.end_byte(); + + let new_end_byte = start_byte + keyword.len(); + let new_end_position = Point { + row: start_position.row, + column: start_position.column + keyword.len(), + }; + + shared_tree.edit(&InputEdit { + new_end_byte, + new_end_position, + old_end_byte, + old_end_position, + start_byte, + start_position, + }); + + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(&pgls_treesitter_grammar::LANGUAGE.into()) + .unwrap(); + + let replaced_sql = format!( + "{}{}{}", + &text[..start_byte], + keyword, + &text[old_end_byte..] + ); + + let tree = parser.parse(replaced_sql, Some(shared_tree)).unwrap(); + + // undo edit so shared_tree can be reused + shared_tree.edit(&InputEdit { + new_end_byte: old_end_byte, + new_end_position: old_end_position, + old_end_byte: new_end_byte, + old_end_position: new_end_position, + start_byte, + start_position, + }); + + tree +} + #[derive(Debug)] pub(crate) struct CompletionFilter<'a> { data: CompletionRelevanceData<'a>, @@ -15,17 +76,23 @@ impl<'a> From> for CompletionFilter<'a> { } impl CompletionFilter<'_> { - pub fn is_relevant(&self, ctx: &TreesitterContext) -> Option<()> { - self.completable_context(ctx)?; - - self.check_specific_node_type(ctx) - // we want to rely on treesitter more, so checking the clause is a fallback - .or_else(|| self.check_clause(ctx))?; - - self.check_invocation(ctx)?; - self.check_mentioned_schema_or_alias(ctx)?; - - Some(()) + pub fn is_relevant(&self, ctx: &TreesitterContext, shared_tree: &mut Tree) -> Option<()> { + if let CompletionRelevanceData::Keyword(kw) = self.data { + self.check_keyword_requires_prefix(ctx, kw)?; + self.valid_keyword(ctx, shared_tree)?; + Some(()) + } else { + self.completable_context(ctx)?; + + self.check_specific_node_type(ctx) + // we want to rely on treesitter more, so checking the clause is a fallback + .or_else(|| self.check_clause(ctx))?; + + self.check_invocation(ctx)?; + self.check_mentioned_schema_or_alias(ctx)?; + + Some(()) + } } fn completable_context(&self, ctx: &TreesitterContext) -> Option<()> { @@ -108,15 +175,18 @@ impl CompletionFilter<'_> { "any_identifier" => match self.data { CompletionRelevanceData::Column(_) => { - ctx.node_under_cursor_is_within_field(&[ + let matches_field = ctx.node_under_cursor_is_within_field(&[ "object_reference_1of1", "object_reference_2of2", "object_reference_3of3", "column_reference_1of1", "column_reference_2of2", "column_reference_3of3", - ]) && (!ctx.node_under_cursor_is_within_field(&["binary_expr_right"]) - || ctx.has_any_qualifier()) + ]); + + let has_any_qualifier = ctx.has_any_qualifier(); + + matches_field || has_any_qualifier } CompletionRelevanceData::Schema(_) => ctx.node_under_cursor_is_within_field(&[ @@ -359,6 +429,8 @@ impl CompletionFilter<'_> { _ => false, }, + + CompletionRelevanceData::Keyword(_) => true, } }) .and_then(|is_ok| if is_ok { Some(()) } else { None }) @@ -401,6 +473,7 @@ impl CompletionFilter<'_> { CompletionRelevanceData::Schema(_) => false, // no policy or row completion if user typed a schema node first. CompletionRelevanceData::Policy(_) | CompletionRelevanceData::Role(_) => false, + CompletionRelevanceData::Keyword(_) => false, }; if !matches { @@ -409,6 +482,127 @@ impl CompletionFilter<'_> { Some(()) } + + /// Filters out keywords marked with `require_prefix` unless the user has started typing them. + /// + /// Some keywords like `and`, `as`, `like` are too noisy to show unprompted since they'd + /// appear in nearly every completion list. We only suggest them once the user types at + /// least the first character. + fn check_keyword_requires_prefix( + &self, + ctx: &TreesitterContext, + kw: &crate::providers::SqlKeyword, + ) -> Option<()> { + if !kw.require_prefix { + return Some(()); + } + + let content = ctx.get_node_under_cursor_content()?; + if content.is_empty() || crate::sanitization::is_sanitized_token(&content) { + return None; + } + + if !kw.name.starts_with(content.chars().next().unwrap()) { + return None; + } + + Some(()) + } + + /// Validates whether a keyword would produce valid SQL at the current cursor position. + /// + /// Uses speculative parsing: injects the keyword into the SQL text at the cursor position, + /// re-parses, and checks if the result is grammatically valid. The `shared_tree` is + /// temporarily edited to enable tree-sitter's incremental parsing optimization. + /// + /// # Validation rules + /// + /// 1. **Parse error** → reject. The keyword produces invalid SQL. + /// + /// 2. **Error recovery** → accept. If the previous clause was an ERROR node and injecting + /// the keyword fixes it, the keyword helped tree-sitter recover. + /// + /// 3. **Statement boundary** → only accept `starts_statement` keywords (like `SELECT`, + /// `INSERT`) when there's no current clause or we're after a semicolon. + /// + /// 4. **Clause completion check** → the core logic. Replacing/inserting a keyword is valid + /// only if it doesn't + /// - make a current finished clause unfinished + /// - fully replaces the previous unfinished clause + /// + /// See `GRAMMAR_GUIDELINES.md` for how `@end` field markers track clause completion. + fn valid_keyword(&self, ctx: &TreesitterContext, shared_tree: &mut Tree) -> Option<()> { + let keyword = if let CompletionRelevanceData::Keyword(kw) = self.data { + kw + } else { + return Some(()); + }; + + let tree = + parse_with_replaced_keyword(shared_tree, ctx.text, keyword.name, ctx.node_under_cursor); + + if tree.root_node().has_error() { + return None; + } + + if ctx.previous_clause.is_some_and(|n| n.kind() == "ERROR") { + return Some(()); + } + + let clause_to_investigate = if ctx.node_under_cursor.kind() != "ERROR" { + ctx.current_clause + } else { + ctx.previous_clause + }; + + if clause_to_investigate.is_none() || ctx.previous_clause.is_some_and(|n| n.kind() == ";") { + if keyword.starts_statement { + return Some(()); + } else { + return None; + } + } + + let start_byte = ctx.node_under_cursor.start_byte(); + + if let Some(investigated_node) = goto_node_at_position(&tree, start_byte) { + if !previous_sibling_completed(investigated_node) { + return None; + } + + let old_unfinished_parent = clause_to_investigate.unwrap(); + + let mut new_parent = investigated_node.parent(); + + while let Some(parent) = new_parent { + if !previous_sibling_completed(parent) { + return None; + } + + if parent.kind() == old_unfinished_parent.kind() + || parent.start_byte() < old_unfinished_parent.start_byte() + { + break; + } + + new_parent = parent.parent(); + } + + if let Some(new_parent) = new_parent { + if new_parent.kind() != old_unfinished_parent.kind() { + return None; + } + + if new_parent.start_byte() != old_unfinished_parent.start_byte() { + return None; + } + + return Some(()); + } + } + + None + } } #[cfg(test)] @@ -433,8 +627,12 @@ mod tests { pool.execute(setup).await.unwrap(); - assert_no_complete_results( + assert_complete_results( format!("select * {}", QueryWithCursorPosition::cursor_marker()).as_str(), + vec![CompletionAssertion::LabelAndKind( + "from".into(), + crate::CompletionItemKind::Keyword, + )], None, &pool, ) diff --git a/crates/pgls_completions/src/relevance/scoring.rs b/crates/pgls_completions/src/relevance/scoring.rs index 193552d5a..cf84f5e50 100644 --- a/crates/pgls_completions/src/relevance/scoring.rs +++ b/crates/pgls_completions/src/relevance/scoring.rs @@ -33,6 +33,7 @@ impl CompletionScore<'_> { } pub fn calc_score(&mut self, ctx: &TreesitterContext) { + self.check_is_keyword(); self.check_is_user_defined(); self.check_matches_schema(ctx); self.check_matches_query_input(ctx); @@ -44,6 +45,12 @@ impl CompletionScore<'_> { self.check_is_not_wellknown_migration(ctx); } + fn check_is_keyword(&mut self) { + if matches!(self.data, CompletionRelevanceData::Keyword(_)) { + self.score -= 10; + } + } + fn check_matches_query_input(&mut self, ctx: &TreesitterContext) { let content = match ctx.get_node_under_cursor_content() { Some(c) if !sanitization::is_sanitized_token(c.as_str()) => c.replace('"', ""), @@ -59,6 +66,7 @@ impl CompletionScore<'_> { CompletionRelevanceData::Schema(s) => s.name.as_str().to_ascii_lowercase(), CompletionRelevanceData::Policy(p) => p.name.as_str().to_ascii_lowercase(), CompletionRelevanceData::Role(r) => r.name.as_str().to_ascii_lowercase(), + CompletionRelevanceData::Keyword(k) => k.name.to_ascii_lowercase(), }; let fz_matcher = SkimMatcherV2::default(); @@ -197,6 +205,8 @@ impl CompletionScore<'_> { WrappingClause::DropRole | WrappingClause::AlterRole => 25, _ => -50, }, + + CompletionRelevanceData::Keyword(_) => 0, } } @@ -265,7 +275,9 @@ impl CompletionScore<'_> { ctx.head_qualifier_sanitized() } - CompletionRelevanceData::Schema(_) | CompletionRelevanceData::Role(_) => None, + CompletionRelevanceData::Schema(_) + | CompletionRelevanceData::Role(_) + | CompletionRelevanceData::Keyword(_) => None, }; if schema_from_qualifier.is_none() { @@ -294,6 +306,7 @@ impl CompletionScore<'_> { CompletionRelevanceData::Schema(s) => s.name.as_str(), CompletionRelevanceData::Policy(p) => p.name.as_str(), CompletionRelevanceData::Role(r) => r.name.as_str(), + CompletionRelevanceData::Keyword(k) => k.name, } } @@ -305,6 +318,7 @@ impl CompletionScore<'_> { CompletionRelevanceData::Schema(s) => Some(s.name.as_str()), CompletionRelevanceData::Policy(p) => Some(p.schema_name.as_str()), CompletionRelevanceData::Role(_) => None, + CompletionRelevanceData::Keyword(_) => None, } } diff --git a/crates/pgls_completions/src/sanitization.rs b/crates/pgls_completions/src/sanitization.rs index 2b10ee01d..58f8639fb 100644 --- a/crates/pgls_completions/src/sanitization.rs +++ b/crates/pgls_completions/src/sanitization.rs @@ -124,6 +124,7 @@ where tree: Cow::Owned(tree), } } + fn unadjusted(params: CompletionParams<'larger>) -> Self { Self { position: params.position, @@ -146,7 +147,7 @@ fn cursor_inbetween_nodes(sql: &str, position: TextSize) -> bool { let mut chars = sql.chars(); let previous_whitespace = chars - .nth(position - 1) + .nth(position.saturating_sub(1)) .is_some_and(|c| c.is_ascii_whitespace()); let current_whitespace = chars.next().is_some_and(|c| c.is_ascii_whitespace()); @@ -169,7 +170,9 @@ fn cursor_prepared_to_write_token_after_last_node(sql: &str, position: TextSize) fn cursor_on_a_dot(sql: &str, position: TextSize) -> bool { let position: usize = position.into(); - sql.chars().nth(position - 1).is_some_and(|c| c == '.') + sql.chars() + .nth(position.saturating_sub(1)) + .is_some_and(|c| c == '.') } fn cursor_before_semicolon(tree: &tree_sitter::Tree, position: TextSize) -> bool { @@ -244,7 +247,11 @@ fn cursor_between_parentheses(sql: &str, position: TextSize) -> bool { // early check: '(|)' // however, we want to check this after the level nesting. let mut chars = sql.chars(); - if chars.nth(position - 1).is_some_and(|c| c == '(') && chars.next().is_some_and(|c| c == ')') { + if chars + .nth(position.saturating_sub(1)) + .is_some_and(|c| c == '(') + && chars.next().is_some_and(|c| c == ')') + { return true; } diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__after_from_clause.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__after_from_clause.snap new file mode 100644 index 000000000..504a4e958 --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__after_from_clause.snap @@ -0,0 +1,87 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create table public.users ( + id serial primary key, + email varchar(255) +); + + +-------------- + +select email from users | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + +select email from users w| + +Results: +where - where (Keyword) +window - window (Keyword) + +-------------- + +select email from users where | + +Results: +email - public.users.email (Column) +id - public.users.id (Column) +abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +action_condition - information_schema.triggers.action_condition (Column) +action_order - information_schema.triggers.action_order (Column) + +-------------- + +select email from users where i| + +Results: +id - public.users.id (Column) +email - public.users.email (Column) +ident - pg_catalog.pg_backend_memory_contexts.ident (Column) +identity_cycle - information_schema.columns.identity_cycle (Column) +identity_generation - information_schema.columns.identity_generation (Column) + +-------------- + +select email from users where id | + +Results: +group - group (Keyword) +limit - limit (Keyword) +order - order (Keyword) +window - window (Keyword) + +-------------- + +select email from users where id = | + +Results: +email - public.users.email (Column) +id - public.users.id (Column) +abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +action_condition - information_schema.triggers.action_condition (Column) +action_order - information_schema.triggers.action_order (Column) + +-------------- + +select email from users where id = 1| +select email from users where id = 1; | + +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_in_join_on_clause.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_in_join_on_clause.snap index 73e340190..cc9cca2db 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_in_join_on_clause.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_in_join_on_clause.snap @@ -56,6 +56,16 @@ user_id - auth.posts.user_id (Column) -------------- select u.id, auth.posts.content from auth.users u join auth.posts p on p.user_id | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + select u.id, auth.posts.content from auth.users u join auth.posts p on p.user_id = | Results: @@ -86,3 +96,12 @@ uid - auth.users.uid (Column) -------------- select u.id, auth.posts.content from auth.users u join auth.posts p on p.user_id = u.uid; | + +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_join_kw.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_join_kw.snap new file mode 100644 index 000000000..dfad07c11 --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_join_kw.snap @@ -0,0 +1,16 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create table public.users ( + id serial primary key, + email varchar(255) +); + + +-------------- + +select email from users left | +select email from users left j | diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns.snap index 8ef51386a..490bec446 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns.snap @@ -17,6 +17,15 @@ create table private.users ( -------------- s| + +Results: +select - select (Keyword) +set - set (Keyword) +insert - insert (Keyword) +reset - reset (Keyword) + +-------------- + select | Results: @@ -62,7 +71,19 @@ encoding - pg_catalog.pg_database.encoding (Column) -------------- select "email" | + +Results: +from - from (Keyword) + +-------------- + select "email" f| + +Results: +from - from (Keyword) + +-------------- + select "email" from | Results: @@ -116,3 +137,12 @@ users - private.users (Table) select "email" from "private".u| select "email" from "private".users; | + +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns_with_aliases.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns_with_aliases.snap index a21fe79fe..580ca1614 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns_with_aliases.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__completes_quoted_columns_with_aliases.snap @@ -24,6 +24,15 @@ create table public.names ( ***Case 1:*** s| + +Results: +select - select (Keyword) +set - set (Keyword) +insert - insert (Keyword) +reset - reset (Keyword) + +-------------- + select | Results: @@ -73,7 +82,19 @@ select "pr"."| select "pr"."|" select "pr"."e|" select "pr"."email" | + +Results: +from - from (Keyword) + +-------------- + select "pr"."email" f| + +Results: +from - from (Keyword) + +-------------- + select "pr"."email" from | Results: @@ -111,11 +132,31 @@ users - private.users (Table) -------------- select "pr"."email" from private.users | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + select "pr"."email" from private.users "| select "pr"."email" from private.users "|" select "pr"."email" from private.users "p|" select "pr"."email" from private.users "pr" | +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + + diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__does_not_complete_cols_in_join_clauses.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__does_not_complete_cols_in_join_clauses.snap index 629e98bc6..3a6dd9965 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__does_not_complete_cols_in_join_clauses.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__does_not_complete_cols_in_join_clauses.snap @@ -24,6 +24,15 @@ create table auth.posts ( -------------- s| + +Results: +select - select (Keyword) +set - set (Keyword) +insert - insert (Keyword) +reset - reset (Keyword) + +-------------- + select | Results: @@ -51,7 +60,19 @@ pid - auth.posts.pid (Column) select u.uid, p.| select u.uid, p.c| select u.uid, p.content | + +Results: +from - from (Keyword) + +-------------- + select u.uid, p.content f| + +Results: +from - from (Keyword) + +-------------- + select u.uid, p.content from | **Schema suggestions should be prioritized, since we want to push users to specify them.** @@ -94,8 +115,34 @@ users - auth.users (Table) -------------- select u.uid, p.content from auth.users | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + select u.uid, p.content from auth.users u | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + select u.uid, p.content from auth.users u j| + +Results: +join - join (Keyword) + +-------------- + select u.uid, p.content from auth.users u join | Results: @@ -134,8 +181,28 @@ posts - auth.posts (Table) -------------- select u.uid, p.content from auth.users u join auth.posts | + +Results: +on - on (Keyword) +using - using (Keyword) + +-------------- + select u.uid, p.content from auth.users u join auth.posts p | + +Results: +on - on (Keyword) +using - using (Keyword) + +-------------- + select u.uid, p.content from auth.users u join auth.posts p o| + +Results: +on - on (Keyword) + +-------------- + select u.uid, p.content from auth.users u join auth.posts p on | Results: @@ -164,6 +231,16 @@ uid - auth.users.uid (Column) -------------- select u.uid, p.content from auth.users u join auth.posts p on u.uid | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + select u.uid, p.content from auth.users u join auth.posts p on u.uid = | Results: @@ -194,3 +271,12 @@ user_id - auth.posts.user_id (Column) -------------- select u.uid, p.content from auth.users u join auth.posts p on u.uid = p.user_id | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__filters_out_by_aliases_in_join_on.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__filters_out_by_aliases_in_join_on.snap index 37c635810..7d0f26a33 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__filters_out_by_aliases_in_join_on.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__filters_out_by_aliases_in_join_on.snap @@ -24,7 +24,20 @@ create table auth.posts ( -------------- select u.id, p.content from auth.users u join auth.posts p | + +Results: +on - on (Keyword) +using - using (Keyword) + +-------------- + select u.id, p.content from auth.users u join auth.posts p o| + +Results: +on - on (Keyword) + +-------------- + select u.id, p.content from auth.users u join auth.posts p on | **Should prefer primary indices here.** @@ -55,6 +68,16 @@ email - auth.users.email (Column) -------------- select u.id, p.content from auth.users u join auth.posts p on u.id | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + select u.id, p.content from auth.users u join auth.posts p on u.id = | Results: @@ -86,3 +109,12 @@ user_id - auth.posts.user_id (Column) -------------- select u.id, p.content from auth.users u join auth.posts p on u.id = p.user_id | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__ignores_cols_in_from_clause.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__ignores_cols_in_from_clause.snap index a6c1b9f57..3c16b91c7 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__ignores_cols_in_from_clause.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__ignores_cols_in_from_clause.snap @@ -56,3 +56,12 @@ users - private.users (Table) -------------- select * from private.users | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__prefers_not_mentioned_columns.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__prefers_not_mentioned_columns.snap index 9ccf98a9a..ab52b99cd 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__prefers_not_mentioned_columns.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__prefers_not_mentioned_columns.snap @@ -116,8 +116,8 @@ Results: c - public.two.c (Column) cache_size - pg_catalog.pg_sequences.cache_size (Column) calls - pg_catalog.pg_stat_user_functions.calls (Column) +cast - cast (Keyword) castcontext - pg_catalog.pg_cast.castcontext (Column) -castfunc - pg_catalog.pg_cast.castfunc (Column) -------------- @@ -268,8 +268,8 @@ Results: c - public.two.c (Column) cache_size - pg_catalog.pg_sequences.cache_size (Column) calls - pg_catalog.pg_stat_user_functions.calls (Column) +cast - cast (Keyword) castcontext - pg_catalog.pg_cast.castcontext (Column) -castfunc - pg_catalog.pg_cast.castfunc (Column) -------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__shows_multiple_columns_if_no_relation_specified.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__shows_multiple_columns_if_no_relation_specified.snap index 463bca8f4..6defa0825 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__shows_multiple_columns_if_no_relation_specified.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__shows_multiple_columns_if_no_relation_specified.snap @@ -25,6 +25,15 @@ create table private.audio_books ( -------------- s| + +Results: +select - select (Keyword) +set - set (Keyword) +insert - insert (Keyword) +reset - reset (Keyword) + +-------------- + select | **Should suggest all columns with n first** @@ -44,9 +53,14 @@ Results: name - public.users.name (Column) narrator - public.audio_books.narrator (Column) narrator_id - private.audio_books.narrator_id (Column) +null - null (Keyword) name - Schema: pg_catalog.name (Function) -nameconcatoid - Schema: pg_catalog.nameconcatoid (Function) -------------- select narrator_id | + +Results: +from - from (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_alter_table_and_drop_table.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_alter_table_and_drop_table.snap index 76dc39d7e..11ff82787 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_alter_table_and_drop_table.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_alter_table_and_drop_table.snap @@ -17,6 +17,13 @@ create table instruments ( ***Case 1:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -95,6 +102,13 @@ alter table instruments drop column name | ***Case 2:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -197,6 +211,13 @@ alter table instruments drop column if exists name | ***Case 3:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -230,7 +251,7 @@ created_at - public.instruments.created_at (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) -abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +column - column (Keyword) -------------- @@ -238,10 +259,10 @@ alter table instruments alter c| Results: created_at - public.instruments.created_at (Column) +column - column (Keyword) cache_size - pg_catalog.pg_sequences.cache_size (Column) calls - pg_catalog.pg_stat_user_functions.calls (Column) castcontext - pg_catalog.pg_cast.castcontext (Column) -castfunc - pg_catalog.pg_cast.castfunc (Column) -------------- @@ -289,6 +310,13 @@ instruments - public.instruments (Table) ***Case 4:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -322,7 +350,7 @@ created_at - public.instruments.created_at (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) -abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +column - column (Keyword) -------------- @@ -330,10 +358,10 @@ alter table instruments alter n| Results: name - public.instruments.name (Column) +column - column (Keyword) n_dead_tup - pg_catalog.pg_stat_all_tables.n_dead_tup (Column) n_distinct - pg_catalog.pg_stats.n_distinct (Column) n_ins_since_vacuum - pg_catalog.pg_stat_all_tables.n_ins_since_vacuum (Column) -n_live_tup - pg_catalog.pg_stat_all_tables.n_live_tup (Column) -------------- @@ -359,6 +387,13 @@ instruments - public.instruments (Table) ***Case 5:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -408,7 +443,7 @@ created_at - public.instruments.created_at (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) -abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +column - column (Keyword) -------------- @@ -416,10 +451,10 @@ alter table public.instruments alter c| Results: created_at - public.instruments.created_at (Column) +column - column (Keyword) cache_size - pg_catalog.pg_sequences.cache_size (Column) calls - pg_catalog.pg_stat_user_functions.calls (Column) castcontext - pg_catalog.pg_cast.castcontext (Column) -castfunc - pg_catalog.pg_cast.castfunc (Column) -------------- @@ -453,6 +488,13 @@ alter table public.instruments alter column name | ***Case 6:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -486,7 +528,7 @@ created_at - public.instruments.created_at (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) -abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +column - column (Keyword) -------------- @@ -494,10 +536,10 @@ alter table instruments alter n| Results: name - public.instruments.name (Column) +column - column (Keyword) n_dead_tup - pg_catalog.pg_stat_all_tables.n_dead_tup (Column) n_distinct - pg_catalog.pg_stats.n_distinct (Column) n_ins_since_vacuum - pg_catalog.pg_stat_all_tables.n_ins_since_vacuum (Column) -n_live_tup - pg_catalog.pg_stat_all_tables.n_live_tup (Column) -------------- @@ -509,6 +551,13 @@ alter table instruments alter name | ***Case 7:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -542,7 +591,7 @@ created_at - public.instruments.created_at (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) -abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +column - column (Keyword) -------------- @@ -550,15 +599,27 @@ alter table instruments rename n| Results: name - public.instruments.name (Column) +column - column (Keyword) n_dead_tup - pg_catalog.pg_stat_all_tables.n_dead_tup (Column) n_distinct - pg_catalog.pg_stats.n_distinct (Column) n_ins_since_vacuum - pg_catalog.pg_stat_all_tables.n_ins_since_vacuum (Column) -n_live_tup - pg_catalog.pg_stat_all_tables.n_live_tup (Column) -------------- alter table instruments rename name | + +Results: +to - to (Keyword) + +-------------- + alter table instruments rename name t| + +Results: +to - to (Keyword) + +-------------- + alter table instruments rename name to | alter table instruments rename name to n| alter table instruments rename name to new_col | @@ -569,6 +630,13 @@ alter table instruments rename name to new_col | ***Case 8:*** a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + alter | alter t| alter table | @@ -618,7 +686,7 @@ created_at - public.instruments.created_at (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) -abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +column - column (Keyword) -------------- @@ -626,10 +694,10 @@ alter table public.instruments rename c| Results: created_at - public.instruments.created_at (Column) +column - column (Keyword) cache_size - pg_catalog.pg_sequences.cache_size (Column) calls - pg_catalog.pg_stat_user_functions.calls (Column) castcontext - pg_catalog.pg_cast.castcontext (Column) -castfunc - pg_catalog.pg_cast.castfunc (Column) -------------- @@ -656,7 +724,19 @@ n_live_tup - pg_catalog.pg_stat_all_tables.n_live_tup (Column) -------------- alter table public.instruments rename column name | + +Results: +to - to (Keyword) + +-------------- + alter table public.instruments rename column name t| + +Results: +to - to (Keyword) + +-------------- + alter table public.instruments rename column name to | alter table public.instruments rename column name to n| alter table public.instruments rename column name to new_col | diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_insert_clause.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_insert_clause.snap index 0d300f984..0323de0f3 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_insert_clause.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_insert_clause.snap @@ -22,8 +22,26 @@ create table others ( ***Case 1:*** i| + +Results: +insert - insert (Keyword) + +-------------- + insert | + +Results: +into - into (Keyword) + +-------------- + insert i| + +Results: +into - into (Keyword) + +-------------- + insert into | Results: @@ -47,6 +65,13 @@ pg_catalog.pg_ident_file_mappings - pg_catalog.pg_ident_file_mappings (Table) -------------- insert into instruments | + +Results: +select - select (Keyword) +values - values (Keyword) + +-------------- + insert into instruments (| insert into instruments (|) @@ -54,8 +79,8 @@ Results: id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) +select - select (Keyword) a - public.others.a (Column) -b - public.others.b (Column) -------------- @@ -93,7 +118,20 @@ n_live_tup - pg_catalog.pg_stat_all_tables.n_live_tup (Column) -------------- insert into instruments (id, name) | + +Results: +select - select (Keyword) +values - values (Keyword) + +-------------- + insert into instruments (id, name) v| + +Results: +values - values (Keyword) + +-------------- + insert into instruments (id, name) values | insert into instruments (id, name) values (| insert into instruments (id, name) values (|) @@ -102,8 +140,8 @@ Results: z - public.instruments.z (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) +default - default (Keyword) a - public.others.a (Column) -b - public.others.b (Column) -------------- @@ -114,22 +152,50 @@ Results: z - public.instruments.z (Column) id - public.instruments.id (Column) name - public.instruments.name (Column) +default - default (Keyword) a - public.others.a (Column) -b - public.others.b (Column) -------------- insert into instruments (id, name) values (1, '|) insert into instruments (id, name) values (1, 'my_bass'); | +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- + + ***Case 2:*** i| + +Results: +insert - insert (Keyword) + +-------------- + insert | + +Results: +into - into (Keyword) + +-------------- + insert i| + +Results: +into - into (Keyword) + +-------------- + insert into | Results: @@ -153,6 +219,13 @@ pg_catalog.pg_ident_file_mappings - pg_catalog.pg_ident_file_mappings (Table) -------------- insert into instruments | + +Results: +select - select (Keyword) +values - values (Keyword) + +-------------- + insert into instruments (| insert into instruments (|) @@ -160,8 +233,8 @@ Results: id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) +select - select (Keyword) a - public.others.a (Column) -b - public.others.b (Column) -------------- @@ -221,7 +294,20 @@ n_live_tup - pg_catalog.pg_stat_all_tables.n_live_tup (Column) -------------- insert into instruments ("id", "name") | + +Results: +select - select (Keyword) +values - values (Keyword) + +-------------- + insert into instruments ("id", "name") v| + +Results: +values - values (Keyword) + +-------------- + insert into instruments ("id", "name") values | insert into instruments ("id", "name") values (| insert into instruments ("id", "name") values (|) @@ -230,8 +316,8 @@ Results: id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) +default - default (Keyword) a - public.others.a (Column) -b - public.others.b (Column) -------------- @@ -242,14 +328,24 @@ Results: id - public.instruments.id (Column) name - public.instruments.name (Column) z - public.instruments.z (Column) +default - default (Keyword) a - public.others.a (Column) -b - public.others.b (Column) -------------- insert into instruments ("id", "name") values (1, '|) insert into instruments ("id", "name") values (1, 'my_bass'); | +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- + + diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_where_clause.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_where_clause.snap index a291aad9e..a4f591bc0 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_where_clause.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_in_where_clause.snap @@ -21,7 +21,24 @@ create table others ( -------------- select name from instruments i join others o on i.z = o.a | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + select name from instruments i join others o on i.z = o.a w| + +Results: +where - where (Keyword) +window - window (Keyword) + +-------------- + select name from instruments i join others o on i.z = o.a where | Results: @@ -34,7 +51,7 @@ i.id - public.instruments.id (Column) -------------- select name from instruments i join others o on i.z = o.a where o.| -**should respect alias speciifcation** +**should respect alias specification** Results: a - public.others.a (Column) @@ -44,15 +61,24 @@ c - public.others.c (Column) -------------- select name from instruments i join others o on i.z = o.a where o.a | + +Results: +group - group (Keyword) +limit - limit (Keyword) +order - order (Keyword) +window - window (Keyword) + +-------------- + select name from instruments i join others o on i.z = o.a where o.a = | **should not prioritize suggest columns or schemas (right side of binary expression)** Results: -instruments - public.instruments (Table) -others - public.others (Table) -_sqlx_migrations - public._sqlx_migrations (Table) -information_schema - information_schema (Schema) -pg_catalog - pg_catalog (Schema) +o.b - public.others.b (Column) +o.c - public.others.c (Column) +i.created_at - public.instruments.created_at (Column) +i.id - public.instruments.id (Column) +i.name - public.instruments.name (Column) -------------- @@ -67,6 +93,15 @@ z - public.instruments.z (Column) -------------- select name from instruments i join others o on i.z = o.a where o.a = i.z | + +Results: +group - group (Keyword) +limit - limit (Keyword) +order - order (Keyword) +window - window (Keyword) + +-------------- + select name from instruments i join others o on i.z = o.a where o.a = i.z a| select name from instruments i join others o on i.z = o.a where o.a = i.z and | **should prioritize columns that aren't already mentioned** @@ -98,16 +133,34 @@ id - public.instruments.id (Column) -------------- select name from instruments i join others o on i.z = o.a where o.a = i.z and i.id | + +Results: +group - group (Keyword) +limit - limit (Keyword) +order - order (Keyword) +window - window (Keyword) + +-------------- + select name from instruments i join others o on i.z = o.a where o.a = i.z and i.id > | Results: -instruments - public.instruments (Table) -others - public.others (Table) -_sqlx_migrations - public._sqlx_migrations (Table) -information_schema - information_schema (Schema) -pg_catalog - pg_catalog (Schema) +o.b - public.others.b (Column) +o.c - public.others.c (Column) +i.created_at - public.instruments.created_at (Column) +i.name - public.instruments.name (Column) +i.z - public.instruments.z (Column) -------------- select name from instruments i join others o on i.z = o.a where o.a = i.z and i.id > 5| select name from instruments i join others o on i.z = o.a where o.a = i.z and i.id > 5; | + +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_policy_using_clause.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_policy_using_clause.snap index d3db86856..d7441a1ef 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_policy_using_clause.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_columns_policy_using_clause.snap @@ -31,10 +31,10 @@ create policy "my_pol" on public.instruments for select using (i|) Results: id - public.instruments.id (Column) +interval - interval (Keyword) ident - pg_catalog.pg_backend_memory_contexts.ident (Column) identity_cycle - information_schema.columns.identity_cycle (Column) identity_generation - information_schema.columns.identity_generation (Column) -identity_increment - information_schema.columns.identity_increment (Column) -------------- @@ -67,10 +67,10 @@ create policy "my_pol" on public.instruments for select using (id = 1 and c|) Results: created_at - public.instruments.created_at (Column) +cast - cast (Keyword) cache_size - pg_catalog.pg_sequences.cache_size (Column) calls - pg_catalog.pg_stat_user_functions.calls (Column) castcontext - pg_catalog.pg_cast.castcontext (Column) -castfunc - pg_catalog.pg_cast.castfunc (Column) -------------- @@ -99,10 +99,10 @@ create policy "my_pol" on public.instruments for insert with check (i|) Results: id - public.instruments.id (Column) +interval - interval (Keyword) ident - pg_catalog.pg_backend_memory_contexts.ident (Column) identity_cycle - information_schema.columns.identity_cycle (Column) identity_generation - information_schema.columns.identity_generation (Column) -identity_increment - information_schema.columns.identity_increment (Column) -------------- @@ -135,10 +135,10 @@ create policy "my_pol" on public.instruments for insert with check (id = 1 and c Results: created_at - public.instruments.created_at (Column) +cast - cast (Keyword) cache_size - pg_catalog.pg_sequences.cache_size (Column) calls - pg_catalog.pg_stat_user_functions.calls (Column) castcontext - pg_catalog.pg_cast.castcontext (Column) -castfunc - pg_catalog.pg_cast.castfunc (Column) -------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_relevant_columns_without_letters.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_relevant_columns_without_letters.snap index 758932c93..4ee4242ae 100644 --- a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_relevant_columns_without_letters.snap +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_relevant_columns_without_letters.snap @@ -15,6 +15,15 @@ create table users ( -------------- s| + +Results: +select - select (Keyword) +set - set (Keyword) +insert - insert (Keyword) +reset - reset (Keyword) + +-------------- + select | Results: @@ -30,15 +39,27 @@ select n| Results: name - public.users.name (Column) +null - null (Keyword) +name - Schema: pg_catalog.name (Function) nameconcatoid - Schema: pg_catalog.nameconcatoid (Function) nameeq - Schema: pg_catalog.nameeq (Function) -nameeqtext - Schema: pg_catalog.nameeqtext (Function) -namege - Schema: pg_catalog.namege (Function) -------------- select name | + +Results: +from - from (Keyword) + +-------------- + select name f| + +Results: +from - from (Keyword) + +-------------- + select name from | Results: @@ -62,3 +83,12 @@ information_schema.user_defined_types - information_schema.user_defined_types (T -------------- select name from users | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_alter_statements.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_alter_statements.snap new file mode 100644 index 000000000..308c56e34 --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_alter_statements.snap @@ -0,0 +1,103 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create schema auth; + +create table auth.users ( + uid serial primary key, + name text not null, + email text unique not null +); + +create table auth.posts ( + pid serial primary key, + user_id int not null references auth.users(uid), + title text not null, + content text, + created_at timestamp default now() +); + + +-------------- + +a| + +Results: +truncate - truncate (Keyword) +update - update (Keyword) + +-------------- + +alter | +alter t| +alter table | + +Results: +auth - auth (Schema) +auth.posts - auth.posts (Table) +auth.users - auth.users (Table) +_sqlx_migrations - public._sqlx_migrations (Table) +information_schema - information_schema (Schema) + +-------------- + +alter table i| + +Results: +information_schema - information_schema (Schema) +information_schema.information_schema_catalog_name - information_schema.information_schema_catalog_name (Table) +public - public (Schema) +pg_catalog.pg_ident_file_mappings - pg_catalog.pg_ident_file_mappings (Table) +pg_catalog.pg_index - pg_catalog.pg_index (Table) + +-------------- + +alter table if | +alter table if e| + +Results: +exists - exists (Keyword) + +-------------- + +alter table if exists | + +Results: +auth - auth (Schema) +auth.posts - auth.posts (Table) +auth.users - auth.users (Table) +_sqlx_migrations - public._sqlx_migrations (Table) +information_schema - information_schema (Schema) + +-------------- + +alter table if exists a| + +Results: +auth - auth (Schema) +information_schema.administrable_role_authorizations - information_schema.administrable_role_authorizations (Table) +information_schema.applicable_roles - information_schema.applicable_roles (Table) +information_schema.attributes - information_schema.attributes (Table) +information_schema.collation_character_set_applicability - information_schema.collation_character_set_applicability (Table) + +-------------- + +alter table if exists auth.| + +Results: +posts - auth.posts (Table) +users - auth.users (Table) + +-------------- + +alter table if exists auth.p| + +Results: +posts - auth.posts (Table) + +-------------- + +alter table if exists auth.posts | diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_drop_statements.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_drop_statements.snap new file mode 100644 index 000000000..14e8d3ef3 --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_drop_statements.snap @@ -0,0 +1,102 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create schema auth; + +create table auth.users ( + uid serial primary key, + name text not null, + email text unique not null +); + +create table auth.posts ( + pid serial primary key, + user_id int not null references auth.users(uid), + title text not null, + content text, + created_at timestamp default now() +); + + +-------------- + +d| + +Results: +update - update (Keyword) + +-------------- + +drop | +drop t| +drop table | + +Results: +auth - auth (Schema) +auth.posts - auth.posts (Table) +auth.users - auth.users (Table) +_sqlx_migrations - public._sqlx_migrations (Table) +information_schema - information_schema (Schema) + +-------------- + +drop table i| + +Results: +information_schema - information_schema (Schema) +information_schema.information_schema_catalog_name - information_schema.information_schema_catalog_name (Table) +public - public (Schema) +pg_catalog.pg_ident_file_mappings - pg_catalog.pg_ident_file_mappings (Table) +pg_catalog.pg_index - pg_catalog.pg_index (Table) + +-------------- + +drop table if | +drop table if e| +drop table if exists | + +Results: +auth - auth (Schema) +auth.posts - auth.posts (Table) +auth.users - auth.users (Table) +_sqlx_migrations - public._sqlx_migrations (Table) +information_schema - information_schema (Schema) + +-------------- + +drop table if exists a| + +Results: +auth - auth (Schema) +information_schema.administrable_role_authorizations - information_schema.administrable_role_authorizations (Table) +information_schema.applicable_roles - information_schema.applicable_roles (Table) +information_schema.attributes - information_schema.attributes (Table) +information_schema.collation_character_set_applicability - information_schema.collation_character_set_applicability (Table) + +-------------- + +drop table if exists auth.| + +Results: +posts - auth.posts (Table) +users - auth.users (Table) + +-------------- + +drop table if exists auth.p| + +Results: +posts - auth.posts (Table) + +-------------- + +drop table if exists auth.posts | + +Results: +cascade - cascade (Keyword) +restrict - restrict (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_join.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_join.snap new file mode 100644 index 000000000..136d848e8 --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_join.snap @@ -0,0 +1,53 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create schema auth; + +create table auth.users ( + uid serial primary key, + name text not null, + email text unique not null +); + +create table auth.posts ( + pid serial primary key, + user_id int not null references auth.users(uid), + title text not null, + content text, + created_at timestamp default now() +); + + +-------------- + +select * from auth.users u | + +Results: +cross - cross (Keyword) +full - full (Keyword) +group - group (Keyword) +inner - inner (Keyword) +join - join (Keyword) + +-------------- + +select * from auth.users u j| + +Results: +join - join (Keyword) + +-------------- + +select * from auth.users u join | + +Results: +auth - auth (Schema) +information_schema - information_schema (Schema) +pg_catalog - pg_catalog (Schema) +pg_toast - pg_toast (Schema) +auth.posts - auth.posts (Table) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_update.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_update.snap new file mode 100644 index 000000000..fe3282315 --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__suggests_tables_in_update.snap @@ -0,0 +1,155 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create table coos ( + id serial primary key, + name text +); + + +-------------- + +u| + +Results: +update - update (Keyword) +truncate - truncate (Keyword) + +-------------- + +update | + +Results: +coos - public.coos (Table) +_sqlx_migrations - public._sqlx_migrations (Table) +information_schema - information_schema (Schema) +pg_catalog - pg_catalog (Schema) +pg_toast - pg_toast (Schema) + +-------------- + +update p| + +Results: +public - public (Schema) +pg_catalog - pg_catalog (Schema) +pg_toast - pg_toast (Schema) +information_schema.parameters - information_schema.parameters (Table) +pg_catalog.pg_aggregate - pg_catalog.pg_aggregate (Table) + +-------------- + +update public.| + +Results: +coos - public.coos (Table) +_sqlx_migrations - public._sqlx_migrations (Table) + +-------------- + +update public.c| + +Results: +coos - public.coos (Table) + +-------------- + +update public.coos | + +Results: +set - set (Keyword) + +-------------- + +update public.coos s| + +Results: +set - set (Keyword) + +-------------- + +update public.coos set | + +Results: +id - public.coos.id (Column) +name - public.coos.name (Column) +information_schema - information_schema (Schema) +pg_catalog - pg_catalog (Schema) +pg_toast - pg_toast (Schema) + +-------------- + +update public.coos set n| + +Results: +name - public.coos.name (Column) +information_schema - information_schema (Schema) +n_dead_tup - pg_catalog.pg_stat_all_tables.n_dead_tup (Column) +n_distinct - pg_catalog.pg_stats.n_distinct (Column) +n_ins_since_vacuum - pg_catalog.pg_stat_all_tables.n_ins_since_vacuum (Column) + +-------------- + +update public.coos set name | +update public.coos set name = | + +Results: +coos - public.coos (Table) +id - public.coos.id (Column) +name - public.coos.name (Column) +_sqlx_migrations - public._sqlx_migrations (Table) +information_schema - information_schema (Schema) + +-------------- + +update public.coos set name = '| +update public.coos set name = 'cool' | +update public.coos set name = 'cool' w| +update public.coos set name = 'cool' where | + +Results: +id - public.coos.id (Column) +name - public.coos.name (Column) +abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +action_condition - information_schema.triggers.action_condition (Column) +action_order - information_schema.triggers.action_order (Column) + +-------------- + +update public.coos set name = 'cool' where i| + +Results: +id - public.coos.id (Column) +ident - pg_catalog.pg_backend_memory_contexts.ident (Column) +identity_cycle - information_schema.columns.identity_cycle (Column) +identity_generation - information_schema.columns.identity_generation (Column) +identity_increment - information_schema.columns.identity_increment (Column) + +-------------- + +update public.coos set name = 'cool' where id | +update public.coos set name = 'cool' where id = | + +Results: +name - public.coos.name (Column) +id - public.coos.id (Column) +abbrev - pg_catalog.pg_timezone_abbrevs.abbrev (Column) +action_condition - information_schema.triggers.action_condition (Column) +action_order - information_schema.triggers.action_order (Column) + +-------------- + +update public.coos set name = 'cool' where id = 5| +update public.coos set name = 'cool' where id = 5; | + +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__works_in_session_authorization_statement.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__works_in_session_authorization_statement.snap new file mode 100644 index 000000000..fca7a55b5 --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__works_in_session_authorization_statement.snap @@ -0,0 +1,61 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create table users ( + id serial primary key, + email varchar, + address text +); + + +-------------- + +s| + +Results: +select - select (Keyword) +set - set (Keyword) +insert - insert (Keyword) +reset - reset (Keyword) + +-------------- + +set | +set s| +set session | +set session a| +set session authorization | + +Results: +anon - anon (Role) +authenticated - authenticated (Role) +owner - owner (Role) +service_role - service_role (Role) +test_login - test_login (Role) + +-------------- + +set session authorization a| + +Results: +anon - anon (Role) +authenticated - authenticated (Role) +pg_read_all_data - pg_read_all_data (Role) +pg_read_all_settings - pg_read_all_settings (Role) +pg_read_all_stats - pg_read_all_stats (Role) + +-------------- + +set session authorization authenticated; | + +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__works_in_set_role_statement.snap b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__works_in_set_role_statement.snap new file mode 100644 index 000000000..43ee1a56e --- /dev/null +++ b/crates/pgls_completions/src/snapshots/pgls_completions__test_helper__works_in_set_role_statement.snap @@ -0,0 +1,59 @@ +--- +source: crates/pgls_completions/src/test_helper.rs +expression: final_snapshot +--- +***Setup*** + +create table users ( + id serial primary key, + email varchar, + address text +); + + +-------------- + +s| + +Results: +select - select (Keyword) +set - set (Keyword) +insert - insert (Keyword) +reset - reset (Keyword) + +-------------- + +set | +set r| +set role | + +Results: +anon - anon (Role) +authenticated - authenticated (Role) +owner - owner (Role) +service_role - service_role (Role) +test_login - test_login (Role) + +-------------- + +set role a| + +Results: +anon - anon (Role) +authenticated - authenticated (Role) +pg_read_all_data - pg_read_all_data (Role) +pg_read_all_settings - pg_read_all_settings (Role) +pg_read_all_stats - pg_read_all_stats (Role) + +-------------- + +set role anon; | + +Results: +insert - insert (Keyword) +reset - reset (Keyword) +select - select (Keyword) +set - set (Keyword) +truncate - truncate (Keyword) + +-------------- diff --git a/crates/pgls_completions/src/test_helper.rs b/crates/pgls_completions/src/test_helper.rs index 7613f2815..8c59860ba 100644 --- a/crates/pgls_completions/src/test_helper.rs +++ b/crates/pgls_completions/src/test_helper.rs @@ -181,9 +181,10 @@ pub(crate) async fn assert_complete_results( assert!( items.len() >= existing.len(), - "Not enough items returned. Expected at least {} items, but got {}", + "Not enough items returned. Expected at least {} items, but got {}. query: {}", existing.len(), - items.len() + items.len(), + query ); for item in &items { @@ -555,7 +556,9 @@ impl TestCompletionsCase { write!(writer, " - ").unwrap(); match item.kind { - CompletionItemKind::Schema | CompletionItemKind::Role => {} + CompletionItemKind::Schema + | CompletionItemKind::Role + | CompletionItemKind::Keyword => {} _ => { write!(writer, "{}.", item.description).unwrap(); } diff --git a/crates/pgls_lsp/src/handlers/completions.rs b/crates/pgls_lsp/src/handlers/completions.rs index 2b06a6090..9bb4104bd 100644 --- a/crates/pgls_lsp/src/handlers/completions.rs +++ b/crates/pgls_lsp/src/handlers/completions.rs @@ -79,5 +79,6 @@ fn to_lsp_types_completion_item_kind( pgls_completions::CompletionItemKind::Schema => lsp_types::CompletionItemKind::CLASS, pgls_completions::CompletionItemKind::Policy => lsp_types::CompletionItemKind::CONSTANT, pgls_completions::CompletionItemKind::Role => lsp_types::CompletionItemKind::CONSTANT, + pgls_completions::CompletionItemKind::Keyword => lsp_types::CompletionItemKind::KEYWORD, } } diff --git a/crates/pgls_test_utils/src/bin/tree_print.rs b/crates/pgls_test_utils/src/bin/tree_print.rs index 1116137a0..d88e408a9 100644 --- a/crates/pgls_test_utils/src/bin/tree_print.rs +++ b/crates/pgls_test_utils/src/bin/tree_print.rs @@ -27,7 +27,7 @@ fn main() { .expect("Failed to parse query."); let mut result = String::new(); - print_ts_tree(&tree.root_node(), &query, 0, &mut result); + print_ts_tree(&tree.root_node(), &query, &mut result); print!("{result}") } diff --git a/crates/pgls_test_utils/src/lib.rs b/crates/pgls_test_utils/src/lib.rs index 1a07cb88b..8fcc58a4c 100644 --- a/crates/pgls_test_utils/src/lib.rs +++ b/crates/pgls_test_utils/src/lib.rs @@ -45,7 +45,17 @@ impl Display for QueryWithCursorPosition { } } -pub fn print_ts_tree(node: &tree_sitter::Node, source: &str, level: usize, result: &mut String) { +pub fn print_ts_tree(node: &tree_sitter::Node, source: &str, result: &mut String) { + print_ts_tree_recur(node, source, 0, result, None); +} + +fn print_ts_tree_recur( + node: &tree_sitter::Node, + source: &str, + level: usize, + result: &mut String, + field_name: Option<&str>, +) { let indent = " ".repeat(level); let node_text = node @@ -57,19 +67,22 @@ pub fn print_ts_tree(node: &tree_sitter::Node, source: &str, level: usize, resul result.push_str( format!( - "{}{} [{}..{}] '{}'\n", + "{}{} [{}..{}] '{}'{}\n", indent, node.kind(), node.start_position().column, node.end_position().column, - node_text + node_text, + field_name.map(|n| format!(" (@{n})")).unwrap_or("".into()) ) .as_str(), ); let mut cursor = node.walk(); - for child in node.children(&mut cursor) { - print_ts_tree(&child, source, level + 1, result); + for (idx, child) in node.children(&mut cursor).enumerate() { + let idx_u32: u32 = idx.try_into().unwrap(); + let field_name = node.field_name_for_child(idx_u32); + print_ts_tree_recur(&child, source, level + 1, result, field_name); } } diff --git a/crates/pgls_treesitter/src/context/mod.rs b/crates/pgls_treesitter/src/context/mod.rs index a536cc9a8..54e80f15d 100644 --- a/crates/pgls_treesitter/src/context/mod.rs +++ b/crates/pgls_treesitter/src/context/mod.rs @@ -384,7 +384,7 @@ impl<'a> TreesitterContext<'a> { "where" => Some(WrappingClause::Where), "update" => Some(WrappingClause::Update), "select" => Some(WrappingClause::Select), - "delete" => Some(WrappingClause::Delete), + "delete_statement" => Some(WrappingClause::Delete), "from" => Some(WrappingClause::From), "drop_table" => Some(WrappingClause::DropTable), "alter_role" => Some(WrappingClause::AlterRole), @@ -579,7 +579,6 @@ mod tests { } #[test] - #[ignore = "will be reintroduced after stacked keyword-completion PRs merge"] fn identifies_clauses() { let test_cases = vec![ ( diff --git a/crates/pgls_treesitter/src/helper.rs b/crates/pgls_treesitter/src/helper.rs index 3119a2b4c..4689cb3ac 100644 --- a/crates/pgls_treesitter/src/helper.rs +++ b/crates/pgls_treesitter/src/helper.rs @@ -1,6 +1,6 @@ use tree_sitter::{Node, Tree}; -pub static SINGLE_TOKEN_RULES: &[&'static str] = &[ +pub static SINGLE_TOKEN_RULES: &[&str] = &[ "any_identifier", "column_identifier", "schema_identifier", @@ -97,7 +97,7 @@ pub fn previous_sibling_completed(node: tree_sitter::Node) -> bool { is_finished && last_children_completed(prev) } else { - false + true } } diff --git a/crates/pgls_treesitter_grammar/Cargo.toml b/crates/pgls_treesitter_grammar/Cargo.toml index e33b198fb..5cf1fa354 100644 --- a/crates/pgls_treesitter_grammar/Cargo.toml +++ b/crates/pgls_treesitter_grammar/Cargo.toml @@ -14,16 +14,16 @@ build = "build.rs" include = ["grammar.js", "queries/*", "src/*", "tree-sitter.json", "LICENSE", "NOTICE"] [dependencies] -tree-sitter-language = "0.1" tree-sitter.workspace = true +tree-sitter-language = "0.1" [build-dependencies] cc = "1.2" [dev-dependencies] +criterion.workspace = true insta = { version = "1.42.1" } pgls_test_utils.workspace = true -criterion.workspace = true [[bench]] harness = false @@ -35,4 +35,4 @@ name = "parsing" [[bench]] harness = false -name = "parsing_with_existing_tree" \ No newline at end of file +name = "parsing_with_existing_tree" diff --git a/crates/pgls_treesitter_grammar/benches/parsing.rs b/crates/pgls_treesitter_grammar/benches/parsing.rs index 7d753e17d..be2ce68fd 100644 --- a/crates/pgls_treesitter_grammar/benches/parsing.rs +++ b/crates/pgls_treesitter_grammar/benches/parsing.rs @@ -3,7 +3,7 @@ use criterion::{Criterion, black_box, criterion_group, criterion_main}; pub fn criterion_benchmark(c: &mut Criterion) { // takes about 3 microseconds on MacBook Pro M2 with 16GB Memory c.bench_function("parsing > small sql", |b| { - let content = format!("select * from users;"); + let content = "select * from users;".to_string(); b.iter(|| { let mut parser = tree_sitter::Parser::new(); @@ -17,8 +17,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { // takes about 38 microseconds on MacBook Pro M2 with 16GB Memory c.bench_function("parsing > mid sql", |b| { - let content = format!( - r#"select + let content = r#"select n.oid :: int8 as "id!", n.nspname as name, u.rolname as "owner!" @@ -33,7 +32,7 @@ where ) and not pg_catalog.starts_with(n.nspname, 'pg_temp_') and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_');"# - ); + .to_string(); b.iter(|| { let mut parser = tree_sitter::Parser::new(); @@ -47,8 +46,7 @@ where // takes about 137 microseconds on MacBook Pro M2 with 16GB Memory c.bench_function("parsing > large sql", |b| { - let content = format!( - r#"with + let content = r#"with available_tables as ( select c.relname as table_name, @@ -104,7 +102,7 @@ where -- system columns, such as `cmax` or `tableoid`, have negative `attnum`s atts.attnum >= 0; "# - ); + .to_string(); b.iter(|| { let mut parser = tree_sitter::Parser::new(); diff --git a/crates/pgls_treesitter_grammar/benches/parsing_with_existing_tree.rs b/crates/pgls_treesitter_grammar/benches/parsing_with_existing_tree.rs index 6b696ccdd..5687185e1 100644 --- a/crates/pgls_treesitter_grammar/benches/parsing_with_existing_tree.rs +++ b/crates/pgls_treesitter_grammar/benches/parsing_with_existing_tree.rs @@ -4,7 +4,7 @@ use tree_sitter::{InputEdit, Point, StreamingIterator}; pub fn criterion_benchmark(c: &mut Criterion) { // takes about 3 microseconds on MacBook Pro M2 with 16GB Memory c.bench_function("parsing with existing tree > small sql", |b| { - let content = format!("select * from users;"); + let content = "select * from users;".to_string(); let mut parser = tree_sitter::Parser::new(); parser @@ -89,8 +89,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { // takes about 12 microseconds on MacBook Pro M2 with 16GB Memory c.bench_function("parsing with existing tree > mid sql", |b| { - let content = format!( - r#" + let content = r#" select n.oid :: int8 as "id!", n.nspname as name, @@ -107,7 +106,7 @@ where and not pg_catalog.starts_with(n.nspname, 'pg_temp_') and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_'); "# - ); + .to_string(); let mut parser = tree_sitter::Parser::new(); parser @@ -188,8 +187,7 @@ where // takes about 12 microseconds on MacBook Pro M2 with 16GB Memory c.bench_function("parsing with existing tree > large sql", |b| { - let content = format!( - r#" + let content = r#" with available_tables as ( select c.relname as table_name, @@ -245,7 +243,7 @@ where -- system columns, such as `cmax` or `tableoid`, have negative `attnum`s atts.attnum >= 0; "# - ); + .to_string(); let mut parser = tree_sitter::Parser::new(); parser diff --git a/crates/pgls_treesitter_grammar/grammar.js b/crates/pgls_treesitter_grammar/grammar.js index 6ea8161ba..83222001e 100644 --- a/crates/pgls_treesitter_grammar/grammar.js +++ b/crates/pgls_treesitter_grammar/grammar.js @@ -70,7 +70,7 @@ module.exports = grammar({ // any number of transactions, statements, or blocks with a terminating ; repeat(seq(choice($.transaction, $.statement, $.block), ";")), // optionally, a single statement without a terminating ; - optional($.statement) + optional($.statement), ), keyword_select: (_) => make_keyword("select"), @@ -401,7 +401,7 @@ module.exports = grammar({ choice( make_keyword("int"), make_keyword("integer"), - make_keyword("int4") + make_keyword("int4"), ), keyword_bigint: (_) => choice(make_keyword("bigint"), make_keyword("int8")), keyword_decimal: (_) => make_keyword("decimal"), @@ -420,7 +420,7 @@ module.exports = grammar({ keyword_varchar: ($) => choice( make_keyword("varchar"), - seq(make_keyword("character"), $.keyword_varying) + seq(make_keyword("character"), $.keyword_varying), ), keyword_text: (_) => make_keyword("text"), keyword_binary: (_) => make_keyword("binary"), @@ -500,10 +500,10 @@ module.exports = grammar({ $.keyword_regproc, $.keyword_regtype, - field("custom_type", $.object_reference) + field("custom_type", $.object_reference), ), - optional($.array_size_definition) - ) + optional($.array_size_definition), + ), ), // TODO: clean up @@ -511,8 +511,8 @@ module.exports = grammar({ prec.left( choice( seq($.keyword_array, optional($._array_size_definition)), - repeat1($._array_size_definition) - ) + repeat1($._array_size_definition), + ), ), _array_size_definition: ($) => @@ -527,16 +527,16 @@ module.exports = grammar({ $.keyword_bit, seq( $.keyword_bit, - prec(0, parametric_type($, $.keyword_varying, ["precision"])) + prec(0, parametric_type($, $.keyword_varying, ["precision"])), ), - prec(1, parametric_type($, $.keyword_bit, ["precision"])) + prec(1, parametric_type($, $.keyword_bit, ["precision"])), ), // TODO: should qualify against /\\b(0?[1-9]|[1-4][0-9]|5[0-4])\\b/g float: ($) => choice( parametric_type($, $.keyword_float, ["precision"]), - parametric_type($, $.keyword_float, ["precision", "scale"]) + parametric_type($, $.keyword_float, ["precision", "scale"]), ), double: ($) => @@ -547,18 +547,18 @@ module.exports = grammar({ "precision", "scale", ]), - parametric_type($, $.keyword_real, ["precision", "scale"]) + parametric_type($, $.keyword_real, ["precision", "scale"]), ), decimal: ($) => choice( parametric_type($, $.keyword_decimal, ["precision"]), - parametric_type($, $.keyword_decimal, ["precision", "scale"]) + parametric_type($, $.keyword_decimal, ["precision", "scale"]), ), numeric: ($) => choice( parametric_type($, $.keyword_numeric, ["precision"]), - parametric_type($, $.keyword_numeric, ["precision", "scale"]) + parametric_type($, $.keyword_numeric, ["precision", "scale"]), ), char: ($) => parametric_type($, $.keyword_char), varchar: ($) => parametric_type($, $.keyword_varchar), @@ -567,21 +567,21 @@ module.exports = grammar({ seq( choice($.keyword_with, $.keyword_without), $.keyword_time, - $.keyword_zone + $.keyword_zone, ), time: ($) => seq(parametric_type($, $.keyword_time), optional($._include_time_zone)), timestamp: ($) => seq( parametric_type($, $.keyword_timestamp), - optional($._include_time_zone) + optional($._include_time_zone), ), timestamptz: ($) => parametric_type($, $.keyword_timestamptz), enum: ($) => seq( $.keyword_enum, - paren_list(field("value", alias($._literal_string, $.literal)), true) + paren_list(field("value", alias($._literal_string, $.literal)), true), ), array: ($) => @@ -589,8 +589,8 @@ module.exports = grammar({ $.keyword_array, choice( seq("[", comma_list($._expression, false), field("end", "]")), - seq("(", $._dml_read, field("end", ")")) - ) + seq("(", $._dml_read, field("end", ")")), + ), ), comment: (_) => /--.*/, @@ -603,7 +603,7 @@ module.exports = grammar({ optional($.keyword_transaction), optional(";"), repeat(seq($.statement, ";")), - choice($._commit, $._rollback) + choice($._commit, $._rollback), ), _commit: ($) => seq($.keyword_commit, optional($.keyword_transaction)), @@ -615,7 +615,7 @@ module.exports = grammar({ $.keyword_begin, optional(";"), repeat(seq($.statement, ";")), - $.keyword_end + $.keyword_end, ), statement: ($) => @@ -624,14 +624,14 @@ module.exports = grammar({ seq( $.keyword_explain, optional($.keyword_analyze), - optional($.keyword_verbose) - ) + optional($.keyword_verbose), + ), ), choice( $._ddl_statement, $._dml_write, - optional_parenthesis($._dml_read) - ) + optional_parenthesis($._dml_read), + ), ), _ddl_statement: ($) => @@ -645,7 +645,7 @@ module.exports = grammar({ $.set_statement, $.reset_statement, $.revoke_statement, - $.grant_statement + $.grant_statement, ), _cte: ($) => @@ -653,7 +653,7 @@ module.exports = grammar({ $.keyword_with, optional($.keyword_recursive), $.cte, - repeat(seq(",", $.cte)) + repeat(seq(",", $.cte)), ), _dml_write: ($) => @@ -661,21 +661,21 @@ module.exports = grammar({ seq( optional($._cte), choice( - $._delete_statement, + $.delete_statement, $._insert_statement, $._update_statement, $._truncate_statement, - $._copy_statement - ) - ) + $._copy_statement, + ), + ), ), _dml_read: ($) => seq( optional(optional_parenthesis($._cte)), optional_parenthesis( - choice($._select_statement, $.set_operation, $._show_statement) - ) + choice($._select_statement, $.set_operation, $._show_statement), + ), ), _show_statement: ($) => @@ -688,8 +688,8 @@ module.exports = grammar({ $.keyword_as, optional(seq(optional($.keyword_not), $.keyword_materialized)), wrapped_in_parenthesis( - alias(choice($._dml_read, $._dml_write), $.statement) - ) + alias(choice($._dml_read, $._dml_write), $.statement), + ), ), set_operation: ($) => @@ -702,12 +702,12 @@ module.exports = grammar({ choice( seq($.keyword_union, optional($.keyword_all)), $.keyword_except, - $.keyword_intersect - ) + $.keyword_intersect, + ), ), - $._select_statement - ) - ) + $._select_statement, + ), + ), ), _select_statement: ($) => @@ -715,8 +715,8 @@ module.exports = grammar({ seq( $.select, optional(seq($.keyword_into, $.select_expression)), - optional($.from) - ) + optional($.from), + ), ), comment_statement: ($) => @@ -725,7 +725,7 @@ module.exports = grammar({ $.keyword_on, $._comment_target, $.keyword_is, - choice($.keyword_null, alias($._literal_string, $.literal)) + choice($.keyword_null, alias($._literal_string, $.literal)), ), _argmode: ($) => @@ -734,7 +734,7 @@ module.exports = grammar({ $.keyword_out, $.keyword_inout, $.keyword_variadic, - seq($.keyword_in, $.keyword_out) + seq($.keyword_in, $.keyword_out), ), function_argument: ($) => @@ -742,7 +742,7 @@ module.exports = grammar({ optional($._argmode), optional($.any_identifier), $.type, - optional(seq(choice($.keyword_default, "="), $.literal)) + optional(seq(choice($.keyword_default, "="), $.literal)), ), function_arguments: ($) => paren_list($.function_argument, false), @@ -765,7 +765,7 @@ module.exports = grammar({ seq( $.keyword_function, $.function_reference, - optional($.function_arguments) + optional($.function_arguments), ), seq($.keyword_index, $.object_reference), // TODO: large object @@ -791,16 +791,16 @@ module.exports = grammar({ $.keyword_trigger, $.any_identifier, $.keyword_on, - $.table_reference + $.table_reference, ), seq($.keyword_type, $.type_reference), - seq($.keyword_view, $.object_reference) + seq($.keyword_view, $.object_reference), ), select: ($) => partialSeq( $.keyword_select, - seq(optional($.keyword_distinct), field("end", $.select_expression)) + seq(optional($.keyword_distinct), field("end", $.select_expression)), ), select_expression: ($) => field("end", comma_list($.term, true)), @@ -814,14 +814,14 @@ module.exports = grammar({ optional($.keyword_table), optional($.keyword_only), comma_list($.table_reference, false), - optional($._drop_behavior) + optional($._drop_behavior), ), - _delete_statement: ($) => + delete_statement: ($) => seq( $.keyword_delete, alias($._delete_from, $.from), - optional($.returning) + optional($.returning), ), _delete_from: ($) => @@ -831,7 +831,7 @@ module.exports = grammar({ $.table_reference, optional($.where), optional($.order_by), - optional($.limit) + optional($.limit), ), _create_statement: ($) => @@ -849,8 +849,8 @@ module.exports = grammar({ $.create_extension, $.create_trigger, $.create_policy, - prec.left(seq($.create_schema, repeat($._create_statement))) - ) + prec.left(seq($.create_schema, repeat($._create_statement))), + ), ), _table_settings: ($) => @@ -858,7 +858,7 @@ module.exports = grammar({ $.table_partition, seq($.keyword_without, $.keyword_oids), $.storage_parameters, - $.table_option + $.table_option, ), storage_parameters: ($) => @@ -866,8 +866,8 @@ module.exports = grammar({ $.keyword_with, paren_list( seq($.any_identifier, optional(seq("=", choice($.literal, $.array)))), - true - ) + true, + ), ), // left precedence because 'quoted' table options otherwise conflict with @@ -879,7 +879,7 @@ module.exports = grammar({ seq( $.keyword_create, optional( - choice($._temporary, $.keyword_unlogged, $.keyword_external) + choice($._temporary, $.keyword_unlogged, $.keyword_external), ), $.keyword_table, optional($._if_not_exists), @@ -888,11 +888,11 @@ module.exports = grammar({ seq( $.column_definitions, repeat($._table_settings), - optional(seq($.keyword_as, $._select_statement)) + optional(seq($.keyword_as, $._select_statement)), ), - seq(repeat($._table_settings), seq($.keyword_as, $.create_query)) - ) - ) + seq(repeat($._table_settings), seq($.keyword_as, $.create_query)), + ), + ), ), create_policy: ($) => @@ -903,7 +903,10 @@ module.exports = grammar({ $.keyword_on, $.table_reference, optional( - seq($.keyword_as, choice($.keyword_permissive, $.keyword_restrictive)) + seq( + $.keyword_as, + choice($.keyword_permissive, $.keyword_restrictive), + ), ), optional( seq( @@ -913,12 +916,12 @@ module.exports = grammar({ $.keyword_select, $.keyword_insert, $.keyword_update, - $.keyword_delete - ) - ) + $.keyword_delete, + ), + ), ), optional($.policy_to_role), - optional($.check_or_using_clause) + optional($.check_or_using_clause), ), alter_policy: ($) => @@ -931,10 +934,10 @@ module.exports = grammar({ choice( seq($.keyword_rename, $.keyword_to, $.any_identifier), $.policy_to_role, - optional($.check_or_using_clause) - ) - ) - ) + optional($.check_or_using_clause), + ), + ), + ), ), policy_to_role: ($) => seq($.keyword_to, $.role_specification), @@ -945,15 +948,15 @@ module.exports = grammar({ $.keyword_drop, $.keyword_policy, optional($._if_exists), - $.policy_identifier + $.policy_identifier, ), optional( seq( $.keyword_on, $.table_reference, - optional(choice($.keyword_cascade, $.keyword_restrict)) - ) - ) + optional(choice($.keyword_cascade, $.keyword_restrict)), + ), + ), ), check_or_using_clause: ($) => @@ -962,14 +965,14 @@ module.exports = grammar({ seq( $.keyword_with, $.keyword_check, - wrapped_in_parenthesis($._expression) - ) + wrapped_in_parenthesis($._expression), + ), ), reset_statement: ($) => partialSeq( $.keyword_reset, - field("end", choice($.keyword_all, $.any_identifier)) + field("end", choice($.keyword_all, $.any_identifier)), ), _transaction_mode: ($) => @@ -980,14 +983,14 @@ module.exports = grammar({ $.keyword_serializable, seq($.keyword_repeatable, $.keyword_read), seq($.keyword_read, $.keyword_committed), - seq($.keyword_read, $.keyword_uncommitted) + seq($.keyword_read, $.keyword_uncommitted), ), choice( seq($.keyword_read, $.keyword_write), - seq($.keyword_read, $.keyword_only) + seq($.keyword_read, $.keyword_only), ), optional($.keyword_not), - field("end", $.keyword_deferrable) + field("end", $.keyword_deferrable), ), set_statement: ($) => @@ -1007,9 +1010,9 @@ module.exports = grammar({ $.keyword_default, $.any_identifier, $.keyword_on, - $.keyword_off - ) - ) + $.keyword_off, + ), + ), ), seq($.keyword_schema, field("end", $.literal)), seq($.keyword_names, field("end", $.literal)), @@ -1018,24 +1021,24 @@ module.exports = grammar({ $.keyword_zone, field( "end", - choice($.literal, $.keyword_local, $.keyword_default) - ) + choice($.literal, $.keyword_local, $.keyword_default), + ), ), seq( $.keyword_session, $.keyword_authorization, - field("end", choice($.any_identifier, $.keyword_default)) + field("end", choice($.any_identifier, $.keyword_default)), ), seq( $.keyword_role, - field("end", choice($.any_identifier, $.keyword_none)) - ) - ) + field("end", choice($.any_identifier, $.keyword_none)), + ), + ), ), seq( $.keyword_constraints, choice($.keyword_all, comma_list($.any_identifier, true)), - field("end", choice($.keyword_deferred, $.keyword_immediate)) + field("end", choice($.keyword_deferred, $.keyword_immediate)), ), seq($.keyword_transaction, $._transaction_mode), seq($.keyword_transaction, $.keyword_snapshot, $._transaction_mode), @@ -1044,9 +1047,9 @@ module.exports = grammar({ $.keyword_characteristics, $.keyword_as, $.keyword_transaction, - $._transaction_mode - ) - ) + $._transaction_mode, + ), + ), ), create_query: ($) => $._dml_read, @@ -1070,12 +1073,12 @@ module.exports = grammar({ seq( $.keyword_with, optional(choice($.keyword_local, $.keyword_cascaded)), - $._check_option - ) - ) - ) - ) - ) + $._check_option, + ), + ), + ), + ), + ), ), create_materialized_view: ($) => @@ -1093,11 +1096,11 @@ module.exports = grammar({ $.keyword_as, $.create_query, optional( - seq($.keyword_with, optional($.keyword_no), $.keyword_data) - ) - ) - ) - ) + seq($.keyword_with, optional($.keyword_no), $.keyword_data), + ), + ), + ), + ), ), // This is only used in create function statement, it is not needed to check @@ -1117,7 +1120,7 @@ module.exports = grammar({ $.type, seq($.keyword_setof, $.type), seq($.keyword_table, $.column_definitions), - $.keyword_trigger + $.keyword_trigger, ), repeat( choice( @@ -1129,8 +1132,8 @@ module.exports = grammar({ $.function_strictness, $.function_cost, $.function_rows, - $.function_support - ) + $.function_support, + ), ), // ensure that there's only one function body -- other specifiers are less // variable but the body can have all manner of conflicting stuff @@ -1145,9 +1148,9 @@ module.exports = grammar({ $.function_strictness, $.function_cost, $.function_rows, - $.function_support - ) - ) + $.function_support, + ), + ), ), _function_return: ($) => seq($.keyword_return, $._expression), @@ -1163,11 +1166,11 @@ module.exports = grammar({ wrapped_in_parenthesis($.statement), // TODO are there more possibilities here? We can't use `_expression` since // that includes subqueries - $.literal - ) - ) + $.literal, + ), + ), ), - ";" + ";", ), _function_body_statement: ($) => choice($.statement, $._function_return), @@ -1179,7 +1182,7 @@ module.exports = grammar({ $.keyword_begin, $.keyword_atomic, repeat1(seq($._function_body_statement, ";")), - $.keyword_end + $.keyword_end, ), seq( $.keyword_as, @@ -1189,22 +1192,22 @@ module.exports = grammar({ repeat1(seq($._function_body_statement, ";")), $.keyword_end, optional(";"), - alias($._dollar_quoted_string_end_tag, $.dollar_quote) + alias($._dollar_quoted_string_end_tag, $.dollar_quote), ), seq( $.keyword_as, alias( choice($._single_quote_string, $._double_quote_string), - $.literal - ) + $.literal, + ), ), seq( $.keyword_as, alias($._dollar_quoted_string_start_tag, $.dollar_quote), $._function_body_statement, optional(";"), - alias($._dollar_quoted_string_end_tag, $.dollar_quote) - ) + alias($._dollar_quoted_string_end_tag, $.dollar_quote), + ), ), function_language: ($) => @@ -1214,7 +1217,7 @@ module.exports = grammar({ // regard to the defined language to match either sql, plsql or // plpgsql. Currently the function_body_statement support only sql. And // maybe for other language the function_body should be a string. - $.any_identifier + $.any_identifier, ), function_volatility: ($) => @@ -1227,13 +1230,13 @@ module.exports = grammar({ seq( optional($.keyword_external), $.keyword_security, - choice($.keyword_invoker, $.keyword_definer) + choice($.keyword_invoker, $.keyword_definer), ), function_safety: ($) => seq( $.keyword_parallel, - choice($.keyword_safe, $.keyword_unsafe, $.keyword_restricted) + choice($.keyword_safe, $.keyword_unsafe, $.keyword_restricted), ), function_strictness: ($) => @@ -1242,9 +1245,9 @@ module.exports = grammar({ choice($.keyword_called, seq($.keyword_returns, $.keyword_null)), $.keyword_on, $.keyword_null, - $.keyword_input + $.keyword_input, ), - $.keyword_strict + $.keyword_strict, ), function_cost: ($) => seq($.keyword_cost, $._natural_number), @@ -1260,9 +1263,9 @@ module.exports = grammar({ optional( field( "opclass_parameters", - wrapped_in_parenthesis(comma_list($.term, false)) - ) - ) + wrapped_in_parenthesis(comma_list($.term, false)), + ), + ), ), _index_field: ($) => @@ -1270,12 +1273,12 @@ module.exports = grammar({ choice( field("expression", wrapped_in_parenthesis($._expression)), field("function", $.invocation), - field("column", $._column) + field("column", $._column), ), optional(seq($.keyword_collate, $.any_identifier)), optional($._operator_class), optional($.direction), - optional(seq($.keyword_nulls, choice($.keyword_first, $.keyword_last))) + optional(seq($.keyword_nulls, choice($.keyword_first, $.keyword_last))), ), index_fields: ($) => @@ -1301,13 +1304,13 @@ module.exports = grammar({ $.keyword_gist, $.keyword_spgist, $.keyword_gin, - $.keyword_brin - ) - ) + $.keyword_brin, + ), + ), ), - $.index_fields + $.index_fields, ), - optional($.where) + optional($.where), ), create_schema: ($) => @@ -1319,11 +1322,11 @@ module.exports = grammar({ seq( optional($._if_not_exists), $.any_identifier, - optional(seq($.keyword_authorization, $.role_specification)) + optional(seq($.keyword_authorization, $.role_specification)), ), - seq($.keyword_authorization, $.role_specification) - ) - ) + seq($.keyword_authorization, $.role_specification), + ), + ), ), _with_settings: ($) => @@ -1331,16 +1334,16 @@ module.exports = grammar({ seq( $.keyword_owner, optional("="), - choice($.role_identifier, $.keyword_default) + choice($.role_identifier, $.keyword_default), ), seq( field("name", $.any_identifier), optional("="), field( "value", - choice($.any_identifier, alias($._single_quote_string, $.literal)) - ) - ) + choice($.any_identifier, alias($._single_quote_string, $.literal)), + ), + ), ), create_database: ($) => @@ -1350,7 +1353,7 @@ module.exports = grammar({ optional($._if_not_exists), $.any_identifier, optional($.keyword_with), - repeat($._with_settings) + repeat($._with_settings), ), create_role: ($) => @@ -1359,7 +1362,7 @@ module.exports = grammar({ choice($.keyword_user, $.keyword_role, $.keyword_group), $.any_identifier, optional($.keyword_with), - repeat(choice($._user_access_role_config, $._role_options)) + repeat(choice($._user_access_role_config, $._role_options)), ), _role_options: ($) => @@ -1368,27 +1371,27 @@ module.exports = grammar({ seq( $.keyword_valid, $.keyword_until, - field("valid_until", alias($._literal_string, $.literal)) + field("valid_until", alias($._literal_string, $.literal)), ), seq( $.keyword_connection, $.keyword_limit, - field("connection_limit", alias($._integer, $.literal)) + field("connection_limit", alias($._integer, $.literal)), ), seq( optional($.keyword_encrypted), $.keyword_password, choice( field("password", alias($._literal_string, $.literal)), - $.keyword_null - ) - ) + $.keyword_null, + ), + ), ), _user_access_role_config: ($) => seq( choice(seq(optional($.keyword_in), $.keyword_role), $.keyword_admin), - comma_list($.role_identifier, true) + comma_list($.role_identifier, true), ), create_sequence: ($) => @@ -1397,8 +1400,8 @@ module.exports = grammar({ optional( choice( choice($.keyword_temporary, $.keyword_temp), - $.keyword_unlogged - ) + $.keyword_unlogged, + ), ), $.keyword_sequence, optional($._if_not_exists), @@ -1409,22 +1412,22 @@ module.exports = grammar({ seq( $.keyword_increment, optional($.keyword_by), - field("increment", alias($._integer, $.literal)) + field("increment", alias($._integer, $.literal)), ), seq( $.keyword_minvalue, - choice($.literal, seq($.keyword_no, $.keyword_minvalue)) + choice($.literal, seq($.keyword_no, $.keyword_minvalue)), ), seq($.keyword_no, $.keyword_minvalue), seq( $.keyword_maxvalue, - choice($.literal, seq($.keyword_no, $.keyword_maxvalue)) + choice($.literal, seq($.keyword_no, $.keyword_maxvalue)), ), seq($.keyword_no, $.keyword_maxvalue), seq( $.keyword_start, optional($.keyword_with), - field("start", alias($._integer, $.literal)) + field("start", alias($._integer, $.literal)), ), seq($.keyword_cache, field("cache", alias($._integer, $.literal))), seq(optional($.keyword_no), $.keyword_cycle), @@ -1432,10 +1435,10 @@ module.exports = grammar({ $.keyword_owned, $.keyword_by, // todo(@juleswritescode): here, column reference may only have two fields? - choice($.keyword_none, $.column_reference) - ) - ) - ) + choice($.keyword_none, $.column_reference), + ), + ), + ), ), create_extension: ($) => @@ -1449,10 +1452,10 @@ module.exports = grammar({ optional( seq( $.keyword_version, - choice($.any_identifier, alias($._literal_string, $.literal)) - ) + choice($.any_identifier, alias($._literal_string, $.literal)), + ), ), - optional($.keyword_cascade) + optional($.keyword_cascade), ), create_trigger: ($) => @@ -1465,7 +1468,7 @@ module.exports = grammar({ choice( $.keyword_before, $.keyword_after, - seq($.keyword_instead, $.keyword_of) + seq($.keyword_instead, $.keyword_of), ), $._create_trigger_event, repeat(seq($.keyword_or, $._create_trigger_event)), @@ -1478,28 +1481,28 @@ module.exports = grammar({ seq($.keyword_not, $.keyword_deferrable), $.keyword_deferrable, seq($.keyword_initially, $.keyword_immediate), - seq($.keyword_initially, $.keyword_deferred) + seq($.keyword_initially, $.keyword_deferred), ), seq( $.keyword_referencing, choice($.keyword_old, $.keyword_new), $.keyword_table, optional($.keyword_as), - $.any_identifier + $.any_identifier, ), seq( $.keyword_for, optional($.keyword_each), - choice($.keyword_row, $.keyword_statement) + choice($.keyword_row, $.keyword_statement), ), - seq($.keyword_when, wrapped_in_parenthesis($._expression)) - ) + seq($.keyword_when, wrapped_in_parenthesis($._expression)), + ), ), $.keyword_execute, choice($.keyword_function, $.keyword_procedure), // todo(@juleswritescode): we can filter for return type trigger here. $.function_reference, - paren_list(field("parameter", $.term), false) + paren_list(field("parameter", $.term), false), ), _create_trigger_event: ($) => @@ -1507,10 +1510,10 @@ module.exports = grammar({ $.keyword_insert, seq( $.keyword_update, - optional(seq($.keyword_of, comma_list($.column_identifier, true))) + optional(seq($.keyword_of, comma_list($.column_identifier, true))), ), $.keyword_delete, - $.keyword_truncate + $.keyword_truncate, ), create_type: ($) => @@ -1524,24 +1527,24 @@ module.exports = grammar({ seq( $.keyword_as, $.column_definitions, - optional(seq($.keyword_collate, $.any_identifier)) + optional(seq($.keyword_collate, $.any_identifier)), ), seq($.keyword_as, $.keyword_enum, $.enum_elements), seq( optional(seq($.keyword_as, $.keyword_range)), - paren_list($._with_settings, false) - ) - ) - ) - ) + paren_list($._with_settings, false), + ), + ), + ), + ), ), enum_elements: ($) => seq( paren_list( field("enum_element", alias($._literal_string, $.literal)), - false - ) + false, + ), ), _alter_statement: ($) => @@ -1555,8 +1558,8 @@ module.exports = grammar({ $.alter_database, $.alter_role, $.alter_sequence, - $.alter_policy - ) + $.alter_policy, + ), ), alter_table: ($) => @@ -1570,10 +1573,10 @@ module.exports = grammar({ choice( seq( $._alter_specifications, - repeat(seq(",", $._alter_specifications)) - ) - ) - ) + repeat(seq(",", $._alter_specifications)), + ), + ), + ), ), _alter_specifications: ($) => @@ -1586,7 +1589,7 @@ module.exports = grammar({ $.rename_object, $.rename_column, $.set_schema, - $.change_ownership + $.change_ownership, ), // TODO: optional `keyword_add` is necessary to allow for chained alter statements in t-sql @@ -1597,7 +1600,7 @@ module.exports = grammar({ optional($.keyword_column), optional($._if_not_exists), $.column_definition, - optional($.column_position) + optional($.column_position), ), add_constraint: ($) => @@ -1605,7 +1608,7 @@ module.exports = grammar({ $.keyword_add, optional($.keyword_constraint), $.any_identifier, - $.constraint + $.constraint, ), drop_constraint: ($) => @@ -1614,7 +1617,7 @@ module.exports = grammar({ $.keyword_constraint, optional($._if_exists), $.any_identifier, - optional($._drop_behavior) + optional($._drop_behavior), ), alter_column: ($) => @@ -1627,12 +1630,12 @@ module.exports = grammar({ seq( choice($.keyword_set, $.keyword_drop), $.keyword_not, - $.keyword_null + $.keyword_null, ), seq( optional(seq($.keyword_set, $.keyword_data)), $.keyword_type, - field("type", $.type) + field("type", $.type), ), seq( $.keyword_set, @@ -1645,19 +1648,19 @@ module.exports = grammar({ $.keyword_external, $.keyword_extended, $.keyword_main, - $.keyword_default - ) + $.keyword_default, + ), ), seq( $.keyword_compression, - field("compression_method", $._identifier) + field("compression_method", $._identifier), ), seq(paren_list($._key_value_pair, true)), - seq($.keyword_default, $._expression) - ) + seq($.keyword_default, $._expression), + ), ), - seq($.keyword_drop, $.keyword_default) - ) + seq($.keyword_drop, $.keyword_default), + ), ), column_position: ($) => @@ -1668,7 +1671,7 @@ module.exports = grammar({ $.keyword_drop, optional($.keyword_column), optional($._if_exists), - $.column_identifier + $.column_identifier, ), rename_column: ($) => @@ -1677,7 +1680,7 @@ module.exports = grammar({ optional($.keyword_column), $.column_identifier, $.keyword_to, - field("new_name", $.any_identifier) + field("new_name", $.any_identifier), ), alter_view: ($) => @@ -1691,8 +1694,8 @@ module.exports = grammar({ $.rename_object, $.rename_column, $.set_schema, - $.change_ownership - ) + $.change_ownership, + ), ), alter_schema: ($) => @@ -1702,7 +1705,7 @@ module.exports = grammar({ $.schema_identifier, choice($.keyword_rename, $.keyword_owner), $.keyword_to, - $.any_identifier + $.any_identifier, ), alter_database: ($) => @@ -1718,17 +1721,17 @@ module.exports = grammar({ $.keyword_reset, choice( $.keyword_all, - field("configuration_parameter", $.any_identifier) - ) + field("configuration_parameter", $.any_identifier), + ), ), seq( $.keyword_set, choice( seq($.keyword_tablespace, $.any_identifier), - $.set_configuration - ) - ) - ) + $.set_configuration, + ), + ), + ), ), alter_role: ($) => @@ -1745,11 +1748,11 @@ module.exports = grammar({ seq($.keyword_set, $.set_configuration), seq( $.keyword_reset, - choice($.keyword_all, field("option", $.any_identifier)) - ) - ) - ) - ) + choice($.keyword_all, field("option", $.any_identifier)), + ), + ), + ), + ), ), set_configuration: ($) => @@ -1762,10 +1765,10 @@ module.exports = grammar({ choice( field("parameter", $.any_identifier), $.literal, - $.keyword_default - ) - ) - ) + $.keyword_default, + ), + ), + ), ), alter_index: ($) => @@ -1782,7 +1785,7 @@ module.exports = grammar({ alias($._natural_number, $.literal), $.keyword_set, $.keyword_statistics, - alias($._natural_number, $.literal) + alias($._natural_number, $.literal), ), seq($.keyword_reset, paren_list($.any_identifier, false)), seq( @@ -1791,11 +1794,11 @@ module.exports = grammar({ seq($.keyword_tablespace, $.any_identifier), paren_list( seq($.any_identifier, "=", field("value", $.literal)), - false - ) - ) - ) - ) + false, + ), + ), + ), + ), ), alter_sequence: ($) => @@ -1811,33 +1814,33 @@ module.exports = grammar({ seq($.keyword_increment, optional($.keyword_by), $.literal), seq( $.keyword_minvalue, - choice($.literal, seq($.keyword_no, $.keyword_minvalue)) + choice($.literal, seq($.keyword_no, $.keyword_minvalue)), ), seq( $.keyword_maxvalue, - choice($.literal, seq($.keyword_no, $.keyword_maxvalue)) + choice($.literal, seq($.keyword_no, $.keyword_maxvalue)), ), seq( $.keyword_start, optional($.keyword_with), - field("start", alias($._integer, $.literal)) + field("start", alias($._integer, $.literal)), ), seq( $.keyword_restart, optional($.keyword_with), - field("restart", alias($._integer, $.literal)) + field("restart", alias($._integer, $.literal)), ), seq( $.keyword_cache, - field("cache", alias($._integer, $.literal)) + field("cache", alias($._integer, $.literal)), ), seq(optional($.keyword_no), $.keyword_cycle), seq( $.keyword_owned, $.keyword_by, - choice($.keyword_none, $.column_reference) - ) - ) + choice($.keyword_none, $.column_reference), + ), + ), ), $.rename_object, $.change_ownership, @@ -1845,10 +1848,10 @@ module.exports = grammar({ $.keyword_set, choice( choice($.keyword_logged, $.keyword_unlogged), - seq($.keyword_schema, $.schema_identifier) - ) - ) - ) + seq($.keyword_schema, $.schema_identifier), + ), + ), + ), ), alter_type: ($) => @@ -1866,7 +1869,7 @@ module.exports = grammar({ $.any_identifier, $.keyword_to, $.any_identifier, - optional($._drop_behavior) + optional($._drop_behavior), ), seq( $.keyword_add, @@ -1876,16 +1879,16 @@ module.exports = grammar({ optional( seq( choice($.keyword_before, $.keyword_after), - alias($._single_quote_string, $.literal) - ) - ) + alias($._single_quote_string, $.literal), + ), + ), ), seq( $.keyword_rename, $.keyword_value, alias($._single_quote_string, $.literal), $.keyword_to, - alias($._single_quote_string, $.literal) + alias($._single_quote_string, $.literal), ), seq( choice( @@ -1894,7 +1897,7 @@ module.exports = grammar({ $.keyword_drop, $.keyword_attribute, optional($._if_exists), - $.any_identifier + $.any_identifier, ), seq( $.keyword_alter, @@ -1902,13 +1905,13 @@ module.exports = grammar({ $.any_identifier, optional(seq($.keyword_set, $.keyword_data)), $.keyword_type, - $.type - ) + $.type, + ), ), optional(seq($.keyword_collate, $.any_identifier)), - optional($._drop_behavior) - ) - ) + optional($._drop_behavior), + ), + ), ), _drop_behavior: ($) => choice($.keyword_cascade, $.keyword_restrict), @@ -1926,8 +1929,8 @@ module.exports = grammar({ $.drop_sequence, $.drop_extension, $.drop_function, - $.drop_policy - ) + $.drop_policy, + ), ), drop_table: ($) => @@ -1936,7 +1939,7 @@ module.exports = grammar({ $.keyword_table, optional($._if_exists), $.table_reference, - optional($._drop_behavior) + optional($._drop_behavior), ), drop_view: ($) => @@ -1945,7 +1948,7 @@ module.exports = grammar({ $.keyword_view, optional($._if_exists), $.object_reference, - optional($._drop_behavior) + optional($._drop_behavior), ), drop_schema: ($) => @@ -1954,7 +1957,7 @@ module.exports = grammar({ $.keyword_schema, optional($._if_exists), $.schema_identifier, - optional($._drop_behavior) + optional($._drop_behavior), ), drop_database: ($) => @@ -1964,7 +1967,7 @@ module.exports = grammar({ optional($._if_exists), $.any_identifier, optional($.keyword_with), - optional($.keyword_force) + optional($.keyword_force), ), drop_role: ($) => @@ -1972,7 +1975,7 @@ module.exports = grammar({ $.keyword_drop, choice($.keyword_group, $.keyword_role, $.keyword_user), optional($._if_exists), - $.role_identifier + $.role_identifier, ), drop_type: ($) => @@ -1981,7 +1984,7 @@ module.exports = grammar({ $.keyword_type, optional($._if_exists), $.type_reference, - optional($._drop_behavior) + optional($._drop_behavior), ), drop_sequence: ($) => @@ -1990,7 +1993,7 @@ module.exports = grammar({ $.keyword_sequence, optional($._if_exists), $.object_reference, - optional($._drop_behavior) + optional($._drop_behavior), ), drop_index: ($) => @@ -2000,7 +2003,7 @@ module.exports = grammar({ optional($.keyword_concurrently), optional($._if_exists), field("name", $.any_identifier), - optional($._drop_behavior) + optional($._drop_behavior), ), drop_extension: ($) => @@ -2009,7 +2012,7 @@ module.exports = grammar({ $.keyword_extension, optional($._if_exists), comma_list($.any_identifier, true), - optional(choice($.keyword_cascade, $.keyword_restrict)) + optional(choice($.keyword_cascade, $.keyword_restrict)), ), drop_function: ($) => @@ -2018,7 +2021,7 @@ module.exports = grammar({ $.keyword_function, optional($._if_exists), $.function_reference, - optional($._drop_behavior) + optional($._drop_behavior), ), rename_object: ($) => @@ -2039,7 +2042,7 @@ module.exports = grammar({ choice( $.keyword_stdin, alias($._literal_string, "filename"), - seq($.keyword_program, alias($._literal_string, "command")) + seq($.keyword_program, alias($._literal_string, "command")), ), optional($.keyword_with), wrapped_in_parenthesis( @@ -2047,12 +2050,12 @@ module.exports = grammar({ choice( seq( $.keyword_format, - choice($.keyword_csv, $.keyword_binary, $.keyword_text) + choice($.keyword_csv, $.keyword_binary, $.keyword_text), ), seq($.keyword_freeze, choice($.keyword_true, $.keyword_false)), seq( $.keyword_header, - choice($.keyword_true, $.keyword_false, $.keyword_match) + choice($.keyword_true, $.keyword_false, $.keyword_match), ), seq( choice( @@ -2061,22 +2064,22 @@ module.exports = grammar({ $.keyword_default, $.keyword_escape, $.keyword_quote, - $.keyword_encoding + $.keyword_encoding, ), - alias($._literal_string, $.any_identifier) + alias($._literal_string, $.any_identifier), ), seq( choice( $.keyword_force_null, $.keyword_force_not_null, - $.keyword_force_quote + $.keyword_force_quote, ), - $._column_list - ) - ) - ) + $._column_list, + ), + ), + ), ), - optional($.where) + optional($.where), ), _insert_statement: ($) => seq($.insert, optional($.returning)), @@ -2092,24 +2095,24 @@ module.exports = grammar({ seq( $.keyword_overriding, choice($.keyword_user, $.keyword_system), - $.keyword_value - ) + $.keyword_value, + ), ), choice( seq($.keyword_default, $.keyword_values), $.insert_values, - $._select_statement + $._select_statement, ), - optional($._on_conflict) + optional($._on_conflict), ), insert_values: ($) => comma_list( partialSeq( $.keyword_values, - paren_list(choice($._expression, $.keyword_default), true) + paren_list(choice($._expression, $.keyword_default), true), ), - true + true, ), insert_columns: ($) => paren_list($.column_identifier, true), @@ -2125,10 +2128,10 @@ module.exports = grammar({ $.keyword_do, choice( $.keyword_nothing, - seq($.keyword_update, $._set_values, optional($.where)) - ) - ) - ) + seq($.keyword_update, $._set_values, optional($.where)), + ), + ), + ), ), _set_values: ($) => @@ -2151,7 +2154,7 @@ module.exports = grammar({ optional($.alias), $.keyword_on, optional_parenthesis(field("predicate", $._expression)), - repeat1($.when_clause) + repeat1($.when_clause), ), when_clause: ($) => @@ -2162,8 +2165,8 @@ module.exports = grammar({ optional( seq( $.keyword_and, - optional_parenthesis(field("predicate", $._expression)) - ) + optional_parenthesis(field("predicate", $._expression)), + ), ), $.keyword_then, choice( @@ -2175,24 +2178,24 @@ module.exports = grammar({ seq( $.keyword_overriding, choice($.keyword_system, $.keyword_user), - $.keyword_value - ) + $.keyword_value, + ), ), choice( seq($.keyword_default, $.keyword_values), seq( $.keyword_values, - paren_list(choice($._expression, $.keyword_default), true) - ) - ) + paren_list(choice($._expression, $.keyword_default), true), + ), + ), ), // merge_update seq($.keyword_update, $._set_values), // merge_delete $.keyword_delete, - seq($.keyword_do, $.keyword_nothing) - ) + seq($.keyword_do, $.keyword_nothing), + ), ), _vacuum_table: ($) => @@ -2201,7 +2204,7 @@ module.exports = grammar({ optional($._vacuum_option), optional($.keyword_only), $.table_reference, - optional(paren_list($.field, false)) + optional(paren_list($.field, false)), ), _vacuum_option: ($) => @@ -2209,12 +2212,12 @@ module.exports = grammar({ seq($.keyword_full, optional(choice($.keyword_true, $.keyword_false))), seq( $.keyword_parallel, - optional(choice($.keyword_true, $.keyword_false)) + optional(choice($.keyword_true, $.keyword_false)), ), seq( $.keyword_analyze, - optional(choice($.keyword_true, $.keyword_false)) - ) + optional(choice($.keyword_true, $.keyword_false)), + ), // seq($.keyword_freeze, choice($.keyword_true, $.keyword_false)), // seq($.keyword_skip_locked, choice($.keyword_true, $.keyword_false)), // seq($.keyword_truncate, choice($.keyword_true, $.keyword_false)), @@ -2236,7 +2239,7 @@ module.exports = grammar({ $.relation, $._set_values, // optional($.from), - optional($.where) + optional($.where), ), table_partition: ($) => @@ -2244,21 +2247,21 @@ module.exports = grammar({ $.keyword_partition, $.keyword_by, choice($.keyword_range, $.keyword_hash, $.keyword_list), - paren_list($.any_identifier, false) + paren_list($.any_identifier, false), ), _key_value_pair: ($) => seq( field("key", $.any_identifier), "=", - field("value", alias($._literal_string, $.literal)) + field("value", alias($._literal_string, $.literal)), ), assignment: ($) => partialSeq( field("left", $.column_reference), "=", - field("right", $._expression) + field("right", $._expression), ), table_option: ($) => @@ -2267,15 +2270,15 @@ module.exports = grammar({ $.keyword_default, $.keyword_character, $.keyword_set, - $.any_identifier + $.any_identifier, ), seq($.keyword_collate, $.any_identifier), field("name", $.keyword_default), seq( field("name", choice($.any_identifier, $._literal_string)), "=", - field("value", choice($.any_identifier, $._literal_string)) - ) + field("value", choice($.any_identifier, $._literal_string)), + ), ), column_definitions: ($) => @@ -2283,14 +2286,14 @@ module.exports = grammar({ "(", comma_list($.column_definition, true), optional($.constraints), - ")" + ")", ), column_definition: ($) => seq( $.any_identifier, field("type", $.type), - repeat($._column_constraint) + repeat($._column_constraint), ), _column_comment: ($) => @@ -2315,11 +2318,11 @@ module.exports = grammar({ seq( $.keyword_set, choice($.keyword_null, $.keyword_default), - optional(paren_list($.any_identifier, true)) - ) - ) - ) - ) + optional(paren_list($.any_identifier, true)), + ), + ), + ), + ), ), $._default_expression, $._primary_key, @@ -2329,18 +2332,18 @@ module.exports = grammar({ seq( optional(seq($.keyword_generated, $.keyword_always)), $.keyword_as, - $._expression + $._expression, ), $.keyword_stored, - $.keyword_unique - ) + $.keyword_unique, + ), ), _check_constraint: ($) => seq( optional(seq($.keyword_constraint, $.literal)), $.keyword_check, - wrapped_in_parenthesis($.binary_expression) + wrapped_in_parenthesis($.binary_expression), ), _default_expression: ($) => @@ -2355,7 +2358,7 @@ module.exports = grammar({ $.array, $.invocation, $.keyword_current_timestamp, - alias($.implicit_cast, $.cast) + alias($.implicit_cast, $.cast), ), constraints: ($) => seq(",", $.constraint, repeat(seq(",", $.constraint))), @@ -2365,14 +2368,17 @@ module.exports = grammar({ $._constraint_literal, $._key_constraint, $._primary_key_constraint, - $._check_constraint + $._check_constraint, ), _constraint_literal: ($) => seq( $.keyword_constraint, field("name", $.any_identifier), - choice(seq($._primary_key, $.ordered_columns), seq($._check_constraint)) + choice( + seq($._primary_key, $.ordered_columns), + seq($._check_constraint), + ), ), _primary_key_constraint: ($) => seq($._primary_key, $.ordered_columns), @@ -2389,17 +2395,17 @@ module.exports = grammar({ seq( $.keyword_nulls, optional($.keyword_not), - $.keyword_distinct - ) - ) - ) + $.keyword_distinct, + ), + ), + ), ), seq( optional($.keyword_foreign), $.keyword_key, - optional($._if_not_exists) + optional($._if_not_exists), ), - $.keyword_index + $.keyword_index, ), optional(field("name", $.any_identifier)), $.ordered_columns, @@ -2419,13 +2425,13 @@ module.exports = grammar({ seq( $.keyword_set, choice($.keyword_null, $.keyword_default), - optional(paren_list($.any_identifier, true)) - ) - ) - ) - ) - ) - ) + optional(paren_list($.any_identifier, true)), + ), + ), + ), + ), + ), + ), ), ordered_columns: ($) => paren_list(alias($.ordered_column, $.column), true), @@ -2449,8 +2455,8 @@ module.exports = grammar({ $.keyword_then, $._expression, repeat( - seq($.keyword_when, $._expression, $.keyword_then, $._expression) - ) + seq($.keyword_when, $._expression, $.keyword_then, $._expression), + ), ), // standard CASE WHEN x, where x must be a predicate seq( @@ -2459,12 +2465,12 @@ module.exports = grammar({ $.keyword_then, $._expression, repeat( - seq($.keyword_when, $._expression, $.keyword_then, $._expression) - ) - ) + seq($.keyword_when, $._expression, $.keyword_then, $._expression), + ), + ), ), optional(seq($.keyword_else, $._expression)), - $.keyword_end + $.keyword_end, ), field: ($) => field("name", $.column_identifier), @@ -2478,7 +2484,7 @@ module.exports = grammar({ cast: ($) => partialSeq( $.keyword_cast, - wrapped_in_parenthesis(partialSeq($._expression, $.keyword_as, $.type)) + wrapped_in_parenthesis(partialSeq($._expression, $.keyword_as, $.type)), ), filter_expression: ($) => @@ -2495,21 +2501,21 @@ module.exports = grammar({ seq( optional($.keyword_distinct), field("parameter", $.term), - optional($.order_by) + optional($.order_by), ), - true + true, ), // _aggregate_function, e.g. group_concat seq( optional($.keyword_distinct), field("parameter", $.term), optional($.order_by), - optional($.limit) - ) - ) + optional($.limit), + ), + ), ), ")", - optional($.filter_expression) + optional($.filter_expression), ), exists: ($) => partialSeq($.keyword_exists, field("end", $.subquery)), @@ -2518,7 +2524,7 @@ module.exports = grammar({ partialSeq( $.keyword_partition, $.keyword_by, - comma_list($._expression, true) + comma_list($._expression, true), ), frame_definition: ($) => @@ -2532,10 +2538,10 @@ module.exports = grammar({ $.any_identifier, $.binary_expression, alias($._literal_string, $.literal), - alias($._integer, $.literal) - ) + alias($._integer, $.literal), + ), ), - $.keyword_preceding + $.keyword_preceding, ), $._current_row, seq( @@ -2545,13 +2551,13 @@ module.exports = grammar({ $.any_identifier, $.binary_expression, alias($._literal_string, $.literal), - alias($._integer, $.literal) - ) + alias($._integer, $.literal), + ), ), - $.keyword_following + $.keyword_following, ), - seq($.keyword_unbounded, $.keyword_following) - ) + seq($.keyword_unbounded, $.keyword_following), + ), ), window_frame: ($) => @@ -2562,18 +2568,18 @@ module.exports = grammar({ seq( $.keyword_between, $.frame_definition, - optional(seq($.keyword_and, $.frame_definition)) + optional(seq($.keyword_and, $.frame_definition)), ), - seq($.frame_definition) + seq($.frame_definition), ), optional( choice( $._exclude_current_row, $._exclude_group, $._exclude_ties, - $._exclude_no_others - ) - ) + $._exclude_no_others, + ), + ), ), window_clause: ($) => @@ -2581,7 +2587,7 @@ module.exports = grammar({ $.keyword_window, $.any_identifier, $.keyword_as, - field("end", $.window_specification) + field("end", $.window_specification), ), // TODO: partialSeq, split up into variants @@ -2590,21 +2596,21 @@ module.exports = grammar({ seq( optional($.partition_by), optional($.order_by), - optional($.window_frame) - ) + optional($.window_frame), + ), ), window_function: ($) => partialSeq( $.invocation, $.keyword_over, - field("end", choice($.any_identifier, $.window_specification)) + field("end", choice($.any_identifier, $.window_specification)), ), alias: ($) => choice( partialSeq($.keyword_as, field("end", $.any_identifier)), - field("end", $.any_identifier) + field("end", $.any_identifier), ), from: ($) => @@ -2614,13 +2620,13 @@ module.exports = grammar({ field("end", comma_list($.relation, true)), // TODO: work joins repeat( - choice($.join, $.cross_join, $.lateral_join, $.lateral_cross_join) + choice($.join, $.cross_join, $.lateral_join, $.lateral_cross_join), ), optional($.where), optional($.group_by), optional($.window_clause), optional($.order_by), - optional($.limit) + optional($.limit), ), relation: ($) => @@ -2632,11 +2638,11 @@ module.exports = grammar({ $.subquery, $.invocation, $.table_reference, - wrapped_in_parenthesis($.values) - ) + wrapped_in_parenthesis($.values), + ), ), - optional(seq($.alias, optional(alias($._column_list, $.list)))) - ) + optional(seq($.alias, optional(alias($._column_list, $.list)))), + ), ), values: ($) => @@ -2651,7 +2657,7 @@ module.exports = grammar({ partialSeq($.keyword_full, optional($.keyword_outer), $._join), partialSeq($.keyword_right, optional($.keyword_outer), $._join), partialSeq($.keyword_inner, $._join), - $._join + $._join, ), _join: ($) => @@ -2663,16 +2669,16 @@ module.exports = grammar({ partialSeq( $.keyword_using, - field("end", alias($._column_list, $.list)) - ) - ) + field("end", alias($._column_list, $.list)), + ), + ), ), lateral_join: ($) => choice( partialSeq($.keyword_left, optional($.keyword_outer), $._lateral_join), partialSeq($.keyword_inner, $._lateral_join), - $._lateral_join + $._lateral_join, ), _lateral_join: ($) => @@ -2683,11 +2689,11 @@ module.exports = grammar({ optional( choice( seq($.keyword_as, field("alias", $.any_identifier)), - field("alias", $.any_identifier) - ) + field("alias", $.any_identifier), + ), ), $.keyword_on, - field("end", choice($._expression, $.keyword_true, $.keyword_false)) + field("end", choice($._expression, $.keyword_true, $.keyword_false)), ), cross_join: ($) => @@ -2700,7 +2706,7 @@ module.exports = grammar({ field("end", $.alias), // TODO: check if there are more occurences & whether this can be a named group - paren_list($.any_identifier, false) + paren_list($.any_identifier, false), ), lateral_cross_join: ($) => @@ -2709,7 +2715,7 @@ module.exports = grammar({ $.keyword_join, $.keyword_lateral, field("end", choice($.invocation, $.subquery)), - optional($.alias) + optional($.alias), ), where: ($) => partialSeq($.keyword_where, field("end", $._expression)), @@ -2719,7 +2725,7 @@ module.exports = grammar({ $.keyword_group, $.keyword_by, field("end", comma_list($._expression, true)), - optional($.group_by_having) + optional($.group_by_having), ), group_by_having: ($) => @@ -2729,7 +2735,7 @@ module.exports = grammar({ partialSeq( $.keyword_order, $.keyword_by, - field("end", comma_list($.order_target, true)) + field("end", comma_list($.order_target, true)), ), order_target: ($) => @@ -2740,17 +2746,17 @@ module.exports = grammar({ seq( choice( field("end", $.direction), - seq($.keyword_using, field("end", choice("<", ">", "<=", ">="))) + seq($.keyword_using, field("end", choice("<", ">", "<=", ">="))), ), - optional($.order_target_nulls) - ) - ) + optional($.order_target_nulls), + ), + ), ), order_target_nulls: ($) => seq( $.keyword_nulls, - field("end", choice($.keyword_first, $.keyword_last)) + field("end", choice($.keyword_first, $.keyword_last)), ), limit: ($) => @@ -2768,8 +2774,8 @@ module.exports = grammar({ $.keyword_to, comma_list($.role_specification, true), optional(seq($.keyword_with, $.keyword_grant, $.keyword_option)), - optional(seq($.keyword_granted, $.keyword_by, $.role_specification)) - ) + optional(seq($.keyword_granted, $.keyword_by, $.role_specification)), + ), ), // todo: add support for various other revoke statements @@ -2782,19 +2788,19 @@ module.exports = grammar({ seq($.keyword_grant, $.keyword_option, $.keyword_for), seq( optional( - choice($.keyword_admin, $.keyword_inherit, $.keyword_set) + choice($.keyword_admin, $.keyword_inherit, $.keyword_set), ), $.keyword_option, - $.keyword_for - ) - ) + $.keyword_for, + ), + ), ), $.grantables, $.keyword_from, comma_list($.role_specification, true), optional(seq($.keyword_granted, $.keyword_by, $.role_specification)), - optional(choice($.keyword_cascade, $.keyword_restrict)) - ) + optional(choice($.keyword_cascade, $.keyword_restrict)), + ), ), grantables: ($) => @@ -2804,10 +2810,10 @@ module.exports = grammar({ choice( $.grantable_on_table, $.grantable_on_function, - $.grantable_on_all - ) + $.grantable_on_all, + ), ), - comma_list($.role_identifier, true) + comma_list($.role_identifier, true), ), grantable: ($) => @@ -2823,11 +2829,11 @@ module.exports = grammar({ $.keyword_trigger, $.keyword_maintain, $.keyword_execute, - $.keyword_references + $.keyword_references, ), - true + true, ), - seq($.keyword_all, optional($.keyword_privileges)) + seq($.keyword_all, optional($.keyword_privileges)), ), grantable_on_function: ($) => @@ -2836,8 +2842,8 @@ module.exports = grammar({ choice($.keyword_function, $.keyword_procedure, $.keyword_routine), comma_list( seq($.function_reference, optional($.function_arguments)), - true - ) + true, + ), ), grantable_on_table: ($) => @@ -2846,8 +2852,8 @@ module.exports = grammar({ seq( $.keyword_on, optional($.keyword_table), - comma_list($.table_reference, true) - ) + comma_list($.table_reference, true), + ), ), grantable_on_all: ($) => @@ -2858,11 +2864,11 @@ module.exports = grammar({ $.keyword_tables, $.keyword_functions, $.keyword_procedures, - $.keyword_routines + $.keyword_routines, ), $.keyword_in, $.keyword_schema, - comma_list($.schema_identifier, true) + comma_list($.schema_identifier, true), ), role_specification: ($) => @@ -2871,7 +2877,7 @@ module.exports = grammar({ $.keyword_public, $.keyword_current_role, $.keyword_current_user, - $.keyword_session_user + $.keyword_session_user, ), _expression: ($) => @@ -2896,8 +2902,8 @@ module.exports = grammar({ $.interval, $.between_expression, $.field_selection, - $.parenthesized_expression - ) + $.parenthesized_expression, + ), ), field_selection: ($) => @@ -2905,7 +2911,7 @@ module.exports = grammar({ // TODO: partial this choice($.composite_reference, $.parenthesized_expression), ".", - field("end", $.any_identifier) + field("end", $.any_identifier), ), composite_reference: ($) => @@ -2925,11 +2931,11 @@ module.exports = grammar({ seq( field("lower", $._expression), ":", - field("upper", $._expression) - ) + field("upper", $._expression), + ), ), - field("end", "]") - ) + field("end", "]"), + ), ), op_other: ($) => @@ -2975,8 +2981,8 @@ module.exports = grammar({ "?", "-|-", "||", - "^@" - ) + "^@", + ), ), binary_expression: ($) => { @@ -3026,9 +3032,9 @@ module.exports = grammar({ seq( field("binary_expr_left", $._expression), field("binary_expr_operator", operator), - field("end", $._expression) - ) - ) + field("end", $._expression), + ), + ), ), ...clauseChoices.map(([operator, precedence]) => prec.right( @@ -3036,9 +3042,9 @@ module.exports = grammar({ seq( field("binary_expr_left", $._expression), field("binary_expr_operator", operator), - field("end", $._expression) - ) - ) + field("end", $._expression), + ), + ), ), ...binaryChoices.map(([operator, precedence]) => prec.right( @@ -3046,10 +3052,10 @@ module.exports = grammar({ seq( field("binary_expr_left", $._expression), field("binary_expr_operator", operator), - field("end", choice($.list, $.subquery)) - ) - ) - ) + field("end", choice($.list, $.subquery)), + ), + ), + ), ); }, @@ -3069,8 +3075,8 @@ module.exports = grammar({ return choice( ...choices.map(([operator, precedence]) => - prec.left(precedence, seq(operator, field("end", $._expression))) - ) + prec.left(precedence, seq(operator, field("end", $._expression))), + ), ); }, @@ -3091,11 +3097,11 @@ module.exports = grammar({ ...operator, $._expression, $.keyword_and, - field("end", $._expression) - ) - ) - ) - ) + field("end", $._expression), + ), + ), + ), + ), ); }, @@ -3116,8 +3122,8 @@ module.exports = grammar({ $._string_casting, $.keyword_true, $.keyword_false, - $.keyword_null - ) + $.keyword_null, + ), ), _double_quote_string: (_) => /"[^"]*"/, // The norm specify that between two consecutive string must be a return, @@ -3134,19 +3140,19 @@ module.exports = grammar({ $._single_quote_string, $._double_quote_string, $._dollar_quoted_string, - $._postgres_escape_string - ) + $._postgres_escape_string, + ), ), _natural_number: (_) => /\d+/, _integer: ($) => seq( optional(choice("-", "+")), - /(0[xX][0-9A-Fa-f]+(_[0-9A-Fa-f]+)*)|(0[oO][0-7]+(_[0-7]+)*)|(0[bB][01]+(_[01]+)*)|(\d+(_\d+)*(e[+-]?\d+(_\d+)*)?)/ + /(0[xX][0-9A-Fa-f]+(_[0-9A-Fa-f]+)*)|(0[oO][0-7]+(_[0-7]+)*)|(0[bB][01]+(_[01]+)*)|(\d+(_\d+)*(e[+-]?\d+(_\d+)*)?)/, ), _decimal_number: ($) => seq( optional(choice("-", "+")), - /((\d+(_\d+)*)?[.]\d+(_\d+)*(e[+-]?\d+(_\d+)*)?)|(\d+(_\d+)*[.](e[+-]?\d+(_\d+)*)?)/ + /((\d+(_\d+)*)?[.]\d+(_\d+)*(e[+-]?\d+(_\d+)*)?)|(\d+(_\d+)*[.](e[+-]?\d+(_\d+)*)?)/, ), _bit_string: ($) => seq(/[bBxX]'([^']|'')*'/, repeat(/'([^']|'')*'/)), // The identifier should be followed by a string (no parenthesis allowed) @@ -3167,15 +3173,15 @@ module.exports = grammar({ ".", field("object_reference_2of3", $.any_identifier), ".", - field("object_reference_3of3", $.any_identifier) + field("object_reference_3of3", $.any_identifier), ), seq( field("object_reference_1of2", $.any_identifier), ".", - field("object_reference_2of2", $.any_identifier) + field("object_reference_2of2", $.any_identifier), ), - field("object_reference_1of1", $.any_identifier) - ) + field("object_reference_1of1", $.any_identifier), + ), ), type_reference: ($) => @@ -3183,9 +3189,9 @@ module.exports = grammar({ seq( field("type_reference_1of2", $.schema_identifier), ".", - field("type_reference_2of2", $.type_identifier) + field("type_reference_2of2", $.type_identifier), ), - field("type_reference_1of1", $.any_identifier) + field("type_reference_1of1", $.any_identifier), ), table_reference: ($) => @@ -3193,9 +3199,9 @@ module.exports = grammar({ seq( field("table_reference_1of2", $.schema_identifier), ".", - field("table_reference_2of2", $.table_identifier) + field("table_reference_2of2", $.table_identifier), ), - field("table_reference_1of1", $.any_identifier) + field("table_reference_1of1", $.any_identifier), ), column_reference: ($) => @@ -3205,16 +3211,16 @@ module.exports = grammar({ ".", field("column_reference_2of3", $.table_identifier), ".", - field("column_reference_3of3", $.column_identifier) + field("column_reference_3of3", $.column_identifier), ), seq( field("column_reference_1of2", $.any_identifier), ".", - field("column_reference_2of2", $.any_identifier) + field("column_reference_2of2", $.any_identifier), ), - field("column_reference_1of1", $.any_identifier) + field("column_reference_1of1", $.any_identifier), ), function_reference: ($) => @@ -3222,9 +3228,9 @@ module.exports = grammar({ seq( field("function_reference_1of2", $.schema_identifier), ".", - field("function_reference_2of2", $.function_identifier) + field("function_reference_2of2", $.function_identifier), ), - field("function_reference_1of1", $.any_identifier) + field("function_reference_1of1", $.any_identifier), ), any_identifier: ($) => $._any_identifier, @@ -3241,7 +3247,7 @@ module.exports = grammar({ $._identifier, $._double_quote_string, $._sql_parameter, - seq("`", $._identifier, "`") + seq("`", $._identifier, "`"), ), _sql_parameter: (_) => /[:$@?][a-zA-Z_][0-9a-zA-Z_]*/, _identifier: (_) => /[a-zA-Z_][0-9a-zA-Z_]*/, @@ -3298,12 +3304,12 @@ function parametric_type($, rule, params = ["size"]) { field(first, alias($._natural_number, lit)), // fill in the ", next" until done ...params.map((p) => - seq(",", field(p, alias($._natural_number, lit))) - ) - ) - ) - ) - ) + seq(",", field(p, alias($._natural_number, lit))), + ), + ), + ), + ), + ), ); } diff --git a/crates/pgls_treesitter_grammar/src/grammar.json b/crates/pgls_treesitter_grammar/src/grammar.json index 0af312b75..4b5c65896 100644 --- a/crates/pgls_treesitter_grammar/src/grammar.json +++ b/crates/pgls_treesitter_grammar/src/grammar.json @@ -3837,7 +3837,7 @@ "members": [ { "type": "SYMBOL", - "name": "_delete_statement" + "name": "delete_statement" }, { "type": "SYMBOL", @@ -4906,7 +4906,7 @@ } ] }, - "_delete_statement": { + "delete_statement": { "type": "SEQ", "members": [ { diff --git a/crates/pgls_treesitter_grammar/src/node-types.json b/crates/pgls_treesitter_grammar/src/node-types.json index ee8a657f6..fda36ce4a 100644 --- a/crates/pgls_treesitter_grammar/src/node-types.json +++ b/crates/pgls_treesitter_grammar/src/node-types.json @@ -4487,6 +4487,29 @@ ] } }, + { + "type": "delete_statement", + "named": true, + "fields": {}, + "children": { + "multiple": true, + "required": true, + "types": [ + { + "type": "from", + "named": true + }, + { + "type": "keyword_delete", + "named": true + }, + { + "type": "returning", + "named": true + } + ] + } + }, { "type": "direction", "named": true, @@ -9079,6 +9102,10 @@ "type": "cte", "named": true }, + { + "type": "delete_statement", + "named": true + }, { "type": "drop_database", "named": true @@ -9167,10 +9194,6 @@ "type": "keyword_default", "named": true }, - { - "type": "keyword_delete", - "named": true - }, { "type": "keyword_delimiter", "named": true diff --git a/crates/pgls_treesitter_grammar/src/parser.c b/crates/pgls_treesitter_grammar/src/parser.c index a5287c7ea..d1a3ef7b7 100644 --- a/crates/pgls_treesitter_grammar/src/parser.c +++ b/crates/pgls_treesitter_grammar/src/parser.c @@ -1,4 +1,4 @@ -/* Automatically @generated by tree-sitter v0.25.9 */ +/* Automatically @generated by tree-sitter v0.25.5 */ #include "tree_sitter/parser.h" @@ -456,7 +456,7 @@ enum ts_symbol_identifiers { sym_select_expression = 434, sym_term = 435, sym__truncate_statement = 436, - sym__delete_statement = 437, + sym_delete_statement = 437, sym__delete_from = 438, sym__create_statement = 439, sym__table_settings = 440, @@ -1144,7 +1144,7 @@ static const char * const ts_symbol_names[] = { [sym_select_expression] = "select_expression", [sym_term] = "term", [sym__truncate_statement] = "_truncate_statement", - [sym__delete_statement] = "_delete_statement", + [sym_delete_statement] = "delete_statement", [sym__delete_from] = "from", [sym__create_statement] = "_create_statement", [sym__table_settings] = "_table_settings", @@ -1832,7 +1832,7 @@ static const TSSymbol ts_symbol_map[] = { [sym_select_expression] = sym_select_expression, [sym_term] = sym_term, [sym__truncate_statement] = sym__truncate_statement, - [sym__delete_statement] = sym__delete_statement, + [sym_delete_statement] = sym_delete_statement, [sym__delete_from] = sym_from, [sym__create_statement] = sym__create_statement, [sym__table_settings] = sym__table_settings, @@ -3831,8 +3831,8 @@ static const TSSymbolMetadata ts_symbol_metadata[] = { .visible = false, .named = true, }, - [sym__delete_statement] = { - .visible = false, + [sym_delete_statement] = { + .visible = true, .named = true, }, [sym__delete_from] = { @@ -41307,7 +41307,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -54341,7 +54341,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -54885,7 +54885,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55063,7 +55063,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55330,7 +55330,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55419,7 +55419,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55508,7 +55508,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55594,7 +55594,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55772,7 +55772,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55858,7 +55858,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -55948,7 +55948,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56034,7 +56034,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(11565), [sym_select] = STATE(7483), [sym__truncate_statement] = STATE(11606), - [sym__delete_statement] = STATE(11606), + [sym_delete_statement] = STATE(11606), [sym__create_statement] = STATE(11565), [sym_create_table] = STATE(11565), [sym_create_policy] = STATE(11565), @@ -56124,7 +56124,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56210,7 +56210,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(11565), [sym_select] = STATE(7483), [sym__truncate_statement] = STATE(11606), - [sym__delete_statement] = STATE(11606), + [sym_delete_statement] = STATE(11606), [sym__create_statement] = STATE(11565), [sym_create_table] = STATE(11565), [sym_create_policy] = STATE(11565), @@ -56298,7 +56298,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56386,7 +56386,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56474,7 +56474,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56562,7 +56562,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56652,7 +56652,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56738,7 +56738,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -56826,7 +56826,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -57174,7 +57174,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -57261,7 +57261,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -57348,7 +57348,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -57435,7 +57435,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -57522,7 +57522,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -57609,7 +57609,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -58467,7 +58467,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10604), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10604), [sym_create_table] = STATE(10604), [sym_create_policy] = STATE(10604), @@ -58549,7 +58549,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(11025), [sym_select] = STATE(7483), [sym__truncate_statement] = STATE(11606), - [sym__delete_statement] = STATE(11606), + [sym_delete_statement] = STATE(11606), [sym__create_statement] = STATE(11025), [sym_create_table] = STATE(11025), [sym_create_policy] = STATE(11025), @@ -58632,7 +58632,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10213), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10213), [sym_create_table] = STATE(10213), [sym_create_policy] = STATE(10213), @@ -59207,7 +59207,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(11114), [sym_select] = STATE(7483), [sym__truncate_statement] = STATE(11606), - [sym__delete_statement] = STATE(11606), + [sym_delete_statement] = STATE(11606), [sym__create_statement] = STATE(11114), [sym_create_table] = STATE(11114), [sym_create_policy] = STATE(11114), @@ -59453,7 +59453,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(9801), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(9801), [sym_create_table] = STATE(9801), [sym_create_policy] = STATE(9801), @@ -59535,7 +59535,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(11117), [sym_select] = STATE(7483), [sym__truncate_statement] = STATE(11606), - [sym__delete_statement] = STATE(11606), + [sym_delete_statement] = STATE(11606), [sym__create_statement] = STATE(11117), [sym_create_table] = STATE(11117), [sym_create_policy] = STATE(11117), @@ -59859,7 +59859,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(10767), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(10767), [sym_create_table] = STATE(10767), [sym_create_policy] = STATE(10767), @@ -59940,7 +59940,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(9812), [sym_select] = STATE(7256), [sym__truncate_statement] = STATE(10373), - [sym__delete_statement] = STATE(10373), + [sym_delete_statement] = STATE(10373), [sym__create_statement] = STATE(9812), [sym_create_table] = STATE(9812), [sym_create_policy] = STATE(9812), @@ -60102,7 +60102,7 @@ static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { [sym_comment_statement] = STATE(11220), [sym_select] = STATE(7483), [sym__truncate_statement] = STATE(11606), - [sym__delete_statement] = STATE(11606), + [sym_delete_statement] = STATE(11606), [sym__create_statement] = STATE(11220), [sym_create_table] = STATE(11220), [sym_create_policy] = STATE(11220), @@ -411139,7 +411139,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392105] = 20, @@ -411185,7 +411185,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392171] = 4, @@ -411261,7 +411261,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392271] = 20, @@ -411307,7 +411307,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392337] = 20, @@ -411353,7 +411353,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392403] = 20, @@ -411399,7 +411399,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392469] = 20, @@ -411445,7 +411445,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392535] = 3, @@ -411590,7 +411590,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392721] = 20, @@ -411636,7 +411636,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392787] = 20, @@ -411682,7 +411682,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [392853] = 4, @@ -411817,7 +411817,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [393019] = 20, @@ -411863,7 +411863,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(10373), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [393085] = 5, @@ -417509,7 +417509,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(11047), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [399796] = 2, @@ -418536,7 +418536,7 @@ static const uint16_t ts_small_parse_table[] = { sym_set_operation, STATE(9955), 4, sym__truncate_statement, - sym__delete_statement, + sym_delete_statement, sym__insert_statement, sym__update_statement, [401036] = 3, @@ -524601,7 +524601,7 @@ static const TSParseActionEntry ts_parse_actions[] = { [15410] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_alter_type, 7, 0, 136), [15412] = {.entry = {.count = 1, .reusable = true}}, SHIFT(11073), [15414] = {.entry = {.count = 1, .reusable = true}}, SHIFT(11331), - [15416] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__delete_statement, 2, 0, 0), + [15416] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_delete_statement, 2, 0, 0), [15418] = {.entry = {.count = 1, .reusable = true}}, SHIFT(2356), [15420] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_create_extension, 6, 0, 102), [15422] = {.entry = {.count = 1, .reusable = true}}, SHIFT(9593), @@ -525759,7 +525759,7 @@ static const TSParseActionEntry ts_parse_actions[] = { [17742] = {.entry = {.count = 1, .reusable = true}}, SHIFT(360), [17744] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_alter_index, 8, 0, 168), [17746] = {.entry = {.count = 1, .reusable = true}}, SHIFT(3644), - [17748] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__delete_statement, 3, 0, 0), + [17748] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_delete_statement, 3, 0, 0), [17750] = {.entry = {.count = 1, .reusable = true}}, SHIFT(4447), [17752] = {.entry = {.count = 1, .reusable = true}}, SHIFT(3497), [17754] = {.entry = {.count = 1, .reusable = true}}, SHIFT(3500), diff --git a/crates/pgls_treesitter_grammar/tests/grammar_tests.rs b/crates/pgls_treesitter_grammar/tests/grammar_tests.rs index b5bd9d6f9..98eb1a8c0 100644 --- a/crates/pgls_treesitter_grammar/tests/grammar_tests.rs +++ b/crates/pgls_treesitter_grammar/tests/grammar_tests.rs @@ -8,7 +8,7 @@ fn printed_tree(sql: &str) -> String { let mut parser = tree_sitter::Parser::new(); let _ = parser.set_language(&pgls_treesitter_grammar::LANGUAGE.into()); let tree = parser.parse(sql, None).expect("Unable to parse!"); - pgls_test_utils::print_ts_tree(&tree.root_node(), sql, 0, &mut result); + pgls_test_utils::print_ts_tree(&tree.root_node(), sql, &mut result); result } diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_1.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_1.snap index 601cec9c0..43ffd3a50 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_1.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_1.snap @@ -8,15 +8,15 @@ program [0..25] 'select * from auth.users;' statement [0..24] 'select * from auth.users' select [0..8] 'select *' keyword_select [0..6] 'select' - select_expression [7..8] '*' - term [7..8] '*' - all_fields [7..8] '*' + select_expression [7..8] '*' (@end) + term [7..8] '*' (@end) + all_fields [7..8] '*' (@end) * [7..8] '*' from [9..24] 'from auth.users' keyword_from [9..13] 'from' - relation [14..24] 'auth.users' - table_reference [14..24] 'auth.users' - schema_identifier [14..18] 'auth' + relation [14..24] 'auth.users' (@end) + table_reference [14..24] 'auth.users' (@end) + schema_identifier [14..18] 'auth' (@table_reference_1of2) . [18..19] '.' - table_identifier [19..24] 'users' + table_identifier [19..24] 'users' (@table_reference_2of2) ; [24..25] ';' diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql1.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql1.snap index 27b564708..a25f91f10 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql1.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql1.snap @@ -9,14 +9,14 @@ program [0..44] 'update auth.users set email = 'my@mail.com';' update [0..43] 'update auth.users set email = 'my@mail.com'' keyword_update [0..6] 'update' relation [7..17] 'auth.users' - table_reference [7..17] 'auth.users' - schema_identifier [7..11] 'auth' + table_reference [7..17] 'auth.users' (@end) + schema_identifier [7..11] 'auth' (@table_reference_1of2) . [11..12] '.' - table_identifier [12..17] 'users' + table_identifier [12..17] 'users' (@table_reference_2of2) keyword_set [18..21] 'set' assignment [22..43] 'email = 'my@mail.com'' - column_reference [22..27] 'email' - any_identifier [22..27] 'email' + column_reference [22..27] 'email' (@left) + any_identifier [22..27] 'email' (@column_reference_1of1) = [28..29] '=' - literal [30..43] ''my@mail.com'' + literal [30..43] ''my@mail.com'' (@right) ; [43..44] ';' diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql2.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql2.snap index e3c5bf26b..bbe72f15e 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql2.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql2.snap @@ -9,16 +9,16 @@ program [0..50] 'update auth.users set users.email = 'my@mail.com';' update [0..49] 'update auth.users set users.email = 'my@mail.com'' keyword_update [0..6] 'update' relation [7..17] 'auth.users' - table_reference [7..17] 'auth.users' - schema_identifier [7..11] 'auth' + table_reference [7..17] 'auth.users' (@end) + schema_identifier [7..11] 'auth' (@table_reference_1of2) . [11..12] '.' - table_identifier [12..17] 'users' + table_identifier [12..17] 'users' (@table_reference_2of2) keyword_set [18..21] 'set' assignment [22..49] 'users.email = 'my@mail.com'' - column_reference [22..33] 'users.email' - any_identifier [22..27] 'users' + column_reference [22..33] 'users.email' (@left) + any_identifier [22..27] 'users' (@column_reference_1of2) . [27..28] '.' - any_identifier [28..33] 'email' + any_identifier [28..33] 'email' (@column_reference_2of2) = [34..35] '=' - literal [36..49] ''my@mail.com'' + literal [36..49] ''my@mail.com'' (@right) ; [49..50] ';' diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql3.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql3.snap index 4b3c8759e..51d4ee0ef 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql3.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_2_sql3.snap @@ -9,18 +9,18 @@ program [0..55] 'update auth.users set auth.users.email = 'my@mail.com';' update [0..54] 'update auth.users set auth.users.email = 'my@mail.com'' keyword_update [0..6] 'update' relation [7..17] 'auth.users' - table_reference [7..17] 'auth.users' - schema_identifier [7..11] 'auth' + table_reference [7..17] 'auth.users' (@end) + schema_identifier [7..11] 'auth' (@table_reference_1of2) . [11..12] '.' - table_identifier [12..17] 'users' + table_identifier [12..17] 'users' (@table_reference_2of2) keyword_set [18..21] 'set' assignment [22..54] 'auth.users.email = 'my@mail.com'' - column_reference [22..38] 'auth.users.email' - schema_identifier [22..26] 'auth' + column_reference [22..38] 'auth.users.email' (@left) + schema_identifier [22..26] 'auth' (@column_reference_1of3) . [26..27] '.' - table_identifier [27..32] 'users' + table_identifier [27..32] 'users' (@column_reference_2of3) . [32..33] '.' - column_identifier [33..38] 'email' + column_identifier [33..38] 'email' (@column_reference_3of3) = [39..40] '=' - literal [41..54] ''my@mail.com'' + literal [41..54] ''my@mail.com'' (@right) ; [54..55] ';' diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_3.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_3.snap index 0bbd1a28f..ac87ceea9 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_3.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_3.snap @@ -18,57 +18,57 @@ program [0..25] 'select u.id, u.email, cs.user_settings, cs.client_id from auth. statement [0..24] 'select u.id, u.email, cs.user_settings, cs.client_id from auth.users u join public.client_settings cs on u.id = cs.user_id' select [0..16] 'select u.id, u.email, cs.user_settings, cs.client_id' keyword_select [0..6] 'select' - select_expression [4..16] 'u.id, u.email, cs.user_settings, cs.client_id' - term [4..8] 'u.id' - object_reference [4..8] 'u.id' - any_identifier [4..5] 'u' + select_expression [4..16] 'u.id, u.email, cs.user_settings, cs.client_id' (@end) + term [4..8] 'u.id' (@end) + object_reference [4..8] 'u.id' (@end) + any_identifier [4..5] 'u' (@object_reference_1of2) . [5..6] '.' - any_identifier [6..8] 'id' - , [8..9] ',' - term [4..11] 'u.email' - object_reference [4..11] 'u.email' - any_identifier [4..5] 'u' + any_identifier [6..8] 'id' (@object_reference_2of2) + , [8..9] ',' (@end) + term [4..11] 'u.email' (@end) + object_reference [4..11] 'u.email' (@end) + any_identifier [4..5] 'u' (@object_reference_1of2) . [5..6] '.' - any_identifier [6..11] 'email' - , [11..12] ',' - term [4..20] 'cs.user_settings' - object_reference [4..20] 'cs.user_settings' - any_identifier [4..6] 'cs' + any_identifier [6..11] 'email' (@object_reference_2of2) + , [11..12] ',' (@end) + term [4..20] 'cs.user_settings' (@end) + object_reference [4..20] 'cs.user_settings' (@end) + any_identifier [4..6] 'cs' (@object_reference_1of2) . [6..7] '.' - any_identifier [7..20] 'user_settings' - , [20..21] ',' - term [4..16] 'cs.client_id' - object_reference [4..16] 'cs.client_id' - any_identifier [4..6] 'cs' + any_identifier [7..20] 'user_settings' (@object_reference_2of2) + , [20..21] ',' (@end) + term [4..16] 'cs.client_id' (@end) + object_reference [4..16] 'cs.client_id' (@end) + any_identifier [4..6] 'cs' (@object_reference_1of2) . [6..7] '.' - any_identifier [7..16] 'client_id' + any_identifier [7..16] 'client_id' (@object_reference_2of2) from [0..24] 'from auth.users u join public.client_settings cs on u.id = cs.user_id' keyword_from [0..4] 'from' - relation [4..16] 'auth.users u' - table_reference [4..14] 'auth.users' - schema_identifier [4..8] 'auth' + relation [4..16] 'auth.users u' (@end) + table_reference [4..14] 'auth.users' (@end) + schema_identifier [4..8] 'auth' (@table_reference_1of2) . [8..9] '.' - table_identifier [9..14] 'users' + table_identifier [9..14] 'users' (@table_reference_2of2) alias [15..16] 'u' - any_identifier [15..16] 'u' + any_identifier [15..16] 'u' (@end) join [4..24] 'join public.client_settings cs on u.id = cs.user_id' keyword_join [4..8] 'join' relation [9..34] 'public.client_settings cs' - table_reference [9..31] 'public.client_settings' - schema_identifier [9..15] 'public' + table_reference [9..31] 'public.client_settings' (@end) + schema_identifier [9..15] 'public' (@table_reference_1of2) . [15..16] '.' - table_identifier [16..31] 'client_settings' + table_identifier [16..31] 'client_settings' (@table_reference_2of2) alias [32..34] 'cs' - any_identifier [32..34] 'cs' + any_identifier [32..34] 'cs' (@end) keyword_on [4..6] 'on' - binary_expression [7..24] 'u.id = cs.user_id' - object_reference [7..11] 'u.id' - any_identifier [7..8] 'u' + binary_expression [7..24] 'u.id = cs.user_id' (@end) + object_reference [7..11] 'u.id' (@binary_expr_left) + any_identifier [7..8] 'u' (@object_reference_1of2) . [8..9] '.' - any_identifier [9..11] 'id' - = [12..13] '=' - object_reference [14..24] 'cs.user_id' - any_identifier [14..16] 'cs' + any_identifier [9..11] 'id' (@object_reference_2of2) + = [12..13] '=' (@binary_expr_operator) + object_reference [14..24] 'cs.user_id' (@end) + any_identifier [14..16] 'cs' (@object_reference_1of2) . [16..17] '.' - any_identifier [17..24] 'user_id' + any_identifier [17..24] 'user_id' (@object_reference_2of2) ; [24..25] ';' diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_4.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_4.snap index e7212729a..40241c4f6 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_4.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_4.snap @@ -8,9 +8,9 @@ program [0..28] 'select "auth".REPLACED_TOKEN' statement [0..28] 'select "auth".REPLACED_TOKEN' select [0..28] 'select "auth".REPLACED_TOKEN' keyword_select [0..6] 'select' - select_expression [7..28] '"auth".REPLACED_TOKEN' - term [7..28] '"auth".REPLACED_TOKEN' - object_reference [7..28] '"auth".REPLACED_TOKEN' - any_identifier [7..13] '"auth"' + select_expression [7..28] '"auth".REPLACED_TOKEN' (@end) + term [7..28] '"auth".REPLACED_TOKEN' (@end) + object_reference [7..28] '"auth".REPLACED_TOKEN' (@end) + any_identifier [7..13] '"auth"' (@object_reference_1of2) . [13..14] '.' - any_identifier [14..28] 'REPLACED_TOKEN' + any_identifier [14..28] 'REPLACED_TOKEN' (@object_reference_2of2) diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_5.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_5.snap index d7f8a2216..0da42a8cc 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_5.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_5.snap @@ -10,46 +10,46 @@ program [0..71] 'select * from users u where u.active = true and (u.role = 'admi statement [0..70] 'select * from users u where u.active = true and (u.role = 'admin' or u.role = 'moderator')' select [0..8] 'select *' keyword_select [0..6] 'select' - select_expression [7..8] '*' - term [7..8] '*' - all_fields [7..8] '*' + select_expression [7..8] '*' (@end) + term [7..8] '*' (@end) + all_fields [7..8] '*' (@end) * [7..8] '*' from [9..70] 'from users u where u.active = true and (u.role = 'admin' or u.role = 'moderator')' keyword_from [9..13] 'from' - relation [14..21] 'users u' - table_reference [14..19] 'users' - any_identifier [14..19] 'users' + relation [14..21] 'users u' (@end) + table_reference [14..19] 'users' (@end) + any_identifier [14..19] 'users' (@table_reference_1of1) alias [20..21] 'u' - any_identifier [20..21] 'u' + any_identifier [20..21] 'u' (@end) where [2..70] 'where u.active = true and (u.role = 'admin' or u.role = 'moderator')' keyword_where [2..7] 'where' - binary_expression [8..70] 'u.active = true and (u.role = 'admin' or u.role = 'moderator')' - binary_expression [8..23] 'u.active = true' - object_reference [8..16] 'u.active' - any_identifier [8..9] 'u' + binary_expression [8..70] 'u.active = true and (u.role = 'admin' or u.role = 'moderator')' (@end) + binary_expression [8..23] 'u.active = true' (@binary_expr_left) + object_reference [8..16] 'u.active' (@binary_expr_left) + any_identifier [8..9] 'u' (@object_reference_1of2) . [9..10] '.' - any_identifier [10..16] 'active' - = [17..18] '=' - literal [19..23] 'true' + any_identifier [10..16] 'active' (@object_reference_2of2) + = [17..18] '=' (@binary_expr_operator) + literal [19..23] 'true' (@end) keyword_true [19..23] 'true' - keyword_and [24..27] 'and' - parenthesized_expression [28..70] '(u.role = 'admin' or u.role = 'moderator')' + keyword_and [24..27] 'and' (@binary_expr_operator) + parenthesized_expression [28..70] '(u.role = 'admin' or u.role = 'moderator')' (@end) ( [28..29] '(' binary_expression [29..69] 'u.role = 'admin' or u.role = 'moderator'' - binary_expression [29..45] 'u.role = 'admin'' - object_reference [29..35] 'u.role' - any_identifier [29..30] 'u' + binary_expression [29..45] 'u.role = 'admin'' (@binary_expr_left) + object_reference [29..35] 'u.role' (@binary_expr_left) + any_identifier [29..30] 'u' (@object_reference_1of2) . [30..31] '.' - any_identifier [31..35] 'role' - = [36..37] '=' - literal [38..45] ''admin'' - keyword_or [46..48] 'or' - binary_expression [49..69] 'u.role = 'moderator'' - object_reference [49..55] 'u.role' - any_identifier [49..50] 'u' + any_identifier [31..35] 'role' (@object_reference_2of2) + = [36..37] '=' (@binary_expr_operator) + literal [38..45] ''admin'' (@end) + keyword_or [46..48] 'or' (@binary_expr_operator) + binary_expression [49..69] 'u.role = 'moderator'' (@end) + object_reference [49..55] 'u.role' (@binary_expr_left) + any_identifier [49..50] 'u' (@object_reference_1of2) . [50..51] '.' - any_identifier [51..55] 'role' - = [56..57] '=' - literal [58..69] ''moderator'' - ) [69..70] ')' + any_identifier [51..55] 'role' (@object_reference_2of2) + = [56..57] '=' (@binary_expr_operator) + literal [58..69] ''moderator'' (@end) + ) [69..70] ')' (@end) ; [70..71] ';' diff --git a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_6.snap b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_6.snap index 0030c84fe..0aede6486 100644 --- a/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_6.snap +++ b/crates/pgls_treesitter_grammar/tests/snapshots/grammar_tests__test_6.snap @@ -9,45 +9,45 @@ program [0..97] 'select (create_composite_type(a, b)).email, (schema.actual_type statement [0..96] 'select (create_composite_type(a, b)).email, (schema.actual_type).id, client from client_settings' select [0..75] 'select (create_composite_type(a, b)).email, (schema.actual_type).id, client' keyword_select [0..6] 'select' - select_expression [7..75] '(create_composite_type(a, b)).email, (schema.actual_type).id, client' - term [7..42] '(create_composite_type(a, b)).email' - field_selection [7..42] '(create_composite_type(a, b)).email' + select_expression [7..75] '(create_composite_type(a, b)).email, (schema.actual_type).id, client' (@end) + term [7..42] '(create_composite_type(a, b)).email' (@end) + field_selection [7..42] '(create_composite_type(a, b)).email' (@end) parenthesized_expression [7..36] '(create_composite_type(a, b))' ( [7..8] '(' invocation [8..35] 'create_composite_type(a, b)' function_reference [8..29] 'create_composite_type' - any_identifier [8..29] 'create_composite_type' + any_identifier [8..29] 'create_composite_type' (@function_reference_1of1) ( [29..30] '(' - term [30..31] 'a' - object_reference [30..31] 'a' - any_identifier [30..31] 'a' + term [30..31] 'a' (@parameter) + object_reference [30..31] 'a' (@end) + any_identifier [30..31] 'a' (@object_reference_1of1) , [31..32] ',' - term [33..34] 'b' - object_reference [33..34] 'b' - any_identifier [33..34] 'b' + term [33..34] 'b' (@parameter) + object_reference [33..34] 'b' (@end) + any_identifier [33..34] 'b' (@object_reference_1of1) ) [34..35] ')' - ) [35..36] ')' + ) [35..36] ')' (@end) . [36..37] '.' - any_identifier [37..42] 'email' - , [42..43] ',' - term [44..67] '(schema.actual_type).id' - field_selection [44..67] '(schema.actual_type).id' + any_identifier [37..42] 'email' (@end) + , [42..43] ',' (@end) + term [44..67] '(schema.actual_type).id' (@end) + field_selection [44..67] '(schema.actual_type).id' (@end) composite_reference [44..64] '(schema.actual_type)' ( [44..45] '(' object_reference [45..63] 'schema.actual_type' - any_identifier [45..51] 'schema' + any_identifier [45..51] 'schema' (@object_reference_1of2) . [51..52] '.' - any_identifier [52..63] 'actual_type' - ) [63..64] ')' + any_identifier [52..63] 'actual_type' (@object_reference_2of2) + ) [63..64] ')' (@end) . [64..65] '.' - any_identifier [65..67] 'id' - , [67..68] ',' - term [69..75] 'client' - object_reference [69..75] 'client' - any_identifier [69..75] 'client' + any_identifier [65..67] 'id' (@end) + , [67..68] ',' (@end) + term [69..75] 'client' (@end) + object_reference [69..75] 'client' (@end) + any_identifier [69..75] 'client' (@object_reference_1of1) from [76..96] 'from client_settings' keyword_from [76..80] 'from' - relation [81..96] 'client_settings' - table_reference [81..96] 'client_settings' - any_identifier [81..96] 'client_settings' + relation [81..96] 'client_settings' (@end) + table_reference [81..96] 'client_settings' (@end) + any_identifier [81..96] 'client_settings' (@table_reference_1of1) ; [96..97] ';' diff --git a/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts b/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts index c6b93982d..69d727961 100644 --- a/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts @@ -275,7 +275,8 @@ export type CompletionItemKind = | "column" | "schema" | "policy" - | "role"; + | "role" + | "keyword"; export interface UpdateSettingsParams { configuration: PartialConfiguration; gitignore_matches: string[]; diff --git a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts index c6b93982d..69d727961 100644 --- a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts @@ -275,7 +275,8 @@ export type CompletionItemKind = | "column" | "schema" | "policy" - | "role"; + | "role" + | "keyword"; export interface UpdateSettingsParams { configuration: PartialConfiguration; gitignore_matches: string[];