diff --git a/crates/squawk_ide/src/column_name.rs b/crates/squawk_ide/src/column_name.rs
index dd3e2b86..3b76b9d1 100644
--- a/crates/squawk_ide/src/column_name.rs
+++ b/crates/squawk_ide/src/column_name.rs
@@ -214,6 +214,144 @@ fn name_from_expr(expr: ast::Expr, in_type: bool) -> Option<(ColumnName, SyntaxN
return Some((ColumnName::UnknownColumn(None), node));
}
ast::Expr::CallExpr(call_expr) => {
+ if let Some(exists_fn) = call_expr.exists_fn() {
+ return Some((
+ ColumnName::Column("exists".to_string()),
+ exists_fn.syntax().clone(),
+ ));
+ }
+ if let Some(extract_fn) = call_expr.extract_fn() {
+ return Some((
+ ColumnName::Column("extract".to_string()),
+ extract_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_exists_fn) = call_expr.json_exists_fn() {
+ return Some((
+ ColumnName::Column("json_exists".to_string()),
+ json_exists_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_array_fn) = call_expr.json_array_fn() {
+ return Some((
+ ColumnName::Column("json_array".to_string()),
+ json_array_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_object_fn) = call_expr.json_object_fn() {
+ return Some((
+ ColumnName::Column("json_object".to_string()),
+ json_object_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_object_agg_fn) = call_expr.json_object_agg_fn() {
+ return Some((
+ ColumnName::Column("json_objectagg".to_string()),
+ json_object_agg_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_array_agg_fn) = call_expr.json_array_agg_fn() {
+ return Some((
+ ColumnName::Column("json_arrayagg".to_string()),
+ json_array_agg_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_query_fn) = call_expr.json_query_fn() {
+ return Some((
+ ColumnName::Column("json_query".to_string()),
+ json_query_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_scalar_fn) = call_expr.json_scalar_fn() {
+ return Some((
+ ColumnName::Column("json_scalar".to_string()),
+ json_scalar_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_serialize_fn) = call_expr.json_serialize_fn() {
+ return Some((
+ ColumnName::Column("json_serialize".to_string()),
+ json_serialize_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_value_fn) = call_expr.json_value_fn() {
+ return Some((
+ ColumnName::Column("json_value".to_string()),
+ json_value_fn.syntax().clone(),
+ ));
+ }
+ if let Some(json_fn) = call_expr.json_fn() {
+ return Some((
+ ColumnName::Column("json".to_string()),
+ json_fn.syntax().clone(),
+ ));
+ }
+ if let Some(substring_fn) = call_expr.substring_fn() {
+ return Some((
+ ColumnName::Column("substring".to_string()),
+ substring_fn.syntax().clone(),
+ ));
+ }
+ if let Some(position_fn) = call_expr.position_fn() {
+ return Some((
+ ColumnName::Column("position".to_string()),
+ position_fn.syntax().clone(),
+ ));
+ }
+ if let Some(overlay_fn) = call_expr.overlay_fn() {
+ return Some((
+ ColumnName::Column("overlay".to_string()),
+ overlay_fn.syntax().clone(),
+ ));
+ }
+ if let Some(trim_fn) = call_expr.trim_fn() {
+ return Some((
+ ColumnName::Column("trim".to_string()),
+ trim_fn.syntax().clone(),
+ ));
+ }
+ if let Some(xml_root_fn) = call_expr.xml_root_fn() {
+ return Some((
+ ColumnName::Column("xml_root".to_string()),
+ xml_root_fn.syntax().clone(),
+ ));
+ }
+ if let Some(xml_serialize_fn) = call_expr.xml_serialize_fn() {
+ return Some((
+ ColumnName::Column("xml_serialize".to_string()),
+ xml_serialize_fn.syntax().clone(),
+ ));
+ }
+ if let Some(xml_element_fn) = call_expr.xml_element_fn() {
+ return Some((
+ ColumnName::Column("xml_element".to_string()),
+ xml_element_fn.syntax().clone(),
+ ));
+ }
+ if let Some(xml_forest_fn) = call_expr.xml_forest_fn() {
+ return Some((
+ ColumnName::Column("xml_forest".to_string()),
+ xml_forest_fn.syntax().clone(),
+ ));
+ }
+ if let Some(xml_exists_fn) = call_expr.xml_exists_fn() {
+ return Some((
+ ColumnName::Column("xml_exists".to_string()),
+ xml_exists_fn.syntax().clone(),
+ ));
+ }
+ if let Some(xml_parse_fn) = call_expr.xml_parse_fn() {
+ return Some((
+ ColumnName::Column("xml_parse".to_string()),
+ xml_parse_fn.syntax().clone(),
+ ));
+ }
+ if let Some(xml_pi_fn) = call_expr.xml_pi_fn() {
+ return Some((
+ ColumnName::Column("xml_pi".to_string()),
+ xml_pi_fn.syntax().clone(),
+ ));
+ }
if let Some(func_name) = call_expr.expr() {
match func_name {
ast::Expr::ArrayExpr(_)
@@ -334,6 +472,31 @@ fn examples() {
assert_snapshot!(name("count(*)"), @"count");
assert_snapshot!(name("schema.func_name(1)"), @"func_name");
+ // special funcs
+ assert_snapshot!(name("extract(year from now())"), @"extract");
+ assert_snapshot!(name("exists(select 1)"), @"exists");
+ assert_snapshot!(name(r#"json_exists('{"a":1}', '$.a')"#), @"json_exists");
+ assert_snapshot!(name("json_array(1, 2)"), @"json_array");
+ assert_snapshot!(name("json_object('a': 1)"), @"json_object");
+ assert_snapshot!(name("json_objectagg('a': 1)"), @"json_objectagg");
+ assert_snapshot!(name("json_arrayagg(1)"), @"json_arrayagg");
+ assert_snapshot!(name(r#"json_query('{"a":1}', '$.a')"#), @"json_query");
+ assert_snapshot!(name("json_scalar(1)"), @"json_scalar");
+ assert_snapshot!(name(r#"json_serialize('{"a":1}')"#), @"json_serialize");
+ assert_snapshot!(name(r#"json_value('{"a":1}', '$.a')"#), @"json_value");
+ assert_snapshot!(name(r#"json('{"a":1}')"#), @"json");
+ assert_snapshot!(name("substring('hello' from 2 for 3)"), @"substring");
+ assert_snapshot!(name("position('a' in 'abc')"), @"position");
+ assert_snapshot!(name("overlay('hello' placing 'X' from 2)"), @"overlay");
+ assert_snapshot!(name("trim(' hi ')"), @"trim");
+ assert_snapshot!(name("xmlroot('', version '1.0')"), @"xml_root");
+ assert_snapshot!(name("xmlserialize(document '' as text)"), @"xml_serialize");
+ assert_snapshot!(name("xmlelement(name foo, 'bar')"), @"xml_element");
+ assert_snapshot!(name("xmlforest('bar' as foo)"), @"xml_forest");
+ assert_snapshot!(name("xmlexists('//a' passing '')"), @"xml_exists");
+ assert_snapshot!(name("xmlparse(document '')"), @"xml_parse");
+ assert_snapshot!(name("xmlpi(name foo, 'bar')"), @"xml_pi");
+
// index
assert_snapshot!(name("foo[bar]"), @"foo");
assert_snapshot!(name("foo[1]"), @"foo");
diff --git a/crates/squawk_ide/src/goto_definition.rs b/crates/squawk_ide/src/goto_definition.rs
index 59085a3b..29ff9f79 100644
--- a/crates/squawk_ide/src/goto_definition.rs
+++ b/crates/squawk_ide/src/goto_definition.rs
@@ -4995,6 +4995,21 @@ reindex index idx$0;
");
}
+ #[test]
+ fn goto_select_exists_column() {
+ assert_snapshot!(goto("
+select exists$0 from (
+ select exists(select 1)
+);
+"), @r"
+ ╭▸
+ 2 │ select exists from (
+ │ ─ 1. source
+ 3 │ select exists(select 1)
+ ╰╴ ──────────────── 2. destination
+ ");
+ }
+
#[test]
fn goto_reindex_schema() {
assert_snapshot!(goto("