diff --git a/crates/squawk_ide/src/code_actions.rs b/crates/squawk_ide/src/code_actions.rs index a1e30caa..ccc7f5cc 100644 --- a/crates/squawk_ide/src/code_actions.rs +++ b/crates/squawk_ide/src/code_actions.rs @@ -47,6 +47,7 @@ pub fn code_actions(file: ast::SourceFile, offset: TextSize) -> Option, + file: &ast::SourceFile, + offset: TextSize, +) -> Option<()> { + let token = token_from_offset(file, offset)?; + let time_type = token.parent_ancestors().find_map(ast::TimeType::cast)?; + + let replacement = match time_type.timezone()? { + ast::Timezone::WithoutTimezone(_) => { + if time_type.timestamp_token().is_some() { + "timestamp" + } else { + "time" + } + } + ast::Timezone::WithTimezone(_) => { + if time_type.timestamp_token().is_some() { + "timestamptz" + } else { + "timetz" + } + } + }; + + actions.push(CodeAction { + title: format!("Rewrite as `{replacement}`"), + edits: vec![Edit::replace(time_type.syntax().text_range(), replacement)], + kind: ActionKind::RefactorRewrite, + }); + + Some(()) +} + fn rewrite_values_as_select( actions: &mut Vec, file: &ast::SourceFile, @@ -2290,4 +2334,66 @@ select myschema.f$0();" "sel$0ect c from t;" )); } + + #[test] + fn rewrite_timestamp_without_tz_column() { + assert_snapshot!(apply_code_action( + rewrite_timestamp_type, + "create table t(a time$0stamp without time zone);"), + @"create table t(a timestamp);" + ); + } + + #[test] + fn rewrite_timestamp_without_tz_cast() { + assert_snapshot!(apply_code_action( + rewrite_timestamp_type, + "select timestamp$0 without time zone '2021-01-01';"), + @"select timestamp '2021-01-01';" + ); + } + + #[test] + fn rewrite_time_without_tz() { + assert_snapshot!(apply_code_action( + rewrite_timestamp_type, + "create table t(a ti$0me without time zone);"), + @"create table t(a time);" + ); + } + + #[test] + fn rewrite_timestamp_without_tz_not_applicable_plain() { + assert!(code_action_not_applicable( + rewrite_timestamp_type, + "create table t(a time$0stamp);" + )); + } + + #[test] + fn rewrite_timestamp_with_tz_column() { + assert_snapshot!(apply_code_action( + rewrite_timestamp_type, + "create table t(a time$0stamp with time zone);"), + @"create table t(a timestamptz);" + ); + } + + #[test] + fn rewrite_timestamp_with_tz_cast() { + assert_snapshot!(apply_code_action( + rewrite_timestamp_type, + "select timestamp$0 with time zone '2021-01-01';"), + @"select timestamptz '2021-01-01';" + ); + } + + #[test] + fn rewrite_time_with_tz() { + assert_snapshot!(apply_code_action( + rewrite_timestamp_type, + "create table t(a ti$0me with time zone);"), + @"create table t(a timetz);" + ); + } } diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index edc99c15..00149952 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -2066,10 +2066,7 @@ fn name_ref_(p: &mut Parser<'_>) -> Option { } p.expect(R_PAREN); } - if p.eat(WITH_KW) || p.eat(WITHOUT_KW) { - p.expect(TIME_KW); - p.expect(ZONE_KW); - } + opt_with_timezone(p); TIME_TYPE } BIT_KW => { diff --git a/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap b/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap index 736a41bf..cbf01e68 100644 --- a/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap @@ -953,11 +953,12 @@ SOURCE_FILE TIME_TYPE TIMESTAMP_KW "timestamp" WHITESPACE " " - WITH_KW "with" - WHITESPACE " " - TIME_KW "time" - WHITESPACE " " - ZONE_KW "zone" + WITH_TIMEZONE + WITH_KW "with" + WHITESPACE " " + TIME_KW "time" + WHITESPACE " " + ZONE_KW "zone" WHITESPACE " " LITERAL STRING "'2005-04-02 12:00:00-07'" @@ -976,11 +977,12 @@ SOURCE_FILE TIME_TYPE TIMESTAMP_KW "timestamp" WHITESPACE " " - WITH_KW "with" - WHITESPACE " " - TIME_KW "time" - WHITESPACE " " - ZONE_KW "zone" + WITH_TIMEZONE + WITH_KW "with" + WHITESPACE " " + TIME_KW "time" + WHITESPACE " " + ZONE_KW "zone" WHITESPACE " " LITERAL STRING "'2001-02-16 20:38:40-05'" @@ -1074,11 +1076,12 @@ SOURCE_FILE TIME_TYPE TIME_KW "time" WHITESPACE " " - WITH_KW "with" - WHITESPACE " " - TIME_KW "time" - WHITESPACE " " - ZONE_KW "zone" + WITH_TIMEZONE + WITH_KW "with" + WHITESPACE " " + TIME_KW "time" + WHITESPACE " " + ZONE_KW "zone" WHITESPACE " " LITERAL STRING "'20:38:40-05'" @@ -1114,11 +1117,12 @@ SOURCE_FILE TIME_TYPE TIMESTAMP_KW "timestamp" WHITESPACE " " - WITH_KW "with" - WHITESPACE " " - TIME_KW "time" - WHITESPACE " " - ZONE_KW "zone" + WITH_TIMEZONE + WITH_KW "with" + WHITESPACE " " + TIME_KW "time" + WHITESPACE " " + ZONE_KW "zone" WHITESPACE " " LITERAL STRING "'2001-02-16 20:38:40-05'"