flattendb 0.0.1.96

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,33 @@
1
+ = flattendb - Flatten relational databases
2
+
3
+ == VERSION
4
+
5
+ This documentation refers to flattendb version 0.0.1
6
+
7
+
8
+ == DESCRIPTION
9
+
10
+ TODO: well, the description... ;-)
11
+
12
+
13
+ == AUTHORS
14
+
15
+ * Jens Wille <mailto:jens.wille@uni-koeln.de>
16
+
17
+
18
+ == LICENSE AND COPYRIGHT
19
+
20
+ Copyright (C) 2007 University of Cologne,
21
+ Albertus-Magnus-Platz, 50932 Cologne, Germany
22
+
23
+ flattendb is free software: you can redistribute it and/or modify it under the
24
+ terms of the GNU General Public License as published by the Free Software
25
+ Foundation, either version 3 of the License, or (at your option) any later
26
+ version.
27
+
28
+ flattendb is distributed in the hope that it will be useful, but WITHOUT ANY
29
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
30
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31
+
32
+ You should have received a copy of the GNU General Public License along with
33
+ flattendb. If not, see <http://www.gnu.org/licenses/>.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'lib/flattendb/version'
2
+
3
+ FILES = FileList['lib/**/*.rb'].to_a
4
+ EXECS = FileList['bin/*'].to_a
5
+ RDOCS = %w[README COPYING ChangeLog]
6
+ OTHER = FileList['[A-Z]*', 'example/*'].to_a
7
+
8
+ task(:doc_spec) {{
9
+ :title => 'flattendb Application documentation',
10
+ :rdoc_files => RDOCS + FILES
11
+ }}
12
+
13
+ task(:gem_spec) {{
14
+ :name => 'flattendb',
15
+ :version => FlattenDB::VERSION,
16
+ :summary => 'Flatten relational databases',
17
+ :files => FILES + EXECS + OTHER,
18
+ :require_path => 'lib',
19
+ :bindir => 'bin',
20
+ :executables => EXECS,
21
+ :extra_rdoc_files => RDOCS,
22
+ :dependencies => %w[highline mysql libxml-ruby builder]
23
+ }}
data/bin/flattendb ADDED
@@ -0,0 +1,129 @@
1
+ #! /usr/bin/ruby
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # flattendb -- Flatten relational databases #
7
+ # #
8
+ # Copyright (C) 2007 University of Cologne, #
9
+ # Albertus-Magnus-Platz, #
10
+ # 50932 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 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 General Public License for #
23
+ # more details. #
24
+ # #
25
+ # You should have received a copy of the GNU General Public License along #
26
+ # with flattendb. If not, see <http://www.gnu.org/licenses/>. #
27
+ # #
28
+ ###############################################################################
29
+ #++
30
+
31
+ require 'optparse'
32
+
33
+ require 'rubygems'
34
+ require 'highline/import'
35
+
36
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
37
+
38
+ require 'flattendb'
39
+
40
+ USAGE = "Usage: #{$0} [-h|--help] [options] <infile> <outfile> <configfile>"
41
+
42
+ $options = {
43
+ :type => :mysql,
44
+ :mysql => {
45
+ :intype => :xml,
46
+ :keep => false
47
+ }
48
+ }
49
+
50
+ def type_options(type, opts, with_heading = true)
51
+ heading = lambda { |name|
52
+ if with_heading
53
+ opts.separator ''
54
+ opts.separator "- #{name}"
55
+ end
56
+ }
57
+
58
+ case type.to_sym
59
+ when :mysql
60
+ heading['MySQL']
61
+
62
+ opts.on('-x', '--xml', "Input file is of type XML [This is the default]") {
63
+ $options[:mysql][:intype] = :xml
64
+ }
65
+ opts.on('-s', '--sql', "Input file is of type SQL") {
66
+ $options[:mysql][:intype] = :sql
67
+ }
68
+ opts.on('-k', '--keep', "Keep intermediate XML dump; only applies if input type is 'sql'") {
69
+ $options[:mysql][:keep] = true
70
+ }
71
+ end
72
+ end
73
+
74
+ OptionParser.new { |opts|
75
+ opts.banner = USAGE
76
+ opts.separator ''
77
+
78
+ opts.separator 'Options:'
79
+ if $type
80
+ opts.separator " [-t, --type] TYPE OVERRIDE IN EFFECT (#{$type})"
81
+ else
82
+ opts.on('-t', '--type TYPE', "Type of database at hand [Default: #{$options[:type]}]") { |t|
83
+ $options[:type] = t.downcase.to_sym
84
+ }
85
+ end
86
+
87
+ opts.separator ''
88
+ opts.separator 'Database-specific Options:'
89
+
90
+ if $type
91
+ type_options($type, opts, false)
92
+ else
93
+ %w[mysql].each { |t|
94
+ type_options(t, opts)
95
+ }
96
+ end
97
+
98
+ opts.separator ''
99
+ opts.separator 'Generic options:'
100
+ opts.on('-h', '--help', 'Print this help message and exit') {
101
+ abort opts.to_s
102
+ }
103
+ opts.on('--version', 'Print program version and exit') {
104
+ abort "#{File.basename($0)} v#{FlattenDB::VERSION}"
105
+ }
106
+ }.parse!
107
+
108
+ $type ||= $options[:type]
109
+ $options = $options[$type] || {}
110
+
111
+ # Load corresponding module
112
+ begin
113
+ require "flattendb/#{$type}"
114
+ rescue LoadError
115
+ abort "Database type '#{$type}' is not supported at the moment."
116
+ end
117
+
118
+ abort USAGE unless ARGV.size == 3
119
+
120
+ $infile, $outfile, configfile = ARGV
121
+
122
+ abort "Input file not found: #{$infile}" unless File.readable?($infile)
123
+
124
+ # Load type-specific script
125
+ load File.join(File.dirname(__FILE__), "flattendb.#{$type}")
126
+
127
+ FlattenDB[$type].new($infile, $outfile, configfile).flatten!.to_xml
128
+
129
+ File.delete($dump_file) if $dump_file && !$options[:keep]
@@ -0,0 +1,97 @@
1
+ #! /usr/bin/ruby
2
+
3
+ # vi:ft=ruby
4
+
5
+ #--
6
+ ###############################################################################
7
+ # #
8
+ # flattendb -- Flatten relational databases #
9
+ # #
10
+ # Copyright (C) 2007 University of Cologne, #
11
+ # Albertus-Magnus-Platz, #
12
+ # 50932 Cologne, Germany #
13
+ # #
14
+ # Authors: #
15
+ # Jens Wille <jens.wille@uni-koeln.de> #
16
+ # #
17
+ # flattendb is free software; you can redistribute it and/or modify it under #
18
+ # the terms of the GNU General Public License as published by the Free #
19
+ # Software Foundation; either version 3 of the License, or (at your option) #
20
+ # any later version. #
21
+ # #
22
+ # flattendb is distributed in the hope that it will be useful, but WITHOUT #
23
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
24
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
25
+ # more details. #
26
+ # #
27
+ # You should have received a copy of the GNU General Public License along #
28
+ # with flattendb. If not, see <http://www.gnu.org/licenses/>. #
29
+ # #
30
+ ###############################################################################
31
+ #++
32
+
33
+ if $0 == __FILE__
34
+ $type = :mysql
35
+ load File.join(File.dirname(__FILE__), 'flattendb')
36
+ else
37
+ case $options[:intype]
38
+ when :xml
39
+ abort "Input file doesn't seem to be a valid XML file, XML declaration missing" \
40
+ unless IO.read($infile, 6) == '<?xml '
41
+ when :sql
42
+ require 'mysql'
43
+
44
+ mysql_cmd = 'mysql'
45
+ dump_cmd = 'mysqldump'
46
+
47
+ [mysql_cmd, dump_cmd].each { |cmd|
48
+ catch :cmd_found do
49
+ ENV['PATH'].split(':').each { |path|
50
+ throw :cmd_found if File.executable?(File.join(path, cmd))
51
+ }
52
+
53
+ abort "Command not found: #{cmd}"
54
+ end
55
+ }
56
+
57
+ mysql_user = ask('Please enter the MySQL user name: ') \
58
+ { |q| q.default = ENV['USER'] }
59
+ mysql_pass = ask("Please enter the MySQL password for that user: ") \
60
+ { |q| q.echo = false }
61
+
62
+ # according to <http://www.adamspiers.org/computing/mysqldiff/#how> MySQL
63
+ # default permissions allow anyone to create databases beginning with the
64
+ # prefix 'test_'
65
+ temp_db = 'flattendb_temp_%d_%d' % [Time.now, $$]
66
+ temp_user = 'flattendb_user'
67
+ temp_pass = 'flattendb_pass'
68
+
69
+ $dump_file = $infile.sub(/\.(?:sql|dump)$/i, '') << '.xml'
70
+ abort "Dump file and output file are the same: #{$dump_file} = #{$outfile}" \
71
+ if File.expand_path($dump_file) == File.expand_path($outfile)
72
+
73
+ mysql_args = "--one-database -u#{temp_user} -p#{temp_pass} #{temp_db} < #{$infile}"
74
+ dump_args = "--xml -u#{temp_user} -p#{temp_pass} #{temp_db} > #{$dump_file}"
75
+
76
+ begin
77
+ mysql = Mysql.real_connect('localhost', mysql_user, mysql_pass)
78
+
79
+ mysql.query("CREATE DATABASE #{temp_db}")
80
+ mysql.query("GRANT ALL ON #{temp_db}.* TO '#{temp_user}'@'localhost' IDENTIFIED BY '#{temp_pass}'")
81
+
82
+ system("#{mysql_cmd} #{mysql_args} && #{dump_cmd} #{dump_args}")
83
+ rescue Mysql::Error => err
84
+ abort "ERROR #{err.errno} (#{err.sqlstate}): #{err.error}"
85
+ ensure
86
+ if mysql
87
+ mysql.query("REVOKE ALL ON #{temp_db}.* FROM '#{temp_user}'@'localhost'") \
88
+ if mysql_user == 'root'
89
+
90
+ mysql.query("DROP DATABASE IF EXISTS #{temp_db}")
91
+ mysql.close
92
+ end
93
+ end
94
+
95
+ $infile = $dump_file
96
+ end
97
+ end
@@ -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>
File without changes
@@ -0,0 +1,162 @@
1
+ <?xml version="1.0"?>
2
+ <mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3
+ <database name="ndr">
4
+ <table_structure name="object">
5
+ <field Field="ObjID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
6
+ <field Field="Bla" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
7
+ <field Field="Blub" Type="varchar(50)" Null="YES" Key="" Extra="" />
8
+ <options Name="object" Engine="MyISAM" Version="10" Row_format="Fixed" Collation="utf8_general_ci" Create_options="" Comment="" />
9
+ </table_structure>
10
+ <table_data name="object">
11
+ <row>
12
+ <field name="ObjID">1</field>
13
+ <field name="Bla">12</field>
14
+ <field name="Blub"></field>
15
+ </row>
16
+ <row>
17
+ <field name="ObjID">2</field>
18
+ <field name="Bla">12</field>
19
+ <field name="Blub">hi</field>
20
+ </row>
21
+ <row>
22
+ <field name="ObjID">3</field>
23
+ <field name="Bla">1</field>
24
+ <field name="Blub">ho</field>
25
+ </row>
26
+ </table_data>
27
+ <table_structure name="fooobject">
28
+ <field Field="ObjID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
29
+ <field Field="attr1ID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
30
+ <field Field="attr3ID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
31
+ <field Field="Foo" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
32
+ <options Name="fooobject" Engine="MyISAM" Version="10" Row_format="Fixed" Collation="utf8_general_ci" Create_options="" Comment="" />
33
+ </table_structure>
34
+ <table_data name="fooobject">
35
+ <row>
36
+ <field name="ObjID">1</field>
37
+ <field name="attr1ID">1</field>
38
+ <field name="attr3ID">2</field>
39
+ <field name="Foo">112</field>
40
+ </row>
41
+ <row>
42
+ <field name="ObjID">2</field>
43
+ <field name="attr1ID">2</field>
44
+ <field name="attr3ID">1</field>
45
+ <field name="Foo">122</field>
46
+ </row>
47
+ <row>
48
+ <field name="ObjID">3</field>
49
+ <field name="attr1ID">3</field>
50
+ <field name="attr3ID">3</field>
51
+ <field name="Foo">111</field>
52
+ </row>
53
+ </table_data>
54
+ <table_structure name="barobject">
55
+ <field Field="ObjID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
56
+ <field Field="attr4ID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
57
+ <field Field="Bar" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
58
+ <options Name="barobject" Engine="MyISAM" Version="10" Row_format="Fixed" Collation="utf8_general_ci" Create_options="" Comment="" />
59
+ </table_structure>
60
+ <table_data name="barobject">
61
+ <row>
62
+ <field name="ObjID">1</field>
63
+ <field name="attr4ID">2</field>
64
+ <field name="Bar">1002</field>
65
+ </row>
66
+ <row>
67
+ <field name="ObjID">2</field>
68
+ <field name="attr4ID">1</field>
69
+ <field name="Bar">1200</field>
70
+ </row>
71
+ <row>
72
+ <field name="ObjID">3</field>
73
+ <field name="attr4ID">3</field>
74
+ <field name="Bar">1000</field>
75
+ </row>
76
+ </table_data>
77
+ <table_structure name="attr1">
78
+ <field Field="ObjID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
79
+ <field Field="attr1ID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
80
+ <field Field="Val" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
81
+ <options Name="attr1" Engine="MyISAM" Version="10" Row_format="Fixed" Collation="utf8_general_ci" Create_options="" Comment="" />
82
+ </table_structure>
83
+ <table_data name="attr1">
84
+ <row>
85
+ <field name="ObjID">1</field>
86
+ <field name="attr1ID">1</field>
87
+ <field name="Val">3</field>
88
+ </row>
89
+ <row>
90
+ <field name="ObjID">2</field>
91
+ <field name="attr1ID">2</field>
92
+ <field name="Val">2</field>
93
+ </row>
94
+ <row>
95
+ <field name="ObjID">3</field>
96
+ <field name="attr1ID">3</field>
97
+ <field name="Val">1</field>
98
+ </row>
99
+ </table_data>
100
+ <table_structure name="attr2">
101
+ <field Field="ObjID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
102
+ <field Field="attr2ID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
103
+ <field Field="Val" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
104
+ <options Name="attr2" Engine="MyISAM" Version="10" Row_format="Fixed" Collation="utf8_general_ci" Create_options="" Comment="" />
105
+ </table_structure>
106
+ <table_data name="attr2">
107
+ <row>
108
+ <field name="ObjID">1</field>
109
+ <field name="attr2ID">3</field>
110
+ <field name="Val">4</field>
111
+ </row>
112
+ <row>
113
+ <field name="ObjID">2</field>
114
+ <field name="attr2ID">2</field>
115
+ <field name="Val">5</field>
116
+ </row>
117
+ <row>
118
+ <field name="ObjID">3</field>
119
+ <field name="attr2ID">1</field>
120
+ <field name="Val">6</field>
121
+ </row>
122
+ </table_data>
123
+ <table_structure name="attr3">
124
+ <field Field="attr3ID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
125
+ <field Field="Val" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
126
+ <options Name="attr3" Engine="MyISAM" Version="10" Row_format="Fixed" Collation="utf8_general_ci" Create_options="" Comment="" />
127
+ </table_structure>
128
+ <table_data name="attr3">
129
+ <row>
130
+ <field name="attr3ID">1</field>
131
+ <field name="Val">0</field>
132
+ </row>
133
+ <row>
134
+ <field name="attr3ID">2</field>
135
+ <field name="Val">8</field>
136
+ </row>
137
+ <row>
138
+ <field name="attr3ID">3</field>
139
+ <field name="Val">7</field>
140
+ </row>
141
+ </table_data>
142
+ <table_structure name="attr4">
143
+ <field Field="attr4ID" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
144
+ <field Field="Val" Type="int(11)" Null="NO" Key="" Default="" Extra="" />
145
+ <options Name="attr4" Engine="MyISAM" Version="10" Row_format="Fixed" Collation="utf8_general_ci" Create_options="" Comment="" />
146
+ </table_structure>
147
+ <table_data name="attr4">
148
+ <row>
149
+ <field name="attr4ID">1</field>
150
+ <field name="Val">0</field>
151
+ </row>
152
+ <row>
153
+ <field name="attr4ID">2</field>
154
+ <field name="Val">0</field>
155
+ </row>
156
+ <row>
157
+ <field name="attr4ID">3</field>
158
+ <field name="Val">9</field>
159
+ </row>
160
+ </table_data>
161
+ </database>
162
+ </mysqldump>
@@ -0,0 +1,10 @@
1
+ object:
2
+ attr1: ObjID
3
+ attr2: ObjID
4
+ fooobject:
5
+ @key: ObjID
6
+ attr1: attr1ID
7
+ attr3: attr3ID
8
+ barobject:
9
+ @key: ObjID
10
+ attr4: attr4ID
@@ -0,0 +1,99 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # A component of flattendb, the relational database flattener. #
5
+ # #
6
+ # Copyright (C) 2007 University of Cologne, #
7
+ # Albertus-Magnus-Platz, #
8
+ # 50932 Cologne, Germany #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@uni-koeln.de> #
12
+ # #
13
+ # flattendb is free software; you can redistribute it and/or modify it under #
14
+ # the terms of the GNU General Public License as published by the Free #
15
+ # Software Foundation; either version 3 of the License, or (at your option) #
16
+ # any later version. #
17
+ # #
18
+ # flattendb is distributed in the hope that it will be useful, but WITHOUT #
19
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
20
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
21
+ # more details. #
22
+ # #
23
+ # You should have received a copy of the GNU General Public License along #
24
+ # with flattendb. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ require 'rubygems'
30
+ require 'builder'
31
+
32
+ module FlattenDB
33
+
34
+ class Base
35
+
36
+ @types = {}
37
+
38
+ BUILDER_OPTIONS = {
39
+ :xml => {
40
+ :indent => 2
41
+ }
42
+ }
43
+
44
+ # cf. <http://www.w3.org/TR/2006/REC-xml-20060816/#NT-Name>
45
+ ELEMENT_START = %r{^[a-zA-Z_:]}
46
+ ELEMENT_CHARS = %q{\w:.-}
47
+
48
+ class << self
49
+
50
+ def types
51
+ Base.instance_variable_get :@types
52
+ end
53
+
54
+ def [](type)
55
+ types[type]
56
+ end
57
+
58
+ protected
59
+
60
+ def inherited(klass)
61
+ types[klass.name.split('::')[1..-1].downcase.to_sym] = klass
62
+ end
63
+
64
+ end
65
+
66
+ def flatten!(*args)
67
+ raise NotImplementedError, 'must be defined by sub-class'
68
+ end
69
+
70
+ def to_xml(*args)
71
+ raise NotImplementedError, 'must be defined by sub-class'
72
+ end
73
+
74
+ private
75
+
76
+ def initialize_builder(type, output, builder_options = {})
77
+ builder_options = (BUILDER_OPTIONS[type] || {}).merge(builder_options)
78
+
79
+ @builder = case type
80
+ when :xml
81
+ Builder::XmlMarkup.new(builder_options.merge(:target => output))
82
+ else
83
+ raise ArgumentError, "builder of type '#{type}' not supported"
84
+ end
85
+ end
86
+
87
+ # mysql:: <http://dev.mysql.com/doc/refman/5.0/en/identifiers.html>
88
+ def column_to_element(column)
89
+ element = column.dup
90
+
91
+ element.insert(0, '_') unless element =~ ELEMENT_START
92
+ element.gsub!(/[^#{ELEMENT_CHARS}]/, '')
93
+
94
+ element
95
+ end
96
+
97
+ end
98
+
99
+ end