From 1176f61276a3296786f4e64a41ddaf751710f77d Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Tue, 8 Oct 2024 14:26:14 -0700 Subject: [PATCH] Make schema_dumper extension format options similar to Hash#inspect on Ruby 3.4+ This fixes the schema_dumper specs on Ruby 3.4.0-preview2. This includes additional changes to avoid deprecation warnings and fix other spec failures on Ruby 3.4.0-preview2. --- CHANGELOG | 4 + lib/sequel/database/misc.rb | 7 +- lib/sequel/extensions/schema_dumper.rb | 18 ++- spec/bin_spec.rb | 6 +- spec/core/database_spec.rb | 2 +- spec/extensions/arbitrary_servers_spec.rb | 15 ++- spec/extensions/schema_dumper_spec.rb | 136 +++++++++++----------- spec/model/association_reflection_spec.rb | 15 ++- spec/model/model_spec.rb | 2 +- 9 files changed, 127 insertions(+), 78 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f2d2bf034c..66d79e27dd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ === master +* Make schema_dumper extension format options similar to Hash#inspect on Ruby 3.4+ (jeremyevans) + +* Avoid deprecation warnings on Ruby 3.4.0-preview2 (jeremyevans) + * Handle FROM tables that are SQL::DelayedEvaluation instances when trying to get primary key values after INSERT on PostgreSQL (tomasmiguez) (#2230, #2232) === 5.85.0 (2025-10-01) diff --git a/lib/sequel/database/misc.rb b/lib/sequel/database/misc.rb index affe302cdf..7ca2320638 100644 --- a/lib/sequel/database/misc.rb +++ b/lib/sequel/database/misc.rb @@ -26,6 +26,11 @@ class Database :time=>Sequel::SQLTime, :boolean=>[TrueClass, FalseClass].freeze, :float=>Float, :decimal=>BigDecimal, :blob=>Sequel::SQL::Blob}.freeze + # :nocov: + URI_PARSER = defined?(::URI::RFC2396_PARSER) ? ::URI::RFC2396_PARSER : ::URI::DEFAULT_PARSER + # :nocov: + private_constant :URI_PARSER + # Nested hook Proc; each new hook Proc just wraps the previous one. @initialize_hook = proc{|db| } @@ -85,7 +90,7 @@ def self.uri_to_options(uri) def self.options_from_uri(uri) uri_options = uri_to_options(uri) uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty? - uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)} + uri_options.to_a.each{|k,v| uri_options[k] = URI_PARSER.unescape(v) if v.is_a?(String)} uri_options end private_class_method :options_from_uri diff --git a/lib/sequel/extensions/schema_dumper.rb b/lib/sequel/extensions/schema_dumper.rb index 771b3c09ed..ea61c18db8 100644 --- a/lib/sequel/extensions/schema_dumper.rb +++ b/lib/sequel/extensions/schema_dumper.rb @@ -27,6 +27,11 @@ module Sequel module SchemaDumper + # :nocov: + IGNORE_INDEX_ERRORS_KEY = RUBY_VERSION >= '3.4' ? 'ignore_index_errors: ' : ':ignore_index_errors=>' + # :nocov: + private_constant :IGNORE_INDEX_ERRORS_KEY + # Convert the column schema information to a hash of column options, one of which must # be :type. The other options added should modify that type (e.g. :size). If a # database type is not recognized, return it as a String type. @@ -161,7 +166,7 @@ def dump_schema_migration(options=OPTS) def dump_table_schema(table, options=OPTS) gen = dump_table_generator(table, options) commands = [gen.dump_columns, gen.dump_constraints, gen.dump_indexes].reject{|x| x == ''}.join("\n\n") - "create_table(#{table.inspect}#{', :ignore_index_errors=>true' if !options[:same_db] && options[:indexes] != false && !gen.indexes.empty?}) do\n#{commands.gsub(/^/, ' ')}\nend" + "create_table(#{table.inspect}#{", #{IGNORE_INDEX_ERRORS_KEY}true" if !options[:same_db] && options[:indexes] != false && !gen.indexes.empty?}) do\n#{commands.gsub(/^/, ' ')}\nend" end private @@ -425,6 +430,13 @@ def use_column_schema_to_ruby_default_fallback? module Schema class CreateTableGenerator + # :nocov: + DEFAULT_KEY = RUBY_VERSION >= '3.4' ? 'default: ' : ':default=>' + IGNORE_ERRORS_KEY = RUBY_VERSION >= '3.4' ? 'ignore_errors: ' : ':ignore_errors=>' + # :nocov: + private_constant :DEFAULT_KEY + private_constant :IGNORE_ERRORS_KEY + # Dump this generator's columns to a string that could be evaled inside # another instance to represent the same columns def dump_columns @@ -508,7 +520,7 @@ def dump_indexes(options=OPTS) c = c.dup cols = c.delete(:columns) if table = options[:add_index] || options[:drop_index] - "#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{', :ignore_errors=>true' if options[:ignore_errors]}#{opts_inspect(c)}" + "#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{", #{IGNORE_ERRORS_KEY}true" if options[:ignore_errors]}#{opts_inspect(c)}" else "index #{cols.inspect}#{opts_inspect(c)}" end @@ -526,7 +538,7 @@ def opts_inspect(opts) if opts[:default] opts = opts.dup de = Sequel.eval_inspect(opts.delete(:default)) - ", :default=>#{de}#{", #{opts.inspect[1...-1]}" if opts.length > 0}" + ", #{DEFAULT_KEY}#{de}#{", #{opts.inspect[1...-1]}" if opts.length > 0}" else ", #{opts.inspect[1...-1]}" if opts.length > 0 end diff --git a/spec/bin_spec.rb b/spec/bin_spec.rb index 77e25dc693..182fa63b28 100644 --- a/spec/bin_spec.rb +++ b/spec/bin_spec.rb @@ -171,15 +171,17 @@ def bin(opts={}) foreign_key :a, :a index :a end + size = RUBY_VERSION >= '3.4' ? 'size: 255' : ':size=>255' + ignore_index_errors = RUBY_VERSION >= '3.4' ? 'ignore_index_errors: true' : ':ignore_index_errors=>true' bin(:args=>'-d').must_equal <255 + String :name, #{size} end - create_table(:b, :ignore_index_errors=>true) do + create_table(:b, #{ignore_index_errors}) do foreign_key :a, :a index [:a] diff --git a/spec/core/database_spec.rb b/spec/core/database_spec.rb index 1d9af58361..55c9cefc74 100644 --- a/spec/core/database_spec.rb +++ b/spec/core/database_spec.rb @@ -2263,7 +2263,7 @@ def @db.database_error_regexps it "should raise an InvalidValue when given an invalid value" do proc{@db.typecast_value(:integer, "13a")}.must_raise(Sequel::InvalidValue) - proc{@db.typecast_value(:float, "4.e2")}.must_raise(Sequel::InvalidValue) + proc{@db.typecast_value(:float, "4.e2a")}.must_raise(Sequel::InvalidValue) proc{@db.typecast_value(:decimal, :invalid_value)}.must_raise(Sequel::InvalidValue) proc{@db.typecast_value(:date, Object.new)}.must_raise(Sequel::InvalidValue) proc{@db.typecast_value(:date, 'a')}.must_raise(Sequel::InvalidValue) diff --git a/spec/extensions/arbitrary_servers_spec.rb b/spec/extensions/arbitrary_servers_spec.rb index 873c7f054f..17c238feb8 100644 --- a/spec/extensions/arbitrary_servers_spec.rb +++ b/spec/extensions/arbitrary_servers_spec.rb @@ -103,7 +103,18 @@ @db[:t].all q1.push nil t.join - @db.sqls.must_equal ['SELECT * FROM t', 'SELECT * FROM t -- {:host=>"a"}', 'SELECT * FROM t', 'SELECT * FROM t -- {:host=>"c"}', 'SELECT * FROM t -- {:host=>"d"}', - 'SELECT * FROM t -- {:host=>"b"}', 'SELECT * FROM t -- {:host=>"a"}', 'SELECT * FROM t', 'SELECT * FROM t -- {:host=>"c"}', 'SELECT * FROM t'] + host = RUBY_VERSION >= '3.4' ? 'host: ' : ':host=>' + @db.sqls.must_equal [ + 'SELECT * FROM t', + "SELECT * FROM t -- {#{host}\"a\"}", + 'SELECT * FROM t', + "SELECT * FROM t -- {#{host}\"c\"}", + "SELECT * FROM t -- {#{host}\"d\"}", + "SELECT * FROM t -- {#{host}\"b\"}", + "SELECT * FROM t -- {#{host}\"a\"}", + 'SELECT * FROM t', + "SELECT * FROM t -- {#{host}\"c\"}", + 'SELECT * FROM t', + ] end end diff --git a/spec/extensions/schema_dumper_spec.rb b/spec/extensions/schema_dumper_spec.rb index 3fa965be8a..62be96d639 100644 --- a/spec/extensions/schema_dumper_spec.rb +++ b/spec/extensions/schema_dumper_spec.rb @@ -1,5 +1,11 @@ require_relative "spec_helper" +if RUBY_VERSION >= '3.4' + fix_inspect = proc{|s| s.gsub(/:([\w]+)=>/, '\1: ')} +else + fix_inspect = proc{|s| s} +end + describe "Sequel::Schema::CreateTableGenerator dump methods" do before do @d = Sequel::Database.new.extension(:schema_dumper) @@ -65,13 +71,13 @@ index [:b, :c], :unique=>true end - g.dump_indexes(:add_index=>:t).must_equal((<:t).must_equal(fix_inspect.((<:blah add_index :t, [:b, :c], :unique=>true END_CODE - g.dump_indexes(:drop_index=>:t).must_equal((<:t).must_equal(fix_inspect.((<true drop_index :t, [:c, :e], :name=>:blah drop_index :t, [:a] @@ -118,59 +124,59 @@ def @d.schema(t, o=OPTS) end it "should not include schema qualification when dumping table with :schema option" do - @d.dump_table_schema(:t1, :schema=>:foo).must_equal "create_table(:t1) do\n primary_key :c1\n String :c2, :size=>20\nend" + @d.dump_table_schema(:t1, :schema=>:foo).must_equal fix_inspect.("create_table(:t1) do\n primary_key :c1\n String :c2, :size=>20\nend") end it "should include schema qualification when dumping table with implicit schema" do - @d.dump_table_schema(Sequel[:x][:t1]).must_equal "create_table(Sequel::SQL::QualifiedIdentifier.new(\"x\", :t1)) do\n primary_key :c1\n String :c2, :size=>20\nend" + @d.dump_table_schema(Sequel[:x][:t1]).must_equal fix_inspect.("create_table(Sequel::SQL::QualifiedIdentifier.new(\"x\", :t1)) do\n primary_key :c1\n String :c2, :size=>20\nend") end it "should support dumping table schemas as create_table method calls" do - @d.dump_table_schema(:t1).must_equal "create_table(:t1) do\n primary_key :c1\n String :c2, :size=>20\nend" + @d.dump_table_schema(:t1).must_equal fix_inspect.("create_table(:t1) do\n primary_key :c1\n String :c2, :size=>20\nend") end it "should support dumping table schemas when given a string" do - @d.dump_table_schema('t__t1').must_equal "create_table(\"t__t1\") do\n primary_key :c1\n String :c2, :size=>20\nend" + @d.dump_table_schema('t__t1').must_equal fix_inspect.("create_table(\"t__t1\") do\n primary_key :c1\n String :c2, :size=>20\nend") end it "should support dumping table schemas when given an identifier" do - @d.dump_table_schema(Sequel.identifier(:t__t1)).must_equal "create_table(Sequel::SQL::Identifier.new(:t__t1)) do\n primary_key :c1\n String :c2, :size=>20\nend" + @d.dump_table_schema(Sequel.identifier(:t__t1)).must_equal fix_inspect.("create_table(Sequel::SQL::Identifier.new(:t__t1)) do\n primary_key :c1\n String :c2, :size=>20\nend") end it "should dump string column sizes using :max_length" do def @d.schema(*s) [[:c1, {:db_type=>'varchar', :max_length=>10}]] end - @d.dump_table_schema(:t6).must_equal "create_table(:t6) do\n String :c1, :size=>10\nend" + @d.dump_table_schema(:t6).must_equal fix_inspect.("create_table(:t6) do\n String :c1, :size=>10\nend") @d.dump_table_schema(:t6, :same_db=>true).must_equal "create_table(:t6) do\n column :c1, \"varchar\"\nend" def @d.database_type; :mssql end - @d.dump_table_schema(:t6, :same_db=>true).must_equal "create_table(:t6) do\n column :c1, \"varchar\", :size=>10\nend" + @d.dump_table_schema(:t6, :same_db=>true).must_equal fix_inspect.("create_table(:t6) do\n column :c1, \"varchar\", :size=>10\nend") end it "should dump non-Integer primary key columns with explicit :type" do def @d.schema(*s) [[:c1, {:db_type=>'bigint', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]] end - @d.dump_table_schema(:t6).must_equal "create_table(:t6) do\n primary_key :c1, :type=>:Bignum\nend" + @d.dump_table_schema(:t6).must_equal fix_inspect.("create_table(:t6) do\n primary_key :c1, :type=>:Bignum\nend") end it "should dump non-Integer primary key columns with explicit :type when using :same_db=>true" do def @d.schema(*s) [[:c1, {:db_type=>'bigint', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]] end - @d.dump_table_schema(:t6, :same_db=>true).must_equal "create_table(:t6) do\n primary_key :c1, :type=>:Bignum\nend" + @d.dump_table_schema(:t6, :same_db=>true).must_equal fix_inspect.("create_table(:t6) do\n primary_key :c1, :type=>:Bignum\nend") end it "should dump auto incrementing primary keys with :keep_order option if they are not first" do - @d.dump_table_schema(:t3).must_equal "create_table(:t3) do\n String :c2, :size=>20\n primary_key :c1, :keep_order=>true\nend" + @d.dump_table_schema(:t3).must_equal fix_inspect.("create_table(:t3) do\n String :c2, :size=>20\n primary_key :c1, :keep_order=>true\nend") end it "should handle foreign keys" do def @d.schema(*s) [[:c1, {:db_type=>'integer', :allow_null=>true}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2]}] end - @d.dump_table_schema(:t6).must_equal "create_table(:t6) do\n foreign_key :c1, :t2, :key=>[:c2]\nend" + @d.dump_table_schema(:t6).must_equal fix_inspect.("create_table(:t6) do\n foreign_key :c1, :t2, :key=>[:c2]\nend") end it "should handle primary keys that are also foreign keys" do def @d.schema(*s) [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2]}] end - @d.dump_table_schema(:t6).must_equal((<:t2, :key=>[:c2] end @@ -181,7 +187,7 @@ def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2]}] end def @d.schema(*s) [[:c1, {:db_type=>'integer', :allow_null=>true}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_delete=>:restrict, :on_update=>:set_null, :deferrable=>true}] end - @d.dump_table_schema(:t6).must_equal((<[:c2], :on_delete=>:restrict, :on_update=>:set_null, :deferrable=>true end @@ -192,7 +198,7 @@ def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_del def @d.schema(*s) [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_delete=>:restrict, :on_update=>:set_null, :deferrable=>true}] end - @d.dump_table_schema(:t6).must_equal((<:t2, :key=>[:c2], :on_delete=>:restrict, :on_update=>:set_null, :deferrable=>true end @@ -203,7 +209,7 @@ def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_del def @d.schema(*s) [[:c1, {:db_type=>'integer', :allow_null=>true}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_delete=>:no_action, :on_update=>:no_action, :deferrable=>false}] end - @d.dump_table_schema(:t6).must_equal((<[:c2] end @@ -214,7 +220,7 @@ def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_del def @d.schema(*s) [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_delete=>:no_action, :on_update=>:no_action, :deferrable=>false}] end - @d.dump_table_schema(:t6).must_equal((<:t2, :key=>[:c2] end @@ -223,25 +229,25 @@ def @d.foreign_key_list(*s) [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_del it "should dump primary key columns with explicit type equal to the database type when :same_db option is passed" do def @d.schema(*s) [[:c1, {:db_type=>'somedbspecifictype', :primary_key=>true, :allow_null=>false}]] end - @d.dump_table_schema(:t7, :same_db => true).must_equal "create_table(:t7) do\n column :c1, \"somedbspecifictype\", :null=>false\n \n primary_key [:c1]\nend" + @d.dump_table_schema(:t7, :same_db => true).must_equal fix_inspect.("create_table(:t7) do\n column :c1, \"somedbspecifictype\", :null=>false\n \n primary_key [:c1]\nend") end it "should use a composite primary_key calls if there is a composite primary key" do - @d.dump_table_schema(:t2).must_equal "create_table(:t2) do\n Integer :c1, :null=>false\n BigDecimal :c2, :null=>false\n \n primary_key [:c1, :c2]\nend" + @d.dump_table_schema(:t2).must_equal fix_inspect.("create_table(:t2) do\n Integer :c1, :null=>false\n BigDecimal :c2, :null=>false\n \n primary_key [:c1, :c2]\nend") end it "should use a composite foreign_key calls if there is a composite foreign key" do def @d.schema(*s) [[:c1, {:db_type=>'integer'}], [:c2, {:db_type=>'integer'}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1, :c2], :table=>:t2, :key=>[:c3, :c4]}] end - @d.dump_table_schema(:t1).must_equal "create_table(:t1) do\n Integer :c1\n Integer :c2\n \n foreign_key [:c1, :c2], :t2, :key=>[:c3, :c4]\nend" + @d.dump_table_schema(:t1).must_equal fix_inspect.("create_table(:t1) do\n Integer :c1\n Integer :c2\n \n foreign_key [:c1, :c2], :t2, :key=>[:c3, :c4]\nend") end it "should use a composite foreign_key calls with options" do def @d.schema(*s) [[:c1, {:db_type=>'integer'}], [:c2, {:db_type=>'integer'}]] end def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(*s) [{:columns=>[:c1, :c2], :table=>:t2, :key=>[:c3, :c4], :on_delete=>:no_action, :on_update=>:no_action, :deferrable=>true}] end - @d.dump_table_schema(:t1).must_equal "create_table(:t1) do\n Integer :c1\n Integer :c2\n \n foreign_key [:c1, :c2], :t2, :key=>[:c3, :c4], :deferrable=>true\nend" + @d.dump_table_schema(:t1).must_equal fix_inspect.("create_table(:t1) do\n Integer :c1\n Integer :c2\n \n foreign_key [:c1, :c2], :t2, :key=>[:c3, :c4], :deferrable=>true\nend") end it "should include index information if available" do @@ -250,11 +256,11 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true, :deferrable=>true}} end - @d.dump_table_schema(:t1).must_equal "create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:i1\n index [:c2, :c1], :unique=>true, :deferrable=>true\nend" + @d.dump_table_schema(:t1).must_equal fix_inspect.("create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:i1\n index [:c2, :c1], :unique=>true, :deferrable=>true\nend") end it "should support dumping the whole database as a migration with a :schema option" do - @d.dump_schema_migration(:schema=>'t__t1').must_equal <<-END_MIG + @d.dump_schema_migration(:schema=>'t__t1').must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(Sequel::SQL::QualifiedIdentifier.new("t__t1", "t__t1")) do @@ -267,7 +273,7 @@ def @d.indexes(t) end it "should support dumping the whole database as a migration" do - @d.dump_schema_migration.must_equal <<-END_MIG + @d.dump_schema_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1) do @@ -287,7 +293,7 @@ def @d.indexes(t) end it "should sort table names when dumping a migration with the :schema option" do - @d.dump_schema_migration(:schema=>:x, :tables=>[:t2, :t1]).must_equal <<-END_MIG + @d.dump_schema_migration(:schema=>:x, :tables=>[:t2, :t1]).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(Sequel::SQL::QualifiedIdentifier.new(:x, :t1)) do @@ -308,7 +314,7 @@ def @d.indexes(t) it "should sort table names when dumping a migration" do def @d.tables(o) [:t2, :t1] end - @d.dump_schema_migration.must_equal <<-END_MIG + @d.dump_schema_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1) do @@ -332,7 +338,7 @@ def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(t) t == Sequel::SQL::QualifiedIdentifier.new(:x, :t1) ? [{:columns=>[:c2], :table=>Sequel::SQL::QualifiedIdentifier.new(:x, :t2), :key=>[:c1]}] : [] end - @d.dump_schema_migration(:schema=>:x, :tables=>[:t1, :t2]).must_equal <<-END_MIG + @d.dump_schema_migration(:schema=>:x, :tables=>[:t1, :t2]).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(Sequel::SQL::QualifiedIdentifier.new(:x, :t2)) do @@ -360,7 +366,7 @@ def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(t) t == :t1 ? [{:columns=>[:c2], :table=>:t2, :key=>[:c1]}] : [] end - @d.dump_schema_migration.must_equal <<-END_MIG + @d.dump_schema_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t2) do @@ -384,7 +390,7 @@ def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(t) t == :t1 ? [{:columns=>[:c2], :table=>:t2, :key=>[:c1]}] : [{:columns=>[:c1], :table=>:t1, :key=>[:c2]}] end - @d.dump_schema_migration.must_equal <<-END_MIG + @d.dump_schema_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1) do @@ -413,7 +419,7 @@ def @d.foreign_key_list(t) raise Sequel::DatabaseError unless [:t1, :t2].include?(t) t == :t1 ? [{:columns=>[:c2], :table=>:t2, :key=>[:c1]}] : [] end - @d.dump_schema_migration.must_equal <<-END_MIG + @d.dump_schema_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t2) do @@ -430,7 +436,7 @@ def @d.foreign_key_list(t) it "should honor the :same_db option to not convert types" do @d.dump_table_schema(:t1, :same_db=>true).must_equal "create_table(:t1) do\n primary_key :c1\n column :c2, \"varchar(20)\"\nend" - @d.dump_schema_migration(:same_db=>true).must_equal <<-END_MIG + @d.dump_schema_migration(:same_db=>true).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1) do @@ -455,8 +461,8 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true}} end - @d.dump_table_schema(:t1, :index_names=>false).must_equal "create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1]\n index [:c2, :c1], :unique=>true\nend" - @d.dump_schema_migration(:index_names=>false).must_equal <<-END_MIG + @d.dump_table_schema(:t1, :index_names=>false).must_equal fix_inspect.("create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1]\n index [:c2, :c1], :unique=>true\nend") + @d.dump_schema_migration(:index_names=>false).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1, :ignore_index_errors=>true) do @@ -487,8 +493,8 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}} end - @d.dump_table_schema(:t1, :index_names=>:namespace).must_equal "create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:i1\n index [:c2, :c1]\nend" - @d.dump_schema_migration(:index_names=>:namespace).must_equal <<-END_MIG + @d.dump_table_schema(:t1, :index_names=>:namespace).must_equal fix_inspect.("create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:i1\n index [:c2, :c1]\nend") + @d.dump_schema_migration(:index_names=>:namespace).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1, :ignore_index_errors=>true) do @@ -520,8 +526,8 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}} end - @d.dump_table_schema(:t1, :index_names=>:namespace).must_equal "create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:t1_i1\n index [:c2, :c1]\nend" - @d.dump_schema_migration(:index_names=>:namespace).must_equal <<-END_MIG + @d.dump_table_schema(:t1, :index_names=>:namespace).must_equal fix_inspect.("create_table(:t1, :ignore_index_errors=>true) do\n primary_key :c1\n String :c2, :size=>20\n \n index [:c1], :name=>:t1_i1\n index [:c2, :c1]\nend") + @d.dump_schema_migration(:index_names=>:namespace).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1, :ignore_index_errors=>true) do @@ -552,8 +558,8 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true}} end - @d.dump_table_schema(:t1, :indexes=>false).must_equal "create_table(:t1) do\n primary_key :c1\n String :c2, :size=>20\nend" - @d.dump_schema_migration(:indexes=>false).must_equal <<-END_MIG + @d.dump_table_schema(:t1, :indexes=>false).must_equal fix_inspect.("create_table(:t1) do\n primary_key :c1\n String :c2, :size=>20\nend") + @d.dump_schema_migration(:indexes=>false).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do create_table(:t1) do @@ -584,7 +590,7 @@ def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(t) t == :t1 ? [{:columns=>[:c2], :table=>:t2, :key=>[:c1]}] : [] end - @d.dump_schema_migration(:indexes=>false, :foreign_keys=>true).must_equal(<false, :foreign_keys=>true).must_equal(fix_inspect.(<{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true}} end - @d.dump_indexes_migration.must_equal <<-END_MIG + @d.dump_indexes_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do add_index :t1, [:c1], :ignore_errors=>true, :name=>:i1 @@ -627,7 +633,7 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>true}} end - @d.dump_indexes_migration(:index_names=>false).must_equal <<-END_MIG + @d.dump_indexes_migration(:index_names=>false).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do add_index :t1, [:c1], :ignore_errors=>true @@ -644,7 +650,7 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}} end - @d.dump_indexes_migration(:index_names=>:namespace).must_equal <<-END_MIG + @d.dump_indexes_migration(:index_names=>:namespace).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do add_index :t1, [:c1], :ignore_errors=>true, :name=>:i1 @@ -665,7 +671,7 @@ def @d.indexes(t) {:i1=>{:columns=>[:c1], :unique=>false}, :t1_c2_c1_index=>{:columns=>[:c2, :c1], :unique=>false}} end - @d.dump_indexes_migration(:index_names=>:namespace).must_equal <<-END_MIG + @d.dump_indexes_migration(:index_names=>:namespace).must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do add_index :t1, [:c1], :ignore_errors=>true, :name=>:t1_i1 @@ -680,7 +686,7 @@ def @d.indexes(t) it "should handle missing index parsing support when dumping index migration" do def @d.tables(o) [:t1] end - @d.dump_indexes_migration.must_equal <<-END_MIG + @d.dump_indexes_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do @@ -691,7 +697,7 @@ def @d.tables(o) [:t1] end it "should handle missing foreign key parsing support when dumping foreign key migration" do def @d.tables(o) [:t1] end - @d.dump_foreign_key_migration.must_equal <<-END_MIG + @d.dump_foreign_key_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do @@ -716,7 +722,7 @@ def @d.foreign_key_list(t, *a) [] end end - @d.dump_foreign_key_migration.must_equal <<-END_MIG + @d.dump_foreign_key_migration.must_equal fix_inspect.(<<-END_MIG) Sequel.migration do change do alter_table(:t1) do @@ -733,7 +739,7 @@ def @d.foreign_key_list(t, *a) it "should handle not null values and defaults" do def @d.schema(*s) [[:c1, {:db_type=>'date', :default=>"'now()'", :allow_null=>true}], [:c2, {:db_type=>'datetime', :allow_null=>false}]] end - @d.dump_table_schema(:t3).must_equal "create_table(:t3) do\n Date :c1\n DateTime :c2, :null=>false\nend" + @d.dump_table_schema(:t3).must_equal fix_inspect.("create_table(:t3) do\n Date :c1\n DateTime :c2, :null=>false\nend") end it "should handle converting common defaults" do @@ -754,8 +760,8 @@ def @d.schema(t, *os) s end e = RUBY_VERSION >= '2.4' ? 'e' : 'E' - @d.dump_table_schema(:t4).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal "create_table(:t4) do\n TrueClass :c1, :default=>false\n String :c2, :default=>\"blah\"\n Integer :c3, :default=>-1\n Float :c4, :default=>1.0\n BigDecimal :c5, :default=>Kernel::BigDecimal(\"0.1005#{e}3\")\n File :c6, :default=>Sequel::SQL::Blob.new(\"blah\")\n Date :c7, :default=>Date.new(2008, 10, 29)\n DateTime :c8, :default=>Time.parse(\"2008-10-29T10:20:30.0\")\n Time :c9, :default=>Sequel::SQLTime.parse(\"10:20:30.0\"), :only_time=>true\n String :c10\n Date :c11, :default=>Sequel::CURRENT_DATE\n DateTime :c12, :default=>Sequel::CURRENT_TIMESTAMP\nend" - @d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal "create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>Kernel::BigDecimal(\"0.1005#{e}3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.new(2008, 10, 29)\n column :c8, \"datetime\", :default=>Time.parse(\"2008-10-29T10:20:30.0\")\n column :c9, \"time\", :default=>Sequel::SQLTime.parse(\"10:20:30.0\")\n column :c10, \"foo\", :default=>Sequel::LiteralString.new(\"'6 weeks'\")\n column :c11, \"date\", :default=>Sequel::CURRENT_DATE\n column :c12, \"timestamp\", :default=>Sequel::CURRENT_TIMESTAMP\nend" + @d.dump_table_schema(:t4).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal fix_inspect.("create_table(:t4) do\n TrueClass :c1, :default=>false\n String :c2, :default=>\"blah\"\n Integer :c3, :default=>-1\n Float :c4, :default=>1.0\n BigDecimal :c5, :default=>Kernel::BigDecimal(\"0.1005#{e}3\")\n File :c6, :default=>Sequel::SQL::Blob.new(\"blah\")\n Date :c7, :default=>Date.new(2008, 10, 29)\n DateTime :c8, :default=>Time.parse(\"2008-10-29T10:20:30.0\")\n Time :c9, :default=>Sequel::SQLTime.parse(\"10:20:30.0\"), :only_time=>true\n String :c10\n Date :c11, :default=>Sequel::CURRENT_DATE\n DateTime :c12, :default=>Sequel::CURRENT_TIMESTAMP\nend") + @d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d\d\d"\)/, '")').gsub(/\.0+/, '.0').must_equal fix_inspect.("create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>Kernel::BigDecimal(\"0.1005#{e}3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.new(2008, 10, 29)\n column :c8, \"datetime\", :default=>Time.parse(\"2008-10-29T10:20:30.0\")\n column :c9, \"time\", :default=>Sequel::SQLTime.parse(\"10:20:30.0\")\n column :c10, \"foo\", :default=>Sequel::LiteralString.new(\"'6 weeks'\")\n column :c11, \"date\", :default=>Sequel::CURRENT_DATE\n column :c12, \"timestamp\", :default=>Sequel::CURRENT_TIMESTAMP\nend") end it "should not use a literal string as a fallback if using MySQL with the :same_db option" do @@ -775,19 +781,19 @@ def @d.schema(t, *os) end it "should not include defaults for generated columns even if parsed" do - @d.dump_table_schema(:t6).must_equal "create_table(:t6) do\n Integer :c1, :null=>false\nend" + @d.dump_table_schema(:t6).must_equal fix_inspect.("create_table(:t6) do\n Integer :c1, :null=>false\nend") @d.dump_table_schema(:t7).must_equal "create_table(:t7) do\n Integer :c1\nend" end it "should not include defaults for generated columns even if parsed when using :same_db option" do - @d.dump_table_schema(:t6, :same_db=>true).must_equal "create_table(:t6) do\n column :c1, \"integer\", :null=>false\nend" + @d.dump_table_schema(:t6, :same_db=>true).must_equal fix_inspect.("create_table(:t6) do\n column :c1, \"integer\", :null=>false\nend") @d.dump_table_schema(:t7, :same_db=>true).must_equal "create_table(:t7) do\n column :c1, \"integer\"\nend" end it "should create generated column when using :same_db option on PostgreSQL" do def @d.database_type; :postgres end - @d.dump_table_schema(:t6, :same_db=>true).must_equal "create_table(:t6) do\n column :c1, \"integer\", :generated_always_as=>Sequel::LiteralString.new(\"1\"), :null=>false\nend" - @d.dump_table_schema(:t7, :same_db=>true).must_equal "create_table(:t7) do\n column :c1, \"integer\", :generated_always_as=>Sequel::LiteralString.new(\"(a + b)\")\nend" + @d.dump_table_schema(:t6, :same_db=>true).must_equal fix_inspect.("create_table(:t6) do\n column :c1, \"integer\", :generated_always_as=>Sequel::LiteralString.new(\"1\"), :null=>false\nend") + @d.dump_table_schema(:t7, :same_db=>true).must_equal fix_inspect.("create_table(:t7) do\n column :c1, \"integer\", :generated_always_as=>Sequel::LiteralString.new(\"(a + b)\")\nend") end it "should convert many database types to ruby types" do @@ -807,7 +813,7 @@ def @d.schema(t, *o) i = 0 types.map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]} end - @d.dump_table_schema(:x).must_equal((<x, :allow_null=>true, :type=>:boolean, :size=>10}]} end - @d.dump_table_schema(:x).must_equal((<x, :allow_null=>false}]} end - @d.dump_table_schema(:x).must_equal((<false Date :c2, :null=>false @@ -935,17 +941,17 @@ def @d.schema(t, *o) it "should force specify :null option for MySQL timestamp columns when using :same_db" do def @d.database_type; :mysql end def @d.schema(*s) [[:c1, {:db_type=>'timestamp', :primary_key=>true, :allow_null=>true}]] end - @d.dump_table_schema(:t3, :same_db=>true).must_equal "create_table(:t3) do\n column :c1, \"timestamp\", :null=>true\n \n primary_key [:c1]\nend" + @d.dump_table_schema(:t3, :same_db=>true).must_equal fix_inspect.("create_table(:t3) do\n column :c1, \"timestamp\", :null=>true\n \n primary_key [:c1]\nend") @d.singleton_class.send(:alias_method, :schema, :schema) def @d.schema(*s) [[:c1, {:db_type=>'timestamp', :primary_key=>true, :allow_null=>false}]] end - @d.dump_table_schema(:t3, :same_db=>true).must_equal "create_table(:t3) do\n column :c1, \"timestamp\", :null=>false\n \n primary_key [:c1]\nend" + @d.dump_table_schema(:t3, :same_db=>true).must_equal fix_inspect.("create_table(:t3) do\n column :c1, \"timestamp\", :null=>false\n \n primary_key [:c1]\nend") end it "should use separate primary_key call with non autoincrementable types" do def @d.schema(*s) [[:c1, {:db_type=>'varchar(8)', :primary_key=>true, :auto_increment=>false}]] end - @d.dump_table_schema(:t3).must_equal "create_table(:t3) do\n String :c1, :size=>8\n \n primary_key [:c1]\nend" - @d.dump_table_schema(:t3, :same_db=>true).must_equal "create_table(:t3) do\n column :c1, \"varchar(8)\"\n \n primary_key [:c1]\nend" + @d.dump_table_schema(:t3).must_equal fix_inspect.("create_table(:t3) do\n String :c1, :size=>8\n \n primary_key [:c1]\nend") + @d.dump_table_schema(:t3, :same_db=>true).must_equal fix_inspect.("create_table(:t3) do\n column :c1, \"varchar(8)\"\n \n primary_key [:c1]\nend") end it "should use explicit type for non integer foreign_key types" do @@ -953,9 +959,9 @@ def @d.schema(*s) [[:c1, {:db_type=>'date', :primary_key=>true, :auto_increment= def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(t, *a) [{:columns=>[:c1], :table=>:t3, :key=>[:c1]}] if t == :t4 end ["create_table(:t4) do\n foreign_key :c1, :t3, :type=>Date, :key=>[:c1]\n \n primary_key [:c1]\nend", - "create_table(:t4) do\n foreign_key :c1, :t3, :key=>[:c1], :type=>Date\n \n primary_key [:c1]\nend"].must_include(@d.dump_table_schema(:t4)) + "create_table(:t4) do\n foreign_key :c1, :t3, :key=>[:c1], :type=>Date\n \n primary_key [:c1]\nend"].map{|s| fix_inspect.(s)}.must_include(@d.dump_table_schema(:t4)) ["create_table(:t4) do\n foreign_key :c1, :t3, :type=>\"date\", :key=>[:c1]\n \n primary_key [:c1]\nend", - "create_table(:t4) do\n foreign_key :c1, :t3, :key=>[:c1], :type=>\"date\"\n \n primary_key [:c1]\nend"].must_include(@d.dump_table_schema(:t4, :same_db=>true)) + "create_table(:t4) do\n foreign_key :c1, :t3, :key=>[:c1], :type=>\"date\"\n \n primary_key [:c1]\nend"].map{|s| fix_inspect.(s)}.must_include(@d.dump_table_schema(:t4, :same_db=>true)) end it "should correctly handing autoincrementing primary keys that are also foreign keys" do @@ -963,7 +969,7 @@ def @d.schema(*s) [[:c1, {:db_type=>'integer', :primary_key=>true, :auto_increme def @d.supports_foreign_key_parsing?; true end def @d.foreign_key_list(t, *a) [{:columns=>[:c1], :table=>:t3, :key=>[:c1]}] if t == :t4 end ["create_table(:t4) do\n primary_key :c1, :table=>:t3, :key=>[:c1]\nend", - "create_table(:t4) do\n primary_key :c1, :key=>[:c1], :table=>:t3\nend"].must_include(@d.dump_table_schema(:t4)) + "create_table(:t4) do\n primary_key :c1, :key=>[:c1], :table=>:t3\nend"].map{|s| fix_inspect.(s)}.must_include(@d.dump_table_schema(:t4)) end it "should handle dumping on PostgreSQL using qualified tables" do diff --git a/spec/model/association_reflection_spec.rb b/spec/model/association_reflection_spec.rb index a1eb86e513..cc2fa8d448 100644 --- a/spec/model/association_reflection_spec.rb +++ b/spec/model/association_reflection_spec.rb @@ -40,12 +40,21 @@ class ::ParParent < Sequel::Model; end ParParent.many_to_one :c ParParent.association_reflection(:c).inspect.must_equal "#" ParParent.many_to_one :c, :class=>ParParent - ParParent.association_reflection(:c).inspect.must_equal "#ParParent>" + [ + "#ParParent>", + "#" + ].must_include(ParParent.association_reflection(:c).inspect) ParParent.many_to_one :c, :class=>ParParent, :key=>:c_id - ParParent.association_reflection(:c).inspect.must_equal "#:c_id, :class=>ParParent>" + [ + "#:c_id, :class=>ParParent>", + "#" + ].must_include(ParParent.association_reflection(:c).inspect) @c.one_to_many :foos do |ds| ds end - @c.association_reflection(:foos).inspect.must_equal "##{@c.association_reflection(:foos)[:block].inspect}>" + [ + "##{@c.association_reflection(:foos)[:block].inspect}>", + "#" + ].must_include(@c.association_reflection(:foos).inspect) end it "should figure out the class if the :class value is not present" do diff --git a/spec/model/model_spec.rb b/spec/model/model_spec.rb index 9fa81ccd39..524251a50a 100644 --- a/spec/model/model_spec.rb +++ b/spec/model/model_spec.rb @@ -787,7 +787,7 @@ def db.schema(*) describe "Model#inspect" do it "should include the class name and the values" do - Sequel::Model.load(:x => 333).inspect.must_equal '#333}>' + ['#333}>', '#'].must_include Sequel::Model.load(:x => 333).inspect end end