dbdiff 0.1.0 → 0.2.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/CHANGELOG +4 -0
- data/COPYING +340 -0
- data/lib/dbdiff.rb +63 -33
- data/lib/dbdiff/database.rb +50 -4
- data/lib/dbdiff/dbdiff_version.rb +3 -0
- data/lib/dbdiff/delta.rb +89 -0
- data/lib/dbdiff/function.rb +14 -0
- data/lib/dbdiff/procedure.rb +13 -0
- data/lib/dbdiff/routine.rb +30 -0
- data/lib/dbdiff/row.rb +9 -1
- data/lib/dbdiff/table.rb +2 -2
- data/lib/dbdiff/trigger.rb +36 -0
- data/lib/dbdiff/view.rb +33 -0
- data/test/function/source.sql +3 -0
- data/test/function/target.sql +1 -0
- data/test/modify_function/source.sql +3 -0
- data/test/modify_function/target.sql +2 -0
- data/test/modify_procedure/source.sql +8 -0
- data/test/modify_procedure/target.sql +9 -0
- data/test/modify_trigger/source.sql +9 -0
- data/test/modify_trigger/target.sql +9 -0
- data/test/modify_view/source.sql +7 -0
- data/test/modify_view/target.sql +7 -0
- data/test/procedure/source.sql +8 -0
- data/test/procedure/target.sql +1 -0
- data/test/suite.rb +3 -0
- data/test/test_dbdiff.rb +13 -5
- data/test/test_function.rb +69 -0
- data/test/test_procedure.rb +64 -0
- data/test/test_row.rb +45 -9
- data/test/test_trigger.rb +68 -0
- data/test/trigger/source.sql +9 -0
- data/test/trigger/target.sql +7 -0
- data/test/view/source.sql +7 -0
- data/test/view/target.sql +9 -0
- metadata +37 -2
data/lib/dbdiff/database.rb
CHANGED
@@ -2,6 +2,10 @@ require 'rubygems'
|
|
2
2
|
require 'mysql'
|
3
3
|
require 'dbdiff/delta'
|
4
4
|
require 'dbdiff/table_element'
|
5
|
+
require 'dbdiff/view'
|
6
|
+
require 'dbdiff/trigger'
|
7
|
+
require 'dbdiff/procedure'
|
8
|
+
require 'dbdiff/function'
|
5
9
|
require 'dbdiff/table'
|
6
10
|
require 'dbdiff/column'
|
7
11
|
require 'dbdiff/foreign_key'
|
@@ -11,7 +15,7 @@ class DbDiff
|
|
11
15
|
|
12
16
|
# XXX validate state of information_schema?
|
13
17
|
class Database
|
14
|
-
attr_reader :dbh, :tables, :name, :host, :user, :password
|
18
|
+
attr_reader :dbh, :tables, :procedures, :functions, :views, :name, :host, :user, :password
|
15
19
|
attr_accessor :deltas
|
16
20
|
|
17
21
|
# XXX add version check
|
@@ -24,6 +28,10 @@ class DbDiff
|
|
24
28
|
@deltas = []
|
25
29
|
|
26
30
|
initialize_tables
|
31
|
+
initialize_functions
|
32
|
+
initialize_procedures
|
33
|
+
initialize_triggers
|
34
|
+
initialize_views
|
27
35
|
initialize_columns
|
28
36
|
initialize_keys
|
29
37
|
initialize_foreign_keys
|
@@ -34,9 +42,38 @@ class DbDiff
|
|
34
42
|
@tables + @deltas.find_all{|d| d.class == Delta::AddTable }.map {|x| x.element}
|
35
43
|
end
|
36
44
|
|
45
|
+
def initialize_triggers
|
46
|
+
select_is(:triggers, :trigger_schema => self.name) do |h|
|
47
|
+
t = Trigger.new(h)
|
48
|
+
tb = table(t.table_name)
|
49
|
+
tb.triggers << t if tb
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize_functions
|
54
|
+
@functions = []
|
55
|
+
select_mysql(:proc, :type => 'FUNCTION') do |h|
|
56
|
+
@functions << Function.new(h)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize_procedures
|
61
|
+
@procedures = []
|
62
|
+
select_mysql(:proc, :type => 'PROCEDURE') do |h|
|
63
|
+
@procedures << Procedure.new(h)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize_views
|
68
|
+
@views = []
|
69
|
+
select_is(:views, :table_schema => self.name) do |h|
|
70
|
+
@views << View.new(h)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
37
74
|
def initialize_tables
|
38
75
|
@tables = []
|
39
|
-
select_is(:tables, :table_schema => self.name) do |h|
|
76
|
+
select_is(:tables, :table_schema => self.name, :table_type => 'BASE TABLE') do |h|
|
40
77
|
t = Table.new(h)
|
41
78
|
t.charset = charset(t.collation)
|
42
79
|
|
@@ -58,7 +95,9 @@ class DbDiff
|
|
58
95
|
|
59
96
|
select_is(:columns) do |h|
|
60
97
|
c = Column.new(h)
|
61
|
-
table(c.table_name)
|
98
|
+
t = table(c.table_name)
|
99
|
+
# we may not have the table since we get view columns here
|
100
|
+
t.columns << c if t
|
62
101
|
end
|
63
102
|
end
|
64
103
|
|
@@ -97,11 +136,18 @@ class DbDiff
|
|
97
136
|
end
|
98
137
|
end
|
99
138
|
|
139
|
+
def select_mysql(table, where = {}, &block)
|
140
|
+
@dbh.select_db('mysql')
|
141
|
+
# XXX
|
142
|
+
where[:db] = self.name
|
143
|
+
self._select(table, where, &block)
|
144
|
+
end
|
145
|
+
|
100
146
|
def select_is(table, where = {}, &block)
|
101
147
|
@dbh.select_db('information_schema')
|
102
148
|
|
103
149
|
# XXX
|
104
|
-
where[:table_schema] = self.name unless table == :character_sets
|
150
|
+
where[:table_schema] = self.name unless table == :character_sets || table == :triggers
|
105
151
|
|
106
152
|
self._select(table, where, &block)
|
107
153
|
end
|
data/lib/dbdiff/delta.rb
CHANGED
@@ -213,6 +213,7 @@ class DbDiff
|
|
213
213
|
super
|
214
214
|
# we don't clone foreign_keys or rows since
|
215
215
|
# the table_elements diff will take care of them
|
216
|
+
@element.triggers = []
|
216
217
|
@element.rows = []
|
217
218
|
@element.foreign_keys = []
|
218
219
|
end
|
@@ -260,6 +261,94 @@ class DbDiff
|
|
260
261
|
database.tables.delete(element)
|
261
262
|
end
|
262
263
|
end
|
264
|
+
|
265
|
+
class AddView < Delta
|
266
|
+
|
267
|
+
def sql
|
268
|
+
return "CREATE VIEW `%s` AS (%s)" % [element.name,element.definition]
|
269
|
+
end
|
270
|
+
|
271
|
+
def process(database)
|
272
|
+
database.views << element
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
class DropView < Delta
|
277
|
+
|
278
|
+
def sql
|
279
|
+
return "DROP VIEW `%s`" % element.name
|
280
|
+
end
|
281
|
+
|
282
|
+
def process(database)
|
283
|
+
database.views.delete(element)
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
class AddFunction < Delta
|
289
|
+
|
290
|
+
def sql
|
291
|
+
return "CREATE FUNCTION `#{element.name}` (#{element.param_list}) RETURNS #{element.returns} #{element.definition}"
|
292
|
+
end
|
293
|
+
|
294
|
+
def process(database)
|
295
|
+
database.functions << element
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
class AddProcedure < Delta
|
300
|
+
|
301
|
+
def sql
|
302
|
+
return "CREATE PROCEDURE `#{element.name}` (#{element.param_list}) #{element.definition}"
|
303
|
+
end
|
304
|
+
|
305
|
+
def process(database)
|
306
|
+
database.procedures << element
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
class DropFunction < Delta
|
311
|
+
def sql
|
312
|
+
return "DROP FUNCTION `%s`" % element.name
|
313
|
+
end
|
314
|
+
|
315
|
+
def process(database)
|
316
|
+
database.functions.delete(element)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
class DropProcedure < Delta
|
321
|
+
def sql
|
322
|
+
return "DROP PROCEDURE `%s`" % element.name
|
323
|
+
end
|
324
|
+
|
325
|
+
def process(database)
|
326
|
+
database.procedures.delete(element)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
class AddTrigger < Delta
|
331
|
+
|
332
|
+
def sql
|
333
|
+
return "CREATE TRIGGER `#{element.name}` #{element.timing} #{element.event} ON #{element.table_name} FOR EACH ROW #{element.definition}"
|
334
|
+
end
|
335
|
+
|
336
|
+
def process(database)
|
337
|
+
table(database).triggers << element
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
class DropTrigger < Delta
|
342
|
+
|
343
|
+
def sql
|
344
|
+
return "DROP TRIGGER `#{element.name}`"
|
345
|
+
end
|
346
|
+
|
347
|
+
def process(database)
|
348
|
+
table(database).triggers.delete(element)
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
263
352
|
end
|
264
353
|
end
|
265
354
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class DbDiff
|
2
|
+
class Routine
|
3
|
+
attr_reader :name, :param_list, :definition, :returns, :routine_type, :comment
|
4
|
+
|
5
|
+
def initialize(info= {})
|
6
|
+
@name = info['name']
|
7
|
+
@definition = info['body']
|
8
|
+
@param_list = info['param_list']
|
9
|
+
@routine_type = info['type']
|
10
|
+
@returns = info['returns']
|
11
|
+
@comment = info['comment']
|
12
|
+
end
|
13
|
+
|
14
|
+
def modify_delta(new_element)
|
15
|
+
[self.drop_delta, new_element.add_delta]
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
self.name == other.name &&
|
20
|
+
self.param_list == other.param_list &&
|
21
|
+
self.routine_type == other.routine_type &&
|
22
|
+
self.returns == other.returns &&
|
23
|
+
self.definition == other.definition
|
24
|
+
end
|
25
|
+
|
26
|
+
def deep_clone
|
27
|
+
Marshal::load(Marshal.dump(self))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/dbdiff/row.rb
CHANGED
@@ -26,7 +26,15 @@ class DbDiff
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def ==(other)
|
29
|
-
|
29
|
+
other_data = other.data.dup
|
30
|
+
source_data = self.data.dup
|
31
|
+
|
32
|
+
%w(created_on updated_on).each do|c|
|
33
|
+
other_data.delete(c)
|
34
|
+
source_data.delete(c)
|
35
|
+
end
|
36
|
+
|
37
|
+
source_data == other_data
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
data/lib/dbdiff/table.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
class DbDiff
|
2
2
|
class Table
|
3
3
|
attr_reader :name
|
4
|
-
attr_accessor :charset, :rows, :keys, :foreign_keys, :columns, :collation, :engine
|
4
|
+
attr_accessor :charset, :rows, :triggers, :keys, :foreign_keys, :columns, :collation, :engine
|
5
5
|
|
6
6
|
def initialize(info = {})
|
7
|
-
@data = {}
|
8
7
|
|
9
8
|
@rows = []
|
10
9
|
@foreign_keys = []
|
11
10
|
@keys = []
|
12
11
|
@columns = []
|
12
|
+
@triggers = []
|
13
13
|
|
14
14
|
@engine = info['ENGINE']
|
15
15
|
@collation = info['TABLE_COLLATION']
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'dbdiff/routine'
|
2
|
+
class DbDiff
|
3
|
+
class Trigger < TableElement
|
4
|
+
attr_reader :definition, :timing, :event
|
5
|
+
# XXX may want dtd_identifier
|
6
|
+
#
|
7
|
+
def initialize(info = {})
|
8
|
+
@name = info['TRIGGER_NAME']
|
9
|
+
@table_name = info['EVENT_OBJECT_TABLE']
|
10
|
+
@definition = info['ACTION_STATEMENT']
|
11
|
+
@timing = info['ACTION_TIMING']
|
12
|
+
@event = info['EVENT_MANIPULATION']
|
13
|
+
end
|
14
|
+
|
15
|
+
def modify_delta(new_element)
|
16
|
+
[self.drop_delta, new_element.add_delta]
|
17
|
+
end
|
18
|
+
|
19
|
+
def drop_delta
|
20
|
+
Delta::DropTrigger.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_delta
|
24
|
+
Delta::AddTrigger.new(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(other)
|
28
|
+
self.name == other.name &&
|
29
|
+
self.definition == other.definition &&
|
30
|
+
self.table_name == other.table_name &&
|
31
|
+
self.timing == other.timing &&
|
32
|
+
self.event == other.event
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/dbdiff/view.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class DbDiff
|
2
|
+
class View
|
3
|
+
attr_reader :name, :definition
|
4
|
+
|
5
|
+
def initialize(info = {})
|
6
|
+
@definition = info['VIEW_DEFINITION']
|
7
|
+
@name = info['TABLE_NAME']
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
self.definition == other.definition
|
13
|
+
end
|
14
|
+
|
15
|
+
def deep_clone
|
16
|
+
t = Marshal::load(Marshal.dump(self))
|
17
|
+
# must clear rows out since they won't necessary be in the copy
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_delta
|
21
|
+
Delta::AddView.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def modify_delta(new_element)
|
25
|
+
[self.drop_delta, new_element.add_delta]
|
26
|
+
end
|
27
|
+
|
28
|
+
def drop_delta
|
29
|
+
Delta::DropView.new(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
CREATE TABLE authors (
|
2
|
+
`id` int(11) NOT NULL auto_increment,
|
3
|
+
`name` char(60) NOT NULL,
|
4
|
+
`address` char(60) NULL,
|
5
|
+
PRIMARY KEY (`id`)
|
6
|
+
) ENGINE=innodb DEFAULT CHARSET=latin1;
|
7
|
+
|
8
|
+
CREATE PROCEDURE simpleproc (OUT param1 INT) BEGIN SELECT COUNT(*) INTO param1 FROM authors WHERE id = 2; END;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
CREATE TABLE authors (
|
2
|
+
`id` int(11) NOT NULL auto_increment,
|
3
|
+
`name` char(60) NOT NULL,
|
4
|
+
`address` char(60) NULL,
|
5
|
+
PRIMARY KEY (`id`)
|
6
|
+
) ENGINE=innodb DEFAULT CHARSET=latin1;
|
7
|
+
|
8
|
+
CREATE PROCEDURE simpleproc (OUT param1 INT) BEGIN SELECT COUNT(*) INTO param1 FROM authors; END;
|
9
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
CREATE TABLE authors (
|
2
|
+
`id` int(11) NOT NULL auto_increment,
|
3
|
+
`name` char(60) NOT NULL,
|
4
|
+
`address` char(60) NULL,
|
5
|
+
PRIMARY KEY (`id`)
|
6
|
+
) ENGINE=innodb DEFAULT CHARSET=latin1;
|
7
|
+
|
8
|
+
create trigger my_auth BEFORE INSERT on authors FOR EACH ROW BEGIN SET NEW.name = 'fXXXX'; END;
|
9
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
CREATE TABLE authors (
|
2
|
+
`id` int(11) NOT NULL auto_increment,
|
3
|
+
`name` char(60) NOT NULL,
|
4
|
+
`address` char(60) NULL,
|
5
|
+
PRIMARY KEY (`id`)
|
6
|
+
) ENGINE=innodb DEFAULT CHARSET=latin1;
|
7
|
+
|
8
|
+
create trigger my_auth BEFORE INSERT on authors FOR EACH ROW BEGIN SET NEW.name = 'fOO'; END;
|
9
|
+
|