<commit_before>
module DmIsReflective::MysqlAdapter
  include DataMapper

  def storages
    select('SHOW TABLES')
  end

  private
  # construct needed table metadata
  def reflective_query_storage storage
    sql = <<-SQL
      SELECT c.column_name, c.column_key, c.column_default, c.is_nullable,
             c.data_type, c.character_maximum_length, c.extra, c.table_name,
             s.index_name
      FROM      `information_schema`.`columns` c
      LEFT JOIN `information_schema`.`statistics` s
      ON       c.column_name = s.column_name
      WHERE    c.table_schema = ? AND c.table_name = ?
      GROUP BY c.column_name;
    SQL

    # TODO: can we fix this shit in dm-mysql-adapter?
    path = (options[:path]     || options['path'] ||
            options[:database] || options['database']).sub('/', '')

    select(Ext::String.compress_lines(sql), path, storage)
  end

  def reflective_field_name field
    field.column_name
  end

  def reflective_primitive field
    field.data_type
  end

  def reflective_attributes field, attrs = {}
    attrs[:serial] = true if field.extra      == 'auto_increment'

    case field.column_key
    when 'PRI'
      attrs[:key] = true
      attrs[:unique_index] = :"#{field.table_name}_pkey"
    when 'UNI'
      attrs[:unique_index] = :"#{field.index_name}"
    when 'MUL'
      attrs[:index]        = :"#{field.index_name}"
    end

    attrs[:allow_nil] = field.is_nullable == 'YES'
    attrs[:default]  = field.column_default           if
      field.column_default

    attrs[:length]   = field.character_maximum_length if
      field.character_maximum_length

    attrs
  end

  def reflective_lookup_primitive primitive
    case primitive.upcase
    when 'YEAR'                           ; Integer
    when /\w*INT(EGER)?( SIGNED| UNSIGNED)?( ZEROFILL)?/
                                          ; Integer
    when /(DOUBLE|FLOAT|DECIMAL)( SIGNED| UNSIGNED)?( ZEROFILL)?/
                                          ; Property::Decimal<commit_msg>now mysql supports multiple composite keys<commit_after>
module DmIsReflective::MysqlAdapter
  include DataMapper

  def storages
    select('SHOW TABLES')
  end

  private
  # construct needed table metadata
  def reflective_query_storage storage
    sql_indices = <<-SQL
      SELECT column_name, index_name, non_unique
      FROM   `information_schema`.`statistics`
      WHERE  table_schema = ? AND table_name = ?
    SQL

    sql_columns = <<-SQL
      SELECT column_name, column_key, column_default, is_nullable,
             data_type, character_maximum_length, extra, table_name
      FROM      `information_schema`.`columns`
      WHERE  table_schema = ? AND table_name = ?
    SQL

    # TODO: can we fix this shit in dm-mysql-adapter?
    path = (options[:path]     || options['path'] ||
            options[:database] || options['database']).sub('/', '')

    indices =
    select(Ext::String.compress_lines(sql_indices), path, storage).
      group_by(&:column_name)

    select(Ext::String.compress_lines(sql_columns), path, storage).
    map do |column|
      if idx = indices[column.column_name]
        idx_uni, idx_com = idx.partition{ |i| i.non_unique == 0 }.map{ |i|
          if i.empty?
            nil
          elsif i.size == 1
            i.first.index_name.to_sym
          else
            i.map{ |ii| ii.index_name.to_sym }
          end
        }
      else
        idx_uni, idx_com = nil
      end

      column.instance_eval <<-RUBY
        def unique_index; #{idx_uni.inspect}; end
        def index       ; #{idx_com.inspect}; end
      RUBY

      column
    end
  end

  def reflective_field_name field
    field.column_name
  end

  def reflective_primitive field
    field.data_type
  end

  def reflective_attributes field, attrs = {}
    attrs[:serial] = true if field.extra == 'auto_increment'

    if field.column_key == 'PRI'
      attrs[:key] = true
      attrs[:unique_index] = :"#{field.table_name}_pkey"
    else
      attrs[:unique_index] = field.unique_index if field.unique_index
      attrs[       :index] = field.       index if field.       index
    end

    attrs[:allow_nil] = field.is_nullable == 'YES'
    attrs[:default]   = field.column_default           if
      field.column_default

    attrs[:length]    = field.character_maximum_length if
      field.character_maximum_length

    attrs
  end

  def reflective_lookup_primitive primitive
    case primitive.upcase
    when 'YEAR'                           ; Integer
    when /\w*INT(EGER)?( SIGNED| UNSIGNED)?( ZEROFILL)?/
                                          ; Integer
    when /(DOUBLE|FLOAT|DECIMAL)( SIGNED| UNSIGNED)?( ZEROFILL)?/
                                          ; Property::Decimal
{'fraction_non_alphanumeric': 0.10103791569582715, 'fraction_numerical': 0.00042363905952128787, 'mean_word_length': 2.2814454482279363, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 2, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1361495', 'n_tokens_mistral': 1460, 'n_tokens_neox': 1405, 'n_words': 325}