ramen 0.4.0 → 0.4.1

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.
@@ -183,15 +183,29 @@ SQL
183
183
 
184
184
  # returns the query for all foreign keys and their meta-data.
185
185
  #
186
- # the query must include the table_schema, table_name, and foreign_key_name.
186
+ # the query must include the table_schema, table_name, foreign_key_name,
187
+ # referenced_table_schema, referenced_table_name.
188
+ #
189
+ # note: the clause "not kcu.referenced_table_schema is null" is necessary
190
+ # on mysql to distinguish foreign keys from unique keys in kcu when
191
+ # there exists both a foreign key and unique key with the same name. see
192
+ # http://www.xcdsql.org/MySQL/information_schema/5.1/MySQL_5_1_INFORMATION_SCHEMA.html
187
193
  def Sql.foreign_keys
188
194
  <<SQL
189
195
  select
190
- constraint_schema as table_schema,
191
- table_name,
192
- constraint_name as foreign_key_name
196
+ tc.constraint_schema as table_schema,
197
+ tc.table_name,
198
+ tc.constraint_name as foreign_key_name,
199
+ kcu.referenced_table_schema,
200
+ kcu.referenced_table_name
193
201
  from information_schema.table_constraints tc
202
+ inner join information_schema.key_column_usage kcu
203
+ on tc.constraint_schema = kcu.constraint_schema
204
+ and tc.table_name = kcu.table_name
205
+ and tc.constraint_name = kcu.constraint_name
194
206
  where tc.constraint_type = 'FOREIGN KEY'
207
+ and not kcu.referenced_table_schema is null
208
+ group by table_schema,table_name,foreign_key_name,referenced_table_schema,referenced_table_name
195
209
  SQL
196
210
  end
197
211
 
@@ -200,6 +214,11 @@ SQL
200
214
  # the query must include foreign_key_name, table_schema, table_name,
201
215
  # column_name, referenced_table_schema, referenced_table_name,
202
216
  # referenced_column_name.
217
+ #
218
+ # note: the clause "not kcu.referenced_table_schema is null" is necessary
219
+ # on mysql to distinguish foreign keys from unique keys in kcu when
220
+ # there exists both a foreign key and unique key with the same name. see
221
+ # http://www.xcdsql.org/MySQL/information_schema/5.1/MySQL_5_1_INFORMATION_SCHEMA.html
203
222
  def Sql.foreign_key_columns
204
223
  <<SQL
205
224
  select
@@ -218,6 +237,35 @@ inner join information_schema.key_column_usage kcu
218
237
  and tc.table_name = kcu.table_name
219
238
  and tc.constraint_name = kcu.constraint_name
220
239
  where tc.constraint_type = 'FOREIGN KEY'
240
+ and not kcu.referenced_table_schema is null
241
+ SQL
242
+ end
243
+
244
+ # returns the query for all DML triggers.
245
+ #
246
+ # ther query must include trigger_schema, trigger_name,
247
+ # event_object_schema, event_object_table.
248
+ def Sql.triggers
249
+ <<SQL
250
+ select
251
+ trigger_schema,
252
+ trigger_name,
253
+ event_object_schema,
254
+ event_object_table,
255
+ event_manipulation,
256
+ action_order,
257
+ action_condition,
258
+ -- skipping due to size: action_statement,
259
+ action_orientation,
260
+ action_timing,
261
+ action_reference_old_table,
262
+ action_reference_new_table,
263
+ action_reference_old_row,
264
+ action_reference_new_row,
265
+ created,
266
+ sql_mode,
267
+ definer
268
+ from information_schema.triggers
221
269
  SQL
222
270
  end
223
271
  end
@@ -119,7 +119,8 @@ SQL
119
119
 
120
120
  # returns the query for all foreign keys and their meta-data.
121
121
  #
122
- # the query must include the table_schema, table_name and foreign_key_name.
122
+ # the query must include the table_schema, table_name, foreign_key_name,
123
+ # referenced_table_schema, referenced_table_name.
123
124
  def Sql.foreign_keys
124
125
  <<SQL
125
126
  select
@@ -138,6 +139,8 @@ select
138
139
  sys.foreign_keys.is_published,
139
140
  sys.foreign_keys.is_schema_published,
140
141
  sys.foreign_keys.referenced_object_id,
142
+ referenced_schema.name as referenced_table_schema,
143
+ referenced_table.name as referenced_table_name,
141
144
  sys.foreign_keys.key_index_id,
142
145
  sys.foreign_keys.is_disabled,
143
146
  sys.foreign_keys.is_not_for_replication,
@@ -152,6 +155,10 @@ inner join sys.tables on
152
155
  sys.foreign_keys.parent_object_id = sys.tables.object_id
153
156
  inner join sys.schemas on
154
157
  sys.tables.schema_id = sys.schemas.schema_id
158
+ inner join sys.tables referenced_table on
159
+ sys.foreign_keys.referenced_object_id = referenced_table.object_id
160
+ inner join sys.schemas referenced_schema on
161
+ referenced_table.schema_id = referenced_schema.schema_id
155
162
  SQL
156
163
  end
157
164
 
@@ -336,6 +343,40 @@ where sys.indexes.is_primary_key = 0
336
343
  SQL
337
344
  end
338
345
 
346
+ # returns the query for all DML triggers.
347
+ #
348
+ # ther query must include trigger_schema, trigger_name,
349
+ # event_object_schema, event_object_table.
350
+ def Sql.triggers
351
+ <<SQL
352
+ select
353
+ sys.schemas.name as trigger_schema,
354
+ t.name as trigger_name,
355
+ sys.schemas.name as event_object_schema,
356
+ sys.tables.name as event_object_table,
357
+ t.object_id,
358
+ t.parent_class,
359
+ t.parent_class_desc,
360
+ t.parent_id,
361
+ t.type,
362
+ t.type_desc,
363
+ t.create_date,
364
+ t.modify_date,
365
+ t.is_ms_shipped,
366
+ t.is_disabled,
367
+ t.is_not_for_replication,
368
+ t.is_instead_of_trigger,
369
+ te.type as event_type,
370
+ te.type_desc as event_type_desc,
371
+ te.is_first as event_is_first,
372
+ te.is_last as event_is_last
373
+ from sys.triggers t
374
+ inner join sys.trigger_events te on t.object_id = te.object_id
375
+ inner join sys.tables on t.parent_id = sys.tables.object_id -- inner join will avoid ddl triggers
376
+ inner join sys.schemas on sys.tables.schema_id = sys.schemas.schema_id
377
+ SQL
378
+ end
379
+
339
380
  # returns the query for all key constraints and their meta-data.
340
381
  #
341
382
  # the query must include the schema_id, table_id,
@@ -14,10 +14,9 @@ module Ramen::Metadata
14
14
  # Database contains many Schema objects, which are accessable through the
15
15
  # schema attribute. Schema contains many Table objects, which are accessable
16
16
  # through Schema#table. Table contains many Column, ForeignKey, Index and
17
- # KeyConstraint objects. ForeignKey contains ForeignKeyColumn objects; which
17
+ # Trigger objects. ForeignKey contains ForeignKeyColumn objects; which
18
18
  # reference the appropriate Column. Index contains IndexColumn objects; which
19
- # reference the appropriate Column. KeyConstraint objects refernece their
20
- # Index.
19
+ # reference the appropriate Column.
21
20
  #
22
21
  # For more details see: http://ramen.rubyforge.org or readme.txt[link:files/readme_txt.html]
23
22
  #
@@ -125,6 +124,7 @@ module Ramen::Metadata
125
124
  load( engine::IndexColumn, sql.index_columns, connection )
126
125
  load( engine::PrimaryKey, sql.primary_keys, connection )
127
126
  load( engine::PrimaryKeyColumn, sql.primary_key_columns, connection )
127
+ load( engine::Trigger, sql.triggers, connection )
128
128
  #load( engine::KeyConstraint, sql.key_constraints, connection )
129
129
  end
130
130
 
@@ -50,6 +50,8 @@ module Ramen::Metadata
50
50
  def initialize( record, database )
51
51
  super( record, database )
52
52
  @columns = Ramen::RamenHash.new( ForeignKeyColumn, 'column' )
53
+ @table = database.schema[ self.table_schema ].table[ self.table_name ]
54
+ @referenced_table = database.schema[ self.referenced_table_schema ].table[ self.referenced_table_name]
53
55
  end
54
56
 
55
57
  # add_to( database )
@@ -57,7 +59,8 @@ module Ramen::Metadata
57
59
  # Add self to the given database. (Choosing Message; Double Dispatch pattern)
58
60
  # (Kent Beck. Smalltalk Best Practices Patterns. Perntice Hall PTR, Upper Saddle River, NJ 1997)
59
61
  def add_to( database )
60
- database.schema[ self.table_schema ].table[ self.table_name ].add_foreign_key( self )
62
+ @table.add_foreign_key( self )
63
+ @referenced_table.add_belongs_to( self )
61
64
  end
62
65
 
63
66
  # add_column( obj ) #=> obj
@@ -67,5 +70,19 @@ module Ramen::Metadata
67
70
  def add_column( obj )
68
71
  @columns.add( obj )
69
72
  end
73
+
74
+ # referenced_table #=> Table
75
+ #
76
+ # Returns the table to which the foreign key references.
77
+ def referenced_table
78
+ @referenced_table
79
+ end
80
+
81
+ # table #=> Table
82
+ #
83
+ # Returns the table which contains this foreign key.
84
+ def table
85
+ @table
86
+ end
70
87
  end
71
88
  end
@@ -4,7 +4,7 @@
4
4
  #++
5
5
 
6
6
  module Ramen::Metadata
7
- # Table contains collections of Column, ForeignKey, Index, KeyConstraint, and
7
+ # Table contains collections of Column, ForeignKey, Index, Trigger, and
8
8
  # PrimaryKey objects. Attributes available for Table are database engine specific.
9
9
  # Ramen only requires the attributes table_name and table_id. See
10
10
  # RowDataGateway for more information.
@@ -42,6 +42,8 @@ module Ramen::Metadata
42
42
  # foreign_key() #=> RamenHash reference
43
43
  #
44
44
  # fk() #=> RamenHash reference
45
+ #
46
+ # has() #=> RamenHash reference
45
47
  #
46
48
  # This attribute provides access to a RamenHash of all ForeignKey objects
47
49
  # in the Table. The hash is indexed by foreign_key_id and foreign_key_name.
@@ -53,10 +55,39 @@ module Ramen::Metadata
53
55
  # table = schema.table['Products']
54
56
  # fk = table.fk['FK_PRODUCTS_ORDERS'] #=> #<ForeignKey...>
55
57
  #
58
+ # The methods #has and #belongs_to barrow their names from ActiveRecord. In
59
+ # ActiveRecord these terms are used to express relations between tables or
60
+ # model objects. In Ramen, #has and #belongs_to don't refer to the other Table
61
+ # directly, instead they provide access to the ForeignKeys that form the
62
+ # relationship. Use ForeignKey#table and ForeignKey#referenced_table to
63
+ # access the other Table.
56
64
  def foreign_key
57
65
  @foreign_keys
58
66
  end
59
67
  alias fk foreign_key
68
+ alias has foreign_key
69
+
70
+ # belongs_to() #=> RamenHash reference
71
+ #
72
+ # This attribute provides access to a RamenHash of all ForeignKey objects
73
+ # where referenced_table is this Table.
74
+ #
75
+ # usage:
76
+ # require 'lib/ramen'
77
+ # db = Ramen.create( configuration )
78
+ # schema = db.schema['Sales']
79
+ # table = schema.table['Orders']
80
+ # table.belongs_to['FK_PRODUCTS_ORDERS'] #=> #<ForeignKey...>
81
+ #
82
+ # The methods #has and #belongs_to get their names from ActiveRecord. In
83
+ # ActiveRecord these terms are used to express relations between tables or
84
+ # model objects. In Ramen, #has and #belongs_to don't refer to the other Table
85
+ # directly, instead they provide access to the ForeignKeys that form the
86
+ # relationship. Use ForeignKey#table and ForeignKey#referenced_table to
87
+ # access the other Table.
88
+ def belongs_to
89
+ @belongs_to
90
+ end
60
91
 
61
92
  # index() #=> RamenHash reference
62
93
  #
@@ -96,6 +127,21 @@ module Ramen::Metadata
96
127
  alias key key_constraint
97
128
  =end
98
129
 
130
+ # trigger() #=> RamenHash reference
131
+ #
132
+ # This attribute provides access to a RamenHash of all Trigger objects
133
+ # in the Table. The hash is indexed by trigger_name.
134
+ #
135
+ # usage:
136
+ # require 'ramen'
137
+ # db = Ramen.create( configuration )
138
+ # schema = db.schema['Sales']
139
+ # table = schema.table['Products']
140
+ # trigger = table.trigger['Products_Insert_Trigger'] #=> #<Trigger...>
141
+ def trigger
142
+ @triggers
143
+ end
144
+
99
145
  # primary_key() #=> PrimaryKey reference
100
146
  #
101
147
  # pk() #=> PrimaryKey reference
@@ -145,8 +191,10 @@ module Ramen::Metadata
145
191
  super( record, database )
146
192
  @columns = Ramen::RamenHash.new( Column )
147
193
  @foreign_keys = Ramen::RamenHash.new( ForeignKey )
194
+ @belongs_to = Ramen::RamenHash.new( ForeignKey )
148
195
  @indexes = Ramen::RamenHash.new( Index )
149
196
  @key_constraints = Ramen::RamenHash.new( KeyConstraint, 'key' )
197
+ @triggers = Ramen::RamenHash.new( Trigger )
150
198
  @primary_key = nil
151
199
  end
152
200
 
@@ -158,6 +206,14 @@ module Ramen::Metadata
158
206
  database.schema[ self.table_schema ].add_table( self )
159
207
  end
160
208
 
209
+ # add_belongs_to( obj ) #=> obj
210
+ #
211
+ # Adds the foreign_key to this table as a belongs_to relationship. Throws
212
+ # a RamenError if the obj is not a foreign_key
213
+ def add_belongs_to( foreign_key )
214
+ @belongs_to.add( foreign_key )
215
+ end
216
+
161
217
  # add_column( obj ) #=> obj
162
218
  #
163
219
  # Adds the column to this table. Throws a RamenError if the obj
@@ -192,6 +248,14 @@ module Ramen::Metadata
192
248
  end
193
249
  =end
194
250
 
251
+ # add_trigger( obj ) #=> obj
252
+ #
253
+ # Adds the trigger to this table. Throws a RamenError if the obj is not
254
+ # a Trigger.
255
+ def add_trigger( obj )
256
+ @triggers.add( obj )
257
+ end
258
+
195
259
  # set_primary_key( obj ) #=> obj
196
260
  #
197
261
  # Sets the primary key for this table.
@@ -0,0 +1,46 @@
1
+ #--
2
+ # Copyright (c) 2007 Gregory N. Houston
3
+ # See ramen.rb for license information.
4
+ #++
5
+ module Ramen::Metadata
6
+
7
+ # Trigger contains meta-data about data manipulation triggers (insert, update,
8
+ # delete). The attributes are database engine specific. Only trigger_name
9
+ # trigger_schema, event_object_schema, event_object_table are required by Ramen.
10
+ # See RowDataGateway for more information.
11
+ #
12
+ # See Database for a description of how Trigger fits in the Ramen collection
13
+ # hierarchy. For simplicity, Triggers are accessable in Ramen via their
14
+ # event_object_schema, event_object_name; that is, they are stored in the
15
+ # Table#trigger collection.
16
+ #
17
+ # Links: readme.txt[link:files/readme_txt.html]; source[link:rcov/lib-ramen-trigger_rb.html]
18
+ #
19
+ class Trigger < Ramen::RowDataGateway
20
+ # :section: External Methods
21
+ # The following methods are intended for use by Ramen's clients.
22
+
23
+ # Comparison, returns -1,0,+1, compares trigger_name
24
+ #
25
+ # TODO improve the comparison to ensure uniqueness
26
+ def <=> other
27
+ Ramen::RowDataGateway.compare( trigger_name, other )
28
+ end
29
+
30
+ # :section: Internal Methods
31
+ # The following methods are for Ramen's internal use. They
32
+ # are not intended for clients of Ramen to use.
33
+
34
+ def initialize( record, database )
35
+ super( record, database )
36
+ end
37
+
38
+ # add_to( database )
39
+ #
40
+ # Add self to the given database. (Choosing Message; Double Dispatch pattern)
41
+ # (Kent Beck. Smalltalk Best Practices Patterns. Perntice Hall PTR, Upper Saddle River, NJ 1997)
42
+ def add_to( database )
43
+ database.schema[ self.event_object_schema ].table[ self.event_object_table ].add_trigger( self )
44
+ end
45
+ end
46
+ end
data/lib/ramen/version.rb CHANGED
@@ -10,7 +10,7 @@ module Ramen
10
10
  module Version
11
11
  MAJOR = 0
12
12
  MINOR = 4
13
- REVISION = 0
13
+ REVISION = 1
14
14
  STRING = [MAJOR, MINOR, REVISION].join('.')
15
15
  end
16
16
  end
data/lib/ramen.rb CHANGED
@@ -48,6 +48,7 @@ require 'ramen/metadata/primary_key'
48
48
  require 'ramen/metadata/primary_key_column'
49
49
  require 'ramen/metadata/schema'
50
50
  require 'ramen/metadata/table'
51
+ require 'ramen/metadata/trigger'
51
52
 
52
53
  require 'ramen/engine/engine'
53
54
  require 'ramen/engine/sql2005'
data/readme.txt CHANGED
@@ -7,10 +7,33 @@ _data_ _dictionary_, _system_ _catalog_, or _INFORMATION_ _SCHEMA_.
7
7
 
8
8
  Version:: 0.4.0 SQL Server 2005 and MySQL 5.0.
9
9
 
10
- It is easy to support additional database engines. All that is needed are
11
- the SQL statements to query the metadata, and maybe a few tweaks to the
12
- unit tests. Please contact the author if you want help getting Ramen to
13
- support another database.
10
+ What can you do with Ramen?
11
+ * Build a tool for generating test data (see Noodle on Rubyforge)
12
+ * Refect the structure of your database in Ruby.
13
+ * Check your database for design problems.
14
+ * Dynamically generate code from the database's structure. (Similar to
15
+ ActiveRecord which generates the Model based on table structure.
16
+
17
+ How is Ramen different than ActiveRecord?
18
+ * ActiveRecord is for getting your data into and out of the database. Ramen is
19
+ for getting meta-data about your database design. For example, ActiveRecord can
20
+ get the Employee Name and Address from an Employees Table and Addresses Table (Data).
21
+ Ramen can tell you the database contains an Employees Table with a Name column
22
+ and a Foreign Key to an Address table which contains an Address column (Meta-data).
23
+
24
+ * ActiveRecord normalizes the data types to a few common types which will work
25
+ on many database engines. For example ActiveRecord doesn't support TIMESTAMP
26
+ which is a type in SQL Server 2005, but isn't available on other databases.
27
+ Ramen doesn't normalize the meta-data. Instead it provides the information
28
+ in as much detail as possible, even when this creates variation between
29
+ databases. (Ramen is also planning on adding a Normalization layer for
30
+ situations where a common interface is desired.)
31
+
32
+ Can Ramen support my database engine?
33
+ * Ramen 0.4.0 works with SQL Server 2005 and MySQL 5.0. It is easy to support
34
+ additional database engines. All that is needed are the SQL statements to query
35
+ the metadata, and maybe a few tweaks to the unit tests. Please contact the
36
+ author if you want help getting Ramen to support another database.
14
37
 
15
38
  == Links:
16
39
 
@@ -1,4 +1,4 @@
1
- DROP DATABASE IF EXISTS RamenTestSchema;
1
+ DROP DATABASE IF EXISTS RamenTestSchema;
2
2
  DROP DATABASE IF EXISTS RamenTestSchema2;
3
3
 
4
4
  CREATE DATABASE RamenTestSchema;
@@ -45,3 +45,38 @@ ALTER TABLE RamenTestSchema.Bug1
45
45
  # Note, MySQL cant have a foreign key that spans schemas (databases).
46
46
  # Some databases dont have this restriction.
47
47
  */
48
+ CREATE TABLE RamenTestSchema.MultiColumnPK (
49
+ PK1 INTEGER UNSIGNED NOT NULL,
50
+ PK2 INTEGER UNSIGNED NOT NULL,
51
+ PRIMARY KEY (PK1, PK2)
52
+ );
53
+
54
+ CREATE TABLE RamenTestSchema.MultiColumnFK (
55
+ PK VARCHAR(16) NOT NULL,
56
+ FK1 INTEGER UNSIGNED NOT NULL,
57
+ FK2 INTEGER UNSIGNED NOT NULL,
58
+ PRIMARY KEY (PK)
59
+ );
60
+ ALTER TABLE RamenTestSchema.MultiColumnFK
61
+ ADD CONSTRAINT FK_MultiColumnFK_MultiColumnPK
62
+ FOREIGN KEY FK_MultiColumnFK_MultiColumnPK (FK1, FK2)
63
+ REFERENCES MultiColumnPK (PK1, PK2)
64
+ ON DELETE RESTRICT
65
+ ON UPDATE RESTRICT;
66
+
67
+ CREATE TABLE RamenTestSchema.TriggerTable (
68
+ PK INTEGER UNSIGNED NOT NULL,
69
+ PRIMARY KEY (PK)
70
+ );
71
+ CREATE TRIGGER RamenTestSchema.TriggerTable_ITrig AFTER INSERT ON RamenTestSchema.TriggerTable
72
+ FOR EACH ROW BEGIN
73
+ -- do nothing
74
+ END;
75
+ CREATE TRIGGER RamenTestSchema.TriggerTable_UTrig AFTER UPDATE ON RamenTestSchema.TriggerTable
76
+ FOR EACH ROW BEGIN
77
+ -- do nothing
78
+ END;
79
+ CREATE TRIGGER RamenTestSchema.TriggerTable_DTrig AFTER DELETE ON RamenTestSchema.TriggerTable
80
+ FOR EACH ROW BEGIN
81
+ -- do nothing
82
+ END;
@@ -9,7 +9,13 @@ USE MASTER
9
9
  GO
10
10
 
11
11
  IF EXISTS (SELECT name FROM sys.databases WHERE name = N'RamenTest')
12
- DROP DATABASE RamenTest
12
+ ALTER DATABASE [RamenTest] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
13
+ GO
14
+ IF EXISTS (SELECT name FROM sys.databases WHERE name = N'RamenTest')
15
+ ALTER DATABASE [RamenTest] SET SINGLE_USER
16
+ GO
17
+ IF EXISTS (SELECT name FROM sys.databases WHERE name = N'RamenTest')
18
+ DROP DATABASE [RamenTest]
13
19
  GO
14
20
 
15
21
  CREATE DATABASE RamenTest
@@ -28,6 +34,11 @@ CREATE SCHEMA RamenTestSchema
28
34
  CONSTRAINT PK_Employee_EmployeeID PRIMARY KEY CLUSTERED (EmployeeID ASC))
29
35
  CREATE TABLE EmployeeAddress (EmployeeID int, AddressID int
30
36
  CONSTRAINT PK_EmployeeAddress_EmployeeID_AddressID PRIMARY KEY CLUSTERED (EmployeeID ASC, AddressID ASC))
37
+ CREATE TABLE MultiColumnPK (PK1 int, PK2 int
38
+ CONSTRAINT PK_MultiColumnPK PRIMARY KEY CLUSTERED(PK1 ASC, PK2 ASC))
39
+ CREATE TABLE MultiColumnFK (PK nvarchar(16), FK1 int, FK2 int
40
+ CONSTRAINT PK_MultiColumnFK PRIMARY KEY CLUSTERED(PK ASC))
41
+ CREATE TABLE TriggerTable (PK int)
31
42
  GO
32
43
 
33
44
  CREATE UNIQUE NONCLUSTERED INDEX IX_Employee_LoginID ON RamenTestSchema.Employee (LoginID ASC)
@@ -36,10 +47,21 @@ ALTER TABLE RamenTestSchema.Employee ADD CONSTRAINT FK_Employee_Employee_Manager
36
47
  ALTER TABLE RamenTestSchema.Employee CHECK CONSTRAINT FK_Employee_Employee_ManagerID
37
48
  ALTER TABLE RamenTestSchema.EmployeeAddress ADD CONSTRAINT FK_EmployeeAddress_Employee FOREIGN KEY(EmployeeID) REFERENCES RamenTestSchema.Employee (EmployeeID)
38
49
  ALTER TABLE RamenTestSchema.EmployeeAddress CHECK CONSTRAINT FK_EmployeeAddress_Employee
50
+ ALTER TABLE RamenTestSchema.MultiColumnFK ADD CONSTRAINT FK_MultiColumnFK_MultiColumnPK FOREIGN KEY(FK1, FK2) REFERENCES RamenTestSchema.MultiColumnPK (PK1, PK2)
51
+ ALTER TABLE RamenTestSchema.MultiColumnFK CHECK CONSTRAINT FK_MultiColumnFK_MultiColumnPK
52
+ GO
53
+
54
+ CREATE TRIGGER RamenTestSchema.TriggerTable_ITrig ON TriggerTable FOR INSERT AS SELECT * FROM INSERTED
55
+ GO
56
+ CREATE TRIGGER RamenTestSchema.TriggerTable_UTrig ON TriggerTable FOR UPDATE AS SELECT * FROM INSERTED
57
+ GO
58
+ CREATE TRIGGER RamenTestSchema.TriggerTable_DTrig ON TriggerTable FOR DELETE AS SELECT * FROM DELETED
59
+ GO
60
+ CREATE TRIGGER RamenTestSchema.TriggerTable_IUTrig ON TriggerTable FOR INSERT, UPDATE AS SELECT * FROM INSERTED
39
61
  GO
40
62
 
41
63
  ALTER TABLE RamenTestSchema2.Bug1 ADD CONSTRAINT FK_Bug1_Employee FOREIGN KEY(PkID) REFERENCES RamenTestSchema.Employee (EmployeeID)
42
64
  GO
43
65
 
44
- --CREATE SCHEMA Person
45
- --GO
66
+ USE MASTER
67
+ GO
data/test/test_ramen.rb CHANGED
@@ -10,6 +10,7 @@ require 'dbi'
10
10
  require 'yaml'
11
11
  require 'test/helper.rb'
12
12
  require 'test/test_bugs'
13
+ require 'pp'
13
14
 
14
15
  # not a very good test suite, but even so it has proved invaluable when
15
16
  # making changes to ensure everything is still working.
@@ -133,6 +134,17 @@ class Test_Ramen < Test::Unit::TestCase
133
134
  assert_equal( 'employeeid', table.pk.column['EmployeeID'].column_name.downcase )
134
135
  end
135
136
 
137
+ def t_trigger_access( key, db )
138
+ @name = "test_trigger_access_#{key}"
139
+ table = db.schema['RamenTestSchema'].table['TriggerTable']
140
+ begin
141
+ trigger = table.trigger['TriggerTable_ITrig']
142
+ rescue RamenError
143
+ trigger = table.trigger['triggertable_itrig'] # TODO make RamenHash case-insensitive
144
+ end
145
+ assert_equal( 'ramentestschema', trigger.trigger_schema.downcase)
146
+ end
147
+
136
148
  def t2_all( key, db, conn )
137
149
  @name = "test_all_#{key}"
138
150
  db.list_tables(conn).each do |record|
@@ -218,7 +230,16 @@ class Test_Ramen < Test::Unit::TestCase
218
230
  unless address.pk.primary_key_name == 'PRIMARY' and employee.pk.primary_key_name == 'PRIMARY' then # mysql
219
231
  compare_helper address.pk, employee.pk
220
232
  end
221
- compare_helper address.pk.column['AddressID'], employee.pk.column['EmployeeID']
233
+ compare_helper address.pk.column['AddressID'], employee.pk.column['EmployeeID']
234
+ begin
235
+ trigger1 = db.schema['RamenTestSchema'].table['TriggerTable'].trigger['TriggerTable_DTrig']
236
+ trigger2 = db.schema['RamenTestSchema'].table['TriggerTable'].trigger['TriggerTable_UTrig']
237
+ rescue RamenError
238
+ # TODO make RamenHash case-insensitive
239
+ trigger1 = db.schema['RamenTestSchema'].table['TriggerTable'].trigger['triggertable_dtrig']
240
+ trigger2 = db.schema['RamenTestSchema'].table['TriggerTable'].trigger['triggertable_utrig']
241
+ end
242
+ compare_helper trigger1, trigger2
222
243
  # compare_helper address.key['PK_EmployeeAddress_EmployeeID_AddressID'], employee.key['PK_Employee_EmployeeID']
223
244
  end
224
245
 
@@ -228,6 +249,42 @@ class Test_Ramen < Test::Unit::TestCase
228
249
  assert_equal( 1, b <=> a, "b <=> a; #{msg}")
229
250
  assert_equal( 0, a <=> a, "a <=> a; #{msg}")
230
251
  end
252
+
253
+ def t_fk_table( key, db )
254
+ @name = 'test_fk_table_#{key}'
255
+ table = db.schema['RamenTestSchema'].table['EmployeeAddress']
256
+ fk = table.fk['FK_EmployeeAddress_Employee']
257
+ assert_same( table, fk.table )
258
+ end
259
+
260
+ def t_fk_referenced_table( key, db )
261
+ @name = 'test_fk_referenced_table_#{key}'
262
+ table = db.schema['RamenTestSchema'].table['EmployeeAddress']
263
+ fk = table.fk['FK_EmployeeAddress_Employee']
264
+ referenced_table = db.schema['RamenTestSchema'].table['Employee']
265
+ assert_same( referenced_table, fk.referenced_table )
266
+ end
267
+
268
+ def t_fk_multicolumn( key, db )
269
+ @name = 'test_fk_multicolumn_#{key}'
270
+ table = db.schema['RamenTestSchema'].table['MultiColumnFK']
271
+ fk = table.fk['FK_MultiColumnFK_MultiColumnPK']
272
+ referenced_table = db.schema['RamenTestSchema'].table['MultiColumnPK']
273
+ assert_same( referenced_table, fk.referenced_table )
274
+ if fk.respond_to? :foreign_key_id
275
+ assert_equal( 4, fk.column.size )
276
+ else
277
+ assert_equal( 2, fk.column.size )
278
+ assert_equal( ['fk1', 'fk2'], fk.column.keys.sort )
279
+ end
280
+ end
281
+
282
+ def t_belongs_to( key, db )
283
+ @name = "test_belongs_to_#{key}"
284
+ belongs_to = db.schema['RamenTestSchema'].table['Employee'].belongs_to['FK_EmployeeAddress_Employee']
285
+ fk = db.schema['RamenTestSchema'].table['EmployeeAddress'].fk['FK_EmployeeAddress_Employee']
286
+ assert_same( fk, belongs_to )
287
+ end
231
288
 
232
289
  self.instance_methods.each do |method_name|
233
290
  if method_name =~ /^t_/ then
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: ramen
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.4.0
7
- date: 2008-03-14 00:00:00 -05:00
6
+ version: 0.4.1
7
+ date: 2008-04-28 00:00:00 -05:00
8
8
  summary: Ramen, database reflection library. Easy access to the definition of schemas, tables, columns, indexes, and foreign keys.
9
9
  require_paths:
10
10
  - lib
@@ -47,6 +47,7 @@ files:
47
47
  - lib/ramen/metadata/primary_key_column.rb
48
48
  - lib/ramen/metadata/schema.rb
49
49
  - lib/ramen/metadata/table.rb
50
+ - lib/ramen/metadata/trigger.rb
50
51
  - lib/ramen/ramen_error.rb
51
52
  - lib/ramen/ramen_hash.rb
52
53
  - lib/ramen/ramen_module.rb
@@ -66,9 +67,7 @@ files:
66
67
  - test/test_ramen_hash.rb
67
68
  - test/test_ramen_module.rb
68
69
  - readme.txt
69
- - doc/doc_resources/MetaData_Class_Diagram.gif
70
70
  - doc/doc_resources/MetaData_Class_Diagram.png
71
- - doc/doc_resources/Thumbs.db
72
71
  test_files:
73
72
  - test/config
74
73
  - test/config/config.yml
Binary file