diff --git a/CHANGELOG.md b/CHANGELOG.md index b6d7dfe..5a9e1fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## [Unreleased] +- Introduce StatementAppender for better spacing between statements + ## [0.2.1] - 2025-02-15 - Add transform to remove SET commands with default values diff --git a/README.md b/README.md index 1e83a8e..dec7eed 100644 --- a/README.md +++ b/README.md @@ -191,8 +191,6 @@ INSERT INTO "schema_migrations" (version) VALUES into this normalize (and much more compatch & readable) version: ```sql - - CREATE EXTENSION IF NOT EXISTS pgcrypto SCHEMA public; diff --git a/lib/activerecord-pg-format-db-structure.rb b/lib/activerecord-pg-format-db-structure.rb index ca15248..b8b80d8 100644 --- a/lib/activerecord-pg-format-db-structure.rb +++ b/lib/activerecord-pg-format-db-structure.rb @@ -3,6 +3,7 @@ require_relative "activerecord-pg-format-db-structure/version" require_relative "activerecord-pg-format-db-structure/deparser" +require_relative "activerecord-pg-format-db-structure/statement_appender" require_relative "activerecord-pg-format-db-structure/transforms/remove_comments_on_extensions" require_relative "activerecord-pg-format-db-structure/transforms/inline_serials" require_relative "activerecord-pg-format-db-structure/transforms/inline_primary_keys" @@ -29,6 +30,7 @@ module ActiveRecordPgFormatDbStructure ].freeze DEFAULT_DEPARSER = Deparser + DEFAULT_STATEMENT_APPENDER = StatementAppender end # :nocov: diff --git a/lib/activerecord-pg-format-db-structure/deparser.rb b/lib/activerecord-pg-format-db-structure/deparser.rb index aed01d9..ca8ea2e 100644 --- a/lib/activerecord-pg-format-db-structure/deparser.rb +++ b/lib/activerecord-pg-format-db-structure/deparser.rb @@ -32,42 +32,42 @@ def deparse_raw_statement(raw_statement) private def deparse_stmt_generic(stmt) - generic_str = +"\n\n" + generic_str = +"" generic_str << deparse_stmt_and_indent(stmt) generic_str << ";" generic_str end def deparse_stmt_compact(stmt) - compact_str = +"\n" + compact_str = +"" compact_str << deparse_stmt(stmt) compact_str << ";" compact_str end def deparse_insert_stmt(stmt) - insert_str = +"\n\n\n" + insert_str = +"" insert_str << deparse_stmt_and_indent(stmt) insert_str << "\n;" insert_str end def deparse_create_stmt(stmt) - table_str = "\n\n\n-- Name: #{stmt.relation.relname}; Type: TABLE;\n\n" + table_str = "-- Name: #{stmt.relation.relname}; Type: TABLE;\n\n" table_str << deparse_stmt_and_indent(stmt) table_str << ";" table_str end def deparse_view_stmt(stmt) - table_str = "\n\n\n-- Name: #{stmt.view.relname}; Type: VIEW;\n\n" + table_str = "-- Name: #{stmt.view.relname}; Type: VIEW;\n\n" table_str << deparse_stmt_and_indent(stmt) table_str << ";" table_str end def deparse_create_table_as_stmt(stmt) - table_str = "\n\n\n-- Name: #{stmt.into.rel.relname}; Type: MATERIALIZED VIEW;\n\n" + table_str = "-- Name: #{stmt.into.rel.relname}; Type: MATERIALIZED VIEW;\n\n" table_str << deparse_stmt_and_indent(stmt) # couldn't find a better solution for this, but probably an OK workaround? diff --git a/lib/activerecord-pg-format-db-structure/formatter.rb b/lib/activerecord-pg-format-db-structure/formatter.rb index 086f974..4e0e1b5 100644 --- a/lib/activerecord-pg-format-db-structure/formatter.rb +++ b/lib/activerecord-pg-format-db-structure/formatter.rb @@ -6,14 +6,16 @@ module ActiveRecordPgFormatDbStructure # Formats & normalizes in place the given SQL string class Formatter - attr_reader :transforms, :deparser + attr_reader :transforms, :deparser, :statement_appender def initialize( transforms: DEFAULT_TRANSFORMS, - deparser: DEFAULT_DEPARSER + deparser: DEFAULT_DEPARSER, + statement_appender: DEFAULT_STATEMENT_APPENDER ) @transforms = transforms @deparser = deparser + @statement_appender = statement_appender end def format(source) @@ -23,9 +25,17 @@ def format(source) transform.new(raw_statements).transform! end - raw_statements.map do |raw_statement| - deparser.new(source).deparse_raw_statement(raw_statement) - end.compact.join + appender = statement_appender.new + raw_statements.each do |raw_statement| + statement = deparser.new(source).deparse_raw_statement(raw_statement) + appender.append_statement!( + statement, + statement_kind: PgQuery::Node.inner_class_to_name( + raw_statement.stmt.inner.class + ) + ) + end + appender.output end end end diff --git a/lib/activerecord-pg-format-db-structure/railtie.rb b/lib/activerecord-pg-format-db-structure/railtie.rb index d38c26b..bc90cd7 100644 --- a/lib/activerecord-pg-format-db-structure/railtie.rb +++ b/lib/activerecord-pg-format-db-structure/railtie.rb @@ -6,6 +6,7 @@ class Railtie < Rails::Railtie config.activerecord_pg_format_db_structure = ActiveSupport::OrderedOptions.new config.activerecord_pg_format_db_structure.transforms = DEFAULT_TRANSFORMS.dup config.activerecord_pg_format_db_structure.deparser = DEFAULT_DEPARSER + config.activerecord_pg_format_db_structure.statement_appender = DEFAULT_STATEMENT_APPENDER rake_tasks do load "activerecord-pg-format-db-structure/tasks/clean_db_structure.rake" diff --git a/lib/activerecord-pg-format-db-structure/statement_appender.rb b/lib/activerecord-pg-format-db-structure/statement_appender.rb new file mode 100644 index 0000000..021cc4a --- /dev/null +++ b/lib/activerecord-pg-format-db-structure/statement_appender.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require "pg_query" +require_relative "indenter" + +module ActiveRecordPgFormatDbStructure + # Appends statements with reasonable spacing in-between + class StatementAppender + attr_reader :output + + def initialize(output = +"") + @output = output + @previous_statement_kind = nil + end + + def append_statement!(statement, statement_kind:) + output.chomp! + output << newlines_separator( + previous_kind: @previous_statement_kind, + current_kind: statement_kind + ) + @previous_statement_kind = statement_kind + output << statement + output << "\n" + end + + private + + def newlines_separator(previous_kind:, current_kind:) + case [ + previous_kind, + current_kind + ] + in [ + nil, + _ + ] + "" + in [ + _, + :insert_stmt | :create_stmt | :view_stmt | :create_table_as_stmt + ] + "\n\n\n" + in [ + :create_stmt | :view_stmt | :create_table_as_stmt | :index_stmt, + :index_stmt + ] | [ + :variable_set_stmt, + :variable_set_stmt + ] + "\n" + else + "\n\n" + end + end + end +end diff --git a/spec/activerecord-pg-format-db-structure/deparser_spec.rb b/spec/activerecord-pg-format-db-structure/deparser_spec.rb index c6ed93f..a8d03bb 100644 --- a/spec/activerecord-pg-format-db-structure/deparser_spec.rb +++ b/spec/activerecord-pg-format-db-structure/deparser_spec.rb @@ -15,9 +15,7 @@ SELECT * FROM my_table WHERE 1 = 1; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) SELECT * FROM my_table WHERE 1 = 1; @@ -29,9 +27,7 @@ SELECT '1'::integer; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) SELECT '1'::int; SQL end @@ -48,9 +44,7 @@ WHERE bar > 10 OR bar < 5 OR (bar < 2 AND baz); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) SELECT sum(foo) AS column_a, CASE WHEN foo = 'a' THEN 1 @@ -71,10 +65,7 @@ INSERT INTO schema_migrations (version) VALUES ('20250124155339'), ('20250134155339') , ('20250144155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) INSERT INTO schema_migrations (version) VALUES ('20250124155339') , ('20250134155339') @@ -89,10 +80,7 @@ SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) INSERT INTO schema_migrations (version) SELECT foo FROM bar @@ -107,8 +95,7 @@ CREATE UNIQUE INDEX only_one_pending_per_comment_id ON public.my_table USING btree (comment_id) WHERE pending; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - + expect(formatter.format(source)).to eq(<<~SQL) CREATE UNIQUE INDEX only_one_pending_per_comment_id ON public.my_table USING btree (comment_id) WHERE pending; SQL end @@ -122,10 +109,7 @@ ); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: post_stats; Type: VIEW; CREATE VIEW public.post_stats AS @@ -141,10 +125,7 @@ ); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: post_stats; Type: VIEW; CREATE VIEW public.post_stats AS @@ -160,9 +141,7 @@ SELECT * from my_cte; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) WITH my_cte AS ( SELECT foo, baz @@ -182,10 +161,7 @@ ); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: post_stats; Type: MATERIALIZED VIEW; CREATE MATERIALIZED VIEW public.post_stats AS @@ -201,10 +177,7 @@ ) WITH NO DATA; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: post_stats; Type: MATERIALIZED VIEW; CREATE MATERIALIZED VIEW public.post_stats AS @@ -250,10 +223,7 @@ ) main_status; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: my_bigg_aggregated_view; Type: VIEW; CREATE VIEW public.my_bigg_aggregated_view AS diff --git a/spec/activerecord-pg-format-db-structure/formatter_spec.rb b/spec/activerecord-pg-format-db-structure/formatter_spec.rb index 3730bd5..7367bdc 100644 --- a/spec/activerecord-pg-format-db-structure/formatter_spec.rb +++ b/spec/activerecord-pg-format-db-structure/formatter_spec.rb @@ -178,17 +178,13 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) SET client_encoding TO "UTF8"; SELECT pg_catalog.set_config('search_path', '', false); SET check_function_bodies TO TRUE; - SET client_min_messages TO warning; - SET row_security TO OFF; CREATE EXTENSION IF NOT EXISTS pgcrypto SCHEMA public; diff --git a/spec/activerecord-pg-format-db-structure/transforms/group_alter_table_statements_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/group_alter_table_statements_spec.rb index 31c5aba..220032f 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/group_alter_table_statements_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/group_alter_table_statements_spec.rb @@ -56,10 +56,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( @@ -143,10 +140,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( diff --git a/spec/activerecord-pg-format-db-structure/transforms/inline_constraints_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/inline_constraints_spec.rb index 4e11be6..7968186 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/inline_constraints_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/inline_constraints_spec.rb @@ -50,10 +50,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( diff --git a/spec/activerecord-pg-format-db-structure/transforms/inline_foreign_keys_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/inline_foreign_keys_spec.rb index d909b19..0f9bd67 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/inline_foreign_keys_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/inline_foreign_keys_spec.rb @@ -50,10 +50,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( diff --git a/spec/activerecord-pg-format-db-structure/transforms/inline_primary_keys_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/inline_primary_keys_spec.rb index 84bbb6f..bf41fe8 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/inline_primary_keys_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/inline_primary_keys_spec.rb @@ -47,10 +47,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( diff --git a/spec/activerecord-pg-format-db-structure/transforms/inline_serials_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/inline_serials_spec.rb index 27b1a02..8bda2fe 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/inline_serials_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/inline_serials_spec.rb @@ -202,9 +202,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) CREATE EXTENSION IF NOT EXISTS pgcrypto SCHEMA public; COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions'; diff --git a/spec/activerecord-pg-format-db-structure/transforms/move_indices_after_create_table_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/move_indices_after_create_table_spec.rb index f17c07f..d4c4a1c 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/move_indices_after_create_table_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/move_indices_after_create_table_spec.rb @@ -39,10 +39,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( diff --git a/spec/activerecord-pg-format-db-structure/transforms/remove_comments_on_extensions_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/remove_comments_on_extensions_spec.rb index 55fbd9c..7d9658a 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/remove_comments_on_extensions_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/remove_comments_on_extensions_spec.rb @@ -37,9 +37,7 @@ ('20250124155339'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) CREATE EXTENSION IF NOT EXISTS pgcrypto SCHEMA public; diff --git a/spec/activerecord-pg-format-db-structure/transforms/remove_defaults_set_commands_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/remove_defaults_set_commands_spec.rb index ebe646d..00908fe 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/remove_defaults_set_commands_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/remove_defaults_set_commands_spec.rb @@ -21,17 +21,13 @@ SET row_security = off; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) SET client_encoding TO "UTF8"; SELECT pg_catalog.set_config('search_path', '', false); SET check_function_bodies TO FALSE; - SET client_min_messages TO warning; - SET row_security TO OFF; SQL end @@ -55,27 +51,18 @@ SET row_security = on; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) SET statement_timeout TO 1; - SET default_with_oids TO TRUE; - SET lock_timeout TO 2; - SET idle_in_transaction_session_timeout TO 3; - SET client_encoding TO "UTF8"; - SET standard_conforming_strings TO OFF; SELECT pg_catalog.set_config('search_path', '', false); SET check_function_bodies TO FALSE; - SET client_min_messages TO warning; - SET row_security TO ON; SQL end @@ -89,9 +76,7 @@ SET statement_timeout = 10.0; SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - + expect(formatter.format(source)).to eq(<<~SQL) SET statement_timeout TO 10.0; SQL end diff --git a/spec/activerecord-pg-format-db-structure/transforms/sort_schema_migrations_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/sort_schema_migrations_spec.rb index bce541f..fe341b7 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/sort_schema_migrations_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/sort_schema_migrations_spec.rb @@ -23,10 +23,7 @@ ('20250101000001'); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( diff --git a/spec/activerecord-pg-format-db-structure/transforms/sort_table_columns_spec.rb b/spec/activerecord-pg-format-db-structure/transforms/sort_table_columns_spec.rb index 584ce34..b7ba2ce 100644 --- a/spec/activerecord-pg-format-db-structure/transforms/sort_table_columns_spec.rb +++ b/spec/activerecord-pg-format-db-structure/transforms/sort_table_columns_spec.rb @@ -26,10 +26,7 @@ ADD CONSTRAINT postive_score_take_2 CHECK (score > 0); SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( @@ -77,10 +74,7 @@ SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments ( @@ -129,10 +123,7 @@ SQL - expect(formatter.format(source)).to eq(<<~SQL.chomp) - - - + expect(formatter.format(source)).to eq(<<~SQL) -- Name: comments; Type: TABLE; CREATE TABLE public.comments (