Skip to content

Commit

Permalink
dump inherited table options to schema.rb (#42)
Browse files Browse the repository at this point in the history
* dump inherited table options to schema.rb

* fix for no inherited tables

* dump inherited tables after

* control ordering of dumping

* stree
  • Loading branch information
waymondo authored Jan 11, 2024
1 parent 7575d55 commit ce0a9cc
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 10 deletions.
10 changes: 7 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

- *Breaking Change* - Support for Ruby 2.7 and Rails 6.1 is dropped
- *Breaking Change* - The default scoping clause that controls the inherited table SQL construction
changes from a where clause using `tableoid`s to using `FROM ONLY`.
- fixes an issue for Rails 7.1 regarding accessing version table columns through aliased attributes
changes from a where clause using `tableoid`s to using `FROM ONLY`
- Fixes an issue for Rails 7.1 regarding accessing version table columns through aliased attributes
- Fixes an issue where `Hoardable::RichText` couldn’t be loaded if `ActionText::RichText` wasn’t yet
loaded
- Supports dumping `INHERITS (table_name)` options to `schema.rb` and ensures the inherited tables
are dumped after their parents

## 0.14.3

- The migration template is updated to make the primary key on the versions table its actual primary key.
- The migration template is updated to make the primary key on the versions table its actual primary key

## 0.14.2

Expand Down
12 changes: 6 additions & 6 deletions lib/generators/hoardable/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ class InstallGenerator < Rails::Generators::Base

def create_initializer_file
create_file("config/initializers/hoardable.rb", <<~TEXT)
# Hoardable configuration defaults are below. Learn more at https://github.com/waymondo/hoardable#configuration
#
# Hoardable.enabled = true
# Hoardable.version_updates = true
# Hoardable.save_trash = true
TEXT
# Hoardable configuration defaults are below. Learn more at https://github.com/waymondo/hoardable#configuration
#
# Hoardable.enabled = true
# Hoardable.version_updates = true
# Hoardable.save_trash = true
TEXT
end

def create_migration_file
Expand Down
2 changes: 2 additions & 0 deletions lib/hoardable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
require "fx"
require_relative "hoardable/version"
require_relative "hoardable/arel_visitors"
require_relative "hoardable/schema_statements"
require_relative "hoardable/schema_dumper"
require_relative "hoardable/engine"
require_relative "hoardable/finder_methods"
require_relative "hoardable/scopes"
Expand Down
10 changes: 10 additions & 0 deletions lib/hoardable/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,15 @@ class Engine < ::Rails::Engine
require_relative "encrypted_rich_text" if SUPPORTS_ENCRYPTED_ACTION_TEXT
end
end

initializer "hoardable.schema_statements" do
ActiveSupport.on_load(:active_record_postgresqladapter) do
# We need to control the table dumping order of tables, so revert these to just +super+
Fx::SchemaDumper::Trigger.module_eval("def tables(streams); super; end")

ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend(SchemaDumper)
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements.prepend(SchemaStatements)
end
end
end
end
25 changes: 25 additions & 0 deletions lib/hoardable/schema_dumper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module Hoardable
module SchemaDumper
def ignored?(table_name)
super || @connection.inherited_table?(table_name)
end

def tables(stream)
super
dump_inherited_tables(stream)
empty_line(stream)
triggers(stream)
end

private def dump_inherited_tables(stream)
sorted_tables = @connection.tables.filter { |table| @connection.inherited_table?(table) }.sort
sorted_tables.each do |table_name|
table(table_name, stream)
foreign_keys(table_name, stream)
end
end
end
private_constant :SchemaDumper
end
33 changes: 33 additions & 0 deletions lib/hoardable/schema_statements.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module Hoardable
module SchemaStatements
def table_options(table_name)
options = super || {}
if inherited_table_names = parent_table_names(table_name)
options[:options] = "INHERITS (#{inherited_table_names.join(", ")})"
end
options
end

private def parent_table_names(table_name)
scope = quoted_scope(table_name, type: "BASE TABLE")

query_values(<<~SQL.presence, "SCHEMA").presence
SELECT parent.relname
FROM pg_catalog.pg_inherits i
JOIN pg_catalog.pg_class child ON i.inhrelid = child.oid
JOIN pg_catalog.pg_class parent ON i.inhparent = parent.oid
LEFT JOIN pg_namespace n ON n.oid = child.relnamespace
WHERE child.relname = #{scope[:name]}
AND child.relkind IN (#{scope[:type]})
AND n.nspname = #{scope[:schema]}
SQL
end

def inherited_table?(table_name)
parent_table_names(table_name).present?
end
end
private_constant :SchemaStatements
end
1 change: 0 additions & 1 deletion test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
require "hoardable"
require "fx"

def tmp_dir
File.expand_path("../tmp", __dir__)
Expand Down
38 changes: 38 additions & 0 deletions test/test_schema_dumper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

require "helper"

class TestSchemaDumper < ActiveSupport::TestCase
test "it dumps table inheritance options to schema.rb" do
output = dump_table_schema("post_versions")
assert_match(<<~SCHEMA.squish, output)
create_table \"post_versions\",
id: :bigint,
default: -> { \"nextval('posts_id_seq'::regclass)\" },
options: \"INHERITS (posts)\"
SCHEMA
end

test "it does not dump table inheritance options for non inherited table" do
output = dump_table_schema("posts")
assert_match("create_table \"posts\", force: :cascade do |t|\n", output)
end

test "it dumps inherited table after parent table, and trigger after both" do
output = dump_table_schema("post_versions", "posts")
assert posts_index = output.index(/create_table "posts"/)
assert post_versions_index = output.index(/create_table "post_versions"/)
assert(
post_versions_trigger_index = output.index(/create_trigger :post_versions_prevent_update/)
)
assert post_versions_index > posts_index
assert post_versions_trigger_index > post_versions_index
end

private def dump_table_schema(*table_names)
connection = ActiveRecord::Base.connection
ActiveRecord::SchemaDumper.ignore_tables = connection.data_sources - table_names
stream = StringIO.new
ActiveRecord::SchemaDumper.dump(connection, stream).string
end
end

0 comments on commit ce0a9cc

Please sign in to comment.