require 'spec_helper' require 'flydata-core/table_def' module FlydataCore module TableDef describe MysqlTableDef do # file full path which exists in same directory. def full_path(file_name) File.join(File.dirname(__FILE__), file_name) end def file_io(file_name) File.new(full_path(file_name)) end describe '.to_flydata_tabledef' do let(:dump_file_io) { raise "dump_file_io must be override on context." } subject { MysqlTableDef.create(dump_file_io).to_flydata_tabledef } context 'when dump file includes single table with all kind of format types' do let(:dump_file_io) { file_io('mysqldump_test_table_all.dump') } it 'should set correct table name' do expect(subject[:table_name]).to eq('test_table_all') end it 'should set correct table name' do expect(subject[:columns]).to eq( [ {:column=>"id", :type=>"int8(20)", :auto_increment=>true, :not_null=>true, :primary_key=>true}, {:column=>"col_binary", :type=>"binary(202)", :default=>nil}, {:column=>"col_blob", :type=>"varbinary(65535)"}, {:column=>"col_bool", :type=>"int1(1)", :default=>"'0'"}, {:column=>"col_char", :type=>"varchar(18)", :default=>nil}, {:column=>"col_date", :type=>"date", :default=>nil}, {:column=>"col_datetime", :type=>"datetime", :default=>nil}, {:column=>"col_decimal", :type=>"numeric(5,2)", :default=>nil}, {:column=>"col_double", :type=>"float8", :default=>nil}, {:column=>"col_float", :type=>"float4", :default=>nil}, {:column=>"col_float_4_2", :type=>"float4(4,2)", :default=>nil}, {:column=>"col_int", :type=>"int4(11)", :default=>nil}, {:column=>"col_int_6", :type=>"int4(6)", :default=>nil}, {:column=>"col_longblob", :type=>"varbinary(4294967295)"}, {:column=>"col_longtext", :type=>"text"}, {:column=>"col_mediumblob", :type=>"varbinary(16777215)"}, {:column=>"col_mediumint", :type=>"int3(9)", :default=>nil}, {:column=>"col_mediumtext", :type=>"text"}, {:column=>"col_smallint", :type=>"int2(6)", :default=>nil}, {:column=>"col_text", :type=>"text"}, {:column=>"col_time", :type=>"time", :default=>nil}, {:column=>"col_timestamp", :type=>"datetime", :not_null=>true, :default=>"CURRENT_TIMESTAMP"}, {:column=>"col_tinyblob", :type=>"varbinary(255)"}, {:column=>"col_tinyint", :type=>"int1(4)", :default=>nil}, {:column=>"col_tinytext", :type=>"text"}, {:column=>"col_varbinary", :type=>"varbinary(512)", :default=>nil}, {:column=>"col_varchar", :type=>"varchar(372)", :default=>nil} ] ) end it 'default_charset should be set' do expect(subject[:default_charset]).to eq('utf8') end it 'comment should be set' do expect(subject[:comment]).to eq('test table includes all kind of format type') end end context 'when table does not have primary key' do let(:dump_file_io) { file_io('mysqldump_test_table_no_pk.dump') } it 'should raise an error' do expect{subject}.to raise_error(FlydataCore::TableDefError) end end context 'when column has comment' do let(:dump_file_io) { file_io('mysqldump_test_table_column_comment.dump') } it 'comment should be set' do expect(subject[:columns]).to eq( [ {:column=>"id", :type=>"int4(11)", :not_null=>true, :default=>"'0'", :comment=>"this is primary key", :primary_key=>true}, {:column=>"value", :type=>"text"} ] ) end end context 'when table has multiple pk' do let(:dump_file_io) { file_io('mysqldump_test_table_multi_pk.dump') } it 'multi pk should be set' do expect(subject[:columns]).to eq( [ {:column=>"id1", :type=>"int4(11)", :not_null=>true, :default=>"'0'", :primary_key=>true}, {:column=>"id2", :type=>"int4(11)", :not_null=>true, :default=>"'0'", :primary_key=>true}, {:column=>"value", :type=>"text"} ] ) end end context 'when table has enum column' do let(:dump_file_io) { file_io('mysqldump_test_table_enum.dump') } it 'enum columns should be parsed' do expect(subject[:columns]).to eq( [ {:column=>"id", :type=>"int4(11)", :not_null=>true, :primary_key=>true}, {:column=>"enum_1", :type=>"enum('apple','orange','banana')", :default=>nil}, {:column=>"enum_2", :type=>"enum('a','b','c')", :default=>"'a'"}, {:column=>"enum_3", :type=>"enum('e','f','g')", :not_null=>true}, ] ) end end context 'when table has index and foreign key constraints' do let(:dump_file_io) { file_io('mysqldump_test_foreign_key.dump') } it 'should parse the dump correctly' do expect(subject[:columns]).to eq( [ {:column=>"no", :type=>"int4(11)", :auto_increment=>true, :not_null=>true, :primary_key=>true}, {:column=>"product_category", :type=>"int4(11)", :not_null=>true}, {:column=>"product_id", :type=>"int4(11)", :not_null=>true}, {:column=>"customer_id", :type=>"int4(11)", :not_null=>true}, ] ) end end context 'when table has unsigned column' do let(:dump_file_io) { file_io('mysqldump_test_unsigned.dump')} it 'should include unsigned in column type' do expect(subject[:columns]).to eq( [ {:column=>"id", :type=>"int4(11)", :auto_increment=>true, :not_null=>true, :primary_key=>true}, {:column=>"value_int", :type=>"int4(10) unsigned", :default=>nil}, {:column=>"value_float", :type=>"float4 unsigned", :default=>nil}, {:column=>"value_dec", :type=>"numeric(10,2) unsigned", :default=>nil}, {:column=>"value_double", :type=>"float8 unsigned", :default=>nil}, {:column=>"name", :type=>"varchar(768)", :default=>nil}, {:column=>"value_small_int", :type=>"int2(5) unsigned", :default=>nil} ] ) end end context 'when table has unique keys' do let(:dump_file_io) { file_io('mysqldump_test_unique_key.dump')} it 'should include unique in column def' do expect(subject[:columns]).to eq( [ {:column=>"id", :type=>"int4(11)", :auto_increment=>true, :not_null=>true, :primary_key=>true}, {:column=>"title", :type=>"varchar(768)", :unique=>true, :default=>nil}, {:column=>"name", :type=>"text"}, {:column=>"num", :type=>"int4(11)", :unique=>true, :default=>nil} ] ) end end context 'when table has an unique key with a key name different than the column name' do let(:dump_file_io) { file_io('mysqldump_test_unique_key2.dump')} it 'should include unique in column def' do expect(subject[:columns]).to eq( [ {:column=>"id", :type=>"int4(11)", :auto_increment=>true, :not_null=>true, :primary_key=>true}, {:column=>"title", :type=>"varchar(768)", :unique=>true, :default=>nil}, {:column=>"name", :type=>"text"}, {:column=>"num", :type=>"int4(11)", :unique=>true, :default=>nil} ] ) end end context 'when table has unique keys with length specified' do let(:dump_file_io) { file_io('mysqldump_test_unique_key3.dump')} it 'should include unique in column def' do subject[:columns].each { |col| expect(col[:unique]).to eq(true) if ['app_id','overage_id','item_name'].include? col[:column] } end end context 'when table has bit with 0b default value' do let(:dump_file_io) { file_io('mysqldump_test_bit_table.dump')} it 'should extract default bit value appropriately' do expect(subject[:columns][1][:default]).to eq("b'1'") end end context 'when table has int with 0x default value' do let(:dump_file_io) { file_io('mysqldump_test_bit_table.dump')} it 'should extract default int value appropriately' do expect(subject[:columns][2][:default]).to eq("x'10'") end end end end end end