diff --git a/lib/rein.rb b/lib/rein.rb index f26ed22..93ee0f3 100644 --- a/lib/rein.rb +++ b/lib/rein.rb @@ -14,6 +14,7 @@ require 'rein/schema' require 'rein/type/enum' require 'rein/view' +require 'rein/schema_dumper' module ActiveRecord class Migration # :nodoc: @@ -33,4 +34,8 @@ class Migration # :nodoc: include Rein::Type::Enum include Rein::View end + + class SchemaDumper + prepend Rein::SchemaDumper + end end diff --git a/lib/rein/schema_dumper.rb b/lib/rein/schema_dumper.rb new file mode 100644 index 0000000..122784f --- /dev/null +++ b/lib/rein/schema_dumper.rb @@ -0,0 +1,58 @@ +module Rein + # @api private + module SchemaDumper + def tables(stream) + super + check_constraints(stream) + end + + def check_constraints(stream) + puts constraints.to_a + + stream.puts if constraints.any? + + constraints.each do |constraint| + column_name = constraint['column_name'] + check_clause = constraint['check_clause'] + + case check_clause + when /#{column_name}\s+(>=|>|=|!=|<|<=)\s+(\d+)/ + add_numericality_constraint_command(stream, constraint, $1, $2) + end + end + end + + private + + def constraints + @constraints ||= @connection.execute <<-SQL + select * + from information_schema.check_constraints as c, information_schema.constraint_column_usage as u + where c.constraint_name = u.constraint_name + and c.constraint_schema = 'public' + and u.constraint_schema = 'public' + SQL + end + + def add_numericality_constraint_command(stream, constraint, operator, value) + table_name = constraint['table_name'] + column_name = constraint['column_name'] + + definition = definition_from_numerical_operator(operator) + stream.puts <<-RUBY + add_numericality_constraint "#{table_name}", "#{column_name}", #{definition}: #{value} + RUBY + end + + def definition_from_numerical_operator(operator) + case operator + when '>=' then 'greater_than_or_equal_to' + when '>' then 'greater_than' + when '<=' then 'less_than_or_equal_to' + when '<' then 'less_than' + when '=' then 'equal_to' + when '!=' then 'not_equal_to' + end + end + end +end diff --git a/spec/integration/reversible_spec.rb b/spec/integration/reversible_spec.rb index 18e690c..10f457a 100644 --- a/spec/integration/reversible_spec.rb +++ b/spec/integration/reversible_spec.rb @@ -37,6 +37,10 @@ def down(*args) Migrator.migrate end + after(:all) do + Migrator.migrate + end + it 'reverses check constraints' do expect(TableConstraint.where(constraint_name: 'no_r_titles')).to exist Migrator.down(2) diff --git a/spec/integration/schema_dumper_spec.rb b/spec/integration/schema_dumper_spec.rb new file mode 100644 index 0000000..0a79a04 --- /dev/null +++ b/spec/integration/schema_dumper_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +RSpec.describe Rein::SchemaDumper do + it 'dumps constraints from the database' do + stream = StringIO.new + + ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream) + + output = stream.string + expect(output).to include 'add_numericality_constraint "books", "published_month", greater_than_or_equal_to: 1' + end +end