dbdiff 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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).columns << c
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
@@ -0,0 +1,3 @@
1
+ class DbDiff
2
+ Version = '0.2.0'
3
+ end
@@ -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,14 @@
1
+ require 'dbdiff/routine'
2
+ class DbDiff
3
+ class Function < Routine
4
+ # XXX may want dtd_identifier
5
+
6
+ def drop_delta
7
+ Delta::DropFunction.new(self)
8
+ end
9
+
10
+ def add_delta
11
+ Delta::AddFunction.new(self)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require 'dbdiff/routine'
2
+ class DbDiff
3
+ class Procedure < Routine
4
+ # XXX may want dtd_identifier
5
+ def drop_delta
6
+ Delta::DropProcedure.new(self)
7
+ end
8
+
9
+ def add_delta
10
+ Delta::AddProcedure.new(self)
11
+ end
12
+ end
13
+ end
@@ -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
@@ -26,7 +26,15 @@ class DbDiff
26
26
  end
27
27
 
28
28
  def ==(other)
29
- self.data == other.data
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
@@ -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
@@ -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,3 @@
1
+
2
+ create function hello (s char(20)) RETURNS char(50) return concat('hello, ', s , '!');
3
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,3 @@
1
+
2
+ create function hello (s char(20)) RETURNS char(50) return concat('hello, ', s , '!');
3
+
@@ -0,0 +1,2 @@
1
+ create function hello (s char(20)) RETURNS char(50) return concat('hello 444, ', s , '!');
2
+
@@ -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
+
@@ -0,0 +1,7 @@
1
+ CREATE TABLE authors (
2
+ `id` int(11) NOT NULL auto_increment,
3
+ `name` char(60) NOT NULL,
4
+ PRIMARY KEY (`id`)
5
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
6
+
7
+ CREATE VIEW authors_v as (SELECT * FROM authors WHERE name = 'FOO');
@@ -0,0 +1,7 @@
1
+ CREATE TABLE authors (
2
+ `id` int(11) NOT NULL auto_increment,
3
+ `name` char(60) NOT NULL,
4
+ PRIMARY KEY (`id`)
5
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
6
+
7
+ CREATE VIEW authors_v as (SELECT * FROM authors);