module Flydata module Sync class MysqlTableDef TYPE_MAP_M2F = { 'bigint' => 'int8', 'binary' => 'binary', 'blob' => 'varbinary', 'bool' => 'int1', 'boolean' => 'int1', 'char' => 'varchar', 'date' => 'date', 'datetime' => 'datetime', 'dec' => 'numeric', 'decimal' => 'numeric', 'double' => 'float8', 'double precision' => 'float8', 'fixed' => 'numeric', 'float' => 'float4', 'int' => 'int4', 'longblob' => 'varbinary', 'longtext' => 'text', 'mediumblob' => 'varbinary', 'mediumint' => 'int3', 'mediumtext' => 'text', 'numeric' => 'numeric', 'smallint' => 'int2', 'text' => 'text', 'time' => 'time', 'timestamp' => 'datetime', 'tinyblob' => 'varbinary', 'tinyint' => 'int1', 'tinytext' => 'text', 'varbinary' => 'varbinary', 'varchar' => 'varchar', } def self.create(io) params = _create(io) params ? self.new(*params) : nil end def initialize(table_def, table_name, columns, default_charset, comment) @table_def = table_def @table_name = table_name @columns = columns @default_charset = default_charset @comment = comment end def self._create(io) table_def = '' table_name = nil columns = [] default_charset = nil comment = nil position = :before_create_table io.each_line do |line| if line =~ /CREATE TABLE `(.*?)`/ position = :in_create_table table_name = $1 end next unless position == :in_create_table table_def += line.chomp if line =~ /^\s*`(.*?)`\s+([a-z()0-9,\s]+)/ # column def name = $1 type = $2.strip type = type[0..-2] if type.end_with?(',') TYPE_MAP_M2F.each do |mysql_type, flydata_type| type.gsub!(/\b#{mysql_type}\b/, flydata_type) end column = {name: name, type: type} column[:auto_increment] = true if line =~ /AUTO_INCREMENT/ column[:not_null] = true if line =~ /NOT NULL/ if /DEFAULT\s+((?:[^'\s]+\b)|(?:'(?:\\'|[^'])*'))/.match(line) val = $1 val = val.slice(1..-1) if val.start_with?("'") val = val.slice(0..-2) if val.end_with?("'") column[:default] = val == "NULL" ? nil : val end if /COMMENT\s+'(((?:\\'|[^'])*))'/.match(line) column[:comment] = $1 end columns << column end if line =~ /PRIMARY KEY/ primary_keys = line.scan(/`(.*?)`/).collect{|item| item[0]} primary_keys.each do |primary_key| column = columns.detect {|column| column[:name] === primary_key } raise "PK #{primary_key} must exist in the definition " if column.nil? column[:primary_key] = true end end if line =~ /DEFAULT CHARSET\s*=\s*([^\s]+)/ default_charset = $1 end if line =~ /ENGINE=.*/ # TODO Need better parsing. position = :after_create_table break end end position == :after_create_table ? [table_def, table_name, columns, default_charset, comment] : nil end attr_reader :columns, :table_name def to_flydata_tabledef tabledef = { table_name: @table_name, columns: @columns, } tabledef[:default_charset] = @default_charset if @default_charset tabledef[:comment] = @comment if @comment tabledef end end end end