sqlite2dbf 0.1.8 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/sqlite2dbf.rb CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  #encoding: UTF-8
3
2
  =begin
4
3
  /***************************************************************************
@@ -24,140 +23,168 @@
24
23
 
25
24
  require_relative 'file_checking'
26
25
  require_relative 'logging'
26
+ require_relative 'configuration'
27
+ require_relative 'mapping'
27
28
  require 'shp'
28
29
  require 'sqlite3'
29
30
  require_relative 'argparser'
30
31
 
31
32
  =begin
32
- The main program class. Does it.
33
+ The main program class. Does it.
33
34
  =end
34
35
 
35
36
  class SQLite2DBF
36
- include Logging
37
- include Translating
38
-
39
- def initialize(*args)
40
- options = ArgParser::parse(args)
41
- init_logger
42
- level = (options.debug ? Logger::DEBUG : @log.level)
43
- @log.level = level
44
- @log.debug('options are: ' << options.to_s)
45
-
46
- @date_fields = options.datetime ? options.datetime : []
47
- @time_fields = options.time ? options.time : []
48
-
49
- if(options.source)
50
- @dbf_path = nil
51
- sqlite_file = options.source
52
- dbf_file = options.target if options.target
53
- if(options.table_name && options.out_dir)
54
- @dbf_path = options.out_dir
55
- dbf_file = :table
56
- end
57
- dbf_file ||= File.dirname(sqlite_file) << File::Separator << File.basename(sqlite_file, '.*')
58
- msg = nil
59
-
60
- if(dbf_file != :table)
61
- if(File.exist?(dbf_file))
62
- msg = File_Checking.file_check(dbf_file, :file, :writable)
63
- elsif(File.exist?(File.dirname(dbf_file)))
64
- msg = File_Checking.file_check(File.dirname(dbf_file), :directory, :writable)
65
- end
66
- end
67
-
68
- msg ||= File_Checking.file_check(sqlite_file, :exist, :readable, :file)
69
-
70
- if(!msg)
71
- @log.debug('will transform ' << sqlite_file << ' to ' << dbf_file.to_s << '.dbf')
72
- transform(sqlite_file, dbf_file)
73
- else
74
- msg = trl("ERROR! Unsuitable file") << " : %s" %msg
75
- @log.error(msg)
76
- exit false
77
- end
78
- else
79
- puts trl("ERROR! Source-file is a mandatory program parameter!")
80
- puts trl("Start this program with parameter -h or --help to see the usage-message.")
81
- end
82
-
83
- end
84
-
85
- private
86
-
87
- def transform(sqlite_file, dbf_file)
88
- # <------------ mapping SQLite-types to SHP/XBase ------------>
89
- tmap = {'INT' => 1, 'TINYINT' => 1, 'SMALLINT' => 1, 'MEDIUMINT' => 1, 'BIGINT' => 1, 'UNSIGNED BIGINT' => 1, 'VARCHAR' => 0, 'CHARACTER' => 0, 'VARYING CHARACTER' => 0, 'LONGVARCHAR' => 0, 'TEXT' => 0, 'BLOB' => 0, 'INTEGER' => 1, 'FLOAT' => 2, 'REAL' => 2, 'DOUBLE' => 2}
90
- # -----------> in a way ... <--------------
91
-
92
- begin
93
- SQLite3::Database.new(sqlite_file) do |db|
94
- table_names = db.execute('select name from sqlite_master WHERE type="table"')
95
- @log.debug('sqlite contains ' << table_names.size.to_s << ' table(s): ' << table_names.join(', '))
96
- table_names.each_with_index do |tn, num|
97
- tname = tn.join
98
- table_info = db.table_info(tname)
99
- @log.debug(tn[0] << ': ' << table_info.join)
100
- content = db.execute('select * from ' << tname )
101
- if(:table == dbf_file)
102
- dbf_name = @dbf_path << File::Separator << tname << (content.empty? ? '_empty' : '')<< '.dbf'
103
- else
104
- dbf_name = dbf_file.dup << num.to_s << (content.empty? ? '_empty' : '')<< '.dbf'
105
- end
106
- @log.debug('dbf will be ' << dbf_name)
107
- dbt = SHP::DBF.create(dbf_name)
108
- table_info.each_with_index do |field, index|
109
- ftype = 0
110
- field_name = field['name']
111
- if( !@date_fields.include?(field_name) && !@time_fields.include?(field_name) )
112
- @log.debug('field is ' << field.to_s)
113
- # -----> determine the simple dbf data-type that has to do. <----
114
- type_mapping = tmap.detect{|key, value| field['type'].upcase.start_with?(key) }
115
- @log.debug('type_mapping is ' << type_mapping.to_s)
116
- ftype = type_mapping[1] if type_mapping && type_mapping.respond_to?(:to_ary)
117
- # <---- Yes. I know. ---->
118
- end
119
-
120
- dbt.add_field(field_name, ftype, 200, 0)
121
- end
122
-
123
- content.each_with_index do |row, record_no|
124
- @log.debug('row is ' << row.to_s)
125
- row.each_with_index do |svalue, field_index|
126
- sql_type = table_info[field_index]['type']
127
- field_name = table_info[field_index]['name']
128
- @log.debug('field is ' << field_name << ', svalue is ' << svalue.to_s << ', type is ' << sql_type)
129
- if(svalue && !svalue.to_s.empty?)
130
- if( @date_fields.include?(field_name) )
131
- conv_date = db.execute("select strftime('%Y-%m-%d %H:%M:%S', " << svalue.to_s << ", 'unixepoch')").join
132
- @log.debug('conv_date is ' << conv_date)
133
- dbt.write_string_attribute(record_no, field_index, conv_date)
134
- elsif( @time_fields.include?(field_name) )
135
- conv_time = db.execute("select strftime('%s', " << svalue.to_s << ", 'unixepoch')").join
136
- @log.debug('conv_time is ' << conv_time)
137
- dbt.write_string_attribute(record_no, field_index, conv_time)
138
-
139
- else
140
- type_mapping = tmap.detect{|key, value| sql_type.upcase.start_with?(key) }
141
- ftype = type_mapping[1] if type_mapping && type_mapping.respond_to?(:to_ary)
142
- begin
143
- dbt.write_string_attribute(record_no, field_index, svalue ) if 0 == ftype
144
- dbt.write_integer_attribute(record_no, field_index, svalue) if 1 == ftype
145
- dbt.write_double_attribute(record_no, field_index, svalue) if 2 == ftype
146
- rescue StandardError => ex
147
- @log.error(trl("ERROR! cannot write value of type %s" %sql_type) << ': ' << ex.message )
148
- end
149
- end
150
- else
151
- dbt.write_null_attribute(record_no, field_index) if (!svalue || sql_type.empty?)
152
- end
153
- end
154
- end
155
- dbt.close
156
- end
157
- end
158
- puts trl('DONE. Bye.')
159
- end
160
- rescue SQLite3::Exception => er
161
- @log.error trl("ERROR! Cannot read the source-file") << ' (' << sqlite_file << "): %s" %er.message << '.'
162
- end
37
+ include Logging
38
+ include Translating
39
+
40
+ def initialize(*args)
41
+ options = ArgParser::parse(args)
42
+ @config = Configuration.instance()
43
+ @config.set(options)
44
+
45
+ init_logger
46
+ level = (@config.debug ? Logger::DEBUG : @log.level)
47
+ @log.level = level
48
+
49
+ @date_fields = @config.date ? @config.date : []
50
+ @time_fields = @config.time ? @config.time : []
51
+
52
+ if(@config.source)
53
+ @dbf_path = nil
54
+ sqlite_file = @config.source
55
+
56
+ msg = File_Checking::file_check(sqlite_file, :exist, :readable)
57
+ if msg
58
+ @log.error(trl("ERROR! Cannot read the source-file" ) << ": " << msg)
59
+ exit false
60
+ end
61
+
62
+ SQLite3::Database.new(sqlite_file) do |db|
63
+ tables = list(db)
64
+ if(@config.list)
65
+ puts "\n" << trl("Tables in the database") << ":\n\t" << tables.join("\n\t") << "\n\n"
66
+ exit true
67
+ elsif tables.include?(@config.name)
68
+ @mapping = mapping(db)
69
+ else
70
+ @log.error(trl("Verify table-name! %s is not found in the database!") %(@config.name))
71
+ @log.error(trl("Tables are %s") %tables.join(', ') )
72
+
73
+ exit false
74
+ end
75
+
76
+ dbf_file = @config.target if @config.target
77
+ if(@config.out)
78
+ dbf_file = @config.out << File::Separator << @config.name
79
+ end
80
+ dbf_file ||= File.dirname(sqlite_file) << File::Separator << File.basename(sqlite_file, '.*')
81
+
82
+ msg = nil
83
+
84
+ if(File.exist?(dbf_file))
85
+ msg = File_Checking.file_check(dbf_file, :file, :writable)
86
+ elsif(File.exist?(File.dirname(dbf_file)))
87
+ msg = File_Checking.file_check(File.dirname(dbf_file), :directory, :writable)
88
+ end
89
+
90
+ if(!msg)
91
+ @log.debug('will transform ' << sqlite_file << ' to ' << dbf_file.to_s << '.dbf')
92
+ transform(db, dbf_file)
93
+ else
94
+ msg = trl("ERROR! Unsuitable file") << " : %s" %msg
95
+ @log.error(msg)
96
+ exit false
97
+ end
98
+ end
99
+ else
100
+ log.error trl("ERROR! Source-file is a mandatory program parameter!")
101
+ log.error trl("Start this program with parameter -h or --help to see the usage-message.")
102
+ end
103
+
104
+ end
105
+
106
+ private
107
+
108
+ # Create a list of table-names from SQLite
109
+ def list(db)
110
+ table_names = []
111
+ table_names = db.execute('select name from sqlite_master WHERE type="table"').map {|tn| tn[0]}
112
+ @log.debug('sqlite contains ' << table_names.size.to_s << ' table(s): ' << table_names.join(', '))
113
+ return table_names
114
+ end
115
+
116
+ def mapping(db)
117
+ return Mapping.new(@config, db.table_info(@config.name), db.execute('select * from ' << @config.name ) )
118
+ end
119
+
120
+ def create_base(dbase)
121
+ @log.debug('creating fields')
122
+ @mapping.each do |field|
123
+ dbase.add_field(field.name, field.type, 200, 0)
124
+ end
125
+ end
126
+
127
+ def date(db, value)
128
+ dbf_value = db.execute("select strftime('%Y-%m-%d %H:%M:%S', " << value.to_s << ", 'unixepoch')").join
129
+ @log.warn(trl("ATTN! SQLite2DBF cannot convert the date-value %s into DBF-compatible format.") %value.to_s) if dbf_value.start_with?('-')
130
+ dbf_value = db.execute("select strftime('%s', " << value.to_s << ")").join if dbf_value.start_with?('-')
131
+ end
132
+
133
+ def time(db, value)
134
+ db.execute("select strftime('%s', " << value.to_s << ", 'unixepoch')").join
135
+ end
136
+
137
+
138
+
139
+ def transform(db, dbf_file)
140
+
141
+ begin
142
+ tname = @config.name
143
+ table_info = db.table_info(tname)
144
+ content = db.execute('select * from ' << tname )
145
+ @log.debug('have content')
146
+
147
+ if(:table == dbf_file)
148
+ dbf_file = @dbf_path << File::Separator << tname << (content.empty? ? '_empty' : '')<< '.dbf'
149
+ end
150
+ @log.debug('dbf will be ' << dbf_file)
151
+ dbase = SHP::DBF.create(dbf_file)
152
+
153
+ create_base(dbase)
154
+
155
+ content.each_with_index do |row, record_no|
156
+ @log.debug('row is ' << row.to_s)
157
+
158
+ row.each_with_index do |svalue, field_index|
159
+ @log.debug('object is ' << @mapping[field_index].to_s)
160
+ dbf_type = @mapping[field_index].type
161
+ field_name = @mapping[field_index].name
162
+
163
+ if(svalue && !svalue.to_s.empty? && dbf_type)
164
+ svalue = date(db, svalue) if @date_fields.include?(field_name)
165
+ svalue = date(db, svalue) if @time_fields.include?(field_name)
166
+
167
+ @log.debug('field is ' << field_name << ', svalue is ' << svalue.to_s << ', type is ' << dbf_type.to_s)
168
+ begin
169
+ case dbf_type
170
+ when 0
171
+ dbase.write_string_attribute(record_no, field_index, svalue )
172
+ when 1
173
+ dbase.write_integer_attribute(record_no, field_index, svalue)
174
+ when 2
175
+ dbase.write_double_attribute(record_no, field_index, svalue)
176
+ else
177
+ dbase.write_null_attribute(record_no, field_index)
178
+ end
179
+ rescue StandardError => ex
180
+ @log.warn(trl("ATTN! Field %s - Cannot write value of type %s") %[field_name, dbf_type] << ': ' << ex.message )
181
+ end
182
+ end
183
+ end
184
+ end
185
+ puts trl('DONE. Bye.')
186
+ rescue SQLite3::Exception => er
187
+ @log.error trl("ERROR! Cannot read the source-file") << ' (' << db.filename << "): %s" %er.message << '.'
188
+ end
189
+ end
163
190
  end
data/lib/translating.rb CHANGED
@@ -26,6 +26,7 @@ RD = File.expand_path(File.dirname(__FILE__) ) + File::SEPARATOR if !defined?(R
26
26
 
27
27
  require 'yaml'
28
28
  require_relative 'file_checking'
29
+ require_relative 'logging'
29
30
 
30
31
 
31
32
  =begin
@@ -33,59 +34,62 @@ require_relative 'file_checking'
33
34
  Translations are read from a file "translations" in the program folder.
34
35
  =end
35
36
  module Translating
36
- # There are better ways to extend a translated
37
- # string, but I keep the 'wild-card' for
38
- # historical reasons.
39
- @@awild = 'XX'
37
+ self.extend(Logging)
38
+ @@log = init_logger(STDOUT)
39
+ # There are better ways to extend a translated
40
+ # string, but I keep the 'wild-card' for
41
+ # historical reasons.
42
+ @@awild = 'XX'
40
43
 
41
- @@lang = nil
42
- @@lang_file = format("%s%s", RD, 'LANG')
43
- @@tr = YAML::load_file("#{RD}translations")
44
-
45
- # find the current language-setting and return it.
46
- def self.language()
47
- if @@lang == nil
48
- r = ENV['LANG']
49
- if(r)
50
- @@lang = r[0, 2]
51
- elsif( !File_Checking::file_check(@@lang_file, [:exist?, :readable?]) && File::size(@@lang_file) >= 2)
52
- File::open(@@lang_file, 'r') {|f| @@lang = f.readline}
53
- @@lang.chomp!.downcase! if @@lang
54
- end
55
- end
56
- @@lang = 'en' if !@@lang
57
- end
44
+ @@lang = nil
45
+ @@lang_file = format("%s%s", RD, 'LANG')
46
+ @@tr = YAML::load_file("#{RD}translations")
47
+ # find the current language-setting and return it.
48
+ def self.language()
49
+ if @@lang == nil
50
+ r = ENV['LANG']
51
+ if(r)
52
+ @@lang = r[0, 2]
53
+ elsif( !File_Checking::file_check(@@lang_file, [:exist?, :readable?]) && File::size(@@lang_file) >= 2)
54
+ File::open(@@lang_file, 'r') {|f| @@lang = f.readline}
55
+ @@lang.chomp!.downcase! if @@lang
56
+ end
57
+ end
58
+ @@lang = 'en' if !@@lang
59
+ end
58
60
 
59
- # Translate a string to the currently set langage.
60
- # The args parameter may contain replacement-text which
61
- # will appear at the positions indicated by wildcard-characters
62
- # in the original string.
63
- def self.trl(t, *args)
64
- Translating::language()
65
- lt = @@tr[t]
66
- if(lt)
67
- lt = lt[@@lang]
68
- else
69
- # File.open('/tmp/mtf', 'a+') {|f| f << t << "\n"}
70
- puts "\nTRANSLATION MISSING: \"" << t << "\""
71
- end
72
- lt ||= t
73
- if(args && !args.empty?)
74
- i = -1
75
- lt = lt.gsub(@@awild) do |a|
76
- i += 1
77
- args.flatten[i]
78
- end
79
- lt += args[i + 1, args.length].join
80
- end
81
- return lt
82
- end
61
+ # Translate a string to the currently set langage.
62
+ # The args parameter may contain replacement-text which
63
+ # will appear at the positions indicated by wildcard-characters
64
+ # in the original string.
65
+ def self.trl(t, *args)
66
+
67
+ @@log.debug('@tr is ' << @@tr.to_s)
68
+ Translating::language()
69
+ lt = @@tr[t]
70
+ if(lt)
71
+ lt = lt[@@lang]
72
+ else
73
+ # File.open('/tmp/mtf', 'a+') {|f| f << t << "\n"}
74
+ puts "\nTRANSLATION MISSING: \"" << t << "\""
75
+ end
76
+ lt ||= t
77
+ if(args && !args.empty?)
78
+ i = -1
79
+ lt = lt.gsub(@@awild) do |a|
80
+ i += 1
81
+ args.flatten[i]
82
+ end
83
+ lt += args[i + 1, args.length].join
84
+ end
85
+ return lt
86
+ end
83
87
 
84
- # Translate a string to the currently set langage.
85
- # The args parameter may contain replacement-text which
86
- # will appear at the positions indicated by wildcard-characters
87
- # in the original string.
88
- def trl(t, *args )
89
- Translating::trl(t, args)
90
- end
88
+ # Translate a string to the currently set langage.
89
+ # The args parameter may contain replacement-text which
90
+ # will appear at the positions indicated by wildcard-characters
91
+ # in the original string.
92
+ def trl(t, *args )
93
+ Translating::trl(t, args)
94
+ end
91
95
  end