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.
@@ -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);