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.
- data/doc/doc_resources/MetaData_Class_Diagram.png +0 -0
- data/lib/ramen/engine/mysql.rb +52 -4
- data/lib/ramen/engine/sql2005.rb +42 -1
- data/lib/ramen/metadata/database.rb +3 -3
- data/lib/ramen/metadata/foreign_key.rb +18 -1
- data/lib/ramen/metadata/table.rb +65 -1
- data/lib/ramen/metadata/trigger.rb +46 -0
- data/lib/ramen/version.rb +1 -1
- data/lib/ramen.rb +1 -0
- data/readme.txt +27 -4
- data/test/mysql_create_test_db.sql +36 -1
- data/test/sql2005_create_test_db.sql +25 -3
- data/test/test_ramen.rb +58 -1
- metadata +3 -4
- data/doc/doc_resources/MetaData_Class_Diagram.gif +0 -0
- data/doc/doc_resources/Thumbs.db +0 -0
|
Binary file
|
data/lib/ramen/engine/mysql.rb
CHANGED
|
@@ -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,
|
|
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
|
data/lib/ramen/engine/sql2005.rb
CHANGED
|
@@ -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
|
|
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
|
-
#
|
|
17
|
+
# Trigger objects. ForeignKey contains ForeignKeyColumn objects; which
|
|
18
18
|
# reference the appropriate Column. Index contains IndexColumn objects; which
|
|
19
|
-
# reference the appropriate Column.
|
|
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
|
-
|
|
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
|
data/lib/ramen/metadata/table.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
#++
|
|
5
5
|
|
|
6
6
|
module Ramen::Metadata
|
|
7
|
-
# Table contains collections of Column, ForeignKey, Index,
|
|
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
data/lib/ramen.rb
CHANGED
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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.
|
|
7
|
-
date: 2008-
|
|
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
|
data/doc/doc_resources/Thumbs.db
DELETED
|
Binary file
|