class SQLite2DBF

The main program class. Does it.

Public Class Methods

new(*args) click to toggle source
# File lib/sqlite2dbf.rb, line 41
def initialize(*args)
  options = ArgParser::parse(args)
  @config = Configuration.instance()
  @config.set(options)
  # Object level logger. “There can only be one!”
  init_logger
  level = (@config.debug ? Logger::DEBUG : @log.level)
  @log.level = level  

  @date_fields = @config.date ? @config.date : []
  @time_fields = @config.time ? @config.time : []

  if(@config.source)
    @dbf_path = nil
    sqlite_file = @config.source      

    msg = File_Checking::file_check(sqlite_file, :exist, :readable)
    if msg
      @log.error(trl("ERROR! Cannot read the source-file" ) << ": " << msg)
      exit false
    end

    SQLite3::Database.new(sqlite_file) do |db|
      tables = list(db)
      if(@config.list)
        puts "\n" << trl("Tables in the database") << ":\n\t"  << tables.join("\n\t") << "\n\n"
        exit true
      elsif tables.include?(@config.name)
        @mapping = mapping(db)
      else
        @log.error(trl("Verify table-name! %s is not found in the database!") %(@config.name))
        @log.error(trl("Tables are %s") %tables.join(', ') )

        exit false
      end

      # dbf_file is eather named explicitly
      dbf_file = @config.target if @config.target
      # .., derived from the table-name
      dbf_file = @config.out << File::Separator << @config.name if(@config.out)
      # .., or identical with the original sqlite-file, minus extension, plus dbf
      dbf_file ||= File.dirname(sqlite_file) << File::Separator << File.basename(sqlite_file, '.*') << '.dbf'

      msg = nil

      # check if dbf_file can be used
      if(File.exist?(dbf_file))
        msg = File_Checking.file_check(dbf_file, :file, :writable)
      elsif(File.exist?(File.dirname(dbf_file))) 
        msg = File_Checking.file_check(File.dirname(dbf_file), :directory, :writable)
      end

      # then do it
      if(!msg)
        @log.debug('will transform ' << sqlite_file << ' to  ' << dbf_file.to_s)
        transform(db, dbf_file)
      else
        # or not
        msg = trl("ERROR! Unsuitable file") << " : %s" %msg
        @log.error(msg)
        exit false
      end
    end
  else
    log.error trl("ERROR! Source-file is a mandatory program parameter!")
    log.error trl("Start this program with parameter -h or --help to see the usage-message.")  
  end

end

Private Instance Methods

create_base(dbase) click to toggle source
# File lib/sqlite2dbf.rb, line 125
def create_base(dbase)
  @log.debug('creating fields')
  @mapping.each do |field|
    dbase.add_field(field.name, field.type, 200, 0)
  end
end
date(db, value) click to toggle source

create a date-value from value

# File lib/sqlite2dbf.rb, line 133
def date(db, value)
  dbf_value = db.execute("select strftime('%Y-%m-%d %H:%M:%S', " << value.to_s << ", 'unixepoch')").join
  # ... or not.
  @log.warn(trl("ATTN! SQLite2DBF cannot convert the date-value %s into DBF-compatible format.") %value.to_s) if dbf_value.start_with?('-')
  dbf_value = db.execute("select strftime('%s', " << value.to_s << ")").join if dbf_value.start_with?('-')
end
list(db) click to toggle source

Create a list of table-names from SQLite

# File lib/sqlite2dbf.rb, line 114
def list(db)
  table_names = []
  table_names = db.execute('select name from sqlite_master WHERE type="table"').map {|tn| tn[0]} 
  @log.debug('sqlite contains ' << table_names.size.to_s << ' table(s): ' << table_names.join(', '))
  return table_names
end
mapping(db) click to toggle source
# File lib/sqlite2dbf.rb, line 121
def mapping(db)
  return Mapping.new(@config, db.table_info(@config.name), db.execute('select * from ' << @config.name ) )
end
time(db, value) click to toggle source

create a time-value from value

# File lib/sqlite2dbf.rb, line 141
def time(db, value)
  db.execute("select strftime('%s', " << value.to_s << ", 'unixepoch')").join
end
transform(db, dbf_file) click to toggle source
# File lib/sqlite2dbf.rb, line 145
def transform(db, dbf_file)
  begin
    tname = @config.name
    table_info = db.table_info(tname) 
    content = db.execute('select * from ' << tname ) 
    @log.debug('have content')

    if(:table == dbf_file)    
      dbf_file = @dbf_path << File::Separator << tname << (content.empty? ? '_empty' : '')<< '.dbf'
    end
    @log.debug('dbf will be ' << dbf_file)
    dbase = SHP::DBF.create(dbf_file) 

    create_base(dbase)

    content.each_with_index do |row, record_no|
      @log.debug('row is ' << row.to_s)

      row.each_with_index do |svalue, field_index|
        @log.debug('object is ' << @mapping[field_index].to_s)
        dbf_type = @mapping[field_index].type
        field_name = @mapping[field_index].name

        if(svalue && !svalue.to_s.empty? && dbf_type)
          svalue = date(db, svalue) if @date_fields.include?(field_name)
          svalue = time(db, svalue) if @time_fields.include?(field_name)

          @log.debug('field is ' << field_name << ', svalue is ' << svalue.to_s << ', type is ' << dbf_type.to_s)
          # This is Ruby. But if you do not like the verbosity
          # remove the magic numbers and call them text, int and float or
          # similar.
          begin
            case dbf_type
            when 0
              dbase.write_string_attribute(record_no, field_index, svalue ) 
            when 1
              dbase.write_integer_attribute(record_no, field_index, svalue) 
            when 2
              dbase.write_double_attribute(record_no, field_index, svalue) 
            else
              dbase.write_null_attribute(record_no, field_index)
            end
          rescue StandardError => ex
            @log.warn(trl("ATTN! Field %s - Cannot write value of type %s") %[field_name, dbf_type] << ': ' << ex.message )
          end
        end
      end
    end
    puts trl('DONE. Bye.')
  rescue SQLite3::Exception => er
    @log.error trl("ERROR! Cannot read the source-file") << ' (' << db.filename << "): %s" %er.message << '.'
  end
end