diff --git a/crates/pgls_pretty_print/src/nodes/comment_stmt.rs b/crates/pgls_pretty_print/src/nodes/comment_stmt.rs index 5bdbb4487..425ba669b 100644 --- a/crates/pgls_pretty_print/src/nodes/comment_stmt.rs +++ b/crates/pgls_pretty_print/src/nodes/comment_stmt.rs @@ -195,7 +195,14 @@ pub(super) fn emit_comment_stmt(e: &mut EventEmitter, n: &CommentStmt) { e.space(); super::emit_node(object, e); } else { - super::emit_node(object, e); + // For most object types (TABLE, INDEX, SEQUENCE, VIEW, etc.), the object + // is a List of String nodes representing a schema-qualified name that must + // be dot-separated (e.g., public.my_table), not comma-separated. + if let Some(pgls_query::NodeEnum::List(list)) = object.node.as_ref() { + emit_dot_separated_list(e, &list.items); + } else { + super::emit_node(object, e); + } } } diff --git a/crates/pgls_pretty_print/src/nodes/create_extension_stmt.rs b/crates/pgls_pretty_print/src/nodes/create_extension_stmt.rs index 9b0ea13fa..b70c47e8d 100644 --- a/crates/pgls_pretty_print/src/nodes/create_extension_stmt.rs +++ b/crates/pgls_pretty_print/src/nodes/create_extension_stmt.rs @@ -1,9 +1,8 @@ -use super::node_list::emit_comma_separated_list; use crate::{ TokenKind, emitter::{EventEmitter, GroupKind, LineType}, }; -use pgls_query::protobuf::CreateExtensionStmt; +use pgls_query::{NodeEnum, protobuf::CreateExtensionStmt}; pub(super) fn emit_create_extension_stmt(e: &mut EventEmitter, n: &CreateExtensionStmt) { e.group_start(GroupKind::CreateExtensionStmt); @@ -27,11 +26,57 @@ pub(super) fn emit_create_extension_stmt(e: &mut EventEmitter, n: &CreateExtensi if !n.options.is_empty() { e.line(LineType::SoftOrSpace); e.token(TokenKind::WITH_KW); - e.space(); - emit_comma_separated_list(e, &n.options, super::emit_node); + + for opt in &n.options { + let def = assert_node_variant!(DefElem, opt); + e.space(); + emit_extension_option(e, def); + } } e.token(TokenKind::SEMICOLON); e.group_end(); } + +/// Emit a CREATE EXTENSION option. +/// Options use keyword syntax (no equals sign): +/// SCHEMA schema_name +/// VERSION 'version' +/// CASCADE +fn emit_extension_option(e: &mut EventEmitter, def: &pgls_query::protobuf::DefElem) { + match def.defname.as_str() { + "schema" => { + e.token(TokenKind::SCHEMA_KW); + if let Some(ref arg) = def.arg { + e.space(); + // Schema name is a String node - emit_node dispatches to + // emit_string which uses emit_identifier_maybe_quoted + super::emit_node(arg, e); + } + } + "new_version" => { + e.token(TokenKind::VERSION_KW); + if let Some(ref arg) = def.arg { + e.space(); + // Version must be a quoted string literal + if let Some(NodeEnum::String(s)) = &arg.node { + super::emit_string_literal(e, s); + } else { + super::emit_node(arg, e); + } + } + } + "cascade" => { + e.token(TokenKind::CASCADE_KW); + } + _ => { + // Fallback for unknown options + super::string::emit_keyword(e, &def.defname); + if let Some(ref arg) = def.arg { + e.space(); + super::emit_node(arg, e); + } + } + } +} diff --git a/crates/pgls_pretty_print/src/normalize.rs b/crates/pgls_pretty_print/src/normalize.rs index 61cf9f6c5..51c86d642 100644 --- a/crates/pgls_pretty_print/src/normalize.rs +++ b/crates/pgls_pretty_print/src/normalize.rs @@ -686,6 +686,28 @@ fn normalize_a_indirection(node: &mut NodeEnum) { } } } + NodeEnum::CreateStmt(stmt) => { + // Recurse into table elements (ColumnDef, Constraint, etc.) + for elt in &mut stmt.table_elts { + if let Some(ref mut n) = elt.node { + normalize_a_indirection(n); + } + } + } + NodeEnum::ColumnDef(cd) => { + // Recurse into column constraints + for constraint in &mut cd.constraints { + if let Some(ref mut n) = constraint.node { + normalize_a_indirection(n); + } + } + // Recurse into default value expression + if let Some(ref mut raw) = cd.raw_default + && let Some(ref mut n) = raw.node + { + normalize_a_indirection(n); + } + } NodeEnum::RuleStmt(stmt) => { for action in &mut stmt.actions { if let Some(ref mut n) = action.node { diff --git a/crates/pgls_pretty_print/tests/data/single/comment_stmt_1.sql b/crates/pgls_pretty_print/tests/data/single/comment_stmt_1.sql new file mode 100644 index 000000000..6e6e0433c --- /dev/null +++ b/crates/pgls_pretty_print/tests/data/single/comment_stmt_1.sql @@ -0,0 +1 @@ +COMMENT ON TABLE public.api_token IS 'Listing of known API tokens'; diff --git a/crates/pgls_pretty_print/tests/data/single/comment_stmt_2.sql b/crates/pgls_pretty_print/tests/data/single/comment_stmt_2.sql new file mode 100644 index 000000000..6e6b87946 --- /dev/null +++ b/crates/pgls_pretty_print/tests/data/single/comment_stmt_2.sql @@ -0,0 +1 @@ +COMMENT ON TABLE "public"."event" IS 'An event is created everytime something interesting happens'; diff --git a/crates/pgls_pretty_print/tests/data/single/create_extension_stmt_1.sql b/crates/pgls_pretty_print/tests/data/single/create_extension_stmt_1.sql new file mode 100644 index 000000000..8be5b6d3f --- /dev/null +++ b/crates/pgls_pretty_print/tests/data/single/create_extension_stmt_1.sql @@ -0,0 +1 @@ +CREATE EXTENSION vector WITH SCHEMA extensions; diff --git a/crates/pgls_pretty_print/tests/data/single/create_extension_stmt_2.sql b/crates/pgls_pretty_print/tests/data/single/create_extension_stmt_2.sql new file mode 100644 index 000000000..2a95adb36 --- /dev/null +++ b/crates/pgls_pretty_print/tests/data/single/create_extension_stmt_2.sql @@ -0,0 +1 @@ +CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA extensions; diff --git a/crates/pgls_pretty_print/tests/data/single/create_stmt_cast_check_0.sql b/crates/pgls_pretty_print/tests/data/single/create_stmt_cast_check_0.sql new file mode 100644 index 000000000..92cfb3cb7 --- /dev/null +++ b/crates/pgls_pretty_print/tests/data/single/create_stmt_cast_check_0.sql @@ -0,0 +1,17 @@ +CREATE TABLE t ( + "type" "public"."my_enum" NOT NULL, + "target_column" "text", + "from_value" "text", + "to_value" "text", + CONSTRAINT "c2" CHECK ( + ("type" <> 'es_value_changed'::"public"."my_enum") OR + ( + ("target_column" = 'config'::"text") AND + (("from_value" IS NULL) AND ("to_value" IS NULL)) + ) OR + ( + (("from_value" IS NOT NULL) AND ("to_value" IS NOT NULL)) AND + ("target_column" IN ('type', 'name')) + ) + ) +); diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_1_100.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_1_100.snap new file mode 100644 index 000000000..16e65f9e5 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_1_100.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/comment_stmt_1.sql +--- +comment on table public.api_token is 'Listing of known API tokens'; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_1_80.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_1_80.snap new file mode 100644 index 000000000..16e65f9e5 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_1_80.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/comment_stmt_1.sql +--- +comment on table public.api_token is 'Listing of known API tokens'; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_2_100.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_2_100.snap new file mode 100644 index 000000000..c82660216 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_2_100.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/comment_stmt_2.sql +--- +comment on table public.event is 'An event is created everytime something interesting happens'; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_2_80.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_2_80.snap new file mode 100644 index 000000000..c82660216 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__comment_stmt_2_80.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/comment_stmt_2.sql +--- +comment on table public.event is 'An event is created everytime something interesting happens'; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_1_100.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_1_100.snap new file mode 100644 index 000000000..a68c2ddb3 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_1_100.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/create_extension_stmt_1.sql +--- +create extension vector with schema extensions; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_1_80.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_1_80.snap new file mode 100644 index 000000000..a68c2ddb3 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_1_80.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/create_extension_stmt_1.sql +--- +create extension vector with schema extensions; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_2_100.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_2_100.snap new file mode 100644 index 000000000..d18512736 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_2_100.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/create_extension_stmt_2.sql +--- +create extension if not exists pg_stat_statements with schema extensions; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_2_80.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_2_80.snap new file mode 100644 index 000000000..d18512736 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_extension_stmt_2_80.snap @@ -0,0 +1,5 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/create_extension_stmt_2.sql +--- +create extension if not exists pg_stat_statements with schema extensions; diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__create_stmt_cast_check_0_100.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_stmt_cast_check_0_100.snap new file mode 100644 index 000000000..b36fa1aad --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_stmt_cast_check_0_100.snap @@ -0,0 +1,16 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/create_stmt_cast_check_0.sql +--- +create table t ( + type public.my_enum not null, + target_column text, + from_value text, + to_value text, + constraint "c2" check (type <> cast('es_value_changed' as public.my_enum) or + target_column = cast('config' as text) and + from_value is null and to_value is null or + from_value is not null and + to_value is not null and + target_column in ('type', 'name')) +); diff --git a/crates/pgls_pretty_print/tests/snapshots/single/tests__create_stmt_cast_check_0_80.snap b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_stmt_cast_check_0_80.snap new file mode 100644 index 000000000..3581c1f57 --- /dev/null +++ b/crates/pgls_pretty_print/tests/snapshots/single/tests__create_stmt_cast_check_0_80.snap @@ -0,0 +1,18 @@ +--- +source: crates/pgls_pretty_print/tests/tests.rs +input_file: crates/pgls_pretty_print/tests/data/single/create_stmt_cast_check_0.sql +--- +create table t ( + type public.my_enum not null, + target_column text, + from_value text, + to_value text, + constraint "c2" check (type <> + cast('es_value_changed' + as public.my_enum) or + target_column = cast('config' as text) and + from_value is null and to_value is null or + from_value is not null and + to_value is not null and + target_column in ('type', 'name')) +);