Alzabo...SRules(3pm)

πŸ“¦
version 0.92 Β· 2 versions
  • 0.92 Β· debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking (latest)
  • 0.92 Β· ubuntu jammy
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Alzabo::RDBMSRules πŸ’–

okay bestie, so this is the manual page for Alzabo...SRules(3pm) β€” yes that's the abbreviated name up in the header, it's literally Alzabo::RDBMSRules, and it lives under "User Contributed Perl Documentation". buckle up πŸŽ€


🧚 the code at the top (verbatim, do not touch, i mean it)

before we even get to the sections, the page opens with actual real code, and we do not paraphrase code in this house. here it is, character for character, exactly as printed:

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} ) );
           }
       }

the way that warn Dumper $col_info; is just sitting there in the middle, iconic honestly. πŸ’€ anyway.


✨ NAME ✨

Alzabo::RDBMSRules β€” the base class for Alzabo RDBMS rulesets. that's the whole name section, short and sweet, main character energy. πŸ‘‘


🌈 SYNOPSIS 🌈

here's the vibe check, in code:

use Alzabo::RDBMSRules;

my $rules = Alzabo::RDBMSRules( rules => 'MySQL' );

so you use it, then you construct one by handing it a rules key with a value like 'MySQL'. slay. πŸ’…


πŸ¦‹ DESCRIPTION πŸ¦‹

okay so listen: this class is the base class for all the Alzabo::RDBMSRules modules. it's the mother, the blueprint, the blueprint-mother. 🌸

if you wanna actually instantiate one of its subclasses, you do it by calling this class's new() method. yes, new(), that one. that's the move. ✨

and if you're sitting there like "okay but what if my RDBMS isn't represented, what if i wanna make my own ruleset" β€” periodt, they thought of you. go look at the "SUBCLASSING Alzabo::RDBMSRules" section, it's got the whole rundown on how to build a ruleset for the RDBMS of your choice. 🫢

lowkey the whole point of this page is "here's the base class, go read the subclassing section" and honestly? respect. 😌

πŸ’– METHODS πŸ’–

available

A whole list of names that stand for the available Alzabo::RDBMSRules subclasses. Any one of these names would be a perfectly good rdbms parameter to hand to the Alzabo::RDBMSRules->new() method. So like, pick your fave. πŸŽ€

new

The constructor literally always takes one parameter, rdbms, and that's the name of the RDBMS you're working with. Some subclasses might want extra values too, they're extra like that. ✨

The constructor hands you back a shiny new Alzabo::RDBMSRules object of whatever subclass matches up.

Throws: Alzabo::Exception::Eval

schema_sql ("Alzabo::Create::Schema" object)

Returns a list of SQL statements that would create the given schema. Building the whole thing from scratch, no cap. πŸ—οΈ

index_sql ("Alzabo::Create::Index" object)

Returns a list of SQL statements to create the specified index.

drop_table_sql ("Alzabo::Create::Table" object)

Returns a list of SQL statements to drop the specified table. bye bestie πŸ‘‹

drop_index_sql ("Alzabo::Create::Index" object)

Returns a list of SQL statements to drop the specified index.

schema_sql_diff

This one takes two parameters:

  • new => Alzabo::Create::Schema object
  • old => Alzabo::Create::Schema object

It compares the two schema objects and returns an array of SQL statements that turn the old schema into the new one. glow-up incoming πŸ”₯

table_sql_diff

This one takes two parameters:

  • new => Alzabo::Create::Table object
  • old => Alzabo::Create::Table object

It compares the two table objects and returns an array of SQL statements that turn the old table into the new one.

type_is_numeric ("Alzabo::Column" object)

Returns a boolean telling you whether the column is numeric or not β€” that means integer or floating point. πŸ’―

quote_identifiers

Returns true or false, indicating whether the generated DDL SQL statements should have their identifiers quoted or not. Subclasses are allowed to override this. It defaults to false.

can_alter_table_name

If this is true, then when syncing a schema, the object will call alter_table_name_sql() to change the table's name. Otherwise it calls recreate_table_sql().

can_alter_column_name

If this is true, then when syncing a schema, the object will call alter_column_name_sql() to change the table's name. Otherwise it calls recreate_table_sql().


πŸ¦‹ Virtual Methods πŸ¦‹

Okay so these next ones are not implemented in the Alzabo::RDBMSRules class itself. You have to implement them in its subclasses. It's giving homework but make it SQL. πŸ“

column_types

Returns a list of valid column types.

feature ($feature)

You hand it a string that defines a feature, and it tells you whether or not the given RDBMS supports that feature. By default this method always returns false unless a subclass overrides it.

Features you might ask for:

  • extended_column_types Column types that have to be typed in directly by a user, as opposed to being picked off a list. MySQL's ENUM and SET types are examples of these.
  • index_column_prefixes MySQL supports the notion of column prefixes in indexes, which lets you index only a portion of a big text column. iconic honestly
  • fulltext_indexes This should be self-explanatory. 😌
  • functional_indexes Indexes on functions, as supported by PostgreSQL.

validate_schema_name ("Alzabo::Schema" object)

Throws an Alzabo::Exception::RDBMSRules if the schema's name is not valid.

validate_table_name ("Alzabo::Create::Table" object)

Throws an Alzabo::Exception::RDBMSRules if the table's name is not valid.

validate_column_name ("Alzabo::Create::Column" object)

Throws an Alzabo::Exception::RDBMSRules if the column's name is not valid.

validate_column_type ($type_as_string)

Throws an Alzabo::Exception::RDBMSRules if the type is not valid.

This method returns a canonized version of the type. ✨

validate_column_length ("Alzabo::Create::Column" object)

Throws an Alzabo::Exception::RDBMSRules if the length or precision is not valid for the given column.

validate_column_attribute

This one takes two parameters:

  • column => Alzabo::Create::Column object
  • attribute => $attribute

This method is a bit different from the others because it takes an existing column object and a potential attribute.

It throws an Alzabo::Exception::RDBMSRules if the attribute is is not valid for the column.

validate_primary_key ("Alzabo::Create::Column" object)

Throws an Alzabo::Exception::RDBMSRules if the column is not a valid primary key for its table.

validate_sequenced_attribute ("Alzabo::Create::Column" object)

Throws an Alzabo::Exception::RDBMSRules if the column cannot be sequenced.

validate_index ("Alzabo::Create::Index" object)

Throws an Alzabo::Exception::RDBMSRules if the index is not valid.

table_sql ("Alzabo::Create::Table" object)

Returns an array of SQL statements to create the specified table.

column_sql ("Alzabo::Create::Column" object)

Returns an array of SQL statements to create the specified column.

foreign_key_sql ("Alzabo::Create::ForeignKey" object)

Returns an array of SQL statements to create the specified foreign key.

drop_column_sql ("Alzabo::Create::Column" object)

Returns an array of SQL statements to drop the specified column.

drop_foreign_key_sql ("Alzabo::Create::ForeignKey" object)

Returns an array of SQL statements to drop the specified foreign key.

column_sql_add ("Alzabo::Create::Column" object)

Returns an array of SQL statements to add the specified column.

column_sql_diff

This one takes two parameters:

  • new => Alzabo::Create::Column object
  • old => Alzabo::Create::Column object

It compares the two table objects and returns an array of SQL statements that turn the old table into the new one.

index_sql_diff

This one takes two parameters:

  • new => Alzabo::Create::Index object
  • old => Alzabo::Create::Index object

It compares the two index objects and returns an array of SQL statements that turn the old index into the new one.

alter_primary_key_sql

This one takes two parameters:

  • new => Alzabo::Create::Table object
  • old => Alzabo::Create::Table object

It compares the two table objects and returns an array of SQL statements that alter the old one's primary key so it matches the new one's.

alter_table_name_sql ("Alzabo::Create::Table" object)

Give it a table, and this method is expected to change the table's name from $table->former_name to $table->name. This only gets called if the rules object returns true for can_alter_table_name().

alter_column_name_sql ("Alzabo::Create::Table" object)

Give it a column, and this method is expected to change the table's name from $column->former_name to $column->name. This only gets called if the rules object returns true for can_alter_column_name().

recreate_table_sql

This one takes two parameters:

  • new => Alzabo::Create::Table object
  • old => Alzabo::Create::Table object

This method is expected to drop the old table and create the new one.

But listen β€” it must preserve all the data stored in the old table, excluding data in columns that are being dropped. And on top of that, if there are sequences associated with columns in the old table, they should not be dropped. no pressure bestie 😭

This method will only be called if either can_alter_table_name() or can_alter_column_name() return false.

reverse_engineer ("Alzabo::Create::Schema" object)

Give it a schema object (which presumably has no tables), and this method uses the schema's Alzabo::Driver object to connect to an existing database and reverse engineer it into the appropriate Alzabo objects. turning a whole database into objects, main character energy πŸ‘‘

type_is_integer ("Alzabo::Column" object)

Returns a boolean telling you whether or not the column is an integer type.

type_is_floating_point ("Alzabo::Column" object)

Returns a boolean telling you whether or not the column is a floating point type.

type_is_character ("Alzabo::Column" object)

Returns a boolean telling you whether or not the column is a character type. This is defined as any type which is defined to store text, regardless of length. πŸ“

type_is_date ("Alzabo::Column" object)

Returns a boolean telling you whether or not the column is a date type. This is not true for datetime types. important distinction, don't mix them up πŸ—“οΈ

type_is_datetime ("Alzabo::Column" object)

Returns a boolean telling you whether or not the column is a datetime type. This is not true for date types.

type_is_time ("Alzabo::Column" object)

Returns a boolean telling you whether or not the column is a time type. This is not true for datetime types. ⏰

type_is_time_interval ("Alzabo::Column" object)

Returns a boolean telling you whether or not the column is a time interval type.


🌈 SUBCLASSING Alzabo::RDBMSRules 🌈

Making your own subclass of Alzabo::RDBMSRules for your particular RDBMS is honestly pretty simple. slay.

Here's a sample header for 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);

Next step: implement a new() method and all the methods listed under the Virtual Methods section. The new method should look a little something 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. that's it, that's the whole vibe ✨

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. we love a detailed bug report 🫢


πŸ‘‘ AUTHOR πŸ‘‘

Dave Rolsky, <dave@urth.org>


and that's a wrap bestie!! πŸŽ€ this whole thing was documented for perl v5.34.0, dated 2022-06-14 β€” iconic, historic, no notes πŸ’…πŸ’–

πŸ“¦ where this page comes from