55
66module Lhm
77 class Table
8- attr_reader :name , :columns , :indices , :pk , :ddl
8+ attr_reader :schema , : name, :columns , :indices , :constraints , :pk , :ddl
99
10- def initialize ( name , pk = 'id' , ddl = nil )
10+ def initialize ( name , schema = 'default' , pk = 'id' , ddl = nil )
1111 @name = name
12+ @schema = schema
1213 @columns = { }
1314 @indices = { }
15+ @constraints = { }
1416 @pk = pk
1517 @ddl = ddl
1618 end
@@ -28,6 +30,32 @@ def self.parse(table_name, connection)
2830 Parser . new ( table_name , connection ) . parse
2931 end
3032
33+ def destination_ddl
34+ original = %r{CREATE TABLE ("|`)#{ name } \1 }
35+ repl = '\1'
36+ replacement = %Q{CREATE TABLE #{ repl } #{ destination_name } #{ repl } }
37+
38+ dest = ddl
39+ dest . gsub! ( original , replacement )
40+
41+ foreign_keys = constraints . select { |col , c | !c [ :referenced_column ] . nil? }
42+
43+ foreign_keys . keys . each_with_index do |key , i |
44+ original = foreign_keys [ key ] [ :name ]
45+ replacement = replacement_constraint ( original )
46+ dest . gsub! ( original , replacement )
47+ end
48+
49+ dest
50+ end
51+
52+ @@schema_constraints = { }
53+
54+ def self . schema_constraints ( schema , value = nil )
55+ @@schema_constraints [ schema ] = value if value
56+ @@schema_constraints [ schema ]
57+ end
58+
3159 class Parser
3260 include SqlHelper
3361
@@ -47,7 +75,7 @@ def ddl
4775 def parse
4876 schema = read_information_schema
4977
50- Table . new ( @table_name , extract_primary_key ( schema ) , ddl ) . tap do |table |
78+ Table . new ( @table_name , @schema_name , extract_primary_key ( schema ) , ddl ) . tap do |table |
5179 schema . each do |defn |
5280 column_name = struct_key ( defn , 'COLUMN_NAME' )
5381 column_type = struct_key ( defn , 'COLUMN_TYPE' )
@@ -64,6 +92,15 @@ def parse
6492 extract_indices ( read_indices ) . each do |idx , columns |
6593 table . indices [ idx ] = columns
6694 end
95+
96+ constraints = { }
97+ extract_constraints ( read_constraints ( nil ) ) . each do |data |
98+ if data [ :schema ] == @schema_name && data [ :table ] == @table_name
99+ table . constraints [ data [ :column ] ] = data
100+ end
101+ constraints [ data [ :name ] ] = data
102+ end
103+ Table . schema_constraints ( @schema_name , constraints )
67104 end
68105 end
69106
@@ -98,6 +135,47 @@ def extract_indices(indices)
98135 end
99136 end
100137
138+ def read_constraints ( table = @table_name )
139+ query = %Q{
140+ select *
141+ from information_schema.key_column_usage
142+ where table_schema = '#{ @schema_name } '
143+ and referenced_column_name is not null
144+ }
145+ query += %Q{
146+ and table_name = '#{ @table_name } '
147+ } if table
148+
149+ @connection . select_all ( query )
150+ end
151+
152+ def extract_constraints ( constraints )
153+ columns = %w{
154+ CONSTRAINT_NAME
155+ TABLE_SCHEMA
156+ TABLE_NAME
157+ COLUMN_NAME
158+ ORDINAL_POSITION
159+ POSITION_IN_UNIQUE_CONSTRAINT
160+ REFERENCED_TABLE_SCHEMA
161+ REFERENCED_TABLE_NAME
162+ REFERENCED_COLUMN_NAME
163+ }
164+
165+ constraints . map do |row |
166+ result = { }
167+ columns . each do |c |
168+ sym = c . dup
169+ # The order of these substitutions is important
170+ sym . gsub! ( /CONSTRAINT_/ , '' )
171+ sym . gsub! ( /_NAME/ , '' )
172+ sym . gsub! ( /TABLE_/ , '' )
173+ result [ sym . downcase . to_sym ] = row [ struct_key ( row , c ) ]
174+ end
175+ result
176+ end
177+ end
178+
101179 def extract_primary_key ( schema )
102180 cols = schema . select do |defn |
103181 column_key = struct_key ( defn , 'COLUMN_KEY' )
@@ -112,5 +190,12 @@ def extract_primary_key(schema)
112190 keys . length == 1 ? keys . first : keys
113191 end
114192 end
193+
194+ private
195+
196+ def replacement_constraint ( name )
197+ ( name =~ /_lhmn$/ ) . nil? ? "#{ name } _lhmn" : name . gsub ( /_lhmn$/ , '' )
198+ end
199+
115200 end
116201end
0 commit comments