Take me over?
sub reverse_engineer { my $self = shift; my $schema = shift;
my $dbh = $schema->driver->handle;
foreach my $table ( $dbh->tables )
{
my $t = $schema->make_table( name => $table );
$self->reverse_engineer_table($t);
}
}
sub reverse_engineer_table { my $self = shift; my $table = shift;
my $dbh = $table->schema->driver->handle;
my $sth = $dbh->column_info( undef, $table->schema->name, $table->name, undef );
while ( my $col_info = $sth->fetchrow_hashref )
{
use Data::Dumper; warn Dumper $col_info;
my %attr = ( name => $col_info->{COLUMN_NAME},
type => $col_info->{TYPE_NAME},
nullable => $col_info->{NULLABLE} ? 1 : 0,
);
$attr{size} =
$col_info->{COLUMN_SIZE} if $col_info->{COLUMN_SIZE};
$attr{precision} =
$col_info->{DECIMAL_DIGITS} if $col_info->{DECIMAL_DIGITS};
$attr{default} =
$col_info->{COLUMN_DEF} if defined $col_info->{COLUMN_DEF};
$attr{comment} =
$col_info->{REMARKS} if defined $col_info->{REMARKS};
$table->make_column(%attr);
}
$self->reverse_engineer_table_primary_key($table);
}
sub reverse_engineer_table_primary_key { my $self = shift; my $table = shift;
my $dbh = $table->schema->driver->handle;
my $sth = $dbh->column_info( undef, $table->schema->name, $table->name );
while ( my $pk_info = $sth->fetchrow_hashref )
{
$table->add_primary_key( $table->column( $pk_info->{COLUMN_NAME} ) );
}
}
NAME
Alzabo::RDBMSRules - Base class for Alzabo RDBMS rulesets
SYNOPSIS
use Alzabo::RDBMSRules;
my $rules = Alzabo::RDBMSRules( rules => 'MySQL' );
DESCRIPTION
This class is the base class for all Alzabo::RDBMSRules
modules. To instantiate a subclass call this class's new
method. See the "SUBCLASSING Alzabo::RDBMSRules" section for information on how to make a ruleset for the RDBMS of your choice.
METHODS
available
A list of names representing the available Alzabo::RDBMSRules
subclasses. Any one of these names would be appropriate as the rdbms
parameter for the Alzabo::RDBMSRules->new
method.
new
Parameters
rdbms => $rdbms_name
The name of the RDBMS being used.
Some subclasses may accept additional values.
Returns
A new Alzabo::RDBMSRules
object of the appropriate subclass.
schema_sql (Alzabo::Create::Schema
object)
Returns
A list of SQL statements.
index_sql (Alzabo::Create::Index
object)
Returns
A list of SQL statements.
drop_table_sql (Alzabo::Create::Table
object)
Returns
A list of SQL statements.
drop_index_sql (Alzabo::Create::Index
object)
Returns
A list of SQL statements.
schema_sql_diff
Parameters
new =>
Alzabo::Create::Schema
objectold =>
Alzabo::Create::Schema
object
Given two schema objects, this method compares them and generates the SQL necessary to turn the 'old' one into the 'new' one.
Returns
An array of SQL statements.
table_sql_diff
Parameters
new =>
Alzabo::Create::Table
objectold =>
Alzabo::Create::Table
object
Given two table objects, this method compares them and generates the SQL necessary to turn the 'old' one into the 'new' one.
Returns
An array of SQL statements.
Virtual Methods
The following methods are not implemented in the Alzabo::RDBMSRules
class itself and must be implemented in its subclasses.
column_types
Returns
A list of valid column type specifiers.
feature ($feature)
Given a string defining a feature, this method indicates whether or not the given RDBMS supports that feature. By default, this method always returns false unless overridden in the subclass.
Features that may be asked for:
extended_column_types
Column types that must be input directly from a user, as opposed to being chosen from a list. MySQL's ENUM and SET column types are examples of such types.
index_column_prefixes
MySQL supports the notion of column prefixes in indexes, allowing you to index only a portion of a large text column.
fulltext_indexes
This should be self-explanatory.
validate_schema_name (Alzabo::Schema
object)
Returns
A boolean value indicate whether the object's name is valid.
Throws
validate_table_name (Alzabo::Create::Table
object)
Returns
A boolean value indicate whether the object's name is valid.
Throws
validate_column_name (Alzabo::Create::Column
object)
Returns
A boolean value indicate whether the object's name is valid.
Throws
validate_column_type ($type_as_string)
Returns
A canonized version of the type.
Throws
validate_column_attribute
Parameters
column =>
Alzabo::Create::Column
objectattribute => $attribute
This method is a bit different from the others in that it takes an existing column object and a potential attribute.
Returns
A boolean value indicating whether or not this attribute is acceptable for the column.
Throws
validate_primary_key (Alzabo::Create::Column
object)
Returns
Returns a boolean value indicating whether or not the given column can be part of its table's primary key.
Throws
validate_sequenced_attribute (Alzabo::Create::Column
object)
Given a column object, indicates whether or not the column can be sequenced.
Throws
validate_index (Alzabo::Create::Index
object)
Returns
A boolean value indicating whether or not the index is valid.
Throws
table_sql (Alzabo::Create::Table
object)
Returns
A list of SQL statements.
column_sql (Alzabo::Create::Column
object)
Returns
A list of SQL statements.
foreign_key_sql (Alzabo::Create::ForeignKey
object)
Returns
A list of SQL statements.
drop_column_sql (Alzabo::Create::Column
object)
Returns
A list of SQL statements.
drop_foreign_key_sql (Alzabo::Create::ForeignKey
object)
Returns
A list of SQL statements.
column_sql_add (Alzabo::Create::Column
object)
Returns
A list of SQL statements.
column_sql_diff
Parameters
new =>
Alzabo::Create::Column
objectold =>
Alzabo::Create::Column
object
Given two column objects, this method compares them and generates the SQL necessary to turn the 'old' one into the 'new' one.
Returns
A list of SQL statements.
index_sql_diff
Parameters
new =>
Alzabo::Create::Index
objectold =>
Alzabo::Create::Index
object
Given two index objects, this method compares them and generates the SQL necessary to turn the 'old' one into the 'new' one.
Returns
A list of SQL statements.
alter_primary_key_sql
Parameters
new =>
Alzabo::Create::Table
objectold =>
Alzabo::Create::Table
object
Given two table objects, this method compares them and generates the SQL necessary to give change the primary key from the 'old' one's primary key to the 'new' one's primary key.
Returns
A list of SQL statements.
reverse_engineer (Alzabo::Create::Schema
object)
Given a schema object (which presumably has no tables), this method uses the schema's Alzabo::Driver
object to connect to an existing database and reverse engineer it into the appopriate Alzabo objects.
SUBCLASSING Alzabo::RDBMSRules
To create a subclass of Alzabo::RDBMSRules
for your particular RDBMS is fairly simple.
Here's a sample header to the module using a fictional RDBMS called FooDB:
package Alzabo::RDBMSRules::FooDB;
use strict;
use vars qw($VERSION);
use Alzabo::RDBMSRules;
use base qw(Alzabo::RDBMSRules);
The next step is to implement a new
method and the methods listed under the section "Virtual Methods". The new method should look a bit like this:
1: sub new
2: {
3: my $proto = shift;
4: my $class = ref $proto || $proto;
5: my %p = @_;
6:
7: my $self = bless {}, $self;
8:
9: return $self;
10: }
The hash %p contains any values passed to the Alzabo::RDBMSRules->new
method by its caller.
Lines 1-7 should probably be copied verbatim into your own new
method. Line 5 can be deleted if you don't need to look at the parameters.
The rest of your module should simply implement the methods listed under the "Virtual Methods" section of this documentation.
Look at the included Alzabo::RDBMSRules
subclasses for examples. Feel free to contact me for further help if you get stuck. Please tell me what database you're attempting to implement, and include the code you've written so far.
AUTHOR
Dave Rolsky, <dave@urth.org>