flattendb 0.0.8 → 0.1.0
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/README +1 -1
- data/Rakefile +1 -1
- data/bin/flattendb +3 -161
- data/bin/flattendb.mdb +3 -51
- data/bin/flattendb.mysql +3 -88
- data/example/mysql-sample.flat-sql.xml +120 -0
- data/example/mysql-sample.sql +137 -0
- data/lib/flattendb/base.rb +9 -33
- data/lib/flattendb/cli.rb +190 -30
- data/lib/flattendb/types/mdb.rb +16 -4
- data/lib/flattendb/types/mysql.rb +51 -14
- data/lib/flattendb/version.rb +2 -2
- data/lib/flattendb.rb +4 -1
- metadata +14 -11
data/README
CHANGED
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ begin
|
|
14
14
|
:summary => %q{Flatten relational databases.},
|
15
15
|
:author => %q{Jens Wille},
|
16
16
|
:email => %q{jens.wille@uni-koeln.de},
|
17
|
-
:dependencies => %w[
|
17
|
+
:dependencies => %w[libxml-ruby builder ruby-nuggets] << ['athena', '>= 0.1.5']
|
18
18
|
}
|
19
19
|
}}
|
20
20
|
rescue LoadError => err
|
data/bin/flattendb
CHANGED
@@ -28,168 +28,10 @@
|
|
28
28
|
###############################################################################
|
29
29
|
#++
|
30
30
|
|
31
|
-
require 'optparse'
|
32
|
-
|
33
|
-
require 'rubygems'
|
34
|
-
require 'highline/import'
|
35
|
-
require 'nuggets/array/flatten_once'
|
36
|
-
|
37
|
-
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
38
|
-
|
39
|
-
require 'flattendb'
|
40
31
|
require 'flattendb/cli'
|
41
32
|
|
42
|
-
include FlattenDB::CLI
|
43
|
-
|
44
|
-
USAGE = "Usage: #{$0} [-h|--help] [options]"
|
45
|
-
abort USAGE if ARGV.empty?
|
46
|
-
|
47
|
-
$global_options = {
|
48
|
-
:type => :mysql,
|
49
|
-
:infiles => [],
|
50
|
-
:outfile => nil,
|
51
|
-
:confile => nil,
|
52
|
-
:keep => false,
|
53
|
-
:mysql => {
|
54
|
-
:intype => :xml
|
55
|
-
},
|
56
|
-
:mdb => {
|
57
|
-
:intype => :mdb
|
58
|
-
}
|
59
|
-
}
|
60
|
-
|
61
|
-
$opts_by_type = {
|
62
|
-
:mysql => {
|
63
|
-
:title => 'MySQL',
|
64
|
-
:opts => lambda { |opts|
|
65
|
-
opts.on('-x', '--mysql-xml', "Input file is of type XML [This is the default]") {
|
66
|
-
$global_options[:mysql][:intype] = :xml
|
67
|
-
}
|
68
|
-
opts.on('-s', '--sql', "Input file is of type SQL") {
|
69
|
-
$global_options[:mysql][:intype] = :sql
|
70
|
-
}
|
71
|
-
}
|
72
|
-
},
|
73
|
-
:mdb => {
|
74
|
-
:title => 'MS Access',
|
75
|
-
:opts => lambda { |opts|
|
76
|
-
opts.on('-m', '--mdb', "Input file is of type MDB [This is the default]") {
|
77
|
-
$global_options[:mdb][:intype] = :mdb
|
78
|
-
}
|
79
|
-
opts.on('-y', '--mdb-xml', "Input file is of type XML") {
|
80
|
-
$global_options[:mdb][:intype] = :xml
|
81
|
-
}
|
82
|
-
}
|
83
|
-
}
|
84
|
-
}
|
85
|
-
|
86
|
-
def type_options(type, opts, with_heading = true)
|
87
|
-
if type == :all
|
88
|
-
$opts_by_type.keys.sort_by { |t| t.to_s }.each { |t|
|
89
|
-
type_options(t, opts, with_heading)
|
90
|
-
}
|
91
|
-
else
|
92
|
-
opt = $opts_by_type[type.to_sym]
|
93
|
-
|
94
|
-
if with_heading
|
95
|
-
opts.separator ''
|
96
|
-
opts.separator " - [#{type}] #{opt[:title]}"
|
97
|
-
end
|
98
|
-
|
99
|
-
opt[:opts][opts]
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
OptionParser.new { |opts|
|
104
|
-
opts.banner = USAGE
|
105
|
-
|
106
|
-
opts.separator ''
|
107
|
-
opts.separator 'Options:'
|
108
|
-
|
109
|
-
if $type
|
110
|
-
opts.separator " [-t, --type] TYPE OVERRIDE IN EFFECT (#{$type})"
|
111
|
-
else
|
112
|
-
opts.on('-t', '--type TYPE', "Type of database at hand [Default: #{$global_options[:type]}]") { |t|
|
113
|
-
$global_options[:type] = t.downcase.to_sym
|
114
|
-
}
|
115
|
-
end
|
116
|
-
|
117
|
-
opts.separator ''
|
118
|
-
|
119
|
-
opts.on('-i', '--input-file FILE', "Input file; depending on the database type, this option", "may be given multiple times [REQUIRED]") { |f|
|
120
|
-
$global_options[:infiles] << f
|
121
|
-
}
|
122
|
-
|
123
|
-
opts.on('-o', '--output-file FILE', "Output file (flat XML) [REQUIRED]") { |f|
|
124
|
-
$global_options[:outfile] = f
|
125
|
-
}
|
126
|
-
|
127
|
-
opts.on('-c', '--config-file FILE', "Configuration file (YAML) [REQUIRED]") { |f|
|
128
|
-
$global_options[:confile] = f
|
129
|
-
}
|
130
|
-
|
131
|
-
opts.separator ''
|
132
|
-
|
133
|
-
opts.on('-k', '--keep', "Keep any intermediate files (generated XML dumps, etc.)") {
|
134
|
-
$global_options[:keep] = true
|
135
|
-
}
|
136
|
-
|
137
|
-
opts.separator ''
|
138
|
-
opts.separator 'Database-specific Options:'
|
139
|
-
|
140
|
-
if $type
|
141
|
-
type_options($type, opts, false)
|
142
|
-
else
|
143
|
-
type_options(:all, opts)
|
144
|
-
end
|
145
|
-
|
146
|
-
opts.separator ''
|
147
|
-
opts.separator 'Generic options:'
|
148
|
-
|
149
|
-
opts.on('-h', '--help', 'Print this help message and exit') {
|
150
|
-
abort opts.to_s
|
151
|
-
}
|
152
|
-
|
153
|
-
opts.on('--version', 'Print program version and exit') {
|
154
|
-
abort "#{File.basename($0)} v#{FlattenDB::VERSION}"
|
155
|
-
}
|
156
|
-
}.parse!
|
157
|
-
|
158
|
-
$type ||= $global_options[:type]
|
159
|
-
$options = $global_options[$type] || {}
|
160
|
-
|
161
|
-
# Load corresponding module
|
162
|
-
begin
|
163
|
-
require "flattendb/types/#{$type}"
|
164
|
-
rescue LoadError
|
165
|
-
abort "Database type '#{$type}' is not supported at the moment."
|
166
|
-
end
|
167
|
-
|
168
|
-
abort "No output file specified" unless $global_options[:outfile]
|
169
|
-
|
170
|
-
if confile = $global_options[:confile]
|
171
|
-
abort "Configuration file not found: #{confile}" unless File.readable?(confile)
|
172
|
-
else
|
173
|
-
abort "No configuration file specified"
|
174
|
-
end
|
175
|
-
|
176
|
-
$global_options[:infiles].each { |infile|
|
177
|
-
abort "Input file not found: #{infile}" unless File.readable?(infile)
|
178
|
-
}
|
179
|
-
|
180
|
-
$infiles = $global_options[:infiles]
|
181
|
-
$outfile = $global_options[:outfile]
|
182
|
-
$confile = $global_options[:confile]
|
183
|
-
|
184
|
-
# Load type-specific script
|
185
33
|
begin
|
186
|
-
|
187
|
-
rescue
|
188
|
-
|
189
|
-
end
|
190
|
-
|
191
|
-
FlattenDB[$type].new($infile || $infiles, $outfile, $confile).flatten!.to_xml
|
192
|
-
|
193
|
-
unless $global_options[:keep]
|
194
|
-
File.delete($dump_file) if $dump_file
|
34
|
+
FlattenDB::CLI.execute($flattendb_type, ARGV, STDIN, STDOUT, STDERR)
|
35
|
+
rescue ArgumentError => err
|
36
|
+
abort err
|
195
37
|
end
|
data/bin/flattendb.mdb
CHANGED
@@ -1,55 +1,7 @@
|
|
1
1
|
#! /usr/bin/ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
# flattendb -- Flatten relational databases #
|
7
|
-
# #
|
8
|
-
# Copyright (C) 2007-2011 University of Cologne, #
|
9
|
-
# Albertus-Magnus-Platz, #
|
10
|
-
# 50923 Cologne, Germany #
|
11
|
-
# #
|
12
|
-
# Authors: #
|
13
|
-
# Jens Wille <jens.wille@uni-koeln.de> #
|
14
|
-
# #
|
15
|
-
# flattendb is free software; you can redistribute it and/or modify it under #
|
16
|
-
# the terms of the GNU Affero General Public License as published by the Free #
|
17
|
-
# Software Foundation; either version 3 of the License, or (at your option) #
|
18
|
-
# any later version. #
|
19
|
-
# #
|
20
|
-
# flattendb is distributed in the hope that it will be useful, but WITHOUT #
|
21
|
-
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
22
|
-
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License #
|
23
|
-
# for more details. #
|
24
|
-
# #
|
25
|
-
# You should have received a copy of the GNU Affero General Public License #
|
26
|
-
# along with flattendb. If not, see <http://www.gnu.org/licenses/>. #
|
27
|
-
# #
|
28
|
-
###############################################################################
|
29
|
-
#++
|
30
|
-
|
31
|
-
unless $type
|
32
|
-
$type = :mdb
|
33
|
-
load File.join(File.dirname(__FILE__), 'flattendb')
|
34
|
-
else
|
35
|
-
case $options[:intype]
|
36
|
-
when :xml
|
37
|
-
$infiles.each { |infile|
|
38
|
-
unless IO.read(infile, 6) == '<?xml '
|
39
|
-
abort "Input file doesn't seem to be a valid XML file, XML declaration missing: #{infile}"
|
40
|
-
end
|
41
|
-
}
|
42
|
-
when :mdb
|
43
|
-
tables_cmd = 'mdb-tables'
|
44
|
-
export_cmd = 'mdb-export'
|
45
|
-
|
46
|
-
require_commands(tables_cmd, export_cmd, :pkg => 'mdbtools')
|
47
|
-
require_libraries('fastercsv')
|
48
|
-
|
49
|
-
$infiles.map! { |infile|
|
50
|
-
$dump_file
|
51
|
-
}
|
52
|
-
end
|
53
|
-
end
|
3
|
+
ext = File.extname(__FILE__)
|
4
|
+
$flattendb_type = ext.sub(/\A\./, '')
|
5
|
+
load __FILE__.sub(/#{Regexp.escape(ext)}\z/, '')
|
54
6
|
|
55
7
|
# vim:ft=ruby
|
data/bin/flattendb.mysql
CHANGED
@@ -1,92 +1,7 @@
|
|
1
1
|
#! /usr/bin/ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
# flattendb -- Flatten relational databases #
|
7
|
-
# #
|
8
|
-
# Copyright (C) 2007-2011 University of Cologne, #
|
9
|
-
# Albertus-Magnus-Platz, #
|
10
|
-
# 50923 Cologne, Germany #
|
11
|
-
# #
|
12
|
-
# Authors: #
|
13
|
-
# Jens Wille <jens.wille@uni-koeln.de> #
|
14
|
-
# #
|
15
|
-
# flattendb is free software; you can redistribute it and/or modify it under #
|
16
|
-
# the terms of the GNU Affero General Public License as published by the Free #
|
17
|
-
# Software Foundation; either version 3 of the License, or (at your option) #
|
18
|
-
# any later version. #
|
19
|
-
# #
|
20
|
-
# flattendb is distributed in the hope that it will be useful, but WITHOUT #
|
21
|
-
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
22
|
-
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License #
|
23
|
-
# for more details. #
|
24
|
-
# #
|
25
|
-
# You should have received a copy of the GNU Affero General Public License #
|
26
|
-
# along with flattendb. If not, see <http://www.gnu.org/licenses/>. #
|
27
|
-
# #
|
28
|
-
###############################################################################
|
29
|
-
#++
|
30
|
-
|
31
|
-
unless $type
|
32
|
-
$type = :mysql
|
33
|
-
load File.join(File.dirname(__FILE__), 'flattendb')
|
34
|
-
else
|
35
|
-
$infile = $infiles.first
|
36
|
-
|
37
|
-
case $options[:intype]
|
38
|
-
when :xml
|
39
|
-
unless IO.read($infile, 6) == '<?xml '
|
40
|
-
abort "Input file doesn't seem to be a valid XML file, XML declaration missing"
|
41
|
-
end
|
42
|
-
when :sql
|
43
|
-
$dump_file = $infile.sub(/\.(?:sql|dump)(?:\.gz)?\z/i, '') << '.xml'
|
44
|
-
abort "Dump file and output file are the same: #{$dump_file} = #{$outfile}" \
|
45
|
-
if File.expand_path($dump_file) == File.expand_path($outfile)
|
46
|
-
|
47
|
-
mysql_cmd = 'mysql'
|
48
|
-
dump_cmd = 'mysqldump'
|
49
|
-
|
50
|
-
require_commands(mysql_cmd, dump_cmd, :pkg => 'a suitable MySQL client')
|
51
|
-
require_libraries('mysql')
|
52
|
-
|
53
|
-
mysql_user = ask('Please enter the MySQL user name: ') \
|
54
|
-
{ |q| q.default = ENV['USER'] }
|
55
|
-
mysql_pass = ask('Please enter the MySQL password for that user: ') \
|
56
|
-
{ |q| q.echo = false }
|
57
|
-
|
58
|
-
is_root = mysql_user == 'root'
|
59
|
-
|
60
|
-
temp_db = ENV['FLATTEN_DB'] || 'flattendb_temp'
|
61
|
-
temp_db = "#{temp_db}_%d_%d" % [Time.now, $$] if is_root
|
62
|
-
|
63
|
-
temp_user = ENV['FLATTEN_USER'] || 'flattendb_user'
|
64
|
-
temp_pass = ENV['FLATTEN_PASS'] || 'flattendb_pass'
|
65
|
-
|
66
|
-
input = $infile =~ /\.gz\z/i ? "<(zcat #{$infile})" : "< #{$infile}"
|
67
|
-
mysql_args = "--one-database -u#{temp_user} -p#{temp_pass} #{temp_db} #{input}"
|
68
|
-
dump_args = "--xml -u#{temp_user} -p#{temp_pass} #{temp_db} > #{$dump_file}"
|
69
|
-
|
70
|
-
begin
|
71
|
-
mysql = Mysql.real_connect('localhost', mysql_user, mysql_pass)
|
72
|
-
|
73
|
-
mysql.query("CREATE DATABASE #{temp_db}")
|
74
|
-
mysql.query("GRANT ALL ON #{temp_db}.* TO '#{temp_user}'@'localhost' IDENTIFIED BY '#{temp_pass}'") if is_root
|
75
|
-
|
76
|
-
system("#{mysql_cmd} #{mysql_args} && #{dump_cmd} #{dump_args}")
|
77
|
-
rescue Mysql::Error => err
|
78
|
-
abort "ERROR #{err.errno} (#{err.sqlstate}): #{err.error}"
|
79
|
-
ensure
|
80
|
-
if mysql
|
81
|
-
mysql.query("REVOKE ALL ON #{temp_db}.* FROM '#{temp_user}'@'localhost'") if is_root
|
82
|
-
mysql.query("DROP DATABASE IF EXISTS #{temp_db}")
|
83
|
-
|
84
|
-
mysql.close
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
$infile = $dump_file
|
89
|
-
end
|
90
|
-
end
|
3
|
+
ext = File.extname(__FILE__)
|
4
|
+
$flattendb_type = ext.sub(/\A\./, '')
|
5
|
+
load __FILE__.sub(/#{Regexp.escape(ext)}\z/, '')
|
91
6
|
|
92
7
|
# vim:ft=ruby
|
@@ -0,0 +1,120 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<ndr>
|
3
|
+
<row>
|
4
|
+
<Bla>12</Bla>
|
5
|
+
<Blub></Blub>
|
6
|
+
<ObjID>1</ObjID>
|
7
|
+
<attr1>
|
8
|
+
<ObjID>1</ObjID>
|
9
|
+
<Val>3</Val>
|
10
|
+
<attr1ID>1</attr1ID>
|
11
|
+
</attr1>
|
12
|
+
<attr2>
|
13
|
+
<ObjID>1</ObjID>
|
14
|
+
<Val>4</Val>
|
15
|
+
<attr2ID>3</attr2ID>
|
16
|
+
</attr2>
|
17
|
+
<barobject>
|
18
|
+
<Bar>1002</Bar>
|
19
|
+
<ObjID>1</ObjID>
|
20
|
+
<attr4>
|
21
|
+
<Val>0</Val>
|
22
|
+
<attr4ID>2</attr4ID>
|
23
|
+
</attr4>
|
24
|
+
<attr4ID>2</attr4ID>
|
25
|
+
</barobject>
|
26
|
+
<fooobject>
|
27
|
+
<Foo>112</Foo>
|
28
|
+
<ObjID>1</ObjID>
|
29
|
+
<attr1>
|
30
|
+
<ObjID>1</ObjID>
|
31
|
+
<Val>3</Val>
|
32
|
+
<attr1ID>1</attr1ID>
|
33
|
+
</attr1>
|
34
|
+
<attr1ID>1</attr1ID>
|
35
|
+
<attr3>
|
36
|
+
<Val>8</Val>
|
37
|
+
<attr3ID>2</attr3ID>
|
38
|
+
</attr3>
|
39
|
+
<attr3ID>2</attr3ID>
|
40
|
+
</fooobject>
|
41
|
+
</row>
|
42
|
+
<row>
|
43
|
+
<Bla>12</Bla>
|
44
|
+
<Blub>hi</Blub>
|
45
|
+
<ObjID>2</ObjID>
|
46
|
+
<attr1>
|
47
|
+
<ObjID>2</ObjID>
|
48
|
+
<Val>2</Val>
|
49
|
+
<attr1ID>2</attr1ID>
|
50
|
+
</attr1>
|
51
|
+
<attr2>
|
52
|
+
<ObjID>2</ObjID>
|
53
|
+
<Val>5</Val>
|
54
|
+
<attr2ID>2</attr2ID>
|
55
|
+
</attr2>
|
56
|
+
<barobject>
|
57
|
+
<Bar>1200</Bar>
|
58
|
+
<ObjID>2</ObjID>
|
59
|
+
<attr4>
|
60
|
+
<Val>0</Val>
|
61
|
+
<attr4ID>1</attr4ID>
|
62
|
+
</attr4>
|
63
|
+
<attr4ID>1</attr4ID>
|
64
|
+
</barobject>
|
65
|
+
<fooobject>
|
66
|
+
<Foo>122</Foo>
|
67
|
+
<ObjID>2</ObjID>
|
68
|
+
<attr1>
|
69
|
+
<ObjID>2</ObjID>
|
70
|
+
<Val>2</Val>
|
71
|
+
<attr1ID>2</attr1ID>
|
72
|
+
</attr1>
|
73
|
+
<attr1ID>2</attr1ID>
|
74
|
+
<attr3>
|
75
|
+
<Val>0</Val>
|
76
|
+
<attr3ID>1</attr3ID>
|
77
|
+
</attr3>
|
78
|
+
<attr3ID>1</attr3ID>
|
79
|
+
</fooobject>
|
80
|
+
</row>
|
81
|
+
<row>
|
82
|
+
<Bla>1</Bla>
|
83
|
+
<Blub>ho</Blub>
|
84
|
+
<ObjID>3</ObjID>
|
85
|
+
<attr1>
|
86
|
+
<ObjID>3</ObjID>
|
87
|
+
<Val>1</Val>
|
88
|
+
<attr1ID>3</attr1ID>
|
89
|
+
</attr1>
|
90
|
+
<attr2>
|
91
|
+
<ObjID>3</ObjID>
|
92
|
+
<Val>6</Val>
|
93
|
+
<attr2ID>1</attr2ID>
|
94
|
+
</attr2>
|
95
|
+
<barobject>
|
96
|
+
<Bar>1000</Bar>
|
97
|
+
<ObjID>3</ObjID>
|
98
|
+
<attr4>
|
99
|
+
<Val>9</Val>
|
100
|
+
<attr4ID>3</attr4ID>
|
101
|
+
</attr4>
|
102
|
+
<attr4ID>3</attr4ID>
|
103
|
+
</barobject>
|
104
|
+
<fooobject>
|
105
|
+
<Foo>111</Foo>
|
106
|
+
<ObjID>3</ObjID>
|
107
|
+
<attr1>
|
108
|
+
<ObjID>3</ObjID>
|
109
|
+
<Val>1</Val>
|
110
|
+
<attr1ID>3</attr1ID>
|
111
|
+
</attr1>
|
112
|
+
<attr1ID>3</attr1ID>
|
113
|
+
<attr3>
|
114
|
+
<Val>7</Val>
|
115
|
+
<attr3ID>3</attr3ID>
|
116
|
+
</attr3>
|
117
|
+
<attr3ID>3</attr3ID>
|
118
|
+
</fooobject>
|
119
|
+
</row>
|
120
|
+
</ndr>
|
data/example/mysql-sample.sql
CHANGED
@@ -0,0 +1,137 @@
|
|
1
|
+
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
2
|
+
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
3
|
+
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
4
|
+
/*!40101 SET NAMES utf8 */;
|
5
|
+
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
6
|
+
/*!40103 SET TIME_ZONE='+00:00' */;
|
7
|
+
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
8
|
+
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
9
|
+
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
10
|
+
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
11
|
+
|
12
|
+
DROP TABLE IF EXISTS `object`;
|
13
|
+
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
14
|
+
/*!40101 SET character_set_client = utf8 */;
|
15
|
+
CREATE TABLE `object` (
|
16
|
+
`ObjID` int(11) NOT NULL,
|
17
|
+
`Bla` int(11) NOT NULL,
|
18
|
+
`Blub` varchar(50) DEFAULT NULL,
|
19
|
+
PRIMARY KEY (`ObjID`)
|
20
|
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
21
|
+
/*!40101 SET character_set_client = @saved_cs_client */;
|
22
|
+
|
23
|
+
LOCK TABLES `object` WRITE;
|
24
|
+
/*!40000 ALTER TABLE `object` DISABLE KEYS */;
|
25
|
+
INSERT INTO `object` VALUES (1,12,NULL),(2,12,'hi'),(3,1,'ho');
|
26
|
+
/*!40000 ALTER TABLE `object` ENABLE KEYS */;
|
27
|
+
UNLOCK TABLES;
|
28
|
+
|
29
|
+
DROP TABLE IF EXISTS `fooobject`;
|
30
|
+
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
31
|
+
/*!40101 SET character_set_client = utf8 */;
|
32
|
+
CREATE TABLE `fooobject` (
|
33
|
+
`ObjID` int(11) NOT NULL,
|
34
|
+
`attr1ID` int(11) NOT NULL,
|
35
|
+
`attr3ID` int(11) NOT NULL,
|
36
|
+
`Foo` int(11) NOT NULL,
|
37
|
+
PRIMARY KEY (`ObjID`)
|
38
|
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
39
|
+
/*!40101 SET character_set_client = @saved_cs_client */;
|
40
|
+
|
41
|
+
LOCK TABLES `fooobject` WRITE;
|
42
|
+
/*!40000 ALTER TABLE `fooobject` DISABLE KEYS */;
|
43
|
+
INSERT INTO `fooobject` VALUES (1,1,2,112),(2,2,1,122),(3,3,3,111);
|
44
|
+
/*!40000 ALTER TABLE `fooobject` ENABLE KEYS */;
|
45
|
+
UNLOCK TABLES;
|
46
|
+
|
47
|
+
DROP TABLE IF EXISTS `barobject`;
|
48
|
+
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
49
|
+
/*!40101 SET character_set_client = utf8 */;
|
50
|
+
CREATE TABLE `barobject` (
|
51
|
+
`ObjID` int(11) NOT NULL,
|
52
|
+
`attr4ID` int(11) NOT NULL,
|
53
|
+
`Bar` int(11) NOT NULL,
|
54
|
+
PRIMARY KEY (`ObjID`)
|
55
|
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
56
|
+
/*!40101 SET character_set_client = @saved_cs_client */;
|
57
|
+
|
58
|
+
LOCK TABLES `barobject` WRITE;
|
59
|
+
/*!40000 ALTER TABLE `barobject` DISABLE KEYS */;
|
60
|
+
INSERT INTO `barobject` VALUES (1,2,1002),(2,1,1200),(3,3,1000);
|
61
|
+
/*!40000 ALTER TABLE `barobject` ENABLE KEYS */;
|
62
|
+
UNLOCK TABLES;
|
63
|
+
|
64
|
+
DROP TABLE IF EXISTS `attr1`;
|
65
|
+
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
66
|
+
/*!40101 SET character_set_client = utf8 */;
|
67
|
+
CREATE TABLE `attr1` (
|
68
|
+
`ObjID` int(11) NOT NULL,
|
69
|
+
`attr1ID` int(11) NOT NULL,
|
70
|
+
`Val` int(11) NOT NULL,
|
71
|
+
PRIMARY KEY (`attr1ID`)
|
72
|
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
73
|
+
/*!40101 SET character_set_client = @saved_cs_client */;
|
74
|
+
|
75
|
+
LOCK TABLES `attr1` WRITE;
|
76
|
+
/*!40000 ALTER TABLE `attr1` DISABLE KEYS */;
|
77
|
+
INSERT INTO `attr1` VALUES (1,1,3),(2,2,2),(3,3,1);
|
78
|
+
/*!40000 ALTER TABLE `attr1` ENABLE KEYS */;
|
79
|
+
UNLOCK TABLES;
|
80
|
+
|
81
|
+
DROP TABLE IF EXISTS `attr2`;
|
82
|
+
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
83
|
+
/*!40101 SET character_set_client = utf8 */;
|
84
|
+
CREATE TABLE `attr2` (
|
85
|
+
`ObjID` int(11) NOT NULL,
|
86
|
+
`attr2ID` int(11) NOT NULL,
|
87
|
+
`Val` int(11) NOT NULL,
|
88
|
+
PRIMARY KEY (`attr2ID`)
|
89
|
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
90
|
+
/*!40101 SET character_set_client = @saved_cs_client */;
|
91
|
+
|
92
|
+
LOCK TABLES `attr2` WRITE;
|
93
|
+
/*!40000 ALTER TABLE `attr2` DISABLE KEYS */;
|
94
|
+
INSERT INTO `attr2` VALUES (1,3,4),(2,2,5),(3,1,6);
|
95
|
+
/*!40000 ALTER TABLE `attr2` ENABLE KEYS */;
|
96
|
+
UNLOCK TABLES;
|
97
|
+
|
98
|
+
DROP TABLE IF EXISTS `attr3`;
|
99
|
+
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
100
|
+
/*!40101 SET character_set_client = utf8 */;
|
101
|
+
CREATE TABLE `attr3` (
|
102
|
+
`attr3ID` int(11) NOT NULL,
|
103
|
+
`Val` int(11) NOT NULL,
|
104
|
+
PRIMARY KEY (`attr3ID`)
|
105
|
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
106
|
+
/*!40101 SET character_set_client = @saved_cs_client */;
|
107
|
+
|
108
|
+
LOCK TABLES `attr3` WRITE;
|
109
|
+
/*!40000 ALTER TABLE `attr3` DISABLE KEYS */;
|
110
|
+
INSERT INTO `attr3` VALUES (1,0),(2,8),(3,7);
|
111
|
+
/*!40000 ALTER TABLE `attr3` ENABLE KEYS */;
|
112
|
+
UNLOCK TABLES;
|
113
|
+
|
114
|
+
DROP TABLE IF EXISTS `attr4`;
|
115
|
+
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
116
|
+
/*!40101 SET character_set_client = utf8 */;
|
117
|
+
CREATE TABLE `attr4` (
|
118
|
+
`attr4ID` int(11) NOT NULL,
|
119
|
+
`Val` int(11) NOT NULL,
|
120
|
+
PRIMARY KEY (`attr4ID`)
|
121
|
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
122
|
+
/*!40101 SET character_set_client = @saved_cs_client */;
|
123
|
+
|
124
|
+
LOCK TABLES `attr4` WRITE;
|
125
|
+
/*!40000 ALTER TABLE `attr4` DISABLE KEYS */;
|
126
|
+
INSERT INTO `attr4` VALUES (1,0),(2,0),(3,9);
|
127
|
+
/*!40000 ALTER TABLE `attr4` ENABLE KEYS */;
|
128
|
+
UNLOCK TABLES;
|
129
|
+
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
130
|
+
|
131
|
+
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
132
|
+
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
133
|
+
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
134
|
+
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
135
|
+
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
136
|
+
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
137
|
+
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
data/lib/flattendb/base.rb
CHANGED
@@ -27,9 +27,8 @@
|
|
27
27
|
#++
|
28
28
|
|
29
29
|
require 'yaml'
|
30
|
-
|
31
|
-
require 'rubygems'
|
32
30
|
require 'builder'
|
31
|
+
require 'flattendb'
|
33
32
|
|
34
33
|
module FlattenDB
|
35
34
|
|
@@ -49,8 +48,12 @@ module FlattenDB
|
|
49
48
|
|
50
49
|
class << self
|
51
50
|
|
51
|
+
def to_flat!(*args)
|
52
|
+
new(*args).flatten!.to_xml
|
53
|
+
end
|
54
|
+
|
52
55
|
def types
|
53
|
-
Base.instance_variable_get
|
56
|
+
Base.instance_variable_get(:@types)
|
54
57
|
end
|
55
58
|
|
56
59
|
def [](type)
|
@@ -67,40 +70,13 @@ module FlattenDB
|
|
67
70
|
|
68
71
|
attr_reader :root, :config, :input, :output
|
69
72
|
|
70
|
-
def initialize(
|
71
|
-
config =
|
72
|
-
when Hash
|
73
|
-
config
|
74
|
-
when String
|
75
|
-
# assume file name
|
76
|
-
YAML.load_file(config)
|
77
|
-
else
|
78
|
-
raise ArgumentError, "invalid config argument of type '#{config.class}'"
|
79
|
-
end
|
73
|
+
def initialize(options)
|
74
|
+
config = options.select { |k, _| k.is_a?(String) }
|
80
75
|
raise ArgumentError, "can't have more than one primary (root) table" if config.size > 1
|
81
76
|
|
82
77
|
(@root, @config), _ = *config # get "first" (and only) hash element
|
83
78
|
|
84
|
-
@input =
|
85
|
-
case infile
|
86
|
-
when String
|
87
|
-
infile
|
88
|
-
when File
|
89
|
-
infile.path
|
90
|
-
else
|
91
|
-
raise ArgumentError, "invalid infile argument of type '#{infile.class}'"
|
92
|
-
end
|
93
|
-
}
|
94
|
-
|
95
|
-
@output = case outfile
|
96
|
-
when IO
|
97
|
-
outfile
|
98
|
-
when String
|
99
|
-
# assume file name
|
100
|
-
File.open(outfile, 'w')
|
101
|
-
else
|
102
|
-
raise ArgumentError, "invalid outfile argument of type '#{outfile.class}'"
|
103
|
-
end
|
79
|
+
@input, @output = options.values_at(:input, :output)
|
104
80
|
end
|
105
81
|
|
106
82
|
def flatten!(*args)
|
data/lib/flattendb/cli.rb
CHANGED
@@ -26,52 +26,212 @@
|
|
26
26
|
###############################################################################
|
27
27
|
#++
|
28
28
|
|
29
|
+
require 'optparse'
|
30
|
+
require 'yaml'
|
31
|
+
require 'zlib'
|
32
|
+
require 'flattendb'
|
33
|
+
|
29
34
|
module FlattenDB
|
30
35
|
|
31
|
-
|
36
|
+
class CLI
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
USAGE = "Usage: #{$0} [-h|--help] [options]"
|
39
|
+
|
40
|
+
DEFAULTS = {
|
41
|
+
:input => '-',
|
42
|
+
:inputs => [],
|
43
|
+
:output => '-',
|
44
|
+
:config => 'config.yaml'
|
45
|
+
}
|
46
|
+
|
47
|
+
TYPES = {
|
48
|
+
:mysql => {
|
49
|
+
:title => 'MySQL',
|
50
|
+
:opts => lambda { |opts, options|
|
51
|
+
opts.on('-x', '--xml', 'Input file is of type XML [This is the default]') {
|
52
|
+
options[:type] = :xml
|
53
|
+
}
|
54
|
+
opts.on('-s', '--sql', 'Input file is of type SQL') {
|
55
|
+
options[:type] = :sql
|
56
|
+
}
|
57
|
+
}
|
58
|
+
},
|
59
|
+
:mdb => {
|
60
|
+
:title => 'MS Access',
|
61
|
+
:opts => lambda { |opts, options|
|
62
|
+
opts.separator(" NOTE: Repeat '-i' for each .mdb file")
|
63
|
+
}
|
40
64
|
}
|
65
|
+
}
|
66
|
+
|
67
|
+
def self.execute(type = nil, *args)
|
68
|
+
new(type).execute(*args)
|
41
69
|
end
|
42
70
|
|
43
|
-
|
44
|
-
|
45
|
-
catch :cmd_found do
|
46
|
-
ENV['PATH'].split(':').each { |path|
|
47
|
-
throw :cmd_found if File.executable?(File.join(path, cmd))
|
48
|
-
}
|
71
|
+
attr_reader :type, :options, :config, :defaults
|
72
|
+
attr_reader :stdin, :stdout, :stderr
|
49
73
|
|
50
|
-
|
51
|
-
|
52
|
-
|
74
|
+
def initialize(type = nil, defaults = DEFAULTS)
|
75
|
+
@defaults = defaults
|
76
|
+
|
77
|
+
reset(type)
|
78
|
+
|
79
|
+
# prevent backtrace on ^C
|
80
|
+
trap(:INT) { exit 130 }
|
53
81
|
end
|
54
82
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
83
|
+
def execute(arguments = [], *inouterr)
|
84
|
+
reset(type, *inouterr)
|
85
|
+
|
86
|
+
parse_options(arguments, defaults)
|
58
87
|
|
59
|
-
|
88
|
+
if type
|
89
|
+
require "flattendb/types/#{type}"
|
90
|
+
else
|
91
|
+
abort 'Database type is required!'
|
92
|
+
end
|
93
|
+
|
94
|
+
options[:input] = if type == :mdb
|
95
|
+
if options[:inputs].empty?
|
96
|
+
if arguments.empty?
|
97
|
+
options[:inputs] << options[:input]
|
98
|
+
else
|
99
|
+
options[:inputs].concat(arguments)
|
100
|
+
arguments.clear
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
options[:inputs].map! { |file| open_file_or_std(file) }
|
105
|
+
else
|
106
|
+
open_file_or_std(
|
107
|
+
options[:inputs].last || arguments.shift || options[:input]
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
abort USAGE unless arguments.empty?
|
112
|
+
|
113
|
+
options[:output] = open_file_or_std(options[:output], true)
|
114
|
+
|
115
|
+
FlattenDB[type].to_flat!(options)
|
116
|
+
ensure
|
117
|
+
options[:output].close if options[:output].is_a?(Zlib::GzipWriter)
|
118
|
+
end
|
119
|
+
|
120
|
+
def reset(type = nil, stdin = STDIN, stdout = STDOUT, stderr = STDERR)
|
121
|
+
@stdin, @stdout, @stderr = stdin, stdout, stderr
|
122
|
+
self.type, @options, @config = type, {}, {}
|
60
123
|
end
|
61
124
|
|
62
125
|
private
|
63
126
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
127
|
+
def type=(type)
|
128
|
+
if type
|
129
|
+
@type = type.to_s.downcase.to_sym
|
130
|
+
abort "Database type not supported: #{type}" unless TYPES.has_key?(@type)
|
131
|
+
else
|
132
|
+
@type = nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def open_file_or_std(file, write = false)
|
137
|
+
if file == '-'
|
138
|
+
write ? stdout : stdin
|
139
|
+
else
|
140
|
+
gz = file =~ /\.gz\z/i
|
141
|
+
|
142
|
+
if write
|
143
|
+
gz ? Zlib::GzipWriter.open(file) : File.open(file, 'w')
|
144
|
+
else
|
145
|
+
abort "No such file: #{file}" unless File.readable?(file)
|
146
|
+
(gz ? Zlib::GzipReader : File).open(file)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def warn(msg, output = stderr)
|
152
|
+
output.puts(msg)
|
153
|
+
end
|
154
|
+
|
155
|
+
def abort(msg = nil, status = 1, output = stderr)
|
156
|
+
warn(msg, output) if msg
|
157
|
+
exit(status)
|
158
|
+
end
|
159
|
+
|
160
|
+
def parse_options(arguments, defaults)
|
161
|
+
option_parser(defaults).parse!(arguments)
|
162
|
+
|
163
|
+
config_file = options[:config] || defaults[:config]
|
164
|
+
@config = YAML.load_file(config_file) if File.readable?(config_file)
|
165
|
+
|
166
|
+
[config, defaults].each { |hash| hash.each { |key, value| options[key] ||= value } }
|
167
|
+
end
|
168
|
+
|
169
|
+
def option_parser(defaults)
|
170
|
+
sorted_types = TYPES.keys.sort_by { |t| t.to_s }
|
171
|
+
|
172
|
+
OptionParser.new { |opts|
|
173
|
+
opts.banner = USAGE
|
174
|
+
|
175
|
+
if type
|
176
|
+
opts.separator ''
|
177
|
+
opts.separator "TYPE = #{type} (#{TYPES[type][:title]})"
|
178
|
+
end
|
179
|
+
|
180
|
+
opts.separator ''
|
181
|
+
opts.separator 'Options:'
|
182
|
+
|
183
|
+
unless type
|
184
|
+
opts.on('-t', '--type TYPE', 'Type of database [REQUIRED]') { |type|
|
185
|
+
self.type = type
|
186
|
+
}
|
187
|
+
|
188
|
+
opts.separator ''
|
189
|
+
end
|
190
|
+
|
191
|
+
opts.on('-i', '--input FILE', 'Input file(s) [Default: STDIN]') { |input|
|
192
|
+
(options[:inputs] ||= []) << input
|
193
|
+
}
|
194
|
+
|
195
|
+
opts.on('-o', '--output FILE', 'Output file (flat XML) [Default: STDOUT]') { |output|
|
196
|
+
options[:output] = output
|
197
|
+
}
|
198
|
+
|
199
|
+
opts.on('-c', '--config FILE', "Configuration file (YAML) [Default: #{defaults[:config]}#{' (currently not present)' unless File.readable?(defaults[:config])}]") { |config|
|
200
|
+
options[:config] = config
|
201
|
+
}
|
202
|
+
|
203
|
+
opts.separator ''
|
204
|
+
opts.separator 'Database-specific options:'
|
205
|
+
|
206
|
+
type ? type_options(opts) : sorted_types.each { |t| type_options(opts, true, t) }
|
67
207
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
208
|
+
opts.separator ''
|
209
|
+
opts.separator 'Generic options:'
|
210
|
+
|
211
|
+
opts.on('-h', '--help', 'Print this help message and exit') {
|
212
|
+
abort opts.to_s
|
73
213
|
}
|
74
|
-
|
214
|
+
|
215
|
+
opts.on('--version', 'Print program version and exit') {
|
216
|
+
abort "#{File.basename($0)} v#{FlattenDB::VERSION}"
|
217
|
+
}
|
218
|
+
|
219
|
+
unless type
|
220
|
+
opts.separator ''
|
221
|
+
opts.separator "Supported database types: #{sorted_types.map { |t| "#{t} (#{TYPES[t][:title]})" }.join(', ')}."
|
222
|
+
end
|
223
|
+
}
|
224
|
+
end
|
225
|
+
|
226
|
+
def type_options(opts, heading = false, type = type)
|
227
|
+
cfg = TYPES[type]
|
228
|
+
|
229
|
+
if heading
|
230
|
+
opts.separator ''
|
231
|
+
opts.separator " - [#{type}] #{cfg[:title]}"
|
232
|
+
end
|
233
|
+
|
234
|
+
cfg[:opts][opts, options]
|
75
235
|
end
|
76
236
|
|
77
237
|
end
|
data/lib/flattendb/types/mdb.rb
CHANGED
@@ -26,16 +26,28 @@
|
|
26
26
|
###############################################################################
|
27
27
|
#++
|
28
28
|
|
29
|
-
require '
|
29
|
+
require 'fastercsv'
|
30
|
+
require 'nuggets/file/which'
|
31
|
+
require 'flattendb'
|
30
32
|
|
31
33
|
module FlattenDB
|
32
34
|
|
33
35
|
class MDB < Base
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
def initialize(infiles, outfile, config)
|
37
|
+
def initialize(options)
|
38
38
|
super
|
39
|
+
parse
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse
|
43
|
+
tables_cmd, export_cmd = 'mdb-tables', 'mdb-export'
|
44
|
+
|
45
|
+
[tables_cmd, export_cmd].each { |cmd|
|
46
|
+
next if File.which(cmd)
|
47
|
+
abort "Command not found: #{cmd}! Please install `mdbtools' first."
|
48
|
+
}
|
49
|
+
|
50
|
+
# ...
|
39
51
|
end
|
40
52
|
|
41
53
|
def flatten!(options = {}, builder_options = {})
|
@@ -27,8 +27,8 @@
|
|
27
27
|
#++
|
28
28
|
|
29
29
|
require 'libxml'
|
30
|
-
|
31
|
-
require 'flattendb
|
30
|
+
require 'athena'
|
31
|
+
require 'flattendb'
|
32
32
|
|
33
33
|
module FlattenDB
|
34
34
|
|
@@ -36,22 +36,21 @@ module FlattenDB
|
|
36
36
|
|
37
37
|
JOIN_KEY = '@key'
|
38
38
|
|
39
|
-
attr_reader :
|
39
|
+
attr_reader :type, :name, :tables, :builder
|
40
40
|
|
41
|
-
def initialize(
|
41
|
+
def initialize(options)
|
42
42
|
super
|
43
43
|
|
44
|
-
@
|
45
|
-
@
|
46
|
-
|
47
|
-
@tables = {}
|
44
|
+
@type = options[:type] || :xml
|
45
|
+
@name, @tables = parse
|
46
|
+
end
|
48
47
|
|
49
|
-
|
48
|
+
def parse(tables = {})
|
49
|
+
[send("parse_#{type}", tables) || 'root', tables]
|
50
50
|
end
|
51
51
|
|
52
52
|
def flatten!(options = {}, builder_options = {})
|
53
53
|
flatten_tables!(tables, root, config)
|
54
|
-
|
55
54
|
self
|
56
55
|
end
|
57
56
|
|
@@ -76,9 +75,12 @@ module FlattenDB
|
|
76
75
|
|
77
76
|
private
|
78
77
|
|
79
|
-
def
|
78
|
+
def parse_xml(tables)
|
79
|
+
document = LibXML::XML::Document.io(input)
|
80
|
+
database = document.root.find_first('database[@name]')
|
81
|
+
|
80
82
|
database.find('table_data[@name]').each { |table|
|
81
|
-
rows = []
|
83
|
+
rows = tables[table[:name]] ||= []
|
82
84
|
|
83
85
|
table.find('row').each { |row|
|
84
86
|
fields = {}
|
@@ -89,9 +91,44 @@ module FlattenDB
|
|
89
91
|
|
90
92
|
rows << fields
|
91
93
|
}
|
94
|
+
}
|
92
95
|
|
93
|
-
|
96
|
+
database[:name]
|
97
|
+
end
|
98
|
+
|
99
|
+
def parse_sql(tables)
|
100
|
+
columns, table, name = Hash.new { |h, k| h[k] = [] }, nil, nil
|
101
|
+
parser = Athena::Formats::MySQL::SQLParser.new
|
102
|
+
|
103
|
+
input.each { |line|
|
104
|
+
case line
|
105
|
+
when /\AUSE\s+`(.+?)`/i
|
106
|
+
raise 'dump file contains more than one database' if name
|
107
|
+
name = $1
|
108
|
+
when /\ACREATE\s+TABLE\s+`(.+?)`/i
|
109
|
+
table = $1
|
110
|
+
when /\A\s+`(.+?)`/i
|
111
|
+
columns[table] << $1 if table
|
112
|
+
when /\A\).*;\Z/
|
113
|
+
table = nil
|
114
|
+
when /\AINSERT\s+INTO\s+`(.+?)`\s+VALUES\s*(.*);\Z/i
|
115
|
+
_columns = columns[_table = $1]
|
116
|
+
next if _columns.empty?
|
117
|
+
|
118
|
+
parser.parse($2) { |row|
|
119
|
+
fields = {}
|
120
|
+
|
121
|
+
row.each_with_index { |value, index|
|
122
|
+
column = _columns[index] or next
|
123
|
+
fields[column] = value.to_s
|
124
|
+
}
|
125
|
+
|
126
|
+
(tables[_table] ||= []) << fields
|
127
|
+
}
|
128
|
+
end
|
94
129
|
}
|
130
|
+
|
131
|
+
name
|
95
132
|
end
|
96
133
|
|
97
134
|
def flatten_tables!(tables, primary_table, config)
|
@@ -144,7 +181,7 @@ module FlattenDB
|
|
144
181
|
builder.tag!(table) {
|
145
182
|
rows.each { |row|
|
146
183
|
row_to_xml('row', row, builder)
|
147
|
-
}
|
184
|
+
} if rows
|
148
185
|
}
|
149
186
|
end
|
150
187
|
|
data/lib/flattendb/version.rb
CHANGED
data/lib/flattendb.rb
CHANGED
@@ -27,10 +27,13 @@
|
|
27
27
|
#++
|
28
28
|
|
29
29
|
require 'flattendb/version'
|
30
|
-
require 'flattendb/base'
|
31
30
|
|
32
31
|
module FlattenDB
|
33
32
|
|
33
|
+
autoload :Base, 'flattendb/base'
|
34
|
+
autoload :MDB, 'flattendb/types/mdb'
|
35
|
+
autoload :MySQL, 'flattendb/types/mysql'
|
36
|
+
|
34
37
|
extend self
|
35
38
|
|
36
39
|
def [](type)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flattendb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.8
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jens Wille
|
@@ -15,10 +15,10 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-12 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: libxml-ruby
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
none: false
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
type: :runtime
|
33
33
|
version_requirements: *id001
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
35
|
+
name: builder
|
36
36
|
prerelease: false
|
37
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
38
|
none: false
|
@@ -46,7 +46,7 @@ dependencies:
|
|
46
46
|
type: :runtime
|
47
47
|
version_requirements: *id002
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
|
-
name:
|
49
|
+
name: ruby-nuggets
|
50
50
|
prerelease: false
|
51
51
|
requirement: &id003 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
@@ -60,17 +60,19 @@ dependencies:
|
|
60
60
|
type: :runtime
|
61
61
|
version_requirements: *id003
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
63
|
+
name: athena
|
64
64
|
prerelease: false
|
65
65
|
requirement: &id004 !ruby/object:Gem::Requirement
|
66
66
|
none: false
|
67
67
|
requirements:
|
68
68
|
- - ">="
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
hash:
|
70
|
+
hash: 17
|
71
71
|
segments:
|
72
72
|
- 0
|
73
|
-
|
73
|
+
- 1
|
74
|
+
- 5
|
75
|
+
version: 0.1.5
|
74
76
|
type: :runtime
|
75
77
|
version_requirements: *id004
|
76
78
|
description: Flatten relational databases.
|
@@ -100,6 +102,7 @@ files:
|
|
100
102
|
- Rakefile
|
101
103
|
- COPYING
|
102
104
|
- example/mysql-sample.flat.xml
|
105
|
+
- example/mysql-sample.flat-sql.xml
|
103
106
|
- example/mysql-sample2flat.yaml
|
104
107
|
- example/mysql-sample.xml
|
105
108
|
- example/mysql-sample.sql
|
@@ -111,7 +114,7 @@ rdoc_options:
|
|
111
114
|
- --charset
|
112
115
|
- UTF-8
|
113
116
|
- --title
|
114
|
-
- flattendb Application documentation (v0.0
|
117
|
+
- flattendb Application documentation (v0.1.0)
|
115
118
|
- --main
|
116
119
|
- README
|
117
120
|
- --line-numbers
|